Merge branch '1.10.x' of https://github.com/chamilo/chamilo-lms into B9082

Conflicts:
	.gitignore
1.10.x
Angel Fernando Quiroz Campos 11 years ago
commit dfdb3fcce7
  1. 15
      .gitattributes
  2. 3
      .gitignore
  3. 0
      archive/.htaccess
  4. 38
      composer.json
  5. 278
      composer.lock
  6. 6
      data/index.html
  7. 3
      documentation/changelog.html
  8. 18
      documentation/installation_guide.html
  9. 29
      documentation/optimization.html
  10. 89
      main/admin/dashboard_add_users_to_user.php
  11. 2
      main/admin/example_class.csv
  12. 74
      main/admin/index.php
  13. 101
      main/admin/resume_session.php
  14. 50
      main/admin/session_add.php
  15. 72
      main/admin/session_edit.php
  16. 3
      main/admin/session_user_edit.php
  17. 2
      main/admin/skills_wheel.php
  18. 2
      main/admin/statistics/statistics.lib.php
  19. 344
      main/admin/teacher_time_report.php
  20. 1
      main/admin/user_add.php
  21. 1
      main/admin/user_edit.php
  22. 36
      main/admin/user_list.php
  23. 12
      main/admin/usergroup_export.php
  24. 32
      main/admin/usergroup_import.php
  25. 65
      main/announcements/announcements.php
  26. 2
      main/attendance/index.php
  27. 7
      main/auth/courses_controller.php
  28. 4
      main/auth/inscription.php
  29. 14
      main/auth/my_progress.php
  30. 36
      main/calendar/agenda.lib.php
  31. 12
      main/calendar/agenda.php
  32. 8
      main/calendar/agenda_js.php
  33. 4
      main/calendar/agenda_list.php
  34. 2
      main/chat/chat_functions.lib.php
  35. 1
      main/course_info/infocours.php
  36. 2
      main/course_notice/index.php
  37. 4
      main/coursecopy/copy_course_session_selected.php
  38. 105
      main/cron/fix_online_time.php
  39. 172
      main/cron/import_csv.php
  40. 3
      main/cron/user_import/client.php
  41. 181
      main/css/base.css
  42. 36
      main/css/base_chamilo.css
  43. 4
      main/css/chamilo/default.css
  44. 10
      main/document/create_audio.php
  45. 16
      main/document/document.php
  46. 36
      main/document/file.php
  47. 4
      main/exercice/exercise.class.php
  48. 6
      main/exercice/exercise.lib.php
  49. 2
      main/exercice/exercise_report.php
  50. 6
      main/exercice/exercise_show.php
  51. 6
      main/exercice/export/aiken/aiken_import.inc.php
  52. 714
      main/exercice/export/exercise_import.inc.php
  53. 1
      main/exercice/export/exercise_import.php
  54. 578
      main/exercice/export/qti/qti_classes.php
  55. 351
      main/exercice/export/qti/qti_export.php
  56. 202
      main/fonts/opensans/LICENSE.txt
  57. BIN
      main/fonts/opensans/OpenSans-Bold.ttf
  58. BIN
      main/fonts/opensans/OpenSans-BoldItalic.ttf
  59. BIN
      main/fonts/opensans/OpenSans-ExtraBold.ttf
  60. BIN
      main/fonts/opensans/OpenSans-ExtraBoldItalic.ttf
  61. BIN
      main/fonts/opensans/OpenSans-Italic.ttf
  62. BIN
      main/fonts/opensans/OpenSans-Light.ttf
  63. BIN
      main/fonts/opensans/OpenSans-LightItalic.ttf
  64. BIN
      main/fonts/opensans/OpenSans-Regular.ttf
  65. BIN
      main/fonts/opensans/OpenSans-Semibold.ttf
  66. BIN
      main/fonts/opensans/OpenSans-SemiboldItalic.ttf
  67. 3
      main/gradebook/gradebook.php
  68. 3
      main/gradebook/gradebook_flatview.php
  69. 1
      main/gradebook/gradebook_view_result.php
  70. 3
      main/gradebook/index.php
  71. 30
      main/gradebook/lib/be/category.class.php
  72. 16
      main/gradebook/lib/be/evallink.class.php
  73. 2
      main/gradebook/lib/be/exerciselink.class.php
  74. 25
      main/gradebook/lib/be/studentpublicationlink.class.php
  75. 6
      main/gradebook/lib/fe/exportgradebook.php
  76. 490
      main/gradebook/lib/fe/flatviewtable.class.php
  77. 25
      main/gradebook/lib/flatview_data_generator.class.php
  78. 4
      main/gradebook/lib/scoredisplay.class.php
  79. 2
      main/gradebook/user_stats.php
  80. 6
      main/group/example.csv
  81. 7
      main/group/group.php
  82. 27
      main/group/group_overview.php
  83. 4
      main/group/import.php
  84. BIN
      main/img/icons/16/statistics.png
  85. BIN
      main/img/icons/16/statistics_na.png
  86. BIN
      main/img/icons/22/statistics.png
  87. BIN
      main/img/icons/22/survey.png
  88. 68
      main/inc/ajax/admin.ajax.php
  89. 7
      main/inc/ajax/agenda.ajax.php
  90. 2
      main/inc/ajax/install.ajax.php
  91. 2
      main/inc/ajax/model.ajax.php
  92. 2
      main/inc/ajax/myspace.ajax.php
  93. 17
      main/inc/ajax/session.ajax.php
  94. 17
      main/inc/autoload.inc.php
  95. 32
      main/inc/global.inc.php
  96. 0
      main/inc/lib/AnnouncementEmail.php
  97. 101
      main/inc/lib/TeacherTimeReport.php
  98. 4
      main/inc/lib/add_course.lib.inc.php
  99. 2
      main/inc/lib/auth.lib.php
  100. 1190
      main/inc/lib/autoload.class.php
  101. Some files were not shown because too many files have changed in this diff Show More

15
.gitattributes vendored

@ -2,3 +2,18 @@
.gitignore export-ignore
.travis.yml export-ignore
/tests export-ignore
/vendor/ezyang/htmlpurifier/docs export-ignore
/vendor/ezyang/htmlpurifier/benchmarks export-ignore
/vendor/ezyang/htmlpurifier/tests export-ignore
/vendor/ezyang/htmlpurifier/smoketests export-ignore
/vendor/ezyang/htmlpurifier/package.php export-ignore
/vendor/ezyang/htmlpurifier/release1-update.php export-ignore
/vendor/ezyang/htmlpurifier/release2-tag.php export-ignore
/vendor/ezyang/htmlpurifier/test-settings.sample.php export-ignore
/vendor/twig/twig/test export-ignore
/vendor/monolog/monolog/tests/ export-ignore
/vendor/neutron/temporary-filesystem/tests export-ignore
/vendor/sabre/vobject/tests export-ignore
/vendor/twig/twig/test export-ignore
/vendor/symfony/console/Symfony/Component/Console/Tests export-ignore

3
.gitignore vendored

@ -36,5 +36,4 @@ nbproject/*
plugin/bbb/config.vm.php
# Badges images
main/upload/data/badges/*
main/cron/incoming/

@ -1,11 +1,47 @@
{
"name": "chamilo/chamilo-lms",
"description": "E-learning and collaboration software",
"type": "project",
"homepage": "http://www.chamilo.org",
"license": "GPL-3.0",
"support": {
"forum": "http://www.chamilo.org/forum",
"irc": "irc://irc.freenode.org/chamilo"
},
"autoload": {
"classmap": [
"main/auth",
"main/admin",
"main/cron/lang",
"main/coursecopy",
"main/exercice",
"main/gradebook/lib",
"main/newscorm",
"main/inc/lib",
"plugin",
"main/install",
"main/inc/lib/getid3",
"main/survey",
"main/inc/lib/hook"
]
},
"require": {
"php": ">=5.3.3",
"php-ffmpeg/php-ffmpeg": "0.3.x-dev@dev",
"sabre/vobject": "~3.1",
"toin0u/digitalocean": "~1.4",
"twig/twig": "1.*",
"michelf/php-markdown": "1.4.1",
"emojione/emojione": "1.3.0",
"zendframework/zend-config": "2.3.3"
"zendframework/zend-config": "2.3.3",
"ezyang/htmlpurifier": "4.6.0",
"szymach/c-pchart": "1.*",
"aferrandini/phpqrcode": "1.0.1",
"mpdf/mpdf": "5.7.4"
},
"extra": {
"branch-alias": {
"dev-master": "1.10.x-dev"
}
}
}

278
composer.lock generated

@ -4,8 +4,52 @@
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "1abe77cf0b8752805b4ac0e3cde352b0",
"hash": "869c0f0cb81f3231bc4f679445bcc110",
"packages": [
{
"name": "aferrandini/phpqrcode",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/aferrandini/PHPQRCode.git",
"reference": "3c1c0454d43710ab5bbe19a51ad4cb41c22e3d46"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/aferrandini/PHPQRCode/zipball/3c1c0454d43710ab5bbe19a51ad4cb41c22e3d46",
"reference": "3c1c0454d43710ab5bbe19a51ad4cb41c22e3d46",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"autoload": {
"psr-0": {
"PHPQRCode": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ariel Ferrandini",
"email": "arielferrandini@gmail.com",
"homepage": "http://www.ferrandini.com/",
"role": "Developer"
}
],
"description": "PHPQRCode porting and changed for PHP 5.3 compatibility",
"homepage": "https://github.com/aferrandini/PHPQRCode",
"keywords": [
"barcode",
"php",
"qrcode"
],
"time": "2013-07-08 09:39:08"
},
{
"name": "alchemy/binary-driver",
"version": "1.5.0",
@ -65,16 +109,16 @@
},
{
"name": "doctrine/cache",
"version": "v1.3.1",
"version": "v1.4.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/cache.git",
"reference": "cf483685798a72c93bf4206e3dd6358ea07d64e7"
"reference": "2346085d2b027b233ae1d5de59b07440b9f288c8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/cache/zipball/cf483685798a72c93bf4206e3dd6358ea07d64e7",
"reference": "cf483685798a72c93bf4206e3dd6358ea07d64e7",
"url": "https://api.github.com/repos/doctrine/cache/zipball/2346085d2b027b233ae1d5de59b07440b9f288c8",
"reference": "2346085d2b027b233ae1d5de59b07440b9f288c8",
"shasum": ""
},
"require": {
@ -85,6 +129,7 @@
},
"require-dev": {
"phpunit/phpunit": ">=3.7",
"predis/predis": "~0.8",
"satooshi/php-coveralls": "~0.6"
},
"type": "library",
@ -130,7 +175,7 @@
"cache",
"caching"
],
"time": "2014-09-17 14:24:04"
"time": "2015-01-15 20:38:55"
},
{
"name": "emojione/emojione",
@ -210,6 +255,50 @@
],
"time": "2012-05-30 15:01:08"
},
{
"name": "ezyang/htmlpurifier",
"version": "v4.6.0",
"source": {
"type": "git",
"url": "https://github.com/ezyang/htmlpurifier.git",
"reference": "6f389f0f25b90d0b495308efcfa073981177f0fd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/6f389f0f25b90d0b495308efcfa073981177f0fd",
"reference": "6f389f0f25b90d0b495308efcfa073981177f0fd",
"shasum": ""
},
"require": {
"php": ">=5.2"
},
"type": "library",
"autoload": {
"psr-0": {
"HTMLPurifier": "library/"
},
"files": [
"library/HTMLPurifier.composer.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL"
],
"authors": [
{
"name": "Edward Z. Yang",
"email": "admin@htmlpurifier.org",
"homepage": "http://ezyang.com"
}
],
"description": "Standards compliant HTML filter written in PHP",
"homepage": "http://htmlpurifier.org/",
"keywords": [
"html"
],
"time": "2013-11-30 08:25:19"
},
{
"name": "michelf/php-markdown",
"version": "1.4.1",
@ -263,16 +352,16 @@
},
{
"name": "monolog/monolog",
"version": "1.11.0",
"version": "1.12.0",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/monolog.git",
"reference": "ec3961874c43840e96da3a8a1ed20d8c73d7e5aa"
"reference": "1fbe8c2641f2b163addf49cc5e18f144bec6b19f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/ec3961874c43840e96da3a8a1ed20d8c73d7e5aa",
"reference": "ec3961874c43840e96da3a8a1ed20d8c73d7e5aa",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/1fbe8c2641f2b163addf49cc5e18f144bec6b19f",
"reference": "1fbe8c2641f2b163addf49cc5e18f144bec6b19f",
"shasum": ""
},
"require": {
@ -286,7 +375,7 @@
"aws/aws-sdk-php": "~2.4, >2.4.8",
"doctrine/couchdb": "~1.0@dev",
"graylog2/gelf-php": "~1.0",
"phpunit/phpunit": "~3.7.0",
"phpunit/phpunit": "~4.0",
"raven/raven": "~0.5",
"ruflin/elastica": "0.90.*",
"videlalvaro/php-amqplib": "~2.4"
@ -305,7 +394,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.11.x-dev"
"dev-master": "1.12.x-dev"
}
},
"autoload": {
@ -331,7 +420,50 @@
"logging",
"psr-3"
],
"time": "2014-09-30 13:30:58"
"time": "2014-12-29 21:29:35"
},
{
"name": "mpdf/mpdf",
"version": "v5.7.4",
"source": {
"type": "git",
"url": "https://github.com/finwe/mpdf.git",
"reference": "f9a374c7ea975ce8c795cec4dfd17ef55addac9c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/finwe/mpdf/zipball/f9a374c7ea975ce8c795cec4dfd17ef55addac9c",
"reference": "f9a374c7ea975ce8c795cec4dfd17ef55addac9c",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": ">=4.3.10"
},
"type": "library",
"autoload": {
"classmap": [
"mpdf.php",
"classes"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"GPL-1.0+"
],
"authors": [
{
"name": "Ian Back"
}
],
"description": "A PHP class to generate PDF files from HTML with Unicode/UTF-8 and CJK support",
"homepage": "http://www.mpdf1.com/mpdf/index.php",
"keywords": [
"pdf",
"php",
"utf-8"
],
"time": "2014-12-14 18:32:11"
},
{
"name": "neutron/temporary-filesystem",
@ -482,16 +614,16 @@
},
{
"name": "sabre/vobject",
"version": "3.3.4",
"version": "3.3.5",
"source": {
"type": "git",
"url": "https://github.com/fruux/sabre-vobject.git",
"reference": "e7cbc59a7a77325dfa32924865e1802c9216a3e0"
"reference": "77cb636a5bde4c19d7522c2c548b258859ddd1ef"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fruux/sabre-vobject/zipball/e7cbc59a7a77325dfa32924865e1802c9216a3e0",
"reference": "e7cbc59a7a77325dfa32924865e1802c9216a3e0",
"url": "https://api.github.com/repos/fruux/sabre-vobject/zipball/77cb636a5bde4c19d7522c2c548b258859ddd1ef",
"reference": "77cb636a5bde4c19d7522c2c548b258859ddd1ef",
"shasum": ""
},
"require": {
@ -544,21 +676,21 @@
"jCard",
"vCard"
],
"time": "2014-11-19 22:15:24"
"time": "2015-01-10 00:54:52"
},
{
"name": "symfony/console",
"version": "v2.6.1",
"version": "v2.6.4",
"target-dir": "Symfony/Component/Console",
"source": {
"type": "git",
"url": "https://github.com/symfony/Console.git",
"reference": "ef825fd9f809d275926547c9e57cbf14968793e8"
"reference": "e44154bfe3e41e8267d7a3794cd9da9a51cfac34"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Console/zipball/ef825fd9f809d275926547c9e57cbf14968793e8",
"reference": "ef825fd9f809d275926547c9e57cbf14968793e8",
"url": "https://api.github.com/repos/symfony/Console/zipball/e44154bfe3e41e8267d7a3794cd9da9a51cfac34",
"reference": "e44154bfe3e41e8267d7a3794cd9da9a51cfac34",
"shasum": ""
},
"require": {
@ -601,21 +733,21 @@
],
"description": "Symfony Console Component",
"homepage": "http://symfony.com",
"time": "2014-12-02 20:19:20"
"time": "2015-01-25 04:39:26"
},
{
"name": "symfony/filesystem",
"version": "v2.6.1",
"version": "v2.6.4",
"target-dir": "Symfony/Component/Filesystem",
"source": {
"type": "git",
"url": "https://github.com/symfony/Filesystem.git",
"reference": "ff6efc95256cb33031933729e68b01d720b5436b"
"reference": "a1f566d1f92e142fa1593f4555d6d89e3044a9b7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Filesystem/zipball/ff6efc95256cb33031933729e68b01d720b5436b",
"reference": "ff6efc95256cb33031933729e68b01d720b5436b",
"url": "https://api.github.com/repos/symfony/Filesystem/zipball/a1f566d1f92e142fa1593f4555d6d89e3044a9b7",
"reference": "a1f566d1f92e142fa1593f4555d6d89e3044a9b7",
"shasum": ""
},
"require": {
@ -648,21 +780,21 @@
],
"description": "Symfony Filesystem Component",
"homepage": "http://symfony.com",
"time": "2014-12-02 20:19:20"
"time": "2015-01-03 21:13:09"
},
{
"name": "symfony/process",
"version": "v2.6.1",
"version": "v2.6.4",
"target-dir": "Symfony/Component/Process",
"source": {
"type": "git",
"url": "https://github.com/symfony/Process.git",
"reference": "bf0c9bd625f13b0b0bbe39919225cf145dfb935a"
"reference": "ecfc23e89d9967999fa5f60a1e9af7384396e9ae"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Process/zipball/bf0c9bd625f13b0b0bbe39919225cf145dfb935a",
"reference": "bf0c9bd625f13b0b0bbe39919225cf145dfb935a",
"url": "https://api.github.com/repos/symfony/Process/zipball/ecfc23e89d9967999fa5f60a1e9af7384396e9ae",
"reference": "ecfc23e89d9967999fa5f60a1e9af7384396e9ae",
"shasum": ""
},
"require": {
@ -693,23 +825,26 @@
"email": "fabien@symfony.com"
}
],
"description": "Symfony Process Component",
"homepage": "http://symfony.com",
"time": "2014-12-02 20:19:20"
"description": "Standards compliant HTML filter written in PHP",
"homepage": "http://htmlpurifier.org/",
"keywords": [
"html"
],
"time": "2015-01-25 04:39:26"
},
{
"name": "symfony/yaml",
"version": "v2.6.1",
"version": "v2.6.4",
"target-dir": "Symfony/Component/Yaml",
"source": {
"type": "git",
"url": "https://github.com/symfony/Yaml.git",
"reference": "3346fc090a3eb6b53d408db2903b241af51dcb20"
"reference": "60ed7751671113cf1ee7d7778e691642c2e9acd8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Yaml/zipball/3346fc090a3eb6b53d408db2903b241af51dcb20",
"reference": "3346fc090a3eb6b53d408db2903b241af51dcb20",
"url": "https://api.github.com/repos/symfony/Yaml/zipball/60ed7751671113cf1ee7d7778e691642c2e9acd8",
"reference": "60ed7751671113cf1ee7d7778e691642c2e9acd8",
"shasum": ""
},
"require": {
@ -742,7 +877,49 @@
],
"description": "Symfony Yaml Component",
"homepage": "http://symfony.com",
"time": "2014-12-02 20:19:20"
"time": "2015-01-25 04:39:26"
},
{
"name": "szymach/c-pchart",
"version": "1.1.5",
"source": {
"type": "git",
"url": "https://github.com/szymach/c-pchart.git",
"reference": "1d54c14f8b7295abc87039ba806fed45d29d67d9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/szymach/c-pchart/zipball/1d54c14f8b7295abc87039ba806fed45d29d67d9",
"reference": "1d54c14f8b7295abc87039ba806fed45d29d67d9",
"shasum": ""
},
"require": {
"ext-gd": "*",
"php": ">=5.3.3"
},
"type": "project",
"autoload": {
"psr-4": {
"CpChart\\": "src/"
},
"files": [
"src/Resources/data/constants.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "Port of \"pChart\" library into PHP 5.3.",
"homepage": "https://github.com/szymach/c-pchart",
"keywords": [
"c-pChart",
"charts",
"composer",
"pchart",
"statistics"
],
"time": "2015-01-28 19:54:53"
},
{
"name": "toin0u/digitalocean",
@ -866,16 +1043,16 @@
},
{
"name": "twig/twig",
"version": "v1.16.2",
"version": "v1.18.0",
"source": {
"type": "git",
"url": "https://github.com/fabpot/Twig.git",
"reference": "42f758d9fe2146d1f0470604fc05ee43580873fc"
"url": "https://github.com/twigphp/Twig.git",
"reference": "4cf7464348e7f9893a93f7096a90b73722be99cf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fabpot/Twig/zipball/42f758d9fe2146d1f0470604fc05ee43580873fc",
"reference": "42f758d9fe2146d1f0470604fc05ee43580873fc",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/4cf7464348e7f9893a93f7096a90b73722be99cf",
"reference": "4cf7464348e7f9893a93f7096a90b73722be99cf",
"shasum": ""
},
"require": {
@ -884,7 +1061,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.16-dev"
"dev-master": "1.18-dev"
}
},
"autoload": {
@ -910,7 +1087,7 @@
},
{
"name": "Twig Team",
"homepage": "https://github.com/fabpot/Twig/graphs/contributors",
"homepage": "http://twig.sensiolabs.org/contributors",
"role": "Contributors"
}
],
@ -919,7 +1096,7 @@
"keywords": [
"templating"
],
"time": "2014-10-17 12:53:44"
"time": "2015-01-25 17:32:08"
},
{
"name": "zendframework/zend-config",
@ -1035,6 +1212,9 @@
"php-ffmpeg/php-ffmpeg": 20
},
"prefer-stable": false,
"platform": [],
"prefer-lowest": false,
"platform": {
"php": ">=5.3.3"
},
"platform-dev": []
}

@ -0,0 +1,6 @@
<html>
<head>
</head>
<body>
</body>
</html>

@ -101,7 +101,6 @@ All security issues are published and patches are attached on <a href="https://s
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/3bc8fd6fad15e6d92e8c1fd32e28d531c8c07d1d">3bc8fd6f</a>) Add $_configuration['document_if_file_exists_option']</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/73e381620438970423d371e717ad0bb8d5667a29">73e38162</a> - <a href="https://task.beeznest.com/issues/9247">BT#9247</a>) Adding exercise_max_fckeditors_in_page setting</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/b14bcb36ad2145721205145561ae9a2d024a3a36">b14bcb36</a>) Add option $_configuration['certificate_pdf_orientation']</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/6bd4b5df0db53da2e586f1dac514873aca11ba7b">6bd4b5df</a> - <a href="https://task.beeznest.com/issues/8814">BT#8814</a>) Add auto attendance</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/7dbed8004f3a7da69a187df1de1cf7034097dfd7">7dbed800</a> - <a href="https://task.beeznest.com/issues/8703">BT#8703</a>) Add hosting total size checker</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/218dc6a4d7f27026b51df142a4b41d944bf44423">218dc6a4</a> - <a href="https://task.beeznest.com/issues/9175">BT#9175</a>) Add hosting_limit_active_courses setting</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/1d68db47b2dcb00a36e5b2d90e5be3cd6494cd56">1d68db47</a> - <a href="https://support.chamilo.org/issues/398">#398</a>) Support Opale/Scenarii by adding variable to better support SCORM 1.2 by watching over the definition, by the SCO, of the lesson_status and the call to LMSFinish() or the move to another element</li>
@ -112,7 +111,7 @@ All security issues are published and patches are attached on <a href="https://s
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/2db9057d7b589e1d91554f5f39df415c810aeb95">2db9057d</a> - <a href="https://support.chamilo.org/issues/7328">#7328</a>) Add theme_backup and default_template settings</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/8d9a82535e9a1f6e11832f8217809d6e8cae9b36">8d9a8253</a>) Add script to check users data in CSV file</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/f52df87bded7b10787bec5516124024b5ad4edea">f52df87b</a> - <a href="https://task.beeznest.com/issues/8845">BT#8845</a>) Add script to move users from one course to another depending on them having passed an exam or not</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/27493b32acc9d6cde3e95b5a34e4c03dcc004589">27493b32</a> - <a href="https://support.chamilo.org/issues/7324">#7324</a>) Add possibility to hide recordings to students in conferences list in BBB plugin</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/27493b32acc9d6cde3e95b5a34e4c03dcc004589">27493b32</a> - <a href="https://support.chamilo.org/issues/7324">#7324</a>) Add possibility to hide recordings from students in conferences list in BBB plugin</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/c24c758f7469fd73646892f2d37636d158c9fd8a">c24c758f</a> - <a href="https://task.beeznest.com/issues/8840">BT#8840</a>) Add $_configuration['auto_detect_language_custom_pages'] to detect the language in custom pages</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/a2ff44cf6978393a3b5577afd408f11d58694c3c">a2ff44cf</a> - <a href="https://support.chamilo.org/issues/7212">#7212</a>) Add calculated answers feature (in beta test)</li>
<li>(<a href="https://github.com/chamilo/chamilo-lms/commit/25cd7ddc4928c76591dd983b05abf6a7cf929654">25cd7ddc</a>) Use .gitattributes file to enable special Github features for versions packaging</li>

@ -155,8 +155,7 @@ enable CSS styles package upload and sub-language definition:
<li>[chamilo]/main/css/</li>
<li>[chamilo]/main/lang/</li>
</ul>
Starting from Chamilo 1.8.8, you can also enable full-text indexing features which
require the php5-xapian PHP's extension module to be installed. If you do use
Starting from Chamilo 1.8.8, you can also enable full-text indexing features which require the php5-xapian PHP's extension module to be installed. If you do use
it, you will need to allow your system to write into the sarchdb directory:
<ul>
<li>[chamilo]/searchdb</li>
@ -339,10 +338,8 @@ you upgrade.</em>
providers have developed improved migration procedures that use more memory but
process the upgrades up to 20 times faster. If this is the kind of thing you
need, we highly recommend you contact them (see reference below).</div>
<div class="muted"> NOTE: This version of Chamilo can only be used to upgrade from
smaller versions of Chamilo or Dok€os. For example, you cannot use the normal
upgrade scripts from Chamilo 1.9 to upgrade from Dok€os 2.0. If you need this,
please contact one of the Chamilo Association's official providers &lt;providers@chamilo.org&gt;)</div>
<div class="muted"> NOTE: This version of Chamilo can only be used to upgrade from earlier versions of Chamilo or Dok€os. For example, you cannot use the normal
upgrade scripts from Chamilo 1.9 to upgrade from Dok€os 2.0 (which was born after the split with Chamilo). If you need this, please contact one of the Chamilo Association's <a href="https://chamilo.org/providers">official providers</a>)</div>
<p></p>
@ -357,6 +354,7 @@ As this is only a minor version change from previous 1.10.* versions of Chamilo,
"searchdb" directories from the package before you overwrite the previous
files.</li>
<li> edit the main/inc/conf/configuration.php file: at the en of the file, locate the previous version number (e.g. '1.10.4') and change it to this new version (e.g. '1.10.8')</li>
<li> clean your archive/ directory: take a temporary copy of index.html, delete all the contents *in* this directory (do NOT remove the directory itself, only its contents!). It will all be re-generated. You can also delete the contents of this directory through the "Archive directory cleanup" option in the "System" box of the Administration page.</li>
<li> you're done! No other upgrade procedure is required</li>
</ul>
@ -370,6 +368,7 @@ As this is only a minor version change from previous 1.10.* versions of Chamilo,
<li> unzip the new files of Chamilo 1.10 over the files of the older version (or unzip the files in one folder and then copy the files from there to the older version's directory)</li>
<li> point your browser on your portal URL + main/install/</li>
<li> choose your language and click&nbsp;<span style="font-style: italic;">Upgrade from 1.8.x/1.9.x</span></li>
<li> clean your archive/ directory: take a temporary copy of index.html, delete all the contents *in* this directory (do NOT remove the directory itself, only its contents!). It will all be re-generated. You can also delete the contents of this directory through the "Archive directory cleanup" option in the "System" box of the Administration page.</li>
</ul>
<br />
@ -383,6 +382,7 @@ As this is only a minor version change from previous 1.10.* versions of Chamilo,
<li> unzip the new files of Chamilo 1.10 over the files of the older version (or unzip the files in one folder and then copy the files from there to the older version's directory)</li>
<li> point your browser on your portal URL + main/install/</li>
<li> choose your language and click&nbsp;<span style="font-style: italic;">Upgrade from 1.8.x/1.9.x</span></li>
<li> clean your archive/ directory: take a temporary copy of index.html, delete all the contents *in* this directory (do NOT remove the directory itself, only its contents!). It will all be re-generated. You can also delete the contents of this directory through the "Archive directory cleanup" option in the "System" box of the Administration page.</li>
</ul>
A bunch of Chamilo administrators have reported minor issues with the migration between versions considerably apart (like from Dok€os to Chamilo).
This might include loosing some assignments or forum posts. To avoid any ugly effect on your users, we recommend you first establish a checklist
@ -433,6 +433,7 @@ Chamilo/Dok€os root folder</li>
<li> point your browser on your portal URL</li>
<li> choose your language and click&nbsp;<span style="font-style: italic;">Upgrade from 1.6.x</span> and confirm the
current directory of the old version</li>
<li> clean your archive/ directory: take a temporary copy of index.html, delete all the contents *in* this directory (do NOT remove the directory itself, only its contents!). It will all be re-generated. You can also delete the contents of this directory through the "Archive directory cleanup" option in the "System" box of the Administration page.</li>
</ul>
<br />
@ -793,8 +794,9 @@ Then go to your administration page -&gt; Configuration settings -&gt; Search
and enable the search tool. Follow the recommendations on the page to get the
complete indexing suite installed. Once you're done, all documents you import
into your Chamilo portal in a recognized format will be indexed and searchable.
Chamilo Administrators training (which you can ask any <a href="http://www.chamilo.org/en/providers">Chamilo's Official
Provider</a> for) include a full review of the full-text search feature.
Chamilo intermediate Administrators training (which you can ask any <a href="http://www.chamilo.org/en/providers">Chamilo's Official Provider</a> for) include a full review of the full-text search feature.</p>
<p class="muted">
Note: Xapian's licensing for the PHP extension is a bit different than what is necessary to enter the Debian repositories, so it has been excluded. You can, however, generate your own package by following the <a href="http://trac.xapian.org/wiki/FAQ/PHP%20Bindings%20Package">packaging instructions on Xapian's wiki</a>.
</p>
<hr style="width: 100%; height: 2px;" />

@ -51,6 +51,7 @@
<li><a href="#9.xsendfile">Speeding file downloads with mod_xsendfile</a></li>
<li><a href="#10.igbinary">IGBinary for faster courses backups and better sessions</a></li>
<li><a href="#11.permissions-check">Removing files download permissions check</a></li>
<li><a href="#12.MySQL-compression">MySQL/MariaDB compression</a></li>
</ol>
<h2><a name="1.Using-XCache"></a>1. Using xCache or APC</h2>
@ -355,12 +356,14 @@ Don't have time or resources to optimize your Chamilo installation yourself? Hir
<img src="http://jigsaw.w3.org/css-validator/images/vcss-blue" style="margin: 1em; float: right;" alt="Valid CSS" />
</a>
<hr />
<h2><a name="7.High-numbers-memory"></a>Memory considerations for high numbers of users</h2>
Some administration scripts *have to* handle lists of all users, and this might have a considerable impact on portals with very high numbers of users. For example, the main/admin/add_users_to_session.php script that handles the registration of users into a specific session, if used with the (non-default) full list of users, will devour about 3KB per user, which, for 100,000 users, translates into the need for around 300MB of RAM just to show this page, and to around 3GB for 1,000,000 users.<br />
This mode is not loaded by default, but could still be selected, leading to a "Fatal error: Allowed memory size ... exhausted" message.<br />
The only non-scripted solution here is to allow for the corresponding amount of RAM for your PHP configuration (<em>memory_limit = 300M</em>) or your specific VirtualHost if you use mod-php5 (<em>php_value memory_limit 300M</em>).<br/>
<hr />
<h2><a name="#8.Avoid-non-fixed-values"></a>Avoiding non-fixed values</h2>
<h2><a name="8.Avoid-non-fixed-values"></a>Avoiding non-fixed values</h2>
Many things in Chamilo are written focusing on the ease of use, even for the administrator. Sometimes, these settings are weighing a little bit more on the system. This is the case, between others, of the mail.conf.php file (being loaded unconditionally) and its CONSTANT "IS_WINDOWS_OS", which is defined by a function call (api_is_windows_os()) at the beginning of main_api.lib.php.
The definition of this constant (which is executed at *every* page load) can easily be avoided, and the only place where it is used inconditionally (mail.conf.php) can be modified to set the line as you expect it (depending on whether you use sendmail/exim or smtp).
@ -373,7 +376,7 @@ $platform_email['SMTP_MAILER'] = 'mail';
</pre>
In fact, the complete loading of mail.conf.php can also be avoided if loaded conditionally (with <i>require_once</i>) when sending an e-mail (which is the only case where it is useful).
<hr />
<h2><a name="#9.xsendfile"></a>Speeding file downloads with mod_xsendfile</h2>
<h2><a name="9.xsendfile"></a>Speeding file downloads with mod_xsendfile</h2>
<p>It might have come to your attention that file downloads through Chamilo might get slow, under default conditions, in particular using Apache 2.</p>
<p>There are several ways to fix this, one of which is removing the .htaccess inside the courses/ directory. This, however, will remove all permissions checks on the files contained in this directory, so... most of the time, not ideal unless your portal is *really* open to the world.</p>
<p>Another technique, revealed to us by <a href="http://stackoverflow.com/users/46594/virtualblackfox">VirtualBlackFox</a> on <a href="http://stackoverflow.com/questions/3697748/fastest-way-to-serve-a-file-using-php">this Stackoverflow post</a>, is to use the X-SendFile module for Apache 2.2+ (other web servers might offer other solutions, or avoid the problem initially).</p>
@ -398,11 +401,13 @@ $_configuration['enable_x_sendfile_headers'] = true;
</pre>
Done! Now your downloads should go substantially faster. This is still a feature in observation. We're not sure the benefits are sufficient, so don't hesitate to let us know in <a href="https://support.chamilo.org/issues/6853">the related issue in Chamilo's tracking system</a>
</p>
<h2><a name="#10.igbinary"></a>IGBinary for courses backups and better sessions management</h2>
<hr />
<h2><a name="10.igbinary"></a>IGBinary for courses backups and better sessions management</h2>
<p>
<a href="http://pecl.php.net/package/igbinary">IGBinary</a> is a small PECL library that replaces the PHP serializer. It uses less space (so less memory for serialized objects) and is particularly efficient with memory-based storages (like Memcached). Use it for course backups (see <a href="https://support.chamilo.org/issues/4443">issue 4443</a>) or <a href="http://www.neanderthal-technology.com/2011/11/ubuntu-10-install-php-memcached-with-igbinary-support/">to boost sessions management</a>.
</p>
<h2><a name="#11.permissions-check"></a>Removing files download permissions check</h2>
<hr />
<h2><a name="11.permissions-check"></a>Removing files download permissions check</h2>
<p>
This measure is not cumulative with mod_xsendfile explained above. It is not *recommended* either, as it removes an important security layer.<br />
<br />
@ -435,13 +440,29 @@ RewriteRule ([^/]+)/work/(.*)$ /main/work/download.php?file=work/$2&cDir=$1 [QSA
</pre><br />
This is easy, doesn't require a server reload and you should see the results pretty quickly. As mentioned above, if security of your content is an issue, though, you should avoid using this technique.
</p>
<hr />
<h2><a name="12.MySQL-compression"></a>MySQL/MariaDB compression</h2>
<p>
If your database server is separate from your web server, you have to play with bandwidth, firewalls, and network restrictions in general.<br />
In particular, when dealing with large-scale portals, the time a SQL query will take to return to the web server will take longer and, eventually, in the most critical cases, will take <b>too long</b>, and your web servers will be completely overloaded (load average very high because the system is waiting for I/O operations, but processors usage not being very high is a clear sign of this).<br />
To solve this kind of issues, MySQL and MariaDB offer a data compression mechanism, which will reduce the amount of data passed between PHP and the database server. Ultimately, this reduction will lower bandwidth usage and reduce the impact of numerous and heavy data requests (and save you).<br />
In 1.10.0, we have added the possibility to enable this compression very easily, from the configuration.php file, uncommenting the following line:
<pre>
//$_configuration['db_client_flags'] = MYSQL_CLIENT_COMPRESS;
</pre>
This should have an immediate effect on the load average on your server.
</p>
<hr />
<h2>Authors</h2>
<ul>
<li>Yannick Warnier, Zend Certified PHP Engineer, BeezNest Belgium SPRL, <a href="mailto:ywarnier@beeznest.net">ywarnier@beeznest.net</a></li>
</ul>
<hr />
Don't have time or resources to optimize your Chamilo installation yourself? Hire an <a href="http://www.chamilo.org/en/providers">official Chamilo provider</a> and get it sorted out professionally by specialists.
<a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-xhtml10-blue" alt="Valid XHTML 1.0 Transitional" style="margin: 1em; float: right;" height="31" width="88" /></a>
<a href="http://jigsaw.w3.org/css-validator/">
<img src="http://jigsaw.w3.org/css-validator/images/vcss-blue" style="margin: 1em; float: right;" alt="Valid CSS" />
</a>
</div>
</body>
</html>

@ -40,6 +40,8 @@ $user_info = api_get_user_info($user_id);
$user_anonymous = api_get_anonymous_id();
$current_user_id = api_get_user_id();
$userStatus = api_get_user_status($user_id);
$firstLetterUser = isset($_POST['firstLetterUser']) ? $_POST['firstLetterUser'] : null;
// setting the name of the tool
@ -47,6 +49,8 @@ if (UserManager::is_admin($user_id)) {
$tool_name= get_lang('AssignUsersToPlatformAdministrator');
} else if ($user_info['status'] == SESSIONADMIN) {
$tool_name= get_lang('AssignUsersToSessionsAdministrator');
} else if ($user_info['status'] == STUDENT_BOSS) {
$tool_name= get_lang('AssignUsersToBoss');
} else {
$tool_name= get_lang('AssignUsersToHumanResourcesManager');
}
@ -62,7 +66,7 @@ if (!api_is_platform_admin()) {
function search_users($needle,$type)
{
global $tbl_access_url_rel_user, $tbl_user, $user_anonymous, $current_user_id, $user_id;
global $tbl_access_url_rel_user, $tbl_user, $user_anonymous, $current_user_id, $user_id, $userStatus;
$xajax_response = new XajaxResponse();
$return = '';
@ -70,8 +74,17 @@ function search_users($needle,$type)
// xajax send utf8 datas... datas in db can be non-utf8 datas
$charset = api_get_system_encoding();
$needle = api_convert_encoding($needle, $charset, 'utf-8');
$assigned_users_to_hrm = array();
switch ($userStatus) {
case DRH:
$assigned_users_to_hrm = UserManager::get_users_followed_by_drh($user_id);
break;
case STUDENT_BOSS:
$assigned_users_to_hrm = UserManager::getUsersFollowedByStudentBoss($user_id);
break;
}
$assigned_users_to_hrm = UserManager::get_users_followed_by_drh($user_id);
$assigned_users_id = array_keys($assigned_users_to_hrm);
$without_assigned_users = '';
@ -92,7 +105,7 @@ function search_users($needle,$type)
LEFT JOIN $tbl_access_url_rel_user au ON (au.user_id = user.user_id)
WHERE
".(api_sort_by_first_name() ? 'firstname' : 'lastname')." LIKE '$needle%' AND
status NOT IN(".DRH.", ".SESSIONADMIN.") AND
status NOT IN(".DRH.", ".SESSIONADMIN.", " . STUDENT_BOSS . ") AND
user.user_id NOT IN ($user_anonymous, $current_user_id, $user_id)
$without_assigned_users AND
access_url_id = ".api_get_current_access_url_id()."
@ -104,7 +117,7 @@ function search_users($needle,$type)
FROM $tbl_user user
WHERE
".(api_sort_by_first_name() ? 'firstname' : 'lastname')." LIKE '$needle%' AND
status NOT IN(".DRH.", ".SESSIONADMIN.") AND
status NOT IN(".DRH.", ".SESSIONADMIN.", " . STUDENT_BOSS . ") AND
user_id NOT IN ($user_anonymous, $current_user_id, $user_id)
$without_assigned_users
$order_clause
@ -127,10 +140,19 @@ function search_users($needle,$type)
username LIKE "'.$needle.'%" OR
firstname LIKE "'.$needle.'%" OR
lastname LIKE "'.$needle.'%"
) AND
user.status<>6 AND user.status<>'.DRH.' '.
$order_clause.
' LIMIT 11';
) AND ';
switch ($userStatus) {
case DRH:
$sql .= " user.status <> 6 AND user.status <> " . DRH;
break;
case STUDENT_BOSS:
$sql .= " user.status <> 6 AND user.status <> " . STUDENT_BOSS;
break;
}
$sql .= " $order_clause LIMIT 11";
$rs = Database::query($sql);
$i = 0;
while ($user = Database :: fetch_array($rs)) {
@ -267,7 +289,18 @@ if (!empty($filters) && !empty($filterData)) {
$msg = '';
if (isset($_POST['formSent']) && intval($_POST['formSent']) == 1) {
$user_list = $_POST['UsersList'];
$affected_rows = UserManager::suscribe_users_to_hr_manager($user_id, $user_list);
switch ($userStatus) {
case DRH:
$affected_rows = UserManager::suscribe_users_to_hr_manager($user_id, $user_list);
break;
case STUDENT_BOSS;
$affected_rows = UserManager::subscribeUsersToBoss($user_id, $user_list);
break;
default:
$affected_rows = 0;
}
if ($affected_rows) {
$msg = get_lang('AssignedUsersHaveBeenUpdatedSuccessfully');
}
@ -278,11 +311,27 @@ Display::display_header($tool_name);
// actions
echo '<div class="actions">';
echo '<span style="float: right;margin:0px;padding:0px;">
<a href="dashboard_add_courses_to_user.php?user='.$user_id.'">'.
Display::return_icon('course_add.gif', get_lang('AssignCourses'), array('style'=>'vertical-align:middle')).' '.get_lang('AssignCourses').'</a>
<a href="dashboard_add_sessions_to_user.php?user='.$user_id.'">'.
Display::return_icon('view_more_stats.gif', get_lang('AssignSessions'), array('style'=>'vertical-align:middle')).' '.get_lang('AssignSessions').'</a></span>';
if ($userStatus != STUDENT_BOSS) {
$actions = Display::url(
Display::return_icon('course_add.gif', get_lang('AssignCourses'),
array(
'style' => 'vertical-align:middle'
)) . get_lang('AssignCourses'), "dashboard_add_courses_to_user.php?user=$user_id"
);
$actions .= Display::url(
Display::return_icon('view_more_stats.gif', get_lang('AssignSessions'),
array(
'style' => 'vertical-align:middle'
)) . get_lang('AssignSessions'), "dashboard_add_sessions_to_user.php?user=$user_id"
);
echo Display::span($actions, array(
'style' => 'float: right; margin: 0; paddingg: 0;'
));
}
echo Display::url(get_lang('AdvancedSearch'), '#', array('class' => 'advanced_options', 'id' => 'advanced_search'));
echo '</div>';
@ -294,7 +343,15 @@ echo Display::page_header(
sprintf(get_lang('AssignUsersToX'), api_get_person_name($user_info['firstname'], $user_info['lastname']))
);
$assigned_users_to_hrm = UserManager::get_users_followed_by_drh($user_id);
switch ($userStatus) {
case DRH:
$assigned_users_to_hrm = UserManager::get_users_followed_by_drh($user_id);
break;
case STUDENT_BOSS;
$assigned_users_to_hrm = UserManager::getUsersFollowedByStudentBoss($user_id);
break;
}
$assigned_users_id = array_keys($assigned_users_to_hrm);
$without_assigned_users = '';
if (count($assigned_users_id) > 0) {
@ -368,6 +425,8 @@ if(!empty($msg)) {
echo get_lang('AssignedUsersListToPlatformAdministrator');
} else if ($user_info['status'] == SESSIONADMIN) {
echo get_lang('AssignedUsersListToSessionsAdministrator');
} else if ($user_info['status'] == STUDENT_BOSS) {
echo get_lang('AssignedUsersListToStudentBoss');
} else {
echo get_lang('AssignedUsersListToHumanResourcesManager');
}

@ -1,3 +1,3 @@
name;description
name;description;
Class A4;20 students in general courses
Class B5;20 students from technical background

1 name name;description; description
2 Class A4 Class A4;20 students in general courses 20 students in general courses
3 Class B5 Class B5;20 students from technical background 20 students from technical background

@ -26,6 +26,20 @@ api_protect_admin_script(true);
$nameTools = get_lang('PlatformAdmin');
if (api_is_multiple_url_enabled()) {
$accessUrlId = api_get_current_access_url_id();
if ($accessUrlId != -1) {
$urlInfo = api_get_access_url($accessUrlId);
$url = api_remove_trailing_slash(preg_replace('/https?:\/\//i', '', $urlInfo['url']));
$cleanUrl = str_replace('/', '-', $url);
$adminExtraContentDir = api_get_path(SYS_PATH) . "home/$cleanUrl/admin/";
}
} else {
$adminExtraContentDir = api_get_path(SYS_PATH) . "home/admin/";
}
// Displaying the header
$message = '';
@ -61,13 +75,34 @@ if (isset($_GET['msg']) && isset($_GET['type'])) {
$blocks = array();
// Instantiate Hook Event for Admin Block
$hook = HookAdminBlock::create();
if (!empty($hook)) {
// If not empty, then notify Pre process to Hook Observers for Admin Block
$hook->setEventData(array('blocks' => $blocks));
$data = $hook->notifyAdminBlock(HOOK_EVENT_TYPE_PRE);
// Check if blocks data is not null
if (isset($data['blocks'])) {
// Get modified blocks
$blocks = $data['blocks'];
}
}
/* Users */
$blocks['users']['icon'] = Display::return_icon('members.gif', get_lang('Users'), array(), ICON_SIZE_SMALL, false);
$blocks['users']['label'] = api_ucfirst(get_lang('Users'));
$blocks['users']['class'] = 'block-admin-users';
$usersBlockExtraFile = "{$adminExtraContentDir}block-admin-users_extra.html";
if (file_exists($usersBlockExtraFile)) {
$blocks['users']['extraContent'] = file_get_contents($usersBlockExtraFile);
}
if (api_is_platform_admin()) {
$blocks['users']['editable'] = true;
$search_form = '
<form method="get" class="form-search" action="user_list.php">
<input class="span3" type="text" name="keyword" value="">
@ -108,6 +143,13 @@ if (api_is_platform_admin()) {
$blocks['courses']['icon'] = Display::return_icon('course.gif', get_lang('Courses'), array(), ICON_SIZE_MEDIUM, false);
$blocks['courses']['label'] = api_ucfirst(get_lang('Courses'));
$blocks['courses']['class'] = 'block-admin-courses';
$blocks['courses']['editable'] = true;
$coursesBlockExtraFile = "{$adminExtraContentDir}block-admin-courses_extra.html";
if (file_exists($coursesBlockExtraFile)) {
$blocks['courses']['extraContent'] = file_get_contents($coursesBlockExtraFile);
}
$search_form = ' <form method="get" class="form-search" action="course_list.php">
<input class="span3" type="text" name="keyword" value="">
@ -147,7 +189,13 @@ if (api_is_platform_admin()) {
$blocks['platform']['icon'] = Display::return_icon('platform.png', get_lang('Platform'), array(), ICON_SIZE_MEDIUM, false);
$blocks['platform']['label'] = api_ucfirst(get_lang('Platform'));
$blocks['platform']['class'] = 'block-admin-platform';
$blocks['platform']['editable'] = true;
$platformBlockExtraFile = "{$adminExtraContentDir}block-admin-platform_extra.html";
if (file_exists($platformBlockExtraFile)) {
$blocks['platform']['extraContent'] = file_get_contents($platformBlockExtraFile);
}
$search_form = ' <form method="get" action="settings.php" class="form-search">
<input class="span3" type="text" name="search_field" value="" >
@ -156,7 +204,6 @@ if (api_is_platform_admin()) {
</form>';
$blocks['platform']['search_form'] = $search_form;
$items = array();
$items[] = array('url'=>'settings.php', 'label' => get_lang('PlatformConfigSettings'));
$items[] = array('url'=>'settings.php?category=Plugins','label' => get_lang('Plugins'));
@ -167,6 +214,10 @@ if (api_is_platform_admin()) {
$items[] = array('url'=>'configure_inscription.php', 'label' => get_lang('ConfigureInscription'));
$items[] = array('url'=>'statistics/index.php', 'label' => get_lang('Statistics'));
$items[] = array('url'=> api_get_path(WEB_CODE_PATH).'mySpace/company_reports.php', 'label' => get_lang('Reports'));
$items[] = array(
'url'=> api_get_path(WEB_CODE_PATH) . 'admin/teacher_time_report.php',
'label' => get_lang('TeacherTimeReport')
);
/* Event settings */
@ -195,6 +246,15 @@ $blocks['sessions']['icon'] = Display::return_icon('session.png', get_lang('Ses
$blocks['sessions']['label'] = api_ucfirst(get_lang('Sessions'));
$blocks['sessions']['class'] = 'block-admin-sessions';
$sessionsBlockExtraFile = "{$adminExtraContentDir}block-admin-sessions_extra.html";
if (file_exists($sessionsBlockExtraFile)) {
$blocks['sessions']['extraContent'] = file_get_contents($sessionsBlockExtraFile);
}
if (api_is_platform_admin()) {
$blocks['sessions']['editable'] = true;
}
$search_form = ' <form method="GET" class="form-search" action="session_list.php">
<input class="span3" type="text" name="keyword" value="">
@ -335,6 +395,18 @@ if (api_is_platform_admin()) {
$blocks['version_check']['items'] = null;
$blocks['version_check']['class'] = 'block-admin-version_check';
// Check Hook Event for Admin Block Object
if (!empty($hook)) {
// If not empty, then notify Pre process to Hook Observers for Admin Block
$hook->setEventData(array('blocks' => $blocks));
$data = $hook->notifyAdminBlock(HOOK_EVENT_TYPE_PRE);
// Check if blocks data is not null
if (isset($data['blocks'])) {
// Get modified blocks
$blocks = $data['blocks'];
}
}
}
$admin_ajax_url = api_get_path(WEB_AJAX_PATH).'admin.ajax.php';

@ -51,7 +51,8 @@ $sql = 'SELECT
nb_days_access_before_beginning,
nb_days_access_after_end,
session_category_id,
visibility
visibility,
show_description, description
FROM '.$tbl_session.'
LEFT JOIN '.$tbl_user.'
ON id_coach = user_id
@ -232,18 +233,24 @@ if ($multiple_url_is_on) {
echo '</td></tr>';
}
if (SessionManager::durationPerUserIsEnabled()) {
$sessionInfo = api_get_session_info($sessionId);
echo '<tr><td>';
echo get_lang('Duration');
echo '</td>';
echo '<td>';
echo $sessionInfo['duration'].' ';
echo get_lang('Days');
echo '</td></tr>';
$sessionInfo = api_get_session_info($sessionId);
echo '<tr><td>';
echo get_lang('Duration');
echo '</td>';
echo '<td>';
echo $sessionInfo['duration'].' ';
echo get_lang('Days');
echo '</td></tr>';
}
?>
<tr>
<td><?php echo get_lang('Description'); ?></td>
<td><?php echo $session['description'] ?></td>
</tr>
<tr>
<td><?php echo get_lang('ShowDescription'); ?></td>
<td><?php echo $session['show_description'] == 1 ? get_lang('Yes') : get_lang('No') ?></td>
</tr>
</table>
<br />
@ -273,10 +280,7 @@ if ($session['nbr_courses'] == 0) {
} else {
// select the courses
$orderBy = "ORDER BY title";
if (SessionManager::orderCourseIsEnabled()) {
$orderBy = "ORDER BY position";
}
$orderBy = "ORDER BY position";
$sql = "SELECT code,title,visual_code, nbr_users
FROM $tbl_course, $tbl_session_rel_course
@ -332,34 +336,32 @@ if ($session['nbr_courses'] == 0) {
$orderButtons = null;
if (SessionManager::orderCourseIsEnabled()) {
$upIcon = 'up.png';
$urlUp = api_get_self().'?id_session='.$sessionId.'&course_code='.$course['code'].'&action=move_up';
$upIcon = 'up.png';
$urlUp = api_get_self().'?id_session='.$sessionId.'&course_code='.$course['code'].'&action=move_up';
if ($count == 0) {
$upIcon = 'up_na.png';
$urlUp = '#';
}
$orderButtons = Display::url(
Display::return_icon($upIcon, get_lang('MoveUp')),
$urlUp
);
if ($count == 0) {
$upIcon = 'up_na.png';
$urlUp = '#';
}
$downIcon = 'down.png';
$downUrl = api_get_self().'?id_session='.$sessionId.'&course_code='.$course['code'].'&action=move_down';
$orderButtons = Display::url(
Display::return_icon($upIcon, get_lang('MoveUp')),
$urlUp
);
if ($count +1 == count($courses)) {
$downIcon = 'down_na.png';
$downUrl = '#';
}
$downIcon = 'down.png';
$downUrl = api_get_self().'?id_session='.$sessionId.'&course_code='.$course['code'].'&action=move_down';
$orderButtons .= Display::url(
Display::return_icon($downIcon, get_lang('MoveDown')),
$downUrl
);
if ($count +1 == count($courses)) {
$downIcon = 'down_na.png';
$downUrl = '#';
}
$orderButtons .= Display::url(
Display::return_icon($downIcon, get_lang('MoveDown')),
$downUrl
);
$orig_param = '&origin=resume_session';
//hide_course_breadcrumb the parameter has been added to hide the name of the course, that appeared in the default $interbreadcrumb
echo '
@ -449,14 +451,12 @@ if (!empty($userList)) {
}
$editUrl = null;
if (SessionManager::durationPerUserIsEnabled()) {
if (isset($sessionInfo['duration']) && !empty($sessionInfo['duration'])) {
$editUrl = api_get_path(WEB_CODE_PATH) . 'admin/session_user_edit.php?session_id=' . $sessionId . '&user_id=' . $userId;
$editUrl = Display::url(
Display::return_icon('agenda.png', get_lang('SessionDurationEdit')),
$editUrl
);
}
if (isset($sessionInfo['duration']) && !empty($sessionInfo['duration'])) {
$editUrl = api_get_path(WEB_CODE_PATH) . 'admin/session_user_edit.php?session_id=' . $sessionId . '&user_id=' . $userId;
$editUrl = Display::url(
Display::return_icon('agenda.png', get_lang('SessionDurationEdit')),
$editUrl
);
}
$table->setCellContents($row, 0, $userLink);
@ -481,14 +481,3 @@ if (!empty($userList)) {
}
Display :: display_footer();
/*
ALTER TABLE session_rel_course ADD COLUMN position int;
ALTER TABLE session_rel_course ADD COLUMN category varchar(255);
https://task.beeznest.com/issues/8317:
ALTER TABLE session ADD COLUMN duration int;
ALTER TABLE session_rel_user ADD COLUMN duration int;
*
*/

@ -112,6 +112,8 @@ if (isset($_POST['formSent']) && $_POST['formSent']) {
$end_limit = $_POST['end_limit'];
$start_limit = $_POST['start_limit'];
$duration = isset($_POST['duration']) ? $_POST['duration'] : null;
$description = isset($_POST['description']) ? $_POST['description'] : null;
$showDescription = isset($_POST['show_description']) ? 1 : 0;
if (empty($end_limit) && empty($start_limit)) {
$nolimit = 1;
@ -134,12 +136,15 @@ if (isset($_POST['formSent']) && $_POST['formSent']) {
$id_session_category,
$id_visibility,
$start_limit,
false,
$end_limit,
$duration
$duration,
$description,
$showDescription
);
if ($return == strval(intval($return))) {
// integer => no error on session creation
// integer => no error on session creation
header('Location: add_courses_to_session.php?id_session='.$return.'&add=true&msg=');
exit();
}
@ -227,6 +232,22 @@ $Categories = SessionManager::get_all_session_category();
?>
</div>
</div>
<div class="control-group">
<label class="control-label" for="description"><?php echo get_lang('Description') ?></label>
<div class="controls">
<?php $fckEditor = new FCKeditor('description'); ?>
<?php $fckEditor->ToolbarSet = 'TrainingDescription'; ?>
<?php echo $fckEditor->CreateHtml(); ?>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input id="show_description" type="checkbox" name="show_description" />
<?php echo get_lang('ShowDescription') ?>
</label>
</div>
</div>
<div class="control-group">
<label class="control-label">
<?php echo get_lang('SessionCategory') ?>
@ -416,23 +437,16 @@ for ($i=$thisYear-5;$i <= ($thisYear+5);$i++) {
</div>
</div>
<?php
if (SessionManager::durationPerUserIsEnabled()) {
?>
<div class="control-group">
<label class="control-label">
<?php echo get_lang('SessionDurationTitle') ?> <br />
</label>
<div class="controls">
<input id="duration" type="text" name="duration" class="span1" maxlength="50" value="">
<br />
<?php echo get_lang('SessionDurationDescription') ?>
</div>
<div class="control-group">
<label class="control-label">
<?php echo get_lang('SessionDurationTitle') ?> <br />
</label>
<div class="controls">
<input id="duration" type="text" name="duration" class="span1" maxlength="50" value="">
<br />
<?php echo get_lang('SessionDurationDescription') ?>
</div>
<?php
}
?>
</div>
<div class="control-group">
<div class="controls">

@ -102,7 +102,7 @@ if (isset($_POST['formSent']) && $_POST['formSent']) {
);
if ($return == strval(intval($return))) {
header('Location: resume_session.php?id_session='.$return);
header('Location: resume_session.php?id_session='.$return);
exit();
}
}
@ -161,6 +161,23 @@ if (!empty($return)) {
</select>
</div>
</div>
<div class="control-group">
<label class="control-label" for="description"><?php echo get_lang('Description') ?></label>
<div class="controls">
<?php $fckEditor = new FCKeditor('description'); ?>
<?php $fckEditor->ToolbarSet = 'TrainingDescription'; ?>
<?php $fckEditor->Value = $infos['description'] ; ?>
<?php echo $fckEditor->CreateHtml(); ?>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input id="show_description" type="checkbox" name="show_description" <?php echo $showDescriptionChecked ?> />
<?php echo get_lang('ShowDescription') ?>
</label>
</div>
</div>
<div class="control-group">
<label class="control-label">
<?php echo get_lang('SessionCategory') ?>
@ -367,48 +384,23 @@ if (!empty($return)) {
</div>
</div>
<?php if (array_key_exists('show_description', $infos)) { ?>
<div class="control-group">
<div class="controls">
<?php echo get_lang('Description') ?> <br />
<textarea name="description"><?php echo $infos['description']; ?></textarea>
</div>
</div>
<div class="control-group">
<div class="controls">
<label>
<input id="show_description" type="checkbox" name="show_description" <?php echo $showDescriptionChecked ?> />
<?php echo get_lang('ShowDescription') ?>
</label>
</div>
</div>
<?php } ?>
<?php
if (SessionManager::durationPerUserIsEnabled()) {
if (empty($infos['duration'])) {
$duration = null;
} else {
$duration = $infos['duration'];
}
?>
<div class="control-group">
<label class="control-label">
<?php echo get_lang('SessionDurationTitle') ?> <br />
</label>
<div class="controls">
<input id="duration" type="text" name="duration" class="span1" maxlength="50" value="<?php if($formSent) echo Security::remove_XSS($duration); else echo $duration; ?>">
<br />
<?php echo get_lang('SessionDurationDescription') ?>
</div>
</div>
<?php
if (empty($infos['duration'])) {
$duration = null;
} else {
$duration = $infos['duration'];
}
?>
<div class="control-group">
<label class="control-label">
<?php echo get_lang('SessionDurationTitle') ?> <br />
</label>
<div class="controls">
<input id="duration" type="text" name="duration" class="span1" maxlength="50" value="<?php if($formSent) echo Security::remove_XSS($duration); else echo $duration; ?>">
<br />
<?php echo get_lang('SessionDurationDescription') ?>
</div>
</div>
<div class="control-group">
<div class="controls">

@ -24,9 +24,6 @@ if (!isset($sessionInfo['duration']) ||
api_not_allowed(true);
}
if (!SessionManager::durationPerUserIsEnabled()) {
api_not_allowed(true);
}
if (empty($sessionId) || empty($userId)) {
api_not_allowed(true);
}

@ -20,7 +20,7 @@ if (api_get_setting('allow_skills_tool') != 'true') {
}
//Adds the JS needed to use the jqgrid
$htmlHeadXtra[] = api_get_js('d3/d3.v2.min.js');
$htmlHeadXtra[] = api_get_js('d3/d3.v3.5.4.min.js');
$htmlHeadXtra[] = api_get_js('d3/colorbrewer.js');
$htmlHeadXtra[] = api_get_js('d3/jquery.xcolor.js');

@ -252,7 +252,7 @@ class Statistics
// User id.
$row[3] = Display::url(
$row[3],
api_get_path(WEB_CODE_PATH).'admin/user_information?user_id='.$row[4], array('title' => get_lang('UserInfo'))
api_get_path(WEB_CODE_PATH).'admin/user_information.php?user_id='.$row[4], array('title' => get_lang('UserInfo'))
);
$row[4] = TrackingUserLog::get_ip_from_user_event($row[4], $row[5], true);

@ -0,0 +1,344 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Generate a teacher time report in platform or sessions/courses
*
* @author Angel Fernando Quiroz Campos <angel.quiroz@beeznest.com>
* @package chamilo.admin
*/
/* INIT SECTION */
// Language files that need to be included.
if (isset($_GET['category']) && $_GET['category'] == 'Templates') {
$language_file = array('admin', 'document');
} else if (isset($_GET['category']) && $_GET['category'] == 'Gradebook') {
$language_file = array('admin', 'gradebook');
} else {
$language_file = array('admin', 'document');
}
$language_file[] = 'tracking';
// Resetting the course id.
$cidReset = true;
// Including some necessary library files.
require_once '../inc/global.inc.php';
require_once api_get_path(LIBRARY_PATH) . 'TeacherTimeReport.php';
// Setting the section (for the tabs).
$this_section = SECTION_PLATFORM_ADMIN;
$interbreadcrumb[] = array("url" => 'index.php', "name" => get_lang('PlatformAdmin'));
$toolName = get_lang('TeacherTimeReport');
// Access restrictions.
api_protect_admin_script();
$startDate = new DateTime(api_get_local_time());
$startDate->modify('first day of this month');
$limitDate = new DateTime(api_get_local_time());
$selectedCourse = isset($_REQUEST['course']) ? $_REQUEST['course'] : null;
$selectedSession = isset($_REQUEST['session']) ? $_REQUEST['session'] : 0;
$selectedTeacher = isset($_REQUEST['teacher']) ? $_REQUEST['teacher'] : 0;
$selectedFrom = isset($_REQUEST['from']) && !empty($_REQUEST['from']) ? $_REQUEST['from'] : $startDate->format('Y-m-d');
$selectedUntil = isset($_REQUEST['from']) && !empty($_REQUEST['until']) ? $_REQUEST['until'] : $limitDate->format('Y-m-d');
$courseList = CourseManager::get_courses_list(0, 0, 'title');
$sessionsList = SessionManager::get_sessions_list(array(), array('name'));
$teacherList = UserManager::getTeachersList();
$htmlHeadXtra[] = '
<script src="' . api_get_path(WEB_LIBRARY_PATH) . 'javascript/daterange/moment.min.js"></script>
<link rel="stylesheet" href="' . api_get_path(WEB_LIBRARY_PATH) . 'javascript/daterange/daterangepicker-bs2.css">
<script src="' . api_get_path(WEB_LIBRARY_PATH) . 'javascript/daterange/daterangepicker.js"></script>';
$withFilter = false;
$reportTitle = get_lang('TimeReportIncludingAllCoursesAndSessionsByTeacher');
$reportSubTitle = sprintf(get_lang('TimeSpentBetweenXAndY'), $selectedFrom, $selectedUntil);
$timeReport = new TeacherTimeReport();
if (!empty($selectedCourse)) {
$withFilter = true;
$course = api_get_course_info($selectedCourse);
$reportTitle = sprintf(get_lang('TimeReportForCourseX'), $course['title']);
$teachers = CourseManager::get_teacher_list_from_course_code($selectedCourse);
foreach ($teachers as $teacher) {
$totalTime = UserManager::getExpendedTimeInCourses(
$teacher['user_id'],
$selectedCourse,
0,
$selectedFrom,
$selectedUntil
);
$formatedTime = api_format_time($totalTime);
$timeReport->data[] = array(
'session' => null,
'course' => array(
'id' => $course['real_id'],
'name' => $course['title']
),
'coach' => array(
'userId' => $teacher['user_id'],
'lastname' => $teacher['lastname'],
'firstname' => $teacher['firstname'],
'username' => $teacher['username'],
'completeName' => api_get_person_name($teacher['firstname'], $teacher['lastname'])
),
'totalTime' => $formatedTime
);
}
$sessionsByCourse = SessionManager::get_session_by_course($selectedCourse);
foreach ($sessionsByCourse as $session) {
$coaches = CourseManager::get_coachs_from_course($session['id'], $selectedCourse);
if ($coaches) {
foreach ($coaches as $coach) {
$totalTime = UserManager::getExpendedTimeInCourses(
$coach['user_id'],
$selectedCourse,
$session['id'],
$selectedFrom,
$selectedUntil
);
$formatedTime = api_format_time($totalTime);
$timeReport->data[] = array(
'session' => array(
'id' => $session['id'],
'name' => $session['name']
),
'course' => array(
'id' => $course['real_id'],
'name' => $course['title']
),
'coach' => array(
'userId' => $coach['user_id'],
'lastname' => $coach['lastname'],
'firstname' => $coach['firstname'],
'username' => $coach['username'],
'completeName' => api_get_person_name($coach['firstname'], $coach['lastname'])
),
'totalTime' => $formatedTime
);
}
}
}
}
if (!empty($selectedSession)) {
$withFilter = true;
$session = api_get_session_info($selectedSession);
$sessionData = array(
'id' => $session['id'],
'name' => $session['name']
);
$reportTitle = sprintf(get_lang('TimeReportForSessionX'), $session['name']);
$courses = SessionManager::get_course_list_by_session_id($selectedSession);
foreach ($courses as $course) {
$courseData = array(
'id' => $course['id'],
'name' => $course['title']
);
$coaches = CourseManager::get_coachs_from_course($selectedSession, $course['code']);
if ($coaches) {
foreach ($coaches as $coach) {
$totalTime = UserManager::getExpendedTimeInCourses(
$coach['user_id'],
$course['code'],
$selectedSession,
$selectedFrom,
$selectedUntil
);
$formatedTime = api_format_time($totalTime);
$timeReport->data[] = array(
'session' => $sessionData,
'course' => $courseData,
'coach' => array(
'userId' => $coach['user_id'],
'lastname' => $coach['lastname'],
'firstname' => $coach['firstname'],
'username' => $coach['username'],
'completeName' => api_get_person_name($coach['firstname'], $coach['lastname'])
),
'totalTime' => $formatedTime
);
}
}
}
}
if (!empty($selectedTeacher)) {
$withFilter = true;
$teacher = api_get_user_info();
$teacherData = array(
'userId' => $teacher['user_id'],
'lastname' => $teacher['lastname'],
'firstname' => $teacher['firstname'],
'username' => $teacher['username'],
'completeName' => $teacher['complete_name']
);
$reportTitle = sprintf(get_lang('TimeReportForTeacherX'), $teacher['complete_name']);
$courses = CourseManager::get_courses_list_by_user_id($selectedTeacher, false);
if (!empty($courses)) {
foreach ($courses as $course) {
$courseInfo = api_get_course_info($course['code']);
$totalTime = UserManager::getExpendedTimeInCourses(
$selectedTeacher,
$course['code'],
0,
$selectedFrom,
$selectedUntil
);
$formatedTime = api_format_time($totalTime);
$timeReport->data[] = array(
'session' => null,
'course' => array(
'id' => $courseInfo['real_id'],
'name' => $courseInfo['title']
),
'coach' => $teacherData,
'totalTime' => $formatedTime
);
}
}
$coursesInSession = SessionManager::getCoursesListByCourseCoach($selectedTeacher);
foreach ($coursesInSession as $course) {
$session = api_get_session_info($course['id_session']);
$sessionData = array(
'id' => $session['id'],
'name' => $session['name']
);
$courseInfo = api_get_course_info($course['course_code']);
$totalTime = UserManager::getExpendedTimeInCourses(
$selectedTeacher,
$course['course_code'],
$session['id'],
$selectedFrom,
$selectedUntil
);
$formatedTime = api_format_time($totalTime);
$timeReport->data[] = array(
'session' => $sessionData,
'course' => array(
'id' => $courseInfo['real_id'],
'name' => $courseInfo['title']
),
'coach' => $teacherData,
'totalTime' => $formatedTime
);
}
}
if (empty($selectedCourse) && empty($selectedSession) && empty($selectedTeacher)) {
foreach ($teacherList as &$teacher) {
$timeReport->data[] = array(
'coach' => array(
'username' => $teacher['username'],
'completeName' => $teacher['completeName'],
),
'totalTime' => SessionManager::getTotalUserTimeInPlatform($teacher['user_id'], $selectedFrom, $selectedUntil)
);
}
}
$timeReport->sortData($withFilter);
if (isset($_GET['export'])) {
require_once api_get_path(LIBRARY_PATH) . 'export.lib.inc.php';
$dataToExport = $timeReport->prepareDataToExport($withFilter);
$fileName = get_lang('TeacherTimeReport') . ' ' . api_get_local_time();
switch ($_GET['export']) {
case 'pdf':
$params = array(
'add_signatures' => false,
'filename' => $fileName,
'pdf_title' => "$reportTitle - $reportSubTitle",
'pdf_description' => get_lang('TeacherTimeReport'),
'format' => 'A4-L',
'orientation' => 'L'
);
$pdfContent = Export::convert_array_to_html($dataToExport);
Export::export_html_to_pdf($pdfContent, $params);
break;
case 'xls':
array_unshift($dataToExport, array(
$reportTitle
), array(
$reportSubTitle
), array());
Export::export_table_xls_html($dataToExport, $fileName);
break;
}
die;
}
// view
//hack for daterangepicker
$startDate->modify('+1 day');
$limitDate->modify('+1 day');
$tpl = new Template($toolName);
$tpl->assign('reportTitle', $reportTitle);
$tpl->assign('reportSubTitle', $reportSubTitle);
$tpl->assign('filterStartDate', $startDate->format('Y-m-d'));
$tpl->assign('filterEndDate', $limitDate->format('Y-m-d'));
$tpl->assign('filterMaxDate', $limitDate->format('Y-m-d'));
$tpl->assign('selectedCourse', $selectedCourse);
$tpl->assign('selectedSession', $selectedSession);
$tpl->assign('selectedTeacher', $selectedTeacher);
$tpl->assign('selectedFrom', $selectedFrom);
$tpl->assign('selectedUntil', $selectedUntil);
$tpl->assign('withFilter', $withFilter);
$tpl->assign('courses', $courseList);
$tpl->assign('sessions', $sessionsList);
$tpl->assign('courseCoaches', $teacherList);
$tpl->assign('rows', $timeReport->data);
$contentTemplate = $tpl->get_template('admin/teacher_time_report.tpl');
$tpl->display($contentTemplate);

@ -198,6 +198,7 @@ $status[COURSEMANAGER] = get_lang('Teacher');
$status[STUDENT] = get_lang('Learner');
$status[DRH] = get_lang('Drh');
$status[SESSIONADMIN] = get_lang('SessionsAdmin');
$status[STUDENT_BOSS] = get_lang('RoleStudentBoss');
$form->addElement('select', 'status', get_lang('Profile'), $status, array('id' => 'status_select', 'class'=>'chzn-select', 'onchange' => 'javascript: display_drh_list();'));

@ -211,6 +211,7 @@ $status[COURSEMANAGER] = get_lang('Teacher');
$status[STUDENT] = get_lang('Learner');
$status[DRH] = get_lang('Drh');
$status[SESSIONADMIN] = get_lang('SessionsAdmin');
$status[STUDENT_BOSS] = get_lang('RoleStudentBoss');
$form->addElement('select', 'status', get_lang('Profile'), $status, array('id' => 'status_select', 'onchange' => 'javascript: display_drh_list();','class'=>'chzn-select'));

@ -579,13 +579,35 @@ function modify_filter($user_id, $url_params, $row) {
$result .= '<a href="dashboard_add_sessions_to_user.php?user='.$user_id.'">'.Display::return_icon('view_more_stats.gif', get_lang('AssignSessions')).'</a>&nbsp;&nbsp;';
}*/
} else {
if ($current_user_status_label == $statusname[DRH] || UserManager::is_admin($user_id)) {
$result .= '<a href="dashboard_add_users_to_user.php?user='.$user_id.'">'.Display::return_icon('user_subscribe_course.png', get_lang('AssignUsers'),'',ICON_SIZE_SMALL).'</a>';
$result .= '<a href="dashboard_add_courses_to_user.php?user='.$user_id.'">'.Display::return_icon('course_add.gif', get_lang('AssignCourses')).'</a>&nbsp;&nbsp;';
$result .= '<a href="dashboard_add_sessions_to_user.php?user='.$user_id.'">'.Display::return_icon('view_more_stats.gif', get_lang('AssignSessions')).'</a>&nbsp;&nbsp;';
} else if ($current_user_status_label == $statusname[SESSIONADMIN]) {
$result .= '<a href="dashboard_add_sessions_to_user.php?user='.$user_id.'">'.Display::return_icon('view_more_stats.gif', get_lang('AssignSessions')).'</a>&nbsp;&nbsp;';
}
if ($current_user_status_label == $statusname[SESSIONADMIN]) {
$result .= Display::url(
Display::return_icon('view_more_stats.gif', get_lang('AssignSessions')),
"dashboard_add_sessions_to_user.php?user={$user_id}"
);
} else {
if (
$current_user_status_label == $statusname[DRH] ||
UserManager::is_admin($user_id) ||
$current_user_status_label == $statusname[STUDENT_BOSS]
) {
$result .= Display::url(
Display::return_icon('user_subscribe_course.png', get_lang('AssignUsers'), '', ICON_SIZE_SMALL),
"dashboard_add_users_to_user.php?user={$user_id}"
);
}
if ($current_user_status_label == $statusname[DRH] || UserManager::is_admin($user_id)) {
$result .= Display::url(
Display::return_icon('course_add.gif', get_lang('AssignCourses')),
"dashboard_add_courses_to_user.php?user={$user_id}"
);
$result .= Display::url(
Display::return_icon('view_more_stats.gif', get_lang('AssignSessions')),
"dashboard_add_sessions_to_user.php?user={$user_id}"
);
}
}
}
if (api_is_platform_admin()) {

@ -1,11 +1,10 @@
<?php
/* For licensing terms, see /license.txt */
/**
* @package chamilo.admin
*/
/**
* Code
*/
// name of the language file that needs to be included
$language_file = 'admin';
$cidReset = true;
@ -29,14 +28,15 @@ $form->addElement('header', $tool_name);
$form->addElement('style_submit_button', 'submit', get_lang('Export'), 'class="save"');
if ($form->validate()) {
$user_group = new UserGroup;
$header = array(array('id', 'name', 'description'));
$data = $user_group->get_all_for_export();
$userGroup = new UserGroup();
$header = array(array('id', 'name', 'description', 'users'));
$data = $userGroup->getDataToExport();
$data = array_merge($header, $data);
$filename = 'export_classes_'.api_get_local_time();
Export::export_table_csv($data, $filename);
exit;
}
Display :: display_header($tool_name);
$form->display();
Display::display_footer();

@ -1,5 +1,6 @@
<?php
/* For licensing terms, see /license.txt */
/**
* This tool allows platform admins to add classes by uploading a CSV file
* @todo Add some langvars to DLTT
@ -13,7 +14,7 @@ function validate_data($classes) {
$errors = array();
$usergroup = new UserGroup();
foreach ($classes as $index => $class) {
// 1. Check wheter ClassName is available.
// 1. Check of class name is available.
if (!isset($class['name']) || strlen(trim($class['name'])) == 0) {
$class['line'] = $index + 2;
$class['error'] = get_lang('MissingClassName');
@ -41,15 +42,34 @@ function validate_data($classes) {
*/
function save_data($classes)
{
$number_of_added_classes = 0;
$count = 0;
$usergroup = new UserGroup();
foreach ($classes as $index => $class) {
$usersToAdd = isset($class['users']) ? $class['users'] : null;
unset($class['users']);
$id = $usergroup->save($class);
if ($id) {
$number_of_added_classes++;
if (!empty($usersToAdd)) {
$usersToAddList = explode(',', $usersToAdd);
$userIdList = array();
foreach ($usersToAddList as $username) {
$userInfo = api_get_user_info_from_username($username);
$userIdList[] = $userInfo['user_id'];
}
if (!empty($userIdList)) {
$usergroup->subscribe_users_to_usergroup(
$id,
$userIdList,
false
);
}
}
$count++;
}
}
return $number_of_added_classes;
return $count;
}
// Language files that should be included.
@ -113,8 +133,8 @@ $form->display();
<p><?php echo get_lang('CSVMustLookLike') . ' (' . get_lang('MandatoryFields') . ')'; ?> :</p>
<pre>
<b>name;description</b>
"User group 1";"Description"
<b>name;description;</b>users
"User group 1";"Description";admin,username1,username2
</pre>
<?php
// Displaying the footer.

@ -220,7 +220,6 @@ if (api_is_allowed_to_edit(false,true) OR
// tooledit : visibility = 2 : only visible for platform administrator
if ($ctok == $_GET['sec_token']) {
AnnouncementManager::delete_announcement($_course, $id);
//delete_added_resource("Ad_Valvas", $delete);
$id = null;
$emailTitle = null;
@ -263,7 +262,7 @@ if (api_is_allowed_to_edit(false,true) OR
$id = intval($_GET['id']);
if (!api_is_course_coach() || api_is_element_in_the_session(TOOL_ANNOUNCEMENT, $id)) {
$sql="SELECT * FROM $tbl_announcement WHERE c_id = $course_id AND id = '$id'";
$sql = "SELECT * FROM $tbl_announcement WHERE c_id = $course_id AND id = '$id'";
$rs = Database::query($sql);
$myrow = Database::fetch_array($rs);
$last_id = $id;
@ -326,7 +325,6 @@ if (api_is_allowed_to_edit(false,true) OR
while (list ($announcementId, $announcementOrder) = Database::fetch_row($result)) {
// STEP 2 : FOUND THE NEXT ANNOUNCEMENT ID AND ORDER.
// COMMIT ORDER SWAP ON THE DB
if ($thisAnnouncementOrderFound) {
$nextAnnouncementId = $announcementId;
$nextAnnouncementOrder = $announcementOrder;
@ -471,7 +469,7 @@ if (api_is_allowed_to_edit(false,true)) {
} else {
// students only get to see the visible announcements
if (empty($_GET['origin']) or $_GET['origin'] !== 'learnpath') {
$group_memberships=GroupManager::get_group_ids($_course['real_id'], $_user['user_id']);
$group_memberships = GroupManager::get_group_ids($_course['real_id'], $_user['user_id']);
if ((api_get_course_setting('allow_user_edit_announcement') && !api_is_anonymous())) {
@ -494,19 +492,19 @@ if (api_is_allowed_to_edit(false,true)) {
// the user is member of several groups => display personal announcements AND his group announcements AND the general announcements
if (is_array($group_memberships) && count($group_memberships)>0) {
$sql="SELECT announcement.*, ip.visibility, ip.to_group_id, ip.insert_user_id
FROM $tbl_announcement announcement, $tbl_item_property ip
WHERE
announcement.c_id = $course_id AND
ip.c_id = $course_id AND
announcement.id = ip.ref AND
ip.tool='announcement'
AND ip.visibility='1'
$cond_user_id
$condition_session
GROUP BY ip.ref
ORDER BY display_order DESC
LIMIT 0,$maximum";
$sql = "SELECT announcement.*, ip.visibility, ip.to_group_id, ip.insert_user_id
FROM $tbl_announcement announcement, $tbl_item_property ip
WHERE
announcement.c_id = $course_id AND
ip.c_id = $course_id AND
announcement.id = ip.ref AND
ip.tool='announcement'
AND ip.visibility='1'
$cond_user_id
$condition_session
GROUP BY ip.ref
ORDER BY display_order DESC
LIMIT 0, $maximum";
} else {
// the user is not member of any group
// this is an identified user => show the general announcements AND his personal announcements
@ -520,16 +518,16 @@ if (api_is_allowed_to_edit(false,true)) {
$sql="SELECT announcement.*, ip.visibility, ip.to_group_id, ip.insert_user_id
FROM $tbl_announcement announcement, $tbl_item_property ip
WHERE
announcement.c_id = $course_id AND
ip.c_id = $course_id AND
announcement.id = ip.ref
AND ip.tool='announcement'
AND ip.visibility='1'
$cond_user_id
$condition_session
announcement.c_id = $course_id AND
ip.c_id = $course_id AND
announcement.id = ip.ref
AND ip.tool='announcement'
AND ip.visibility='1'
$cond_user_id
$condition_session
GROUP BY ip.ref
ORDER BY display_order DESC
LIMIT 0,$maximum";
LIMIT 0, $maximum";
} else {
if (api_get_course_setting('allow_user_edit_announcement')) {
@ -542,13 +540,13 @@ if (api_is_allowed_to_edit(false,true)) {
$sql="SELECT announcement.*, ip.visibility, ip.to_group_id, ip.insert_user_id
FROM $tbl_announcement announcement, $tbl_item_property ip
WHERE
announcement.c_id = $course_id AND
ip.c_id = $course_id AND
announcement.id = ip.ref
AND ip.tool='announcement'
AND ip.visibility='1'
AND ip.to_group_id='0'
$condition_session
announcement.c_id = $course_id AND
ip.c_id = $course_id AND
announcement.id = ip.ref
AND ip.tool='announcement'
AND ip.visibility='1'
AND ip.to_group_id='0'
$condition_session
GROUP BY ip.ref
ORDER BY display_order DESC
LIMIT 0,$maximum";
@ -619,7 +617,6 @@ if ($display_form) {
$title_to_modify = stripslashes($title_to_modify);
// DISPLAY ADD ANNOUNCEMENT COMMAND
//echo '<form method="post" name="f1" enctype = "multipart/form-data" action="'.api_get_self().'?publish_survey='.Security::remove_XSS($surveyid).'&id='.Security::remove_XSS($_GET['id']).'&db_name='.$db_name.'&cidReq='.Security::remove_XSS($_GET['cidReq']).'" style="margin:0px;">';
$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
echo '<form class="form-horizontal" method="post" name="f1" enctype = "multipart/form-data" action="'.api_get_self().'?id='.$id.'&'.api_get_cidreq().'" style="margin:0px;">';
if (empty($_GET['id'])) {
@ -668,8 +665,6 @@ if ($display_form) {
$title_to_modify = sprintf(get_lang('RemindInactiveLearnersMailSubject'), api_get_setting('siteName'));
$content_to_modify = get_lang('YourAccountIsActiveYouCanLoginAndCheckYourCourses');
}
} else {
//echo '<span id="recipient_overview">' . get_lang('Everybody') . '</span>';
}
AnnouncementManager::show_to_form($to);
echo ' </div>

@ -24,7 +24,7 @@ require_once '../inc/global.inc.php';
require_once api_get_path(SYS_CODE_PATH).'gradebook/lib/gradebook_functions.inc.php';
require_once api_get_path(LIBRARY_PATH).'attendance.lib.php';
require_once api_get_path(LIBRARY_PATH).'app_view.php';
require_once api_get_path(LIBRARY_PATH).'ezpdf/class.ezpdf.php';
require_once 'attendance_controller.php';
require_once api_get_path(SYS_CODE_PATH).'gradebook/lib/fe/exportgradebook.php';
require_once api_get_path(LIBRARY_PATH).'export.lib.inc.php';

@ -547,7 +547,7 @@ class CoursesController
$courseUrl = getCourseCategoryUrl(1, $limit['length'], null, 0, 'subscribe');
foreach ($sessions as $session) {
$sessionsBlocks[] = array(
$sessionsBlock = array(
'id' => $session['id'],
'name' => $session['name'],
'nbr_courses' => $session['nbr_courses'],
@ -556,8 +556,11 @@ class CoursesController
'is_subscribed' => $session['is_subscribed'],
'icon' => $this->getSessionIcon($session['name']),
'date' => SessionManager::getSessionFormattedDate($session),
'subscribe_button' => $this->getRegisterInSessionButton($session['name'])
'subscribe_button' => $this->getRegisterInSessionButton($session['name']),
'showDescription' => $session['show_description']
);
$sessionsBlocks[] = $sessionsBlock;
}
$tpl = new Template();

@ -165,8 +165,8 @@ if ($user_already_registered_show_terms == false) {
'sessionVar' => basename(__FILE__, '.php'),
'imageOptions' => array(
'font_size' => 20,
'font_path' => api_get_path(LIBRARY_PATH).'pchart/fonts/',
'font_file' => 'tahoma.ttf',
'font_path' => api_get_path(SYS_FONTS_PATH) . 'opensans/',
'font_file' => 'OpenSans-Regular.ttf',
//'output' => 'gif'
)
);

@ -44,12 +44,14 @@ $(function() {
});
});
</script>';
require_once api_get_path(SYS_CODE_PATH).'mySpace/myspace.lib.php';
$user_id = api_get_user_id();
$course_user_list = CourseManager::get_courses_list_by_user_id($user_id);
$dates = $issues = '';
$sessionId = isset($_GET['session_id']) ? intval($_GET['session_id']) : 0;
$courseCode = isset($_GET['course']) ? Security::remove_XSS($_GET['course']) : null;
if (!empty($course_user_list)) {
$items = MySpace::get_connections_from_course_list($user_id, $course_user_list);
@ -82,8 +84,10 @@ if (!empty($course_user_list)) {
}
}
$content .= Tracking::show_user_progress(api_get_user_id(), $_GET['session_id']);
$content .= Tracking::show_course_detail(api_get_user_id(), $_GET['course'], $_GET['session_id']);
$content = '';
$content .= Tracking::show_user_progress(api_get_user_id(), $sessionId);
$content .= Tracking::show_course_detail(api_get_user_id(), $courseCode, $sessionId);
if (!empty($dates)) {
if (!empty($content)) {
@ -104,11 +108,13 @@ if (!empty($dates)) {
</div></div>';
}
$message = null;
if (empty($content)) {
$message = Display::return_message(get_lang('NoDataAvailable'), 'warning');
}
$tpl = new Template($tool_name);
$tpl = new Template($nameTools);
$tpl->assign('message', $message);
$tpl->assign('content', $content);

@ -16,6 +16,7 @@ class Agenda
public $senderId;
/** @var array */
public $course;
public $comment;
/**
* Constructor
@ -114,6 +115,7 @@ class Agenda
* @param int $parentEventId
* @param array $attachmentArray $_FILES['']
* @param string $attachmentComment
* @param string $eventComment
*
* @return int
*/
@ -127,7 +129,8 @@ class Agenda
$addAsAnnouncement = false,
$parentEventId = null,
$attachmentArray = array(),
$attachmentComment = null
$attachmentComment = null,
$eventComment = null
) {
$start = api_get_utc_datetime($start);
$end = api_get_utc_datetime($end);
@ -160,6 +163,12 @@ class Agenda
'c_id' => $this->course['real_id']
);
$allow = api_get_configuration_value('allow_agenda_event_comment');
if ($allow) {
$attributes['comment'] = $eventComment;
}
if (!empty($parentEventId)) {
$attributes['parent_event_id'] = $parentEventId;
}
@ -533,6 +542,7 @@ class Agenda
* @param int $editRepeatType
* @param array $attachmentArray
* @param string $attachmentComment
* @param string $comment
*
* @return bool
*/
@ -545,7 +555,8 @@ class Agenda
$content,
$usersToSend = array(),
$attachmentArray = array(),
$attachmentComment = null
$attachmentComment = null,
$comment = null
) {
$start = api_get_utc_datetime($start);
$end = api_get_utc_datetime($end);
@ -594,6 +605,12 @@ class Agenda
'all_day' => $allDay
);
$allow = api_get_configuration_value('allow_agenda_event_comment');
if ($allow) {
$attributes['comment'] = $comment;
}
Database::update(
$this->tbl_course_agenda,
$attributes,
@ -1322,6 +1339,7 @@ class Agenda
}
$sql .= $dateCondition;
$allowComments = api_get_configuration_value('allow_agenda_event_comment');
$result = Database::query($sql);
if (Database::num_rows($result)) {
@ -1428,9 +1446,16 @@ class Agenda
$event['parent_event_id'] = $row['parent_event_id'];
$event['has_children'] = $this->hasChildren($row['id'], $course_id) ? 1 : 0;
if ($allowComments) {
$event['comment'] = $row['comment'];
} else {
$event['comment'] = null;
}
$this->events[] = $event;
}
}
return $this->events;
}
@ -1822,6 +1847,11 @@ class Agenda
);
if ($this->type == 'course') {
$allow = api_get_configuration_value('allow_agenda_event_comment');
if ($allow) {
$form->addElement('textarea', 'comment', get_lang('Comment'));
}
$form->addElement('file', 'user_upload', get_lang('AddAnAttachment'));
if ($showAttachmentForm) {
@ -1839,7 +1869,7 @@ class Agenda
}
}
$form->addElement('textarea', 'file_comment', get_lang('Comment'));
$form->addElement('textarea', 'file_comment', get_lang('FileComment'));
}
if (empty($id)) {

@ -114,6 +114,8 @@ if (api_is_allowed_to_edit(false, true) OR
$attachment = $sendAttachment ? $_FILES['user_upload'] : null;
$attachmentComment = isset($values['file_comment']) ? $values['file_comment'] : null;
$comment = isset($values['comment']) ? $values['comment'] : null;
$startDate = $values['date_range_start'];
$endDate = $values['date_range_end'];
@ -127,7 +129,8 @@ if (api_is_allowed_to_edit(false, true) OR
$sendEmail,
null,
$attachment,
$attachmentComment
$attachmentComment,
$comment
);
if (!empty($values['repeat']) && !empty($eventId)) {
@ -174,6 +177,7 @@ if (api_is_allowed_to_edit(false, true) OR
$sendAttachment = isset($_FILES['user_upload']) ? true : false;
$attachment = $sendAttachment ? $_FILES['user_upload'] : null;
$attachmentComment = isset($values['file_comment']) ? $values['file_comment'] : null;
$comment = isset($values['comment']) ? $values['comment'] : null;
// This is a sub event. Delete the current and create another BT#7803
@ -190,7 +194,8 @@ if (api_is_allowed_to_edit(false, true) OR
false,
null,
$attachment,
$attachmentComment
$attachmentComment,
$comment
);
$message = Display::return_message(get_lang('Updated'), 'confirmation');
@ -209,7 +214,8 @@ if (api_is_allowed_to_edit(false, true) OR
$values['content'],
$values['users_to_send'],
$attachment,
$attachmentComment
$attachmentComment,
$comment
);
if (!empty($values['repeat']) && !empty($eventId)) {

@ -1,5 +1,6 @@
<?php
/* For licensing terms, see /license.txt */
/**
* @package chamilo.calendar
*/
@ -221,10 +222,15 @@ $form->addElement('label', get_lang('Date'), '<span id="start_date"></span><span
$form->addElement('text', 'title', get_lang('Title'), array('id' => 'title'));
$form->addElement('textarea', 'content', get_lang('Description'), array('id' => 'content'));
$allowEventComment = api_get_configuration_value('allow_agenda_event_comment');
if ($agenda->type == 'course') {
$form->addElement('html', '<div id="add_as_announcement_div" style="display: none">');
$form->addElement('checkbox', 'add_as_annonuncement', null, get_lang('AddAsAnnouncement'));
$form->addElement('html', '</div>');
if ($allowEventComment) {
$form->addElement('textarea', 'comment', get_lang('Comment'), array('id' => 'comment'));
}
}
$tpl->assign('form_add', $form->return_form());
@ -234,6 +240,8 @@ $content = $tpl->fetch('default/agenda/month.tpl');
$message = Session::read('message');
$tpl->assign('message', $message);
$tpl->assign('allow_agenda_event_comment', $allowEventComment);
Session::erase('message');
$tpl->assign('content', $content);

@ -3,9 +3,7 @@
/**
* @package chamilo.calendar
*/
/**
* INIT SECTION
*/
// name of the language file that needs to be included
$language_file = array('agenda', 'group', 'announcements');

@ -157,7 +157,7 @@ function saveMessage($message, $userId, $_course, $session_id, $group_id, $previ
if (!api_is_anonymous()) {
if (!empty($message)) {
Emojione\Emojione::$imagePathPNG = api_get_path(WEB_LIBRARY_PATH).'javascript/emojione/png/';
Emojione\Emojione::$imagePathSVG = api_get_path(WEB_LIBRARY_PATH).'javascript/emojione/svg/';
//Emojione\Emojione::$imagePathSVG = api_get_path(WEB_LIBRARY_PATH).'javascript/emojione/svg/';
Emojione\Emojione::$ascii = true;
// Parsing emojis

@ -24,7 +24,6 @@ $nameTools = get_lang('ModifInfo');
/* Libraries */
require_once api_get_path(INCLUDE_PATH).'conf/course_info.conf.php';
require_once api_get_path(LIBRARY_PATH).'pdf.lib.php';
require_once api_get_path(LIBRARY_PATH).'fileDisplay.lib.php';
require_once api_get_path(LIBRARY_PATH).'course_category.lib.php';

@ -6,7 +6,7 @@
* @license see /license.txt
* @author Laurent Opprecht <laurent@opprecht.info> for the Univesity of Geneva
*/
require_once dirname(__FILE__) . '/../inc/autoload.inc.php';
require_once dirname(__FILE__) . '/../../vendor/autoload.php';
$controller = CourseNoticeController::instance();
KeyAuth::enable_services($controller);

@ -8,10 +8,6 @@
* @author Angel Fernando Quiroz Campos <angel.quiroz@beeznest.com> Code conventions
* @package chamilo.backup
*/
/**
* Code
*/
/* INIT SECTION */
// Language files that need to be included
$language_file = array('coursebackup', 'admin');

@ -0,0 +1,105 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Automatic fix online time procedure. If a COURSEMANAGER has been idle for $timeLimit
* or more then the procedure adds $extraTime to his logout_course_date.
* @package chamilo.cron
* @author Imanol Losada <imanol.losada@beeznest.com>
*/
require_once __DIR__ . '/../inc/global.inc.php';
/**
* Get ids of COURSEMANAGERs that are inside a course right now
* @return array COURSEMANAGER's ids
*/
function getTeachersInCourseIds()
{
$table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ONLINE);
$joinStatement = ' JOIN ' . Database::get_main_table(TABLE_MAIN_USER) . ' ON login_user_id = user_id';
return Database::select(
'login_user_id', $table . $joinStatement,
array(
'where' => array(
'course IS NOT NULL AND status = ?' => array(
COURSEMANAGER
)
)
)
);
}
/**
* If a COURSEMANAGER has been idle for $timeLimit or more then
* the procedure adds $extraTime to his logout_course_date.
* @param array COURSEMANAGER's ids
* @return void
*/
function updateTeachersInCourseIdleForTimeLimit($teachersInCourseIds)
{
$timeLimit = '- 30 minute';
$extraTime = '+ 5 minute';
$utcResult = Database::fetch_array(
Database::query('SELECT UTC_TIMESTAMP')
);
$dataBaseCurrentHour = array_shift($utcResult);
$maximumIdleTimeInCourse = date(
'Y-m-d H:i:s',
strtotime($dataBaseCurrentHour . ' ' . $timeLimit)
);
$table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
$onLineTrackTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ONLINE);
foreach ($teachersInCourseIds as $key => $value) {
$value = array_shift($value);
$logResult = Database::select(
'course_access_id,logout_course_date',
$table,
array(
'where' => array(
'user_id = ?' => array(
$value,
)
),
'order' => 'course_access_id DESC',
'limit' => '1'
)
);
$currentTeacherData = array_shift($logResult);
Database::update(
$table,
array(
'logout_course_date' => date(
'Y-m-d H:i:s',
strtotime($currentTeacherData['logout_course_date'] . ' ' . $extraTime)
)
),
array(
'user_id = ? AND logout_course_date < ? AND course_access_id = ?' => array(
$value,
$maximumIdleTimeInCourse,
$currentTeacherData['course_access_id']
)
)
);
/*
* (Avoid multiple updates)
* When the user enters a course, this field is updated with the course code.
* And when the user goes to another tool, returns to NULL
*/
$userId = intval($value);
$updateOnLineSql = "UPDATE $onLineTrackTable SET "
. "COURSE = NULL "
. "WHERE login_user_id = $userId";
Database::query($updateOnLineSql);
}
}
/**
* Initialization
*/
if (php_sapi_name() != 'cli') {
exit; //do not run from browser
}
$teachersInCourseIds = getTeachersInCourseIds();
if (!empty($teachersInCourseIds)) {
updateTeachersInCourseIdleForTimeLimit($teachersInCourseIds);
}

@ -109,7 +109,10 @@ class ImportCsv
$isStatic = strpos($method, 'Static');
if (method_exists($this, $method)) {
if ($method == 'importUnsubscribeStatic' || empty($isStatic)) {
if (($method == 'importUnsubscribeStatic' ||
$method == 'importSubscribeStatic') ||
empty($isStatic)
) {
$fileToProcess[$parts[1]][] = array(
'method' => $method,
'file' => $path.$fileInfo['basename']
@ -144,8 +147,10 @@ class ImportCsv
'teachers',
'courses',
'sessions',
'subscribe-static',
'unsubscribe-static'
);
foreach ($sections as $section) {
$this->logger->addInfo("-- Import $section --");
@ -169,6 +174,7 @@ class ImportCsv
'sessions-static',
'calendar-static',
);
foreach ($sections as $section) {
$this->logger->addInfo("-- Import static files $section --");
@ -644,17 +650,47 @@ class ImportCsv
{
$data = Import::csv_to_array($file);
if ($this->getDumpValues()) {
// Remove all calendar items
$truncateTables = array(
Database::get_course_table(TABLE_AGENDA),
Database::get_course_table(TABLE_AGENDA_ATTACHMENT),
Database::get_course_table(TABLE_AGENDA_REPEAT),
Database::get_course_table(TABLE_AGENDA_REPEAT_NOT),
Database::get_main_table(TABLE_PERSONAL_AGENDA),
Database::get_main_table(TABLE_PERSONAL_AGENDA_REPEAT_NOT),
Database::get_main_table(TABLE_PERSONAL_AGENDA_REPEAT)
);
foreach ($truncateTables as $table) {
$sql = "TRUNCATE $table";
Database::query($sql);
}
$table = Database::get_course_table(TABLE_ITEM_PROPERTY);
$sql = "DELETE FROM $table WHERE tool = 'calendar_event'";
Database::query($sql);
}
if (!empty($data)) {
$this->logger->addInfo(count($data) . " records found.");
$eventsToCreate = array();
$errorFound = false;
foreach ($data as $row) {
$sessionId = SessionManager::get_session_id_from_original_id(
$row['external_sessionID'],
$this->extraFieldIdNameList['session']
);
$sessionId = null;
$externalSessionId = null;
if (isset($row['external_sessionID'])) {
$externalSessionId = $row['external_sessionID'];
$sessionId = SessionManager::get_session_id_from_original_id(
$externalSessionId,
$this->extraFieldIdNameList['session']
);
}
$courseCode = $row['coursecode'];
$courseCode = null;
if (isset($row['coursecode'])) {
$courseCode = $row['coursecode'];
}
$courseInfo = api_get_course_info($courseCode);
if (empty($courseInfo)) {
@ -662,7 +698,7 @@ class ImportCsv
}
if (empty($sessionId)) {
$this->logger->addInfo("external_sessionID: ".$row['external_sessionID']." does not exists.");
$this->logger->addInfo("external_sessionID: ".$externalSessionId." does not exists.");
}
$teacherId = null;
@ -793,6 +829,12 @@ class ImportCsv
$agenda->setSessionId($event['session_id']);
$agenda->setSenderId($event['sender_id']);
$eventComment = $event['comment'];
// To use the event comment you need
// ALTER TABLE c_calendar_event ADD COLUMN comment TEXT;
// add in configuration.php allow_agenda_event_comment = true
if (empty($courseInfo)) {
$this->logger->addInfo(
"No course found for added: #".$event['course_id']." Skipping ..."
@ -814,7 +856,11 @@ class ImportCsv
$event['title'],
$content,
array('everyone'), // send to
false //$addAsAnnouncement = false
false, //$addAsAnnouncement = false
null, // $parentEventId
array(), //$attachmentArray = array(),
null, //$attachmentComment = null,
$eventComment
);
if (!empty($eventId)) {
@ -970,7 +1016,6 @@ class ImportCsv
// 2014-06-30
$dateStart = explode('/', $session['DateStart']);
$dateEnd = explode('/', $session['DateEnd']);
//$visibility = $session['visibility'];
$visibility = $this->defaultSessionVisibility;
$coachId = null;
@ -988,12 +1033,13 @@ class ImportCsv
$dateEnd[0],
$dateEnd[1],
$dateEnd[2],
null, //$session['nb_days_access_before_beginning'],
null, //$session['nb_days_access_after_end'],
$this->daysCoachAccessBeforeBeginning,
$this->daysCoachAccessAfterBeginning,
null,
$coachUserName,
$categoryId,
$visibility
$visibility,
1
);
if (is_numeric($result)) {
@ -1005,6 +1051,28 @@ class ImportCsv
);
}
} else {
$sessionInfo = api_get_session_info($sessionId);
$accessBefore = null;
$accessAfter = null;
if (empty($sessionInfo['nb_days_access_before_beginning']) ||
(!empty($sessionInfo['nb_days_access_before_beginning']) &&
$sessionInfo['nb_days_access_before_beginning'] < $this->daysCoachAccessBeforeBeginning)
) {
$accessBefore = intval($this->daysCoachAccessBeforeBeginning);
}
$accessAfter = null;
if (empty($sessionInfo['nb_days_access_after_end']) ||
(!empty($sessionInfo['nb_days_access_after_end']) &&
$sessionInfo['nb_days_access_after_end'] < $this->daysCoachAccessAfterBeginning)
) {
$accessAfter = intval($this->daysCoachAccessAfterBeginning);
}
$showDescription = isset($sessionInfo['show_description']) ? $sessionInfo['show_description'] : 1;
$result = SessionManager::edit_session(
$sessionId,
$session['SessionName'],
@ -1014,12 +1082,16 @@ class ImportCsv
$dateEnd[0],
$dateEnd[1],
$dateEnd[2],
null,//$session['nb_days_access_before_beginning'],
null,//$session['nb_days_access_after_end'],
$accessBefore,
$accessAfter,
null,
$coachId,
$categoryId,
$visibility
$visibility,
true, //$start_limit =
true, //$end_limit =
null, //$description
$showDescription // $showDescription = null,
);
if (is_numeric($result)) {
@ -1143,7 +1215,10 @@ class ImportCsv
$avoid,
false, // deleteUsersNotInList
false, // updateCourseCoaches
true // sessionWithCoursesModifier
true, // sessionWithCoursesModifier
true, //$addOriginalCourseTeachersAsCourseSessionCoaches
true, //$removeAllTeachersFromCourse
1 // $showDescription
);
if (!empty($result['error_message'])) {
@ -1156,6 +1231,67 @@ class ImportCsv
}
}
/**
* @param string $file
*/
private function importSubscribeStatic($file)
{
$data = Import::csv_reader($file);
if (!empty($data)) {
$this->logger->addInfo(count($data) . " records found.");
foreach ($data as $row) {
$chamiloUserName = $row['UserName'];
$chamiloCourseCode = $row['CourseCode'];
$chamiloSessionId = $row['SessionID'];
$type = $row['Type'];
$sessionInfo = api_get_session_info($chamiloSessionId);
if (empty($sessionInfo)) {
$this->logger->addError('Session does not exists: '.$chamiloSessionId);
continue;
}
$courseInfo = api_get_course_info($chamiloCourseCode);
if (empty($courseInfo)) {
$this->logger->addError('Course does not exists: '.$courseInfo);
continue;
}
$userId = Usermanager::get_user_id_from_username($chamiloUserName);
if (empty($userId)) {
$this->logger->addError('User does not exists: '.$chamiloUserName);
continue;
}
$status = null;
switch ($type) {
case 'student':
SessionManager::subscribe_users_to_session_course(
array($userId),
$chamiloSessionId,
$courseInfo['code'],
null,
false
);
break;
case 'teacher':
SessionManager::set_coach_to_course_session(
$userId,
$chamiloSessionId,
$courseInfo['code']
);
break;
}
$this->logger->addError(
"User '$chamiloUserName' with status $type was added to session: #$chamiloSessionId - Course: " . $courseInfo['code']
);
}
}
}
/**
* @param string $file
*/
@ -1191,7 +1327,9 @@ class ImportCsv
}
CourseManager::unsubscribe_user($userId, $courseInfo['code'], $chamiloSessionId);
$this->logger->addError("User '$chamiloUserName' was removed from session: #$chamiloSessionId, Course: ".$courseInfo['code']);
$this->logger->addError(
"User '$chamiloUserName' was removed from session: #$chamiloSessionId, Course: ".$courseInfo['code']
);
}
}
}

@ -19,9 +19,6 @@ if (php_sapi_name()!='cli') {
die();
}
// include nusoap library
require_once(api_get_path(LIBRARY_PATH).'nusoap/nusoap.php');
// create client
$client = new nusoap_client(api_get_path(WEB_CODE_PATH).'cron/user_import/service.php');

@ -5155,20 +5155,21 @@ i.size-32.icon-new-note{
padding: 10px 0px 10px 40px;
background-repeat:no-repeat;
}
select#question_type_hidden option[value="1"] {background-image: url(../img/icons/32/mcua.gif);}
select#question_type_hidden option[value="2"] {background-image: url(../img/icons/32/mcma.gif);}
select#question_type_hidden option[value="3"] {background-image: url(../img/icons/32/fill_in_blanks.gif);}
select#question_type_hidden option[value="4"] {background-image: url(../img/icons/32/matching.gif);}
select#question_type_hidden option[value="5"] {background-image: url(../img/icons/32/open_answer.gif);}
select#question_type_hidden option[value="6"] {background-image: url(../img/icons/32/hotspot.gif);}
select#question_type_hidden option[value="7"] {background-image: url(../img/icons/32/mcma.gif);}
select#question_type_hidden option[value="8"] {background-image: url(../img/icons/32/mcma.gif);}
select#question_type_hidden option[value="9"] {background-image: url(../img/icons/32/mcmac.gif);}
select#question_type_hidden option[value="10"] {background-image: url(../img/icons/32/mcuao.gif);}
select#question_type_hidden option[value="11"] {background-image: url(../img/icons/32/mcmao.gif);}
select#question_type_hidden option[value="12"] {background-image: url(../img/icons/32/mcmaco.gif);}
select#question_type_hidden option[value="1"] {background-image: url(../img/icons/32/mcua.png);}
select#question_type_hidden option[value="2"] {background-image: url(../img/icons/32/mcma.png);}
select#question_type_hidden option[value="3"] {background-image: url(../img/icons/32/fill_in_blanks.png);}
select#question_type_hidden option[value="4"] {background-image: url(../img/icons/32/matching.png);}
select#question_type_hidden option[value="5"] {background-image: url(../img/icons/32/open_answer.png);}
select#question_type_hidden option[value="6"] {background-image: url(../img/icons/32/hotspot.png);}
select#question_type_hidden option[value="7"] {background-image: url(../img/icons/32/mcma.png);}
select#question_type_hidden option[value="8"] {background-image: url(../img/icons/32/mcma.png);}
select#question_type_hidden option[value="9"] {background-image: url(../img/icons/32/mcmac.png);}
select#question_type_hidden option[value="10"] {background-image: url(../img/icons/32/mcuao.png);}
select#question_type_hidden option[value="11"] {background-image: url(../img/icons/32/mcmao.png);}
select#question_type_hidden option[value="12"] {background-image: url(../img/icons/32/mcmaco.png);}
select#question_type_hidden option[value="13"] {background-image: url(../img/icons/32/audio_question.png);}
select#question_type_hidden option[value="14"] {background-image: url(../img/icons/32/mcmagl.gif);}
select#question_type_hidden option[value="14"] {background-image: url(../img/icons/32/mcmagl.png);}
select#question_type_hidden option[value="16"] {background-image: url(../img/icons/32/calculated_answer.png);}
}
@ -5304,3 +5305,157 @@ i.size-32.icon-new-work{
{
height: 52px;
}
#settings .span6 .well_border .edit-block {
display: none;
}
#settings .span6 .well_border:hover .edit-block {
display: block;
}
#settings .span6:nth-child(2n+1) {
clear:left
/***** Survey *****/
#list-survey p{
display: inline-block;
margin-left: 10px;
}
.survey-block{
width: 100%;
margin: auto;
padding: 10px;
box-sizing:border-box;
-moz-box-sizing:border-box;
-webkit-box-sizing:border-box;
}
.survey-block .table tbody tr:hover td{
background-color: #fff6d5 ;
}
.survey-block .table tbody tr:hover th,.survey-block .table tbody tr th {
background-color: #ececec ;
text-align: center;
}
.survey-block .table .center{
text-align: center;
}
.survey-block .title-survey-block{
padding-top: 10px;
padding-bottom: 10px;
}
.survey-block .title-survey-block h3{
display: inline-block;
margin-left: 10px;
}
#survey_title {
font-size: 24px;
font-weight: 500;
color:#666;
padding-top:10px;
padding-bottom: 10px;
padding-left: 15px;
padding-right: 15px;
background-color: #ececec;
}
#survey_subtitle {
background-color:#F7F7E3;
color:#666;
padding:10px;
font-size:14px ;
}
.survey_content {
color:#666;
padding:5px;
font-size: 13px;
margin-top: 4px;
margin-bottom: 10px;
}
.survey-block #question{
background-color: #ececec;
text-align: center;
}
.survey_question_wrapper {
border-top: 1px solid #DADADA;
background-color: #ffffff;
padding-top: 1em;
padding-bottom: 2em;
padding-left: 1em;
padding-right: 1em;
text-align: left;
}
.survey_question {
/* 264269 4271b5 E5EDF9 */
color:#666;
padding:5px;
font-size: 16px;
font-weight: bold;
}
.survey_question_options {
/* 264269 4271b5 E5EDF9 */
background-color:#FFF;
color:#000;
padding:5px;/*border: 1px solid #264269;*/
}
.survey-next.btn{
border:1px solid #319265; -webkit-border-radius: 3px; -moz-border-radius: 3px;border-radius: 3px;font-size:18px;font-family:arial, helvetica, sans-serif; padding: 10px 20px 10px 20px; text-decoration:none; display:inline-block;font-weight:bold; color: #FFFFFF;
background-color: #3FBC82; background-image: -webkit-gradient(linear, left top, left bottom, from(#3FBC82), to(#308E60));
background-image: -webkit-linear-gradient(top, #3FBC82, #308E60);
background-image: -moz-linear-gradient(top, #3FBC82, #308E60);
background-image: -ms-linear-gradient(top, #3FBC82, #308E60);
background-image: -o-linear-gradient(top, #3FBC82, #308E60);
background-image: linear-gradient(to bottom, #3FBC82, #308E60);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=#3FBC82, endColorstr=#308E60);
text-shadow:none;
margin-top: 1em;
margin-bottom: 1em;
}
.survey-next.btn:hover{
border:1px solid #25704d;
background-color: #329668; background-image: -webkit-gradient(linear, left top, left bottom, from(#329668), to(#236846));
background-image: -webkit-linear-gradient(top, #329668, #236846);
background-image: -moz-linear-gradient(top, #329668, #236846);
background-image: -ms-linear-gradient(top, #329668, #236846);
background-image: -o-linear-gradient(top, #329668, #236846);
background-image: linear-gradient(to bottom, #329668, #236846);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=#329668, endColorstr=#236846);
background-position: 0 0;
}
.survey-block .confirmation-message, .survey-block .error-message{
font-size: 16px;
text-align: center;
}
#question_report_questionnumbers.pagination .disabled a{
background-color:#F5F5F5;
color: #666;
}
.title-question{
font-size: 22px;
}
#display-survey.table tbody tr th, #display-survey.table tbody tr:hover th{
background-color:#666;
text-align: center;
font-size: 14px;
color: #FFFFFF;
}
#display-survey .total{
background-color: #EBF3F5;
text-align: center;
}
#display-survey .center{
text-align: center;
}
#display-survey{
border: 1px solid #ddd;
}
#display-survey.table tbody tr:hover td,#display-survey.table tbody tr:hover th{
background-color: none;
}
.answered-people{
padding: 10px;
border: 1px solid #ddd;
margin-bottom: 20px;
}
.answered-people h4{
margin-bottom: 10px;
font-size: 16px;
font-weight: normal;
}

@ -1003,41 +1003,7 @@ padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0p
.skip {
display: none;
}
/* Survey */
#survey_title {
background-color:#dcdcdc;
color:#000;
padding:2px;
}
#survey_subtitle {
background-color:#dcdcdc;
color:#000;
padding:2px;
}
.survey_content {
background-color:#a0e5fc;
color:#264269;
padding:5px;
border: 1px solid #999;
margin-top: 4px;
}
.survey_question_wrapper {
border: 1px solid #999;
margin-top:4px;
}
.survey_question {
/* 264269 4271b5 E5EDF9 */
background-color:#E5EDF9;
color:#999;
padding:5px;/*border: 1px solid #264269;*/
}
.survey_question_options {
/* 264269 4271b5 E5EDF9 */
background-color:#FFF;
color:#000;
padding:5px;/*border: 1px solid #264269;*/
}
/*
Added: to fit img and blocks in home page
*/
#hellomindfactory {

@ -7,7 +7,7 @@
/* the following for regular <a> elements */
body {
line-height: 25px;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
@ -625,7 +625,7 @@ a.thumbnail:hover{
* FOOTER STYLES *
*****************************************************/
footer {
height: 7em;
height: auto;
background: #00a9e0; /* Old browsers */
color:#ffffff;
border-top: none;

@ -28,7 +28,7 @@ if (api_get_setting('enabled_text2audio') == 'false'){
api_not_allowed(true);
}
$document_data = DocumentManager::get_document_data_by_id($_GET['id'], api_get_course_id());
$document_data = DocumentManager::get_document_data_by_id($_REQUEST['id'], api_get_course_id());
if (empty($document_data)) {
if (api_is_in_group()) {
$group_properties = GroupManager::get_group_properties(api_get_group_id());
@ -212,7 +212,7 @@ $(document).ready(function(){
echo '<div>';
$form = new FormValidator('form1', 'post', null, '', array('id' => 'form1'));
$form->addElement('hidden', 'text2voice_mode', 'google');
$form->addElement('hidden', 'document_id', $document_id);
$form->addElement('hidden', 'id', $document_id);
$form->addElement('text', 'title', get_lang('Title'));
$form->addElement('select', 'lang', get_lang('Language'), $options);
$form->addElement('textarea', 'text', get_lang('InsertText2Audio'), array('id' => 'textarea_google', 'class' =>'span6' ));
@ -235,7 +235,7 @@ $(document).ready(function(){
$form = new FormValidator('form2', 'post', null, '', array('id' => 'form2'));
$form->addElement('hidden', 'text2voice_mode','pediaphon');
$form->addElement('hidden', 'document_id', $document_id);
$form->addElement('hidden', 'id', $document_id);
$form->addElement('text', 'title', get_lang('Title'));
$form->addElement('select', 'lang', get_lang('Language'), $options_pedia, array('onclick' => 'update_voices(this.selectedIndex);'));
$form->addElement('select', 'voices', get_lang('Voice'), array(get_lang('FirstSelectALanguage')), array());
@ -345,7 +345,7 @@ Display :: display_footer();
*/
function downloadMP3_google($filepath, $dir)
{
$location='create_audio.php?'.api_get_cidreq().'&id='.Security::remove_XSS($_POST['document_id']).'&dt2a=google';
$location='create_audio.php?'.api_get_cidreq().'&id='.intval($_POST['id']).'&dt2a=google';
//security
if (!isset($_POST['lang']) && !isset($_POST['text']) && !isset($_POST['title']) && !isset($filepath) && !isset($dir)) {
@ -420,7 +420,7 @@ function downloadMP3_google($filepath, $dir)
* @version january 2011, chamilo 1.8.8
*/
function downloadMP3_pediaphon($filepath, $dir){
$location='create_audio.php?'.api_get_cidreq().'&id='.Security::remove_XSS($_POST['document_id']).'&dt2a=pediaphon';
$location='create_audio.php?'.api_get_cidreq().'&id='.intval($_POST['id']).'&dt2a=pediaphon';
//security
if(!isset($_POST['lang']) && !isset($_POST['text']) && !isset($_POST['title']) && !isset($filepath) && !isset($dir)) {
echo '<script>window.location.href="'.$location.'"</script>';

@ -749,13 +749,13 @@ if ($sessionId == 0) {
if (!file_exists($base_work_dir.'/shared_folder')) {
$usf_dir_title = get_lang('UserFolders');
$usf_dir_name = '/shared_folder';
$groupId = 0;
//$groupId = 0;
$visibility = 0;
create_unexisting_directory(
$courseInfo,
api_get_user_id(),
$sessionId,
$groupId,
0,
$to_user_id,
$base_work_dir,
$usf_dir_name,
@ -767,13 +767,13 @@ if ($sessionId == 0) {
if (!file_exists($base_work_dir.'/shared_folder/sf_user_'.$userId)) {
$usf_dir_title = $userInfo['complete_name'];
$usf_dir_name = '/shared_folder/sf_user_'.$userId;
$groupId = 0;
//$groupId = 0;
$visibility = 1;
create_unexisting_directory(
$courseInfo,
api_get_user_id(),
$sessionId,
$groupId,
0,
$to_user_id,
$base_work_dir,
$usf_dir_name,
@ -786,13 +786,13 @@ if ($sessionId == 0) {
if (!file_exists($base_work_dir.'/shared_folder_session_'.$sessionId)) {
$usf_dir_title = get_lang('UserFolders').' ('.api_get_session_name($sessionId).')';
$usf_dir_name = '/shared_folder_session_'.$sessionId;
$groupId = 0;
//$groupId = 0;
$visibility = 0;
create_unexisting_directory(
$courseInfo,
api_get_user_id(),
$sessionId,
$groupId,
0,
$to_user_id,
$base_work_dir,
$usf_dir_name,
@ -804,13 +804,13 @@ if ($sessionId == 0) {
if (!file_exists($base_work_dir.'/shared_folder_session_'.$sessionId.'/sf_user_'.$userId)) {
$usf_dir_title = $userInfo['complete_name'].'('.api_get_session_name($sessionId).')';
$usf_dir_name = '/shared_folder_session_'.$sessionId.'/sf_user_'.$userId;
$groupId = 0;
//$groupId = 0;
$visibility = 1;
create_unexisting_directory(
$courseInfo,
$userId,
$sessionId,
$groupId,
0,
$to_user_id,
$base_work_dir,
$usf_dir_name,

@ -11,25 +11,25 @@ Use Model\Document;
Use Model\Course;
/**
* Return either
*
* Return either
*
* - one document
* - several documents (file and/or folders) zipped together
*
*
* Used to transfer files to another application through http.
*
*
* Script parameters:
*
* - id id(s) of the document id=1 or id=1,2,4
*
* - id id(s) of the document id=1 or id=1,2,4
* - cidReq course code
*
*
* Note this script enables key authentication so access with a key token is possible.
*
*
* @package chamilo.document
* @license see /license.txt
* @author Laurent Opprecht <laurent@opprecht.info> for the Univesity of Geneva
*/
require_once __DIR__ . '/../inc/autoload.inc.php';
require_once __DIR__ . '/../../vendor/autoload.php';
KeyAuth::enable();
require_once __DIR__ . '/../inc/global.inc.php';
@ -48,14 +48,14 @@ $course = Course::current();
/**
* No files requested. We make sure we return 404 error to tell the client
* that the call failed.
* that the call failed.
*/
if (count($ids) == 0 || empty($course)) {
Response::not_found();
}
/**
* One file requested. In this case we return the file itself.
* One file requested. In this case we return the file itself.
*/
if (count($ids) == 1) {
$id = reset($ids);
@ -77,7 +77,7 @@ if (count($ids) == 1) {
}
/**
* Several files requested. In this case we zip them together.
* Several files requested. In this case we zip them together.
*/
$files = array();
$folders = array();
@ -97,9 +97,9 @@ foreach ($ids as $id) {
$requested_folders = $folders;
/**
* Note that if a parent folder is hidden children should not be accesible
* even if they are visible. It is therefore not sufficient to check document
* visibility.
* Note that if a parent folder is hidden children should not be accesible
* even if they are visible. It is therefore not sufficient to check document
* visibility.
*/
while ($folders) {
$items = $folders;
@ -123,7 +123,7 @@ while ($folders) {
$folders = $requested_folders;
/**
* Requested files may not be accessible.
* Requested files may not be accessible.
*/
if (count($files) == 0) {
Response::not_found();
@ -142,7 +142,7 @@ foreach ($items as $item) {
}
/**
* Zip files together.
* Zip files together.
*/
$temp_zip_path = Chamilo::temp_file('zip');
$zip_folder = new PclZip($temp_zip_path);
@ -155,7 +155,7 @@ foreach ($files as $file) {
}
/**
* Send file for download
* Send file for download
*/
event_download(Uri::here());
DocumentManager::file_send_for_download($temp_zip_path, false, get_lang('Documents') . '.zip');

@ -2341,14 +2341,14 @@ class Exercise
$choice[$ind] = 1;
}
$studentChoice = $choice[$numAnswer];
$studentChoice = isset($choice[$numAnswer]) ? $choice[$numAnswer] : null;
$real_answers[$answerId] = (bool)$studentChoice;
if ($studentChoice) {
$questionScore +=$answerWeighting;
}
} else {
$studentChoice = $choice[$numAnswer];
$studentChoice = isset($choice[$numAnswer]) ? $choice[$numAnswer] : null;
$real_answers[$answerId] = (bool)$studentChoice;
if (isset($studentChoice)) {

@ -1198,7 +1198,7 @@ function get_exam_results_data(
$course_code = api_get_course_id();
$sessionId = api_get_session_id();
$is_allowedToEdit = api_is_allowed_to_edit(null,true) || api_is_allowed_to_edit(true) || api_is_drh();
$is_allowedToEdit = api_is_allowed_to_edit(null,true) || api_is_allowed_to_edit(true) || api_is_drh() || api_is_student_boss();
$TBL_USER = Database :: get_main_table(TABLE_MAIN_USER);
$TBL_EXERCICES = Database :: get_course_table(TABLE_QUIZ_TEST);
@ -1506,8 +1506,8 @@ function get_exam_results_data(
Display :: return_icon('history.gif', get_lang('ViewHistoryChange')).'</a>';
}
// Admin can always delete the attempt
if ($locked == false || api_is_platform_admin()) {
//Admin can always delete the attempt
if (($locked == false || api_is_platform_admin()) && !api_is_student_boss()) {
$ip = TrackingUserLog::get_ip_from_user_event($results[$i]['exe_user_id'], date('Y-m-d h:i:s'), false);
$actions .= '<a href="http://www.whatsmyip.org/ip-geo-location/?ip='.$ip.'" target="_blank"><img src="'.api_get_path(WEB_CODE_PATH).'img/icons/22/info.png" title="'.$ip.'" /></a>';

@ -46,7 +46,7 @@ $gradebook = isset($gradebook) ? $gradebook : null;
$path = isset($_GET['path']) ? Security::remove_XSS($_GET['path']) : null;
/* Constants and variables */
$is_allowedToEdit = api_is_allowed_to_edit(null, true) || api_is_drh();
$is_allowedToEdit = api_is_allowed_to_edit(null, true) || api_is_drh() || api_is_student_boss();
$is_tutor = api_is_allowed_to_edit(true);
$TBL_QUESTIONS = Database :: get_course_table(TABLE_QUIZ_QUESTION);

@ -73,7 +73,7 @@ if (api_is_course_session_coach(
}
$maxEditors = isset($_configuration['exercise_max_fckeditors_in_page']) ? $_configuration['exercise_max_fckeditors_in_page'] : 0;
$is_allowedToEdit = api_is_allowed_to_edit(null, true) || $is_courseTutor || api_is_session_admin() || api_is_drh();
$is_allowedToEdit = api_is_allowed_to_edit(null, true) || $is_courseTutor || api_is_session_admin() || api_is_drh() || api_is_student_boss();
//Getting results from the exe_id. This variable also contain all the information about the exercise
$track_exercise_info = get_exercise_track_exercise_info($id);
@ -512,7 +512,7 @@ foreach ($questionList as $questionId) {
$comnt = null;
if ($show_results) {
if ($is_allowedToEdit && $locked == false && !api_is_drh()) {
if ($is_allowedToEdit && $locked == false && !api_is_drh() && !api_is_student_boss()) {
$name = "fckdiv".$questionId;
$marksname = "marksName".$questionId;
if (in_array($answerType, array(FREE_ANSWER, ORAL_EXPRESSION))) {
@ -712,7 +712,7 @@ if (is_array($arrid) && is_array($arrmarks)) {
$marksid = implode(",",$arrmarks);
}
if ($is_allowedToEdit && $locked == false && !api_is_drh()) {
if ($is_allowedToEdit && $locked == false && !api_is_drh() && !api_is_student_boss()) {
if (in_array($origin, array('tracking_course','user_course','correct_exercise_in_lp'))) {
echo ' <form name="myform" id="myform" action="exercise_report.php?exerciseId='.$exercise_id.'&filter=2&comments=update&exeid='.$id.'&origin='.$origin.'&details=true&course='.Security::remove_XSS($_GET['cidReq']).$fromlink.'" method="post">';
echo '<input type = "hidden" name="lp_item_id" value="'.$learnpath_id.'">';

@ -289,11 +289,11 @@ function aiken_parse_file(&$exercise_info, $exercisePath, $file, $questionFile)
$new_question = true;
} else {
if (empty($exercise_info['question'][$question_index]['title'])) {
if (strlen($info) < 40) {
if (strlen($info) < 100) {
$exercise_info['question'][$question_index]['title'] = $info;
} else {
//Question itself (use a 40-chars long title and a larger description)
$exercise_info['question'][$question_index]['title'] = trim(substr($info,0,40)).'...';
//Question itself (use a 100-chars long title and a larger description)
$exercise_info['question'][$question_index]['title'] = trim(substr($info, 0, 100)) . '...';
$exercise_info['question'][$question_index]['description'] = $info;
}
} else {

@ -13,37 +13,37 @@
/**
* function to create a temporary directory (SAME AS IN MODULE ADMIN)
*/
function tempdir($dir, $prefix = 'tmp', $mode = 0777)
{
if (substr($dir, -1) != '/') {
$dir .= '/';
}
function tempdir($dir, $prefix = 'tmp', $mode = 0777) {
if (substr($dir, -1) != '/')
$dir .= '/';
do {
$path = $dir . $prefix . mt_rand(0, 9999999);
} while (!mkdir($path, $mode));
do {
$path = $dir . $prefix . mt_rand(0, 9999999);
} while (!mkdir($path, $mode));
return $path;
return $path;
}
/**
* the path of the temporary directory where the exercise was uploaded and unzipped
* @param string
* Unzip the exercise in the temp folder
* @param string The path of the temporary directory where the exercise was uploaded and unzipped
* @param string
* @return bool
*/
function get_and_unzip_uploaded_exercise($baseWorkDir, $uploadPath)
{
$_course = api_get_course_info();
$_user = api_get_user_info();
//Check if the file is valid (not to big and exists)
if (!isset($_FILES['userFile']) || !is_uploaded_file($_FILES['userFile']['tmp_name'])) {
// upload failed
return false;
}
//Check if the file is valid (not to big and exists)
if (!isset($_FILES['userFile']) || !is_uploaded_file($_FILES['userFile']['tmp_name'])) {
// upload failed
return false;
}
if (preg_match('/.zip$/i', $_FILES['userFile']['name']) &&
if (preg_match('/.zip$/i', $_FILES['userFile']['name']) &&
handle_uploaded_document(
$_course,
$_FILES['userFile'],
@ -55,93 +55,93 @@ function get_and_unzip_uploaded_exercise($baseWorkDir, $uploadPath)
1
)
) {
return true;
}
return true;
}
return false;
}
/**
* Imports an exercise,
* Imports an exercise in QTI format if the XML structure can be found in it
* @param array $file
* @return an array as a backlog of what was really imported, and error or debug messages to display
*/
function import_exercise($file)
{
global $exercise_info;
global $element_pile;
global $non_HTML_tag_to_avoid;
global $record_item_body;
// used to specify the question directory where files could be found in relation in any question
global $questionTempDir;
$archive_path = api_get_path(SYS_ARCHIVE_PATH) . 'qti2';
$baseWorkDir = $archive_path;
if (!is_dir($baseWorkDir)) {
mkdir($baseWorkDir, api_get_permissions_for_new_directories(), true);
}
global $exercise_info;
global $element_pile;
global $non_HTML_tag_to_avoid;
global $record_item_body;
// used to specify the question directory where files could be found in relation in any question
global $questionTempDir;
$archive_path = api_get_path(SYS_ARCHIVE_PATH) . 'qti2';
$baseWorkDir = $archive_path;
if (!is_dir($baseWorkDir)) {
mkdir($baseWorkDir, api_get_permissions_for_new_directories(), true);
}
$uploadPath = '/';
$uploadPath = '/';
// set some default values for the new exercise
$exercise_info = array ();
$exercise_info['name'] = preg_replace('/.zip$/i', '', $file);
$exercise_info['question'] = array();
$element_pile = array ();
// set some default values for the new exercise
$exercise_info = array();
$exercise_info['name'] = preg_replace('/.zip$/i', '', $file);
$exercise_info['question'] = array();
$element_pile = array();
// create parser and array to retrieve info from manifest
$element_pile = array (); //pile to known the depth in which we are
//$module_info = array (); //array to store the info we need
// create parser and array to retrieve info from manifest
$element_pile = array(); //pile to known the depth in which we are
//$module_info = array (); //array to store the info we need
// if file is not a .zip, then we cancel all
// if file is not a .zip, then we cancel all
if (!preg_match('/.zip$/i', $file)) {
if (!preg_match('/.zip$/i', $file)) {
return 'UplZipCorrupt';
}
return 'UplZipCorrupt';
}
// unzip the uploaded file in a tmp directory
if (!get_and_unzip_uploaded_exercise($baseWorkDir, $uploadPath)) {
// unzip the uploaded file in a tmp directory
if (!get_and_unzip_uploaded_exercise($baseWorkDir, $uploadPath)) {
return 'UplZipCorrupt';
}
return 'UplZipCorrupt';
}
// find the different manifests for each question and parse them.
// find the different manifests for each question and parse them.
$exerciseHandle = opendir($baseWorkDir);
//$question_number = 0;
$file_found = false;
$operation = false;
$exerciseHandle = opendir($baseWorkDir);
//$question_number = 0;
$file_found = false;
$operation = false;
$result = false;
$filePath = null;
// parse every subdirectory to search xml question files
while (false !== ($file = readdir($exerciseHandle))) {
if (is_dir($baseWorkDir . '/' . $file) && $file != "." && $file != "..") {
// Find each manifest for each question repository found
$questionHandle = opendir($baseWorkDir . '/' . $file);
while (false !== ($questionFile = readdir($questionHandle))) {
if (preg_match('/.xml$/i', $questionFile)) {
$result = parse_file($baseWorkDir, $file, $questionFile);
$filePath = $baseWorkDir.$file;
$file_found = true;
}
}
} elseif (preg_match('/.xml$/i', $file)) {
// parse every subdirectory to search xml question files
while (false !== ($file = readdir($exerciseHandle))) {
if (is_dir($baseWorkDir . '/' . $file) && $file != "." && $file != "..") {
// Find each manifest for each question repository found
$questionHandle = opendir($baseWorkDir . '/' . $file);
while (false !== ($questionFile = readdir($questionHandle))) {
if (preg_match('/.xml$/i', $questionFile)) {
$result = parse_file($baseWorkDir, $file, $questionFile);
$filePath = $baseWorkDir . $file;
$file_found = true;
}
}
} elseif (preg_match('/.xml$/i', $file)) {
// Else ignore file
$result = parse_file($baseWorkDir, '', $file);
$filePath = $baseWorkDir.'/'.$file;
$file_found = true;
}
}
$result = parse_file($baseWorkDir, '', $file);
$filePath = $baseWorkDir . '/' . $file;
$file_found = true;
}
}
if (!$file_found) {
if (!$file_found) {
return 'No XML file found in the zip';
}
return 'No XML file found in the zip';
}
if ($result == false) {
return false;
@ -151,61 +151,62 @@ function import_exercise($file)
$doc->load($filePath);
$encoding = $doc->encoding;
// 1. Create exercise.
$exercise = new Exercise();
$exercise->exercise = $exercise_info['name'];
$exercise->save();
$last_exercise_id = $exercise->selectId();
if (!empty($last_exercise_id)) {
// For each question found...
foreach ($exercise_info['question'] as $question_array) {
//2. Create question
$question = new Ims2Question();
$question->type = $question_array['type'];
$question->setAnswer();
$question->updateTitle(formatText($question_array['title']));
// 1. Create exercise.
$exercise = new Exercise();
$exercise->exercise = $exercise_info['name'];
$exercise->save();
$last_exercise_id = $exercise->selectId();
if (!empty($last_exercise_id)) {
// For each question found...
foreach ($exercise_info['question'] as $question_array) {
//2. Create question
$question = new Ims2Question();
$question->type = $question_array['type'];
$question->setAnswer();
$question->updateTitle(formatText($question_array['title']));
//$question->updateDescription($question_array['title']);
$type = $question->selectType();
$question->type = constant($type);
$question->save($last_exercise_id);
$last_question_id = $question->selectId();
//3. Create answer
$answer = new Answer($last_question_id);
$answer->new_nbrAnswers = count($question_array['answer']);
$type = $question->selectType();
$question->type = constant($type);
$question->save($last_exercise_id);
$last_question_id = $question->selectId();
//3. Create answer
$answer = new Answer($last_question_id);
$answer->new_nbrAnswers = count($question_array['answer']);
$totalCorrectWeight = 0;
foreach ($question_array['answer'] as $key => $answers) {
$split = explode('_', $key);
$i = $split[1];
foreach ($question_array['answer'] as $key => $answers) {
$split = explode('_', $key);
$i = $split[1];
// Answer
$answer->new_answer[$i] = formatText($answers['value']);
$answer->new_answer[$i] = formatText($answers['value']);
// Comment
$answer->new_comment[$i] = isset($answers['feedback']) ? formatText($answers['feedback']) : null;
$answer->new_comment[$i] = isset($answers['feedback']) ? formatText($answers['feedback']) : null;
// Position
$answer->new_position[$i] = $i;
// Correct answers
if (in_array($key, $question_array['correct_answers'])) {
$answer->new_correct[$i] = 1;
} else {
$answer->new_correct[$i] = 0;
}
$answer->new_weighting[$i] = $question_array['weighting'][$key];
$answer->new_position[$i] = $i;
// Correct answers
if (in_array($key, $question_array['correct_answers'])) {
$answer->new_correct[$i] = 1;
} else {
$answer->new_correct[$i] = 0;
}
$answer->new_weighting[$i] = $question_array['weighting'][$key];
if ($answer->new_correct[$i]) {
$totalCorrectWeight = $answer->new_weighting[$i];
}
}
}
$question->updateWeighting($totalCorrectWeight);
$question->save($last_exercise_id);
$answer->save();
}
$answer->save();
}
// delete the temp dir where the exercise was unzipped
my_delete($baseWorkDir . $uploadPath);
return $last_exercise_id;
}
// delete the temp dir where the exercise was unzipped
my_delete($baseWorkDir . $uploadPath);
return $last_exercise_id;
}
return false;
return false;
}
/**
* We assume the file charset is UTF8
**/
@ -214,163 +215,156 @@ function formatText($text)
return api_html_entity_decode($text);
}
/**
* Parses a given XML file and fills global arrays with the elements
* @param $exercisePath
* @param $file
* @param $questionFile
* @return bool
*/
function parse_file($exercisePath, $file, $questionFile)
{
global $exercise_info;
global $element_pile;
global $non_HTML_tag_to_avoid;
global $record_item_body;
global $questionTempDir;
$questionTempDir = $exercisePath . '/' . $file . '/';
$questionFilePath = $questionTempDir . $questionFile;
if (!($fp = fopen($questionFilePath, 'r'))) {
Display :: display_error_message(get_lang('Error opening question\'s XML file'));
return false;
} else {
$data = fread($fp, filesize($questionFilePath));
}
//parse XML question file
$data = str_replace(array('<p>', '</p>','<front>','</front>'), '', $data);
//used global variable start values declaration :
$record_item_body = false;
$non_HTML_tag_to_avoid = array (
"SIMPLECHOICE",
"CHOICEINTERACTION",
"INLINECHOICEINTERACTION",
"INLINECHOICE",
"SIMPLEMATCHSET",
"SIMPLEASSOCIABLECHOICE",
"TEXTENTRYINTERACTION",
"FEEDBACKINLINE",
"MATCHINTERACTION",
"ITEMBODY",
"BR",
"IMG"
);
//this array to detect tag not supported by claroline import in the xml file to warn the user.
$non_supported_content_in_question = array (
"GAPMATCHINTERACTION",
"EXTENDEDTEXTINTERACTION",
"HOTTEXTINTERACTION",
"HOTSPOTINTERACTION",
"SELECTPOINTINTERACTION",
"GRAPHICORDERINTERACTION",
"GRAPHICASSOCIATIONINTERACTION",
"GRAPHICGAPMATCHINTERACTION",
"POSITIONOBJECTINTERACTION",
"SLIDERINTERACTION",
"DRAWINGINTERACTION",
"UPLOADINTERACTION",
"RESPONSECONDITION",
"RESPONSEIF"
);
global $non_HTML_tag_to_avoid;
global $record_item_body;
global $questionTempDir;
$questionTempDir = $exercisePath . '/' . $file . '/';
$questionFilePath = $questionTempDir . $questionFile;
if (!($fp = fopen($questionFilePath, 'r'))) {
Display:: display_error_message(get_lang('Error opening question\'s XML file'));
return false;
} else {
$data = fread($fp, filesize($questionFilePath));
}
//parse XML question file
$data = str_replace(array('<p>', '</p>', '<front>', '</front>'), '', $data);
//used global variable start values declaration :
$record_item_body = false;
$non_HTML_tag_to_avoid = array(
"SIMPLECHOICE",
"CHOICEINTERACTION",
"INLINECHOICEINTERACTION",
"INLINECHOICE",
"SIMPLEMATCHSET",
"SIMPLEASSOCIABLECHOICE",
"TEXTENTRYINTERACTION",
"FEEDBACKINLINE",
"MATCHINTERACTION",
"ITEMBODY",
"BR",
"IMG"
);
$question_format_supported = true;
$xml_parser = xml_parser_create();
xml_parser_set_option($xml_parser, XML_OPTION_SKIP_WHITE, false);
xml_set_element_handler($xml_parser, 'startElement', 'endElement');
xml_set_character_data_handler($xml_parser, 'elementData');
if (!xml_parse($xml_parser, $data, feof($fp))) {
// if reading of the xml file in not successful :
// set errorFound, set error msg, break while statement
Display :: display_error_message(get_lang('Error reading XML file'));
return false;
}
//close file
fclose($fp);
if (!$question_format_supported) {
Display :: display_error_message(get_lang('Unknown question format in file %file', array (
'%file' => $questionFile
)));
return false;
}
return true;
$xml_parser = xml_parser_create();
xml_parser_set_option($xml_parser, XML_OPTION_SKIP_WHITE, false);
xml_set_element_handler($xml_parser, 'startElement', 'endElement');
xml_set_character_data_handler($xml_parser, 'elementData');
if (!xml_parse($xml_parser, $data, feof($fp))) {
// if reading of the xml file in not successful :
// set errorFound, set error msg, break while statement
Display:: display_error_message(get_lang('Error reading XML file'));
return false;
}
//close file
fclose($fp);
if (!$question_format_supported) {
Display:: display_error_message(
get_lang(
'Unknown question format in file %file',
array(
'%file' => $questionFile
)
)
);
return false;
}
return true;
}
/**
* Function used by the SAX xml parser when the parser meets a opening tag
*
* @param unknown_type $parser xml parser created with "xml_parser_create()"
* @param unknown_type $name name of the element
* @param unknown_type $attributes
* @param object $parser xml parser created with "xml_parser_create()"
* @param string $name name of the element
* @param array $attributes
*/
function startElement($parser, $name, $attributes)
{
global $element_pile;
global $exercise_info;
global $current_question_ident;
global $current_answer_id;
global $current_match_set;
global $currentAssociableChoice;
global $current_question_item_body;
global $record_item_body;
global $non_HTML_tag_to_avoid;
global $current_inlinechoice_id;
global $cardinality;
global $questionTempDir;
array_push($element_pile, $name);
$current_element = end($element_pile);
if (sizeof($element_pile) >= 2) {
$parent_element = $element_pile[sizeof($element_pile) - 2];
} else {
$parent_element = "";
}
if (sizeof($element_pile) >= 3) {
$grant_parent_element = $element_pile[sizeof($element_pile) - 3];
} else {
$grant_parent_element = "";
}
if ($record_item_body) {
function startElement($parser, $name, $attributes) {
global $element_pile;
global $exercise_info;
global $current_question_ident;
global $current_answer_id;
global $current_match_set;
global $currentAssociableChoice;
global $current_question_item_body;
global $record_item_body;
global $non_HTML_tag_to_avoid;
global $current_inlinechoice_id;
global $cardinality;
global $questionTempDir;
array_push($element_pile, $name);
$current_element = end($element_pile);
if (sizeof($element_pile) >= 2)
$parent_element = $element_pile[sizeof($element_pile) - 2];
else
$parent_element = "";
if (sizeof($element_pile) >= 3)
$grant_parent_element = $element_pile[sizeof($element_pile) - 3];
else
$grant_parent_element = "";
if ($record_item_body) {
if ((!in_array($current_element, $non_HTML_tag_to_avoid))) {
$current_question_item_body .= "<" . $name;
foreach ($attributes as $attribute_name => $attribute_value) {
$current_question_item_body .= " " . $attribute_name . "=\"" . $attribute_value . "\"";
}
$current_question_item_body .= ">";
} else {
//in case of FIB question, we replace the IMS-QTI tag b y the correct answer between "[" "]",
//we first save with claroline tags ,then when the answer will be parsed, the claroline tags will be replaced
if ($current_element == 'INLINECHOICEINTERACTION') {
$current_question_item_body .= "**claroline_start**" . $attributes['RESPONSEIDENTIFIER'] . "**claroline_end**";
}
if ($current_element == 'TEXTENTRYINTERACTION') {
$correct_answer_value = $exercise_info['question'][$current_question_ident]['correct_answers'][$current_answer_id];
$current_question_item_body .= "[" . $correct_answer_value . "]";
}
if ($current_element == 'BR') {
$current_question_item_body .= "<BR/>";
}
}
}
switch ($current_element) {
case 'ASSESSMENTITEM' :
if ((!in_array($current_element, $non_HTML_tag_to_avoid))) {
$current_question_item_body .= "<" . $name;
foreach ($attributes as $attribute_name => $attribute_value) {
$current_question_item_body .= " " . $attribute_name . "=\"" . $attribute_value . "\"";
}
$current_question_item_body .= ">";
} else {
//in case of FIB question, we replace the IMS-QTI tag b y the correct answer between "[" "]",
//we first save with claroline tags ,then when the answer will be parsed, the claroline tags will be replaced
if ($current_element == 'INLINECHOICEINTERACTION') {
$current_question_item_body .= "**claroline_start**" . $attributes['RESPONSEIDENTIFIER'] . "**claroline_end**";
}
if ($current_element == 'TEXTENTRYINTERACTION') {
$correct_answer_value = $exercise_info['question'][$current_question_ident]['correct_answers'][$current_answer_id];
$current_question_item_body .= "[" . $correct_answer_value . "]";
}
if ($current_element == 'BR') {
$current_question_item_body .= "<br />";
}
}
}
switch ($current_element) {
case 'ASSESSMENTITEM':
//retrieve current question
$current_question_ident = $attributes['IDENTIFIER'];
$exercise_info['question'][$current_question_ident] = array ();
$exercise_info['question'][$current_question_ident]['answer'] = array ();
$exercise_info['question'][$current_question_ident]['correct_answers'] = array ();
$exercise_info['question'][$current_question_ident] = array();
$exercise_info['question'][$current_question_ident]['answer'] = array();
$exercise_info['question'][$current_question_ident]['correct_answers'] = array();
$exercise_info['question'][$current_question_ident]['title'] = $attributes['TITLE'];
$exercise_info['question'][$current_question_ident]['tempdir'] = $questionTempDir;
break;
case 'SECTION':
case 'SECTION':
//retrieve exercise name
$exercise_info['name'] = $attributes['TITLE'];
break;
case 'RESPONSEDECLARATION':
break;
case 'RESPONSEDECLARATION':
// Retrieve question type
if ("multiple" == $attributes['CARDINALITY']) {
$exercise_info['question'][$current_question_ident]['type'] = 'MCMA';
@ -382,64 +376,64 @@ function startElement($parser, $name, $attributes) {
}
//needed for FIB
$current_answer_id = $attributes['IDENTIFIER'];
break;
case 'INLINECHOICEINTERACTION' :
break;
case 'INLINECHOICEINTERACTION':
$exercise_info['question'][$current_question_ident]['type'] = 'FIB';
$exercise_info['question'][$current_question_ident]['subtype'] = 'LISTBOX_FILL';
$current_answer_id = $attributes['RESPONSEIDENTIFIER'];
break;
case 'INLINECHOICE' :
$exercise_info['question'][$current_question_ident]['subtype'] = 'LISTBOX_FILL';
$current_answer_id = $attributes['RESPONSEIDENTIFIER'];
break;
case 'INLINECHOICE':
$current_inlinechoice_id = $attributes['IDENTIFIER'];
break;
case 'TEXTENTRYINTERACTION':
break;
case 'TEXTENTRYINTERACTION':
$exercise_info['question'][$current_question_ident]['type'] = 'FIB';
$exercise_info['question'][$current_question_ident]['subtype'] = 'TEXTFIELD_FILL';
$exercise_info['question'][$current_question_ident]['response_text'] = $current_question_item_body;
//replace claroline tags
break;
case 'MATCHINTERACTION':
$exercise_info['question'][$current_question_ident]['type'] = 'MATCHING';
break;
case 'SIMPLEMATCHSET' :
break;
case 'MATCHINTERACTION':
$exercise_info['question'][$current_question_ident]['type'] = 'MATCHING';
break;
case 'SIMPLEMATCHSET':
if (!isset ($current_match_set)) {
$current_match_set = 1;
} else {
$current_match_set++;
}
$exercise_info['question'][$current_question_ident]['answer'][$current_match_set] = array ();
break;
case 'SIMPLEASSOCIABLECHOICE':
$exercise_info['question'][$current_question_ident]['answer'][$current_match_set] = array();
break;
case 'SIMPLEASSOCIABLECHOICE':
$currentAssociableChoice = $attributes['IDENTIFIER'];
break;
//retrieve answers id for MCUA and MCMA questions
case 'SIMPLECHOICE':
break;
//retrieve answers id for MCUA and MCMA questions
case 'SIMPLECHOICE':
$current_answer_id = $attributes['IDENTIFIER'];
if (!isset($exercise_info['question'][$current_question_ident]['answer'][$current_answer_id])) {
$exercise_info['question'][$current_question_ident]['answer'][$current_answer_id] = array ();
$exercise_info['question'][$current_question_ident]['answer'][$current_answer_id] = array();
}
break;
case 'MAPENTRY':
break;
case 'MAPENTRY':
if ($parent_element == "MAPPING") {
$answer_id = $attributes['MAPKEY'];
if (!isset ($exercise_info['question'][$current_question_ident]['weighting'])) {
$exercise_info['question'][$current_question_ident]['weighting'] = array ();
$exercise_info['question'][$current_question_ident]['weighting'] = array();
}
$exercise_info['question'][$current_question_ident]['weighting'][$answer_id] = $attributes['MAPPEDVALUE'];
}
break;
case 'MAPPING':
break;
case 'MAPPING':
if (isset ($attributes['DEFAULTVALUE'])) {
$exercise_info['question'][$current_question_ident]['default_weighting'] = $attributes['DEFAULTVALUE'];
}
case 'ITEMBODY':
case 'ITEMBODY':
$record_item_body = true;
$current_question_item_body = '';
break;
case 'IMG':
break;
case 'IMG':
$exercise_info['question'][$current_question_ident]['attached_file_url'] = $attributes['SRC'];
break;
}
break;
}
}
/**
@ -448,87 +442,93 @@ function startElement($parser, $name, $attributes) {
* @param $parser xml parser created with "xml_parser_create()"
* @param $name name of the element
*/
function endElement($parser, $name)
{
global $element_pile;
global $exercise_info;
global $current_question_ident;
global $record_item_body;
global $current_question_item_body;
global $non_HTML_tag_to_avoid;
global $cardinality;
function endElement($parser, $name) {
global $element_pile;
global $exercise_info;
global $current_question_ident;
global $record_item_body;
global $current_question_item_body;
global $non_HTML_tag_to_avoid;
global $cardinality;
$current_element = end($element_pile);
$current_element = end($element_pile);
//treat the record of the full content of itembody tag :
//treat the record of the full content of itembody tag :
if ($record_item_body && (!in_array($current_element, $non_HTML_tag_to_avoid))) {
$current_question_item_body .= "</" . $name . ">";
}
if ($record_item_body && (!in_array($current_element, $non_HTML_tag_to_avoid))) {
$current_question_item_body .= "</" . $name . ">";
}
switch ($name) {
case 'ITEMBODY':
switch ($name) {
case 'ITEMBODY':
$record_item_body = false;
if ($exercise_info['question'][$current_question_ident]['type'] == 'FIB') {
$exercise_info['question'][$current_question_ident]['response_text'] = $current_question_item_body;
} else {
$exercise_info['question'][$current_question_ident]['statement'] = $current_question_item_body;
}
break;
}
array_pop($element_pile);
break;
}
array_pop($element_pile);
}
function elementData($parser, $data) {
global $element_pile;
global $exercise_info;
global $current_question_ident;
global $current_answer_id;
global $current_match_set;
global $currentAssociableChoice;
global $current_question_item_body;
global $record_item_body;
global $non_HTML_tag_to_avoid;
global $current_inlinechoice_id;
global $cardinality;
$current_element = end($element_pile);
if (sizeof($element_pile) >= 2)
$parent_element = $element_pile[sizeof($element_pile) - 2];
else
$parent_element = "";
if (sizeof($element_pile) >= 3)
$grant_parent_element = $element_pile[sizeof($element_pile) - 3];
else
$grant_parent_element = "";
//treat the record of the full content of itembody tag (needed for question statment and/or FIB text:
if ($record_item_body && (!in_array($current_element, $non_HTML_tag_to_avoid))) {
$current_question_item_body .= $data;
}
switch ($current_element) {
case 'SIMPLECHOICE':
/**
* @param $parser
* @param $data
*/
function elementData($parser, $data)
{
global $element_pile;
global $exercise_info;
global $current_question_ident;
global $current_answer_id;
global $current_match_set;
global $currentAssociableChoice;
global $current_question_item_body;
global $record_item_body;
global $non_HTML_tag_to_avoid;
global $current_inlinechoice_id;
global $cardinality;
$current_element = end($element_pile);
if (sizeof($element_pile) >= 2) {
$parent_element = $element_pile[sizeof($element_pile) - 2];
} else {
$parent_element = "";
}
if (sizeof($element_pile) >= 3) {
$grant_parent_element = $element_pile[sizeof($element_pile) - 3];
} else {
$grant_parent_element = "";
}
//treat the record of the full content of itembody tag (needed for question statment and/or FIB text:
if ($record_item_body && (!in_array($current_element, $non_HTML_tag_to_avoid))) {
$current_question_item_body .= $data;
}
switch ($current_element) {
case 'SIMPLECHOICE':
if (!isset ($exercise_info['question'][$current_question_ident]['answer'][$current_answer_id]['value'])) {
$exercise_info['question'][$current_question_ident]['answer'][$current_answer_id]['value'] = trim($data);
} else {
$exercise_info['question'][$current_question_ident]['answer'][$current_answer_id]['value'] .= ''.trim($data);
$exercise_info['question'][$current_question_ident]['answer'][$current_answer_id]['value'] .= '' . trim($data);
}
break;
case 'FEEDBACKINLINE' :
break;
case 'FEEDBACKINLINE':
if (!isset ($exercise_info['question'][$current_question_ident]['answer'][$current_answer_id]['feedback'])) {
$exercise_info['question'][$current_question_ident]['answer'][$current_answer_id]['feedback'] = trim($data);
} else {
$exercise_info['question'][$current_question_ident]['answer'][$current_answer_id]['feedback'] .= ' ' . trim($data);
}
break;
case 'SIMPLEASSOCIABLECHOICE':
$exercise_info['question'][$current_question_ident]['answer'][$current_match_set][$currentAssociableChoice] = trim($data);
break;
case 'VALUE' :
break;
case 'SIMPLEASSOCIABLECHOICE':
$exercise_info['question'][$current_question_ident]['answer'][$current_match_set][$currentAssociableChoice] = trim($data);
break;
case 'VALUE':
if ($parent_element == "CORRECTRESPONSE") {
if ($cardinality == "single") {
$exercise_info['question'][$current_question_ident]['correct_answers'][$current_answer_id] = $data;
@ -536,22 +536,26 @@ function elementData($parser, $data) {
$exercise_info['question'][$current_question_ident]['correct_answers'][] = $data;
}
}
break;
break;
case 'ITEMBODY' :
case 'ITEMBODY':
$current_question_item_body .= $data;
break;
case 'INLINECHOICE' :
break;
case 'INLINECHOICE':
// if this is the right answer, then we must replace the claroline tags in the FIB text bye the answer between "[" and "]" :
$answer_identifier = $exercise_info['question'][$current_question_ident]['correct_answers'][$current_answer_id];
if ($current_inlinechoice_id == $answer_identifier) {
$current_question_item_body = str_replace("**claroline_start**" . $current_answer_id . "**claroline_end**", "[" . $data . "]", $current_question_item_body);
$current_question_item_body = str_replace(
"**claroline_start**" . $current_answer_id . "**claroline_end**",
"[" . $data . "]",
$current_question_item_body
);
} else {
if (!isset ($exercise_info['question'][$current_question_ident]['wrong_answers'])) {
$exercise_info['question'][$current_question_ident]['wrong_answers'] = array ();
$exercise_info['question'][$current_question_ident]['wrong_answers'] = array();
}
$exercise_info['question'][$current_question_ident]['wrong_answers'][] = $data;
}
break;
}
break;
}
}

@ -25,7 +25,6 @@ require_once api_get_path(LIBRARY_PATH) . 'fileUpload.lib.php';
require_once 'exercise_import.inc.php';
include_once '../exercise.class.php';
include_once '../question.class.php';
include_once 'qti/qti_classes.php';
//SQL table name

@ -1,578 +0,0 @@
<?php // $Id: $
/* For licensing terms, see /license.txt */
/**
* @copyright (c) 2007 Dokeos
* @copyright (c) 2001-2006 Universite catholique de Louvain (UCL)
*
* @license http://www.gnu.org/copyleft/gpl.html (GPL) GENERAL PUBLIC LICENSE
*
* @author Claro Team <cvs@claroline.net>
* @author Yannick Warnier <yannick.warnier@beeznest.com>
* @package chamilo.exercise
*/
/**
* Code
*/
if ( count( get_included_files() ) == 1 ) die( '---' );
require_once '../../exercise.class.php';
require_once '../../question.class.php';
require_once '../../answer.class.php';
require_once '../../unique_answer.class.php';
require_once '../../multiple_answer.class.php';
require_once '../../fill_blanks.class.php';
require_once '../../freeanswer.class.php';
require_once '../../hotspot.class.php';
require_once '../../matching.class.php';
require_once '../../hotspot.class.php';
/**
*
* @package chamilo.exercise
*/
class ImsQuestion extends Question
{
/**
* Include the correct answer class and create answer
*/
function setAnswer()
{
switch($this->type)
{
case MCUA :
$this->answer = new ImsAnswerMultipleChoice($this->id, false);
break;
case MCMA :
$this->answer = new ImsAnswerMultipleChoice($this->id, true);
break;
case TF :
$this->answer = new ImsAnswerTrueFalse($this->id);
break;
case FIB :
$this->answer = new ImsAnswerFillInBlanks($this->id);
break;
case MATCHING :
$this->answer = new ImsAnswerMatching($this->id);
break;
default :
$this->answer = null;
break;
}
return true;
}
/**
* allow to import the question
*
* @param questionArray is an array that must contain all the information needed to build the question
* @author Guillaume Lederer <guillaume@claroline.net>
*/
function import($questionArray, $exerciseTempPath)
{
//import answers
$this->answer->import($questionArray);
//import attached file, if any
if (isset($questionArray['attached_file_url']))
{
$file= array();
$file['name'] = $questionArray['attached_file_url'];
$file['tmp_name'] = $exerciseTempPath.$file['name'];
$this->setAttachment($file);
}
}
}
/**
*
* @package chamilo.exercise
*/
class ImsAnswerMultipleChoice extends answerMultipleChoice
{
/**
* Return the XML flow for the possible answers.
* That's one <response_lid>, containing several <flow_label>
*
* @author Amand Tihon <amand@alrj.org>
*/
function imsExportResponses($questionIdent)
{
// Opening of the response block.
if( $this->multipleAnswer )
{
$out = '<response_lid ident = "MCM_' . $questionIdent . '" rcardinality = "Multiple" rtiming = "No">' . "\n"
. '<render_choice shuffle = "No" minnumber = "1" maxnumber = "' . count($this->answerList) . '">' . "\n";
}
else
{
$out = '<response_lid ident="MCS_' . $questionIdent . '" rcardinality="Single" rtiming="No"><render_choice shuffle="No">' . "\n";
}
// Loop over answers
foreach( $this->answerList as $answer )
{
$responseIdent = $questionIdent . "_A_" . $answer['id'];
$out.= ' <flow_label><response_label ident="' . $responseIdent . '">'.(!$this->multipleAnswer ? '<flow_mat class="list">':'').'<material>' . "\n"
. ' <mattext><![CDATA[' . $answer['answer'] . ']]></mattext>' . "\n"
. ' </material>'.(!$this->multipleAnswer ? '</flow_mat>':'').'</response_label></flow_label>' . "\n";
}
$out.= "</render_choice></response_lid>\n";
return $out;
}
/**
* Return the XML flow of answer processing : a succession of <respcondition>.
*
* @author Amand Tihon <amand@alrj.org>
*/
function imsExportProcessing($questionIdent)
{
$out = '';
foreach( $this->answerList as $answer )
{
$responseIdent = $questionIdent . "_A_" . $answer['id'];
$feedbackIdent = $questionIdent . "_F_" . $answer['id'];
$conditionIdent = $questionIdent . "_C_" . $answer['id'];
if( $this->multipleAnswer )
{
$out .= '<respcondition title="' . $conditionIdent . '" continue="Yes"><conditionvar>' . "\n"
. ' <varequal respident="MCM_' . $questionIdent . '">' . $responseIdent . '</varequal>' . "\n";
}
else
{
$out .= '<respcondition title="' . $conditionIdent . '"><conditionvar>' . "\n"
. ' <varequal respident="MCS_' . $questionIdent . '">' . $responseIdent . '</varequal>' . "\n";
}
$out .= " </conditionvar>\n" . ' <setvar action="Add">' . $answer['grade'] . "</setvar>\n";
// Only add references for actually existing comments/feedbacks.
if( !empty($answer['comment']) )
{
$out .= ' <displayfeedback feedbacktype="Response" linkrefid="' . $feedbackIdent . '" />' . "\n";
}
$out .= "</respcondition>\n";
}
return $out;
}
/**
* Export the feedback (comments to selected answers) to IMS/QTI
*
* @author Amand Tihon <amand@alrj.org>
*/
function imsExportFeedback($questionIdent)
{
$out = "";
foreach( $this->answerList as $answer )
{
if( !empty($answer['comment']) )
{
$feedbackIdent = $questionIdent . "_F_" . $answer['id'];
$out.= '<itemfeedback ident="' . $feedbackIdent . '" view="Candidate"><flow_mat><material>' . "\n"
. ' <mattext><![CDATA[' . $answer['comment'] . "]]></mattext>\n"
. "</material></flow_mat></itemfeedback>\n";
}
}
return $out;
}
/**
* allow to import the answers, feedbacks, and grades of a question
* @param questionArray is an array that must contain all the information needed to build the question
* @author Guillaume Lederer <guillaume@claroline.net>
*/
function import($questionArray)
{
$answerArray = $questionArray['answer'];
$this->answerList = array(); //re-initialize answer object content
foreach ($answerArray as $key => $answer)
{
if (!isset($answer['feedback'])) $answer['feedback'] = "";
if (!isset($questionArray['weighting'][$key]))
{
if (isset($questionArray['default_weighting']))
{
$grade = $questionArray['default_weighting'];
}
else
{
$grade = 0;
}
}
else
{
$grade = $questionArray['weighting'][$key];
}
if (in_array($key,$questionArray['correct_answers'])) $is_correct = true; else $is_correct = false;
$addedAnswer = array(
'answer' => $answer['value'],
'correct' => $is_correct,
'grade' => $grade,
'comment' => $answer['feedback'],
);
$this->answerList[] = $addedAnswer;
}
}
}
/**
*
* @package chamilo.exercise
*/
class ImsAnswerTrueFalse extends answerTrueFalse
{
/**
* Return the XML flow for the possible answers.
* That's one <response_lid>, containing several <flow_label>
*
* @author Amand Tihon <amand@alrj.org>
*/
function imsExportResponses($questionIdent)
{
// Opening of the response block.
$out = '<response_lid ident="TF_' . $questionIdent . '" rcardinality="Single" rtiming="No"><render_choice shuffle="No">' . "\n";
// true
$response_ident = $questionIdent . '_A_true';
$out .=
' <flow_label><response_label ident="'.$response_ident.'"><flow_mat class="list"><material>' . "\n"
. ' <mattext><![CDATA[' . get_lang('True') . ']]></mattext>' . "\n"
. ' </material></flow_mat></response_label></flow_label>' . "\n";
// false
$response_ident = $questionIdent . '_A_false';
$out .=
' <flow_label><response_label ident="'.$response_ident.'"><flow_mat class="list"><material>' . "\n"
. ' <mattext><![CDATA[' . get_lang('False') . ']]></mattext>' . "\n"
. ' </material></flow_mat></response_label></flow_label>' . "\n";
$out .= '</render_choice></response_lid>' . "\n";
return $out;
}
/**
* Return the XML flow of answer processing : a succession of <respcondition>.
*
* @author Amand Tihon <amand@alrj.org>
*/
function imsExportProcessing($questionIdent)
{
$out = '';
// true
$response_ident = $questionIdent. '_A_true';
$feedback_ident = $questionIdent . '_F_true';
$condition_ident = $questionIdent . '_C_true';
$out .=
'<respcondition title="' . $condition_ident . '"><conditionvar>' . "\n"
. ' <varequal respident="TF_' . $questionIdent . '">' . $response_ident . '</varequal>' . "\n"
. ' </conditionvar>' . "\n" . ' <setvar action="Add">' . $this->trueGrade . '</setvar>' . "\n";
// Only add references for actually existing comments/feedbacks.
if( !empty($this->trueFeedback) )
{
$out.= ' <displayfeedback feedbacktype="Response" linkrefid="' . $this->trueFeedback . '" />' . "\n";
}
$out .= '</respcondition>' . "\n";
// false
$response_ident = $questionIdent. '_A_false';
$feedback_ident = $questionIdent . '_F_false';
$condition_ident = $questionIdent . '_C_false';
$out .=
'<respcondition title="' . $condition_ident . '"><conditionvar>' . "\n"
. ' <varequal respident="TF_' . $questionIdent . '">' . $response_ident . '</varequal>' . "\n"
. ' </conditionvar>' . "\n" . ' <setvar action="Add">' . $this->falseGrade . '</setvar>' . "\n";
// Only add references for actually existing comments/feedbacks.
if( !empty($this->falseFeedback) )
{
$out.= ' <displayfeedback feedbacktype="Response" linkrefid="' . $feedback_ident . '" />' . "\n";
}
$out .= '</respcondition>' . "\n";
return $out;
}
/**
* Export the feedback (comments to selected answers) to IMS/QTI
*
* @author Amand Tihon <amand@alrj.org>
*/
function imsExportFeedback($questionIdent)
{
$out = "";
if( !empty($this->trueFeedback) )
{
$feedback_ident = $questionIdent . '_F_true';
$out.= '<itemfeedback ident="' . $feedback_ident . '" view="Candidate"><flow_mat><material>' . "\n"
. ' <mattext><![CDATA[' . $this->trueFeedback . "]]></mattext>\n"
. "</material></flow_mat></itemfeedback>\n";
}
if( !empty($this->falseFeedback) )
{
$feedback_ident = $questionIdent . '_F_false';
$out.= '<itemfeedback ident="' . $feedback_ident . '" view="Candidate"><flow_mat><material>' . "\n"
. ' <mattext><![CDATA[' . $this->falseFeedback . "]]></mattext>\n"
. "</material></flow_mat></itemfeedback>\n";
}
return $out;
}
}
/**
*
* @package chamilo.exercise
*/
class ImsAnswerFillInBlanks extends answerFillInBlanks
{
/**
* Export the text with missing words.
*
* As a side effect, it stores two lists in the class :
* the missing words and their respective weightings.
*
* @author Amand Tihon <amand@alrj.org>
*/
function imsExportResponses($questionIdent)
{
global $charset;
$out = "<flow>\n";
$responsePart = explode(']', $this->answer);
$i = 0; // Used for the reference generation.
foreach($responsePart as $part)
{
$response_ident = $questionIdent . "_A_" . $i;
if( strpos($part,'[') !== false )
{
list($rawText, $blank) = explode('[', $part);
}
else
{
$rawText = $part;
$blank = "";
}
if ($rawText!="")
{
$out.=" <material><mattext><![CDATA[" . $rawText . "]]></mattext></material>\n";
}
if ($blank!="")
{
$out.= ' <response_str ident="' . $response_ident . '" rcardinality="Single" rtiming="No">' . "\n"
. ' <render_fib fibtype="String" prompt="Box" encoding="' . $charset . '">' . "\n"
. ' <response_label ident="A"/>' . "\n"
. " </render_fib>\n"
. " </response_str>\n";
}
$i++;
}
$out.="</flow>\n";
return $out;
}
/**
* Exports the response processing.
*
* It uses the two lists build by export_responses(). This implies that export_responses MUST
* be called before.
*
* @author Amand Tihon <amand@alrj.org>
*/
function imsExportProcessing($questionIdent)
{
$out = "";
$answerCount = count($this->answerList);
for( $i = 0; $i < $answerCount ; $i++ )
{
$response_ident = $questionIdent . "_A_" . $i;
$out.= ' <respcondition continue="Yes"><conditionvar>' . "\n"
. ' <varequal respident="' . $response_ident . '" case="No"><![CDATA[' . $this->answerList[$i] . ']]></varequal>' . "\n"
. ' </conditionvar><setvar action="Add">' . $this->gradeList[$i] . "</setvar>\n"
. " </respcondition>\n";
}
return $out;
}
/**
* Export the feedback (comments to selected answers) to IMS/QTI
*
* @author Amand Tihon <amand@alrj.org>
*/
function imsExportFeedback($questionIdent)
{
// no feedback in this question type
return '';
}
/**
* allow to import the answers, feedbacks, and grades of a question
*
* @param questionArray is an array that must contain all the information needed to build the question
* @author Guillaume Lederer <guillaume@claroline.net>
*/
function import($questionArray)
{
$answerArray = $questionArray['answer'];
$this->answerText = str_replace ("\n","",$questionArray['response_text']);
if ($questionArray['subtype'] == "TEXTFIELD_FILL") $this->type = TEXTFIELD_FILL;
if ($questionArray['subtype'] == "LISTBOX_FILL")
{
$this->wrongAnswerList = $questionArray['wrong_answers'];
$this->type = LISTBOX_FILL;
}
//build correct_answsers array
if (isset($questionArray['weighting']))
{
$this->gradeList = $questionArray['weighting'];
}
}
}
/**
*
* @package chamilo.exercise
*/
class ImsAnswerMatching extends answerMatching
{
/**
* Export the question part as a matrix-choice, with only one possible answer per line.
* @author Amand Tihon <amand@alrj.org>
*/
function imsExportResponses($questionIdent)
{
$out = "";
// Now, loop again, finding questions (rows)
foreach( $this->leftList as $leftElt )
{
$responseIdent = $questionIdent . "_A_" . $leftElt['code'];
$out.= '<response_lid ident="' . $responseIdent . '" rcardinality="Single" rtiming="No">' . "\n"
. '<material><mattext><![CDATA[' . $leftElt['answer'] . "]]></mattext></material>\n"
. ' <render_choice shuffle="No"><flow_label>' . "\n";
foreach( $this->rightList as $rightElt )
{
$out.= ' <response_label ident="' . $rightElt['code'] . '"><material>' . "\n"
. " <mattext><![CDATA[" . $rightElt['answer'] . "]]></mattext>\n"
. " </material></response_label>\n";
}
$out.= "</flow_label></render_choice></response_lid>\n";
}
return $out;
}
/**
* Export the response processing part
* @author Amand Tihon <amand@alrj.org>
*/
function imsExportProcessing($questionIdent)
{
$out = "";
foreach( $this->leftList as $leftElt )
{
$responseIdent = $questionIdent . "_A_" . $leftElt['code'];
$out.= ' <respcondition continue="Yes"><conditionvar>' . "\n"
. ' <varequal respident="' . $responseIdent . '">' . $leftElt['match'] . "</varequal>\n"
. ' </conditionvar><setvar action="Add">' . $leftElt['grade'] . "</setvar>\n"
. " </respcondition>\n";
}
return $out;
}
/**
* Export the feedback (comments to selected answers) to IMS/QTI
*
* @author Amand Tihon <amand@alrj.org>
*/
function imsExportFeedback($questionIdent)
{
// no feedback in this question type
return '';
}
/**
* allow to import the answers, feedbacks, and grades of a question
*
* @param questionArray is an array that must contain all the information needed to build the question
* @author Guillaume Lederer <guillaume@claroline.net>
*/
function import($questionArray)
{
$answerArray = $questionArray['answer'];
//This tick to remove examples in the answers!!!!
$this->leftList = array();
$this->rightList = array();
//find right and left column
$right_column = array_pop($answerArray);
$left_column = array_pop($answerArray);
//1- build answers
foreach ($right_column as $right_key => $right_element)
{
$code = $this->addRight($right_element);
foreach ($left_column as $left_key => $left_element)
{
$matched_pattern = $left_key." ".$right_key;
$matched_pattern_inverted = $right_key." ".$left_key;
if (in_array($matched_pattern, $questionArray['correct_answers']) || in_array($matched_pattern_inverted, $questionArray['correct_answers']))
{
if (isset($questionArray['weighting'][$matched_pattern]))
{
$grade = $questionArray['weighting'][$matched_pattern];
}
else
{
$grade = 0;
}
$this->addLeft($left_element, $code, $grade);
}
}
}
}
}
?>

@ -1,351 +0,0 @@
<?php // $Id: $
/* For licensing terms, see /license.txt */
/**
* @author Claro Team <cvs@claroline.net>
* @author Amand Tihon <amand@alrj.org>
* @author Sebastien Piraux <pir@cerdecam.be>
* @author Yannick Warnier <yannick.warnier@beeznest.com>
* @package chamilo.exercise.qti
*/
/**
* Code
*/
if ( count( get_included_files() ) == 1 ) die( '---' );
include dirname(__FILE__) . '/qti_classes.php';
/*--------------------------------------------------------
Classes
--------------------------------------------------------*/
/**
* This class represents an entire exercise to be exported in IMS/QTI.
* It will be represented by a single <section> containing several <item>.
*
* Some properties cannot be exported, as IMS does not support them :
* - type (one page or multiple pages)
* - start_date and end_date
* - max_attempts
* - show_answer
* - anonymous_attempts
*
* @author Amand Tihon <amand@alrj.org>
* @package chamilo.exercise.qti
*/
class ImsSection
{
var $exercise;
/**
* Constructor.
* @param $exe The Exercise instance to export
* @author Amand Tihon <amand@alrj.org>
*/
function ImsSection($exe)
{
$this->exercise = $exe;
}
function start_section()
{
$out = '<section ident="EXO_' . $this->exercise->getId() . '" title="' . $this->exercise->getTitle() . '">' . "\n";
return $out;
}
function end_section()
{
return "</section>\n";
}
function export_duration()
{
if ($max_time = $this->exercise->getTimeLimit())
{
// return exercise duration in ISO8601 format.
$minutes = floor($max_time / 60);
$seconds = $max_time % 60;
return '<duration>PT' . $minutes . 'M' . $seconds . "S</duration>\n";
}
else
{
return '';
}
}
/**
* Export the presentation (Exercise's description)
* @author Amand Tihon <amand@alrj.org>
*/
function export_presentation()
{
$out = "<presentation_material><flow_mat><material>\n"
. " <mattext><![CDATA[" . $this->exercise->getDescription() . "]]></mattext>\n"
. "</material></flow_mat></presentation_material>\n";
return $out;
}
/**
* Export the ordering information.
* Either sequential, through all questions, or random, with a selected number of questions.
* @author Amand Tihon <amand@alrj.org>
*/
function export_ordering()
{
$out = '';
if ($n = $this->exercise->getShuffle()) {
$out.= "<selection_ordering>"
. " <selection>\n"
. " <selection_number>" . $n . "</selection_number>\n"
. " </selection>\n"
. ' <order order_type="Random" />'
. "\n</selection_ordering>\n";
}
else
{
$out.= '<selection_ordering sequence_type="Normal">' . "\n"
. " <selection />\n"
. "</selection_ordering>\n";
}
return $out;
}
/**
* Export the questions, as a succession of <items>
* @author Amand Tihon <amand@alrj.org>
*/
function export_questions()
{
$out = "";
foreach ($this->exercise->getQuestionList() as $q)
{
$out .= export_question($q['id'], False);
}
return $out;
}
/**
* Export the exercise in IMS/QTI.
*
* @param bool $standalone Wether it should include XML tag and DTD line.
* @return a string containing the XML flow
* @author Amand Tihon <amand@alrj.org>
*/
function export($standalone)
{
global $charset;
$head = $foot = "";
if ($standalone) {
$head = '<?xml version = "1.0" encoding = "' . $charset . '" standalone = "no"?>' . "\n"
. '<!DOCTYPE questestinterop SYSTEM "ims_qtiasiv1p2p1.dtd">' . "\n"
. "<questestinterop>\n";
$foot = "</questestinterop>\n";
}
$out = $head
. $this->start_section()
. $this->export_duration()
. $this->export_presentation()
. $this->export_ordering()
. $this->export_questions()
. $this->end_section()
. $foot;
return $out;
}
}
/*
Some quick notes on identifiers generation.
The IMS format requires some blocks, like items, responses, feedbacks, to be uniquely
identified.
The unicity is mandatory in a single XML, of course, but it's prefered that the identifier stays
coherent for an entire site.
Here's the method used to generate those identifiers.
Question identifier :: "QST_" + <Question Id from the DB> + "_" + <Question numeric type>
Response identifier :: <Question identifier> + "_A_" + <Response Id from the DB>
Condition identifier :: <Question identifier> + "_C_" + <Response Id from the DB>
Feedback identifier :: <Question identifier> + "_F_" + <Response Id from the DB>
*/
/**
* An IMS/QTI item. It corresponds to a single question.
* This class allows export from Claroline to IMS/QTI XML format.
* It is not usable as-is, but must be subclassed, to support different kinds of questions.
*
* Every start_*() and corresponding end_*(), as well as export_*() methods return a string.
*
* Warning: Attached files are NOT exported.
* @package chamilo.exercise.qti
* @author Amand Tihon <amand@alrj.org>
*/
class ImsItem
{
var $question;
var $question_ident;
var $answer;
/**
* Constructor.
*
* @param $question The Question object we want to export.
* @author Anamd Tihon
*/
function ImsItem($question)
{
$this->question = $question;
$this->answer = $question->answer;
$this->questionIdent = "QST_" . $question->getId() ;
}
/**
* Start the XML flow.
*
* This opens the <item> block, with correct attributes.
*
* @author Amand Tihon <amand@alrj.org>
*/
function start_item()
{
return '<item title="' . htmlspecialchars($this->question->getTitle()) . '" ident="' . $this->questionIdent . '">' . "\n";
}
/**
* End the XML flow, closing the </item> tag.
*
* @author Amand Tihon <amand@alrj.org>
*/
function end_item()
{
return "</item>\n";
}
/**
* Create the opening, with the question itself.
*
* This means it opens the <presentation> but doesn't close it, as this is the role of end_presentation().
* Inbetween, the export_responses from the subclass should have been called.
*
* @author Amand Tihon <amand@alrj.org>
*/
function start_presentation()
{
return '<presentation label="' . $this->questionIdent . '"><flow>' . "\n"
. '<material><mattext><![CDATA[' . $this->question->getDescription() . "]]></mattext></material>\n";
}
/**
* End the </presentation> part, opened by export_header.
*
* @author Amand Tihon <amand@alrj.org>
*/
function end_presentation()
{
return "</flow></presentation>\n";
}
/**
* Start the response processing, and declare the default variable, SCORE, at 0 in the outcomes.
*
* @author Amand Tihon <amand@alrj.org>
*/
function start_processing()
{
return '<resprocessing><outcomes><decvar vartype="Integer" defaultval="0" /></outcomes>' . "\n";
}
/**
* End the response processing part.
*
* @author Amand Tihon <amand@alrj.org>
*/
function end_processing()
{
return "</resprocessing>\n";
}
/**
* Export the question as an IMS/QTI Item.
*
* This is a default behaviour, some classes may want to override this.
*
* @param $standalone: Boolean stating if it should be exported as a stand-alone question
* @return A string, the XML flow for an Item.
* @author Amand Tihon <amand@alrj.org>
*/
function export($standalone = False)
{
global $charset;
$head = $foot = "";
if( $standalone )
{
$head = '<?xml version = "1.0" encoding = "'.$charset.'" standalone = "no"?>' . "\n"
. '<!DOCTYPE questestinterop SYSTEM "ims_qtiasiv1p2p1.dtd">' . "\n"
. "<questestinterop>\n";
$foot = "</questestinterop>\n";
}
return $head
. $this->start_item()
. $this->start_presentation()
. $this->answer->imsExportResponses($this->questionIdent)
. $this->end_presentation()
. $this->start_processing()
. $this->answer->imsExportProcessing($this->questionIdent)
. $this->end_processing()
. $this->answer->imsExportFeedback($this->questionIdent)
. $this->end_item()
. $foot;
}
}
/*--------------------------------------------------------
Functions
--------------------------------------------------------*/
/**
* Send a complete exercise in IMS/QTI format, from its ID
*
* @param int $exerciseId The exercise to exporte
* @param boolean $standalone Wether it should include XML tag and DTD line.
* @return The XML as a string, or an empty string if there's no exercise with given ID.
* @author Amand Tihon <amand@alrj.org>
*/
function export_exercise($exerciseId, $standalone=True)
{
$exercise = new Exercise();
if (! $exercise->load($exerciseId))
{
return '';
}
$ims = new ImsSection($exercise);
$xml = $ims->export($standalone);
return $xml;
}
/**
* Returns the XML flow corresponding to one question
*
* @param int The question ID
* @param bool standalone (ie including XML tag, DTD declaration, etc)
* @author Amand Tihon <amand@alrj.org>
*/
function export_question($questionId, $standalone=True)
{
$question = new ImsQuestion();
if( !$question->load($questionId) )
{
return '';
}
$ims = new ImsItem($question);
return $ims->export($standalone);
}
?>

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

@ -30,8 +30,7 @@ require_once 'lib/gradebook_data_generator.class.php';
require_once 'lib/fe/gradebooktable.class.php';
require_once 'lib/fe/displaygradebook.php';
require_once 'lib/fe/userform.class.php';
require_once api_get_path(LIBRARY_PATH).'document.lib.php';
require_once api_get_path(LIBRARY_PATH).'ezpdf/class.ezpdf.php';
$htmlHeadXtra[] = '<script type="text/javascript">
$(document).ready( function() {
for (i=0;i<$(".actions").length;i++) {

@ -21,7 +21,6 @@ require_once 'lib/fe/displaygradebook.php';
require_once 'lib/fe/exportgradebook.php';
require_once 'lib/scoredisplay.class.php';
require_once api_get_path(SYS_CODE_PATH).'gradebook/lib/gradebook_functions.inc.php';
require_once api_get_path(LIBRARY_PATH).'pdf.lib.php';
api_block_anonymous_users();
$isDrhOfCourse = CourseManager::isUserSubscribedInCourseAsDrh(
@ -282,8 +281,6 @@ if (isset($_GET['isStudentView']) && $_GET['isStudentView'] == 'false') {
// main graph
$flatviewtable->display();
// @todo this needs a fix
//$image_file = $flatviewtable->display_graph();
//@todo load images with jquery
echo '<div id="contentArea" style="text-align: center;" >';
if (!empty($image_file)) {

@ -21,7 +21,6 @@ require_once 'lib/results_data_generator.class.php';
require_once 'lib/fe/resulttable.class.php';
require_once 'lib/fe/exportgradebook.php';
require_once 'lib/scoredisplay.class.php';
require_once api_get_path(LIBRARY_PATH) . 'ezpdf/class.ezpdf.php';
require_once api_get_path(SYS_CODE_PATH) . 'gradebook/lib/gradebook_functions.inc.php';
api_block_anonymous_users();

@ -36,8 +36,7 @@ require_once 'lib/gradebook_data_generator.class.php';
require_once 'lib/fe/gradebooktable.class.php';
require_once 'lib/fe/displaygradebook.php';
require_once 'lib/fe/userform.class.php';
require_once api_get_path(LIBRARY_PATH).'ezpdf/class.ezpdf.php';
require_once api_get_path(LIBRARY_PATH).'gradebook.lib.php';
/*
$htmlHeadXtra[] = api_get_css(api_get_path(WEB_LIBRARY_PATH).'javascript/jqplot/jquery.jqplot.min.css');
$htmlHeadXtra[] = api_get_js('jqplot/jquery.jqplot.min.js');

@ -292,7 +292,6 @@ class Category implements GradebookItem
// otherwise a special parameter is given to ask explicitely
$sql .= " AND (session_id IS NULL OR session_id = 0) ";
} else {*/
if (empty($session_id)) {
$sql .= ' AND (session_id IS NULL OR session_id = 0) ';
} else {
@ -326,14 +325,15 @@ class Category implements GradebookItem
$sql .= ' '.$order_by;
}
}
$result = Database::query($sql);
$allcat = array();
$categories = array();
if (Database::num_rows($result) > 0) {
$allcat = Category::create_category_objects_from_sql_result($result);
$categories = Category::create_category_objects_from_sql_result($result);
}
return $allcat;
return $categories;
}
/**
@ -731,7 +731,7 @@ class Category implements GradebookItem
*/
public function calc_score($stud_id = null, $course_code = '', $session_id = null)
{
// get appropriate subcategories, evaluations and links
// Get appropriate subcategories, evaluations and links
if (!empty($course_code)) {
$cats = $this->get_subcategories($stud_id, $course_code, $session_id);
$evals = $this->get_evaluations($stud_id, false, $course_code);
@ -782,10 +782,9 @@ class Category implements GradebookItem
}
if (!empty($links)) {
/** @var EvalLink $link */
/** @var EvalLink|ExerciseLink $link */
foreach ($links as $link) {
$linkres = $link->calc_score($stud_id);
if (!empty($linkres) && $link->get_weight() != 0) {
$linkweight = $link->get_weight();
$link_res_denom = $linkres[1] == 0 ? 1 : $linkres[1];
@ -1296,14 +1295,23 @@ class Category implements GradebookItem
// 1 student
if (isset($stud_id)) {
// special case: this is the root
// Special case: this is the root
if ($this->id == 0) {
return Category::get_root_categories_for_student($stud_id, $course_code, $session_id);
} else {
return Category::load(null,null, $course_code, $this->id, api_is_allowed_to_edit() ? null : 1, $session_id, $order);
return Category::load(
null,
null,
$course_code,
$this->id,
api_is_allowed_to_edit() ? null : 1,
$session_id,
$order
);
}
} else {// all students
// course admin
} else {
// All students
// Course admin
if (api_is_allowed_to_edit() && !api_is_platform_admin()) {
// root
if ($this->id == 0) {

@ -19,18 +19,26 @@ abstract class EvalLink extends AbstractLink
parent::__construct();
}
// Functions implementing AbstractLink
/**
* @return bool
*/
public function has_results()
{
$eval = $this->get_evaluation();
return $eval->has_results();
}
public function calc_score($stud_id = null)
/**
* @param int $userId
*
* @return array
*/
public function calc_score($userId = null)
{
$eval = $this->get_evaluation();
return $eval->calc_score($stud_id);
return $eval->calc_score($userId);
}
public function get_link()

@ -221,7 +221,7 @@ class ExerciseLink extends AbstractLink
if ($student_count == 0) {
return null;
} else {
return array ($sum , $student_count);
return array($sum, $student_count);
}
}
}

@ -158,27 +158,32 @@ class StudentPublicationLink extends AbstractLink
public function calc_score($stud_id = null)
{
$stud_id = intval($stud_id);
$tbl_stats = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
$sql = 'SELECT * FROM '.$tbl_stats."
$table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
$sql = 'SELECT * FROM '.$table."
WHERE
c_id = {$this->course_id} AND
id = '".intval($this->get_ref_id())."' AND
session_id = ".api_get_session_id()."";
session_id = ".api_get_session_id()."
"
;
$query = Database::query($sql);
$assignment = Database::fetch_array($query);
if (count($assignment)==0) {
$v_assigment_id ='0';
if (count($assignment) == 0) {
$parentId = '0';
} else {
$v_assigment_id = $assignment['id'];
$parentId = $assignment['id'];
}
$sql = 'SELECT * FROM '.$tbl_stats.'
$sql = 'SELECT * FROM '.$table.'
WHERE
c_id = '.$this->course_id.' AND
active = 1 AND
parent_id ="'.$v_assigment_id.'" AND
session_id='.api_get_session_id().'';
parent_id = "'.$parentId.'" AND
session_id = '.api_get_session_id() .' AND
qualificator_id <> 0
';
if (!empty($stud_id)) {
$sql .= " AND user_id = $stud_id ";
}

@ -94,7 +94,6 @@ a:active {text-decoration: none; font-weight : bold; color : black;}
* @return void
*/
function export_pdf_attendance($headers_table, $data_table, $headers_pdf, $footers_pdf, $title_pdf) {
require_once api_get_path(LIBRARY_PATH).'mpdf/mpdf.php';
$mpdf = new mPDF('UTF-8', 'A4-L', '', '', 15, 10, 35, 20, 4, 2, 'L');
$mpdf->useOnlyCoreFonts = true;
@ -219,9 +218,8 @@ function export_pdf_attendance($headers_table, $data_table, $headers_pdf, $foote
* @param array pdf footers
* @return void
*/
function export_pdf_with_html($headers_table, $data_table, $headers_pdf, $footers_pdf, $title_pdf) {
require_once api_get_path(LIBRARY_PATH).'pdf.lib.php';
function export_pdf_with_html($headers_table, $data_table, $headers_pdf, $footers_pdf, $title_pdf)
{
$headers_in_pdf = '<img src="'.api_get_path(WEB_CSS_PATH).api_get_setting('stylesheets').'/images/header-logo.png">';
if (is_array($headers_pdf)) {

@ -5,6 +5,10 @@ require_once dirname(__FILE__) . '/../../../inc/global.inc.php';
require_once dirname(__FILE__) . '/../be.inc.php';
set_time_limit(0);
use CpChart\Classes\pData as pData;
use CpChart\Classes\pImage as pImage;
use CpChart\Classes\pCache as pCache;
/**
* Class FlatViewTable
* Table to display flat view (all evaluations and links for all students)
@ -42,7 +46,8 @@ class FlatViewTable extends SortableTable
$addparams = null,
$mainCourseCategory = null
) {
parent :: __construct('flatviewlist', null, null, (api_is_western_name_order() xor api_sort_by_first_name()) ? 1 : 0);
parent :: __construct('flatviewlist', null, null, api_is_western_name_order() ? 1 : 0);
$this->selectcat = $selectcat;
$this->datagen = new FlatViewDataGenerator(
@ -80,159 +85,29 @@ class FlatViewTable extends SortableTable
return $this->mainCourseCategory;
}
/**
* Display the graph of the total results of all students
* */
public function display_graph()
{
include_once api_get_path(LIBRARY_PATH) . 'pchart/pData.class.php';
include_once api_get_path(LIBRARY_PATH) . 'pchart/pChart.class.php';
include_once api_get_path(LIBRARY_PATH) . 'pchart/pCache.class.php';
$header_name = $this->datagen->get_header_names();
$total_users = $this->datagen->get_total_users_count();
$img_file = '';
if ($this->datagen->get_total_items_count() > 0 && $total_users > 0) {
// Removing user names and total
array_shift($header_name);
array_shift($header_name);
array_pop($header_name);
$user_results = $this->datagen->get_data_to_graph();
$pre_result = $new_result = array();
$DataSet = new pData();
//$pre_result total score of students
//filling the Dataset
foreach ($user_results as $result) {
for ($i = 0; $i < count($header_name); $i++) {
$pre_result[$i + 3]+= $result[$i + 1];
}
}
$i = 1;
$show_draw = false;
if ($total_users > 0) {
foreach ($pre_result as $res) {
$total = $res / ($total_users);
if ($total != 0) {
$show_draw = true;
}
$DataSet->AddPoint($total, "Serie" . $i);
$DataSet->SetSerieName(strip_tags($header_name[$i - 1]), "Serie" . $i);
// Dataset definition
$DataSet->AddAllSeries();
$DataSet->SetAbsciseLabelSerie();
$i++;
}
}
// Cache definition
$Cache = new pCache();
// the graph id
$gradebook_id = intval($_GET['selectcat']);
$graph_id = api_get_user_id() . 'AverageResultsVsResource' . $gradebook_id . api_get_course_id();
$data = $DataSet->GetData();
if ($show_draw) {
if ($Cache->IsInCache($graph_id, $DataSet->GetData())) {
//if (0) {
//if we already created the img
//echo 'in cache';
$img_file = $Cache->GetHash($graph_id, $DataSet->GetData());
} else {
// if the image does not exist in the archive/ folder
// Initialise the graph
$angle = -30;
$Test = new pChart(760, 360);
// set font of the axes
$Test->setFontProperties(api_get_path(LIBRARY_PATH) . "pchart/fonts/tahoma.ttf", 8);
$Test = $Test->fixHeightByRotation($DataSet->GetData(), $DataSet->GetDataDescription(), $angle);
//which schema of color will be used
$quant_resources = count($data[0]) - 1;
// Adding the color schemma
if ($quant_resources < 8) {
$Test->loadColorPalette(api_get_path(LIBRARY_PATH) . "pchart/palette/reduced.txt");
} else {
$Test->loadColorPalette(api_get_path(LIBRARY_PATH) . "pchart/palette/default.txt");
}
$Test->setGraphArea(50, 30, 610, 300);
$Test->drawFilledRoundedRectangle(7, 7, $Test->XSize + 20, $Test->YSize - 30, 5, 240, 240, 240);
//$Test->drawRoundedRectangle(5,5,790,330,5,230,230,230);
//background color area & stripe or not
$Test->drawGraphArea(255, 255, 255, TRUE);
$Test->drawScale($DataSet->GetData(), $DataSet->GetDataDescription(), SCALE_START0, 150, 150, 150, TRUE, 0, 1, FALSE);
//background grid
$Test->drawGrid(4, TRUE, 230, 230, 230, 50);
// Draw the 0 line
//$Test->setFontProperties(api_get_path(LIBRARY_PATH)."pchart/fonts/tahoma.ttf",6);
//$Test->drawTreshold(0,143,55,72,TRUE,TRUE);
// Draw the bar graph
$Test->drawBarGraph($DataSet->GetData(), $DataSet->GetDataDescription(), TRUE);
//Set legend properties: width, height and text color and font
$Test->setFontProperties(api_get_path(LIBRARY_PATH) . "pchart/fonts/tahoma.ttf", 9);
$Test->drawLegend(620, 70, $DataSet->GetDataDescription(), 255, 255, 255);
//Set title properties
$Test->setFontProperties(api_get_path(LIBRARY_PATH) . "pchart/fonts/tahoma.ttf", 10);
$Test->drawTitle(50, 22, get_lang('AverageResultsVsResource'), 50, 50, 80, 620);
//------------------
//echo 'not in cache';
$Cache->WriteToCache($graph_id, $DataSet->GetData(), $Test);
ob_start();
$Test->Stroke();
ob_end_clean();
$img_file = $Cache->GetHash($graph_id, $DataSet->GetData());
}
}
}
return api_get_path(WEB_ARCHIVE_PATH) . $img_file;
}
/**
*
*/
public function display_graph_by_resource()
{
require_once api_get_path(LIBRARY_PATH) . 'pchart/pData.class.php';
require_once api_get_path(LIBRARY_PATH) . 'pchart/pChart.class.php';
require_once api_get_path(LIBRARY_PATH) . 'pchart/pCache.class.php';
$header_name = $this->datagen->get_header_names();
$headerName = $this->datagen->get_header_names();
$total_users = $this->datagen->get_total_users_count();
$img_file = '';
if ($this->datagen->get_total_items_count() > 0 && $total_users > 0) {
//Removing first name
array_shift($header_name);
array_shift($headerName);
//Removing last name
array_shift($header_name);
array_shift($headerName);
$displayscore = ScoreDisplay :: instance();
$displayscore = ScoreDisplay::instance();
$customdisplays = $displayscore->get_custom_score_display_settings();
if (is_array($customdisplays) && count(($customdisplays))) {
$user_results = $this->datagen->get_data_to_graph2(false);
$pre_result = $new_result = array();
$DataSet = new pData();
//filling the Dataset
foreach ($user_results as $result) {
//print_r($result);
for ($i = 0; $i < count($header_name); $i++) {
for ($i = 0; $i < count($headerName); $i++) {
$pre_result[$i + 3][] = $result[$i + 1];
}
}
@ -284,197 +159,150 @@ class FlatViewTable extends SortableTable
$resource_list = $new_list;
$i = 1;
$j = 0;
foreach ($resource_list as $key => $resource) {
$new_resource_list = $new_resource_list_name = array();
$DataSet = new pData();
// Reverse array, otherwise we get highest values first
$resource = array_reverse($resource, true);
foreach ($resource as $name => $cant) {
$DataSet->AddPoint($cant, "Serie" . $j);
$DataSet->SetSerieName(strip_tags($name), "Serie" . $j);
$j++;
}
//print_r($pre_result); print_r($header_name);
// Dataset definition
$DataSet->AddAllSeries();
$DataSet->SetAbsciseLabelSerie('');
$DataSet->SetXAxisName(get_lang('GradebookSkillsRanking'));
$DataSet->SetYAxisName(get_lang('Students'));
$show_draw = true;
$dataSet = new pData();
$dataSet->addPoints($resource, 'Serie');
$dataSet->addPoints(array_keys($resource), 'Labels');
$dataSet->setSerieDescription('Labels', strip_tags($headerName[$i - 1]));
$dataSet->setAbscissa('Labels');
$dataSet->setAbscissaName(get_lang('GradebookSkillsRanking'));
$dataSet->setAxisName(0, get_lang('Students'));
$palette = array(
'0' => array('R' => 186, 'G' => 206, 'B' => 151, 'Alpha' => 100),
'1' => array('R' => 210, 'G' => 148, 'B' => 147, 'Alpha' => 100),
'2' => array('R' => 148, 'G' => 170, 'B' => 208, 'Alpha' => 100),
'3' => array('R' => 221, 'G' => 133, 'B' => 61, 'Alpha' => 100),
'4' => array('R' => 65, 'G' => 153, 'B' => 176, 'Alpha' => 100),
'5' => array('R' => 114, 'G' => 88, 'B' => 144, 'Alpha' => 100),
'6' => array('R' => 138, 'G' => 166, 'B' => 78, 'Alpha' => 100),
'7' => array('R' => 171, 'G' => 70, 'B' => 67, 'Alpha' => 100),
'8' => array('R' => 69, 'G' => 115, 'B' => 168, 'Alpha' => 100),
);
// Cache definition
$Cache = new pCache();
// the graph id
$gradebook_id = intval($_GET['selectcat']);
$graph_id = api_get_user_id() . 'ByResource' . $gradebook_id . api_get_course_id() . api_get_session_id();
if ($show_draw) {
//if ($Cache->IsInCache($graph_id, $DataSet->GetData())) {
if (0) {
//if we already created the img we get the img file id
//echo 'in cache';
$img_file = $Cache->GetHash($graph_id, $DataSet->GetData());
} else {
// if the image does not exist in the archive/ folder
// Initialise the graph
$chart_size_w = 480;
$chart_size_h = 250;
$angle = -30;
$Test = new pChart($chart_size_w, $chart_size_h);
// set font of the axes
$Test->setFontProperties(api_get_path(LIBRARY_PATH) . "pchart/fonts/tahoma.ttf", 8);
$Test = $Test->fixHeightByRotation(
$DataSet->GetData(),
$DataSet->GetDataDescription(),
$angle
);
// Adding the color schemma
$Test->loadColorPalette(api_get_path(LIBRARY_PATH) . "pchart/palette/pastel.txt");
$area_graph_w = $chart_size_w - 130;
$Test->setGraphArea(50, 30, $area_graph_w, $chart_size_h - 50);
$Test->drawFilledRoundedRectangle(
5,
5,
$chart_size_w - 1,
$Test->YSize - 20,
5,
240,
240,
240
);
//$Test->drawRoundedRectangle(5,5,790,330,5,230,230,230);
//background color area & stripe or not
$Test->drawGraphArea(255, 255, 255, TRUE);
//Setting max height by default see #3296
if (!empty($max)) {
if (is_int($max)) {
$Test->setFixedScale(0, $max + 1, $max + 1);
} else {
$Test->setFixedScale(0, $max);
}
}
$Test->drawScale(
$DataSet->GetData(),
$DataSet->GetDataDescription(),
SCALE_ADDALLSTART0,
150,
150,
150,
TRUE,
0,
1,
FALSE
);
//background grid
$Test->drawGrid(4, TRUE, 230, 230, 230, 50);
// Draw the 0 line
//$Test->setFontProperties(api_get_path(LIBRARY_PATH)."pchart/fonts/tahoma.ttf",6);
//$Test->drawTreshold(0,143,55,72,TRUE,TRUE);
// Draw the bar graph
$Test->setFontProperties(api_get_path(LIBRARY_PATH) . "pchart/fonts/tahoma.ttf", 11);
$Test->drawBarGraph($DataSet->GetData(), $DataSet->GetDataDescription(), TRUE);
//Set legend properties: width, height and text color and font
$Test->setFontProperties(api_get_path(LIBRARY_PATH) . "pchart/fonts/tahoma.ttf", 9);
$Test->drawLegend($area_graph_w + 10, 50, $DataSet->GetDataDescription(), 255, 255, 255);
//Set title properties
$Test->setFontProperties(api_get_path(LIBRARY_PATH) . "pchart/fonts/tahoma.ttf", 10);
$Test->drawTitle(50, 22, strip_tags($header_name[$i - 1]), 50, 50, 80, $chart_size_w - 50);
//------------------
//echo 'not in cache';
$Cache->WriteToCache($graph_id, $DataSet->GetData(), $Test);
//ob_start();
//$Test->Stroke();
//ob_end_clean();
$img_file = $Cache->GetHash($graph_id, $DataSet->GetData());
}
echo '<img src="' . api_get_path(WEB_ARCHIVE_PATH) . $img_file . '" >';
if ($i % 2 == 0 && $i != 0) {
echo '<br />';
}
$i++;
$cachePath = api_get_path(SYS_ARCHIVE_PATH);
$myCache = new pCache(array('CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)));
$chartHash = $myCache->getHash($dataSet);
if ($myCache->isInCache($chartHash)) {
$imgPath = api_get_path(SYS_ARCHIVE_PATH) . $chartHash;
$myCache->saveFromCache($chartHash, $imgPath);
$imgPath = api_get_path(WEB_ARCHIVE_PATH) . $chartHash;
} else {
/* Create the pChart object */
$widthSize = 480;
$heightSize = 250;
$myPicture = new pImage($widthSize, $heightSize, $dataSet);
/* Turn of Antialiasing */
$myPicture->Antialias = false;
/* Add a border to the picture */
$myPicture->drawRectangle(
0,
0,
$widthSize - 1,
$heightSize - 1,
array(
'R' => 0,
'G' => 0,
'B' => 0
)
);
/* Set the default font */
$myPicture->setFontProperties(
array(
'FontName' => api_get_path(SYS_FONTS_PATH) . 'opensans/OpenSans-Regular.ttf',
'FontSize' => 10
)
);
/* Write the chart title */
$myPicture->drawText(
250,
30,
strip_tags($headerName[$i - 1]),
array(
'FontSize' => 12,
'Align' => TEXT_ALIGN_BOTTOMMIDDLE
)
);
/* Define the chart area */
$myPicture->setGraphArea(50, 40, $widthSize - 20, $heightSize - 50);
/* Draw the scale */
$scaleSettings = array(
'GridR' => 200,
'GridG' => 200,
'GridB' => 200,
'DrawSubTicks' => true,
'CycleBackground' => true,
'Mode' => SCALE_MODE_START0
);
$myPicture->drawScale($scaleSettings);
/* Turn on shadow computing */
$myPicture->setShadow(
true,
array(
'X' => 1,
'Y' => 1,
'R' => 0,
'G' => 0,
'B' => 0,
'Alpha' => 10
)
);
/* Draw the chart */
$myPicture->setShadow(
true,
array(
'X' => 1,
'Y' => 1,
'R' => 0,
'G' => 0,
'B' => 0,
'Alpha' => 10
)
);
$settings = array(
'OverrideColors' => $palette,
'Gradient' => false,
'GradientMode' => GRADIENT_SIMPLE,
'DisplayPos' => LABEL_POS_TOP,
'DisplayValues' => true,
'DisplayR' => 0,
'DisplayG' => 0,
'DisplayB' => 0,
'DisplayShadow' => true,
'Surrounding' => 10,
);
$myPicture->drawBarChart($settings);
/* Render the picture (choose the best way) */
$myCache->writeToCache($chartHash, $myPicture);
$imgPath = api_get_path(SYS_ARCHIVE_PATH) . $chartHash;
$myCache->saveFromCache($chartHash, $imgPath);
$imgPath = api_get_path(WEB_ARCHIVE_PATH) . $chartHash;
}
} //end foreach
} else {
echo get_lang('ToViewGraphScoreRuleMustBeEnabled');
}
// Pie charts
/*
$show_draw = false;
$resource_list = array();
//print_r($pre_result_pie);
if ($total_users>0) {
foreach($pre_result_pie as $key=>$res_array) {
//$resource_list
foreach($res_array as $user_result) {
$total+= $user_result / ($total_users*100);
}
echo $total;
//echo $total = $res / ($total_users*100);
echo '<br>';
//$DataSet->AddPoint($total,"Serie".$i);
//$DataSet->SetSerieName($header_name[$i-1],"Serie".$i);
}
}
//here--------------
foreach($resource_list as $key=>$resource) {
$new_resource_list = $new_resource_list_name = array();
foreach($resource as $name=>$cant) {
$new_resource_list[]=$cant;
$new_resource_list_name[]=$name;
}
//Pie chart
$DataSet = new pData;
$DataSet->AddPoint($new_resource_list,"Serie1");
$DataSet->AddPoint($new_resource_list_name,"Serie2");
$DataSet->AddAllSeries();
$DataSet->SetAbsciseLabelSerie("Serie2");
$Test = new pChart(400,300);
$Test->loadColorPalette(api_get_path(LIBRARY_PATH)."pchart/palette/soft_tones.txt");
// background
//$Test->drawFilledRoundedRectangle(7,7,293,193,5,240,240,240);
// border color
$Test->drawRoundedRectangle(5,5,295,195,5,230,230,230);
// This will draw a shadow under the pie chart
//$Test->drawFilledCircle(122,102,70,200,200,200);
//Draw the pie chart
$Test->setFontProperties(api_get_path(LIBRARY_PATH)."pchart/fonts/tahoma.ttf",8);
$Test->drawBarGraph($DataSet->GetData(),$DataSet->GetDataDescription(),TRUE);
$tmp_path = api_get_path(SYS_ARCHIVE_PATH);
$Test->drawBasicPieGraph($DataSet->GetData(),$DataSet->GetDataDescription(),120,100,70,PIE_PERCENTAGE,255,255,218);
$Test->drawPieLegend(230,15,$DataSet->GetData(),$DataSet->GetDataDescription(),250,250,250);
$user_id = api_get_user_id();
$img_file_generated_name = $key.uniqid('').'gradebook.png';
$Test->Render($tmp_path.$img_file_generated_name);
chmod($tmp_path.$img_file_generated_name, api_get_permissions_for_new_files());
if ($i % 2 == 0 && $i!= 0) {
echo '<br>';
}
echo '<img src="'.api_get_path(WEB_ARCHIVE_PATH).$img_file_generated_name.'">';
}
*/
echo '<img src="' . $imgPath . '" >';
if ($i % 2 == 0 && $i != 0) {
echo '<br /><br />';
} else {
echo '&nbsp;&nbsp;&nbsp;';
}
$i++;
}
} //end foreach
} else {
echo get_lang('ToViewGraphScoreRuleMustBeEnabled');
}
}
@ -541,11 +369,16 @@ class FlatViewTable extends SortableTable
}
// retrieve sorting type
if ($is_western_name_order) {
$users_sorting = ($this->column == 0 ? FlatViewDataGenerator :: FVDG_SORT_FIRSTNAME : FlatViewDataGenerator :: FVDG_SORT_LASTNAME);
//$users_sorting = ($this->column == 0 ? FlatViewDataGenerator :: FVDG_SORT_FIRSTNAME : FlatViewDataGenerator :: FVDG_SORT_LASTNAME);
$users_sorting = FlatViewDataGenerator :: FVDG_SORT_FIRSTNAME;
} else {
$users_sorting = ($this->column == 0 ? FlatViewDataGenerator :: FVDG_SORT_LASTNAME : FlatViewDataGenerator :: FVDG_SORT_FIRSTNAME);
//$users_sorting = ($this->column == 0 ? FlatViewDataGenerator :: FVDG_SORT_LASTNAME : FlatViewDataGenerator :: FVDG_SORT_FIRSTNAME);
$users_sorting = FlatViewDataGenerator :: FVDG_SORT_LASTNAME;
}
if ($this->direction == 'DESC') {
$users_sorting |= FlatViewDataGenerator :: FVDG_SORT_DESC;
} else {
@ -555,16 +388,15 @@ class FlatViewTable extends SortableTable
$header_names = $this->datagen->get_header_names($this->offset, $selectlimit);
$column = 0;
if ($is_western_name_order) {
$this->set_header($column++, $header_names[1]);
$this->set_header($column++, $header_names[0]);
$this->set_header(0, $header_names[1]);
$this->set_header(1, $header_names[0]);
} else {
$this->set_header($column++, $header_names[0]);
$this->set_header($column++, $header_names[1]);
$this->set_header(0, $header_names[0]);
$this->set_header(1, $header_names[1]);
}
$column = 2;
while ($column < count($header_names)) {
$this->set_header($column, $header_names[$column], false);
$column++;

@ -157,9 +157,11 @@ class FlatViewDataGenerator
$session_id,
'ORDER BY id'
);
$evaluationsAdded = array();
if ($parent_id == 0 && !empty($allcat)) {
// Means there are any subcategory
foreach ($allcat as $sub_cat) {
$sub_cat_weight = round(100 * $sub_cat->get_weight() / $main_weight, 1);
$add_weight = " $sub_cat_weight %";
@ -216,7 +218,8 @@ class FlatViewDataGenerator
$max = $score[0];
}
}
return $max ;
return $max;
}
/**
@ -389,7 +392,12 @@ class FlatViewDataGenerator
$course_code = api_get_course_id();
$session_id = api_get_session_id();
$allcat = $this->category->get_subcategories(null, $course_code, $session_id, 'ORDER BY id');
$allcat = $this->category->get_subcategories(
null,
$course_code,
$session_id,
'ORDER BY id'
);
$evaluationsAdded = array();
@ -400,7 +408,7 @@ class FlatViewDataGenerator
$real_score = $score;
$divide = ( ($score[1])==0 ) ? 1 : $score[1];
$divide = $score[1] == 0 ? 1 : $score[1];
$sub_cat_percentage = $sum_categories_weight_array[$sub_cat->get_id()];
$item_value = $score[0]/$divide*$main_weight;
@ -410,10 +418,10 @@ class FlatViewDataGenerator
$item_value = $percentage*$item_value;
$item_total += $sub_cat->get_weight();
/*
if ($convert_using_the_global_weight) {
$score[0] = $score[0]/$main_weight*$sub_cat->get_weight();
$score[1] = $main_weight ;
}
if ($convert_using_the_global_weight) {
$score[0] = $score[0]/$main_weight*$sub_cat->get_weight();
$score[1] = $main_weight ;
}
*/
if (api_get_setting('gradebook_show_percentage_in_reports') == 'false') {
//if (true)
@ -427,8 +435,7 @@ class FlatViewDataGenerator
}
if (!isset($this->params['only_total_category']) ||
(isset($this->params['only_total_category']) &&
$this->params['only_total_category'] == false)
(isset($this->params['only_total_category']) && $this->params['only_total_category'] == false)
) {
if (!$show_all) {
$row[] = $temp_score.' ';

@ -364,9 +364,11 @@ class ScoreDisplay
return $this->display_as_div($score).' (' . $this->display_as_percent($score) . ')'.$custom;
case SCORE_DIV_SIMPLE_WITH_CUSTOM : // X - Good!
$custom = $this->display_custom($score);
if (!empty($custom)) {
$custom = ' - '.$custom;
}
return $this->display_simple_score($score).$custom;
break;
case SCORE_DIV_SIMPLE_WITH_CUSTOM_LETTERS:
@ -377,7 +379,7 @@ class ScoreDisplay
$score = $this->display_simple_score($score);
//needs sudo apt-get install php5-intl
if (class_exists(NumberFormatter)) {
if (class_exists('NumberFormatter')) {
$iso = api_get_language_isocode();
$f = new NumberFormatter($iso, NumberFormatter::SPELLOUT);
$letters = $f->format($score);

@ -87,8 +87,6 @@ if (isset ($_GET['exportpdf'])) {
}
}
$html .= $table->toHtml();
require_once api_get_path(LIBRARY_PATH).'pdf.lib.php';
$pdf = new PDF();
$pdf->content_to_pdf($html);
exit;

@ -1,5 +1,5 @@
"category";"group";"description";"announcements_state";"calendar_state";"chat_state";"doc_state";"forum_state";"work_state";"wiki_state";"max_student";"self_reg_allowed";"self_unreg_allowed";"groups_per_user";
"category";"group";"description";"announcements_state";"calendar_state";"chat_state";"doc_state";"forum_state";"work_state";"wiki_state";"max_student";"self_reg_allowed";"self_unreg_allowed";"groups_per_user";"students";"tutors"
"Category 1";"";"This is a category";"2";"2";"2";"2";"2";"2";"2";"0";"0";"0";"0";
"";"Group 1";"This is a group with no category";"2";"2";"2";"2";"2";"2";"2";"0";"0";"0"
"Category 1";"Group 2";"This is a group in a category 1";"2";"2";"2";"2";"2";"2";"2";"0";"0";"0"
"";"Group 1";"This is a group with no category";"2";"2";"2";"2";"2";"2";"2";"0";"0";"0";"";"username1,username2";"username3,username4"
"Category 1";"Group 2";"This is a group in a category 1";"2";"2";"2";"2";"2";"2";"2";"0";"0";"0";"";"username1,username2";"username3,username4"

Can't render this file because it has a wrong number of fields in line 3.

@ -167,18 +167,15 @@ if (api_is_allowed_to_edit(false, true)) {
echo '<a href="import.php?'.api_get_cidreq().'&action=import">'.
Display::return_icon('import_csv.png', get_lang('Import'), '', ICON_SIZE_MEDIUM).'</a>';
echo '<a href="group_overview.php?'.api_get_cidreq().'&action=export&type=csv">'.
echo '<a href="group_overview.php?'.api_get_cidreq().'&action=export_all&type=csv">'.
Display::return_icon('export_csv.png', get_lang('ExportAsCSV'), '', ICON_SIZE_MEDIUM).'</a>';
echo '<a href="group_overview.php?'.api_get_cidreq().'&action=export&type=xls">'.
echo '<a href="group_overview.php?'.api_get_cidreq().'&action=export_all&type=xls">'.
Display::return_icon('export_excel.png', get_lang('ExportAsXLS'), '', ICON_SIZE_MEDIUM).'</a>';
echo '<a href="group_overview.php?'.api_get_cidreq().'&action=export_pdf">'.
Display::return_icon('pdf.png', get_lang('ExportToPDF'), '', ICON_SIZE_MEDIUM).'</a>';
echo '<a href="group_overview.php?'.api_get_cidreq().'&action=export_all&type=xls">'.
Display::return_icon('export_excel.png', get_lang('ExportSettingsAsXLS'), '', ICON_SIZE_MEDIUM).'</a>';
echo '<a href="group_overview.php?'.api_get_cidreq().'">'.
Display::return_icon('group_summary.png', get_lang('GroupOverview'), '', ICON_SIZE_MEDIUM).'</a>';

@ -1,5 +1,6 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Main page for the group module.
* This script displays the general group settings,
@ -12,9 +13,6 @@
* @author Bart Mollet, code cleaning, use of Display-library, list of courseAdmin-tools, use of GroupManager
* @package chamilo.group
*/
/**
* INIT SECTION
*/
// Name of the language file that needs to be included
$language_file = array('group', 'admin');
@ -39,7 +37,7 @@ $keyword = isset($_GET['keyword']) ? $_GET['keyword'] : null;
if (isset($_GET['action'])) {
switch ($_GET['action']) {
case 'export_all':
$data = GroupManager::exportCategoriesAndGroupsToArray();
$data = GroupManager::exportCategoriesAndGroupsToArray(null, true);
Export::export_table_csv($data);
exit;
break;
@ -54,26 +52,9 @@ if (isset($_GET['action'])) {
break;
case 'export':
$groupId = isset($_GET['id']) ? intval($_GET['id']) : null;
$groups = GroupManager::get_group_list();
$data = array();
foreach ($groups as $index => $group) {
if (!empty($groupId)) {
if ($group['id'] != $groupId) {
continue;
}
}
$users = GroupManager::get_users($group['id']);
foreach ($users as $index => $user) {
$row = array();
$user = api_get_user_info($user);
$row[] = $group['name'];
$row[] = $user['official_code'];
$row[] = $user['lastName'];
$row[] = $user['firstName'];
$data[] = $row;
}
}
$data = GroupManager::exportCategoriesAndGroupsToArray($groupId, true);
switch ($_GET['type']) {
case 'csv':
Export::export_table_csv($data);

@ -35,7 +35,9 @@ $form->addElement('label', null, Display::url(get_lang('ExampleCSVFile'), api_ge
$form->addElement('button', 'submit', get_lang('Import'));
if ($form->validate()) {
if (isset($_FILES['file']['tmp_name']) && !empty($_FILES['file']['tmp_name'])) {
if (isset($_FILES['file']['tmp_name']) &&
!empty($_FILES['file']['tmp_name'])
) {
$groupData = Import::csv_reader($_FILES['file']['tmp_name']);
$deleteNotInArray = $form->getSubmitValue('delete_not_in_file') == 1 ? true : false;

Binary file not shown.

After

Width:  |  Height:  |  Size: 872 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 504 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -35,6 +35,74 @@ switch ($action) {
case 'version':
echo version_check();
break;
case 'save_block_extra':
$content = isset($_POST['content']) ? Security::remove_XSS($_POST['content']) : null;
$blockName = isset($_POST['block']) ? Security::remove_XSS($_POST['block']) : null;
if (empty($blockName)) {
die;
}
if (api_is_multiple_url_enabled()) {
$accessUrlId = api_get_current_access_url_id();
if ($accessUrlId == -1) {
die;
}
$urlInfo = api_get_access_url($accessUrlId);
$url = api_remove_trailing_slash(preg_replace('/https?:\/\//i', '', $urlInfo['url']));
$cleanUrl = str_replace('/', '-', $url);
$newUrlDir = api_get_path(SYS_PATH) . "home/$cleanUrl/admin/";
} else {
$newUrlDir = api_get_path(SYS_PATH) . "home/admin/";
}
if (!is_dir($newUrlDir)) {
@mkdir($newUrlDir, api_get_permissions_for_new_directories(), true);
}
$fullFilePath = "{$newUrlDir}{$blockName}_extra.html";
if (file_exists($fullFilePath)) {
@unlink($fullFilePath);
}
@touch($fullFilePath);
@file_put_contents($fullFilePath, $content);
break;
case 'get_extra_content':
$blockName = isset($_POST['block']) ? Security::remove_XSS($_POST['block']) : null;
if (empty($blockName)) {
die;
}
if (api_is_multiple_url_enabled()) {
$accessUrlId = api_get_current_access_url_id();
if ($accessUrlId == -1) {
die;
}
$urlInfo = api_get_access_url($accessUrlId);
$url = api_remove_trailing_slash(preg_replace('/https?:\/\//i', '', $urlInfo['url']));
$cleanUrl = str_replace('/', '-', $url);
$newUrlDir = api_get_path(SYS_PATH) . "home/$cleanUrl/admin/";
} else {
$newUrlDir = api_get_path(SYS_PATH) . "home/admin/";
}
if (Security::check_abs_path("{$newUrlDir}{$blockName}_extra.html", $newUrlDir)) {
echo @file_get_contents("{$newUrlDir}{$blockName}_extra.html");
}
break;
}

@ -36,6 +36,7 @@ switch ($action) {
break;
}
$add_as_announcement = isset($_REQUEST['add_as_annonuncement']) ? $_REQUEST['add_as_annonuncement'] : null;
$comment = isset($_REQUEST['comment']) ? $_REQUEST['comment'] : null;
echo $agenda->add_event(
$_REQUEST['start'],
$_REQUEST['end'],
@ -43,7 +44,11 @@ switch ($action) {
$_REQUEST['title'],
$_REQUEST['content'],
$_REQUEST['users_to_send'],
$add_as_announcement
$add_as_announcement,
null, //$parentEventId = null,
array(), //$attachmentArray = array(),
null, //$attachmentComment = null,
$comment
);
break;
case 'edit_event':

@ -37,8 +37,6 @@ switch ($action) {
} else {
// save contact information with web service
require_once '../lib/nusoap/nusoap.php';
// create a client
$client = new nusoap_client('http://version.chamilo.org/contact.php?wsdl', true);

@ -658,7 +658,7 @@ switch ($action) {
$course = api_get_course_info();
// Used inside get_exam_results_data()
$documentPath = api_get_path(SYS_COURSE_PATH) . $course['path'] . "/document";
if ($is_allowedToEdit) {
if ($is_allowedToEdit || api_is_student_boss()) {
$columns = array(
'firstname', 'lastname', 'username', 'group_name', 'exe_duration', 'start_date', 'exe_date', 'score', 'status', 'lp', 'actions'
);

@ -9,8 +9,6 @@ $language_file = array('tracking');
require_once '../global.inc.php';
$action = $_GET['a'];
//if (!api_is_platform_admin() && !api_is_xml_http_request()) { exit; }
require_once api_get_path(SYS_CODE_PATH) . 'mySpace/myspace.lib.php';
switch ($action) {
case 'access_detail':

@ -3,7 +3,6 @@
/**
* Responses to AJAX calls
*/
$language_file[] = 'admin';
require_once '../global.inc.php';
@ -16,7 +15,7 @@ switch ($action) {
$list_sessions = SessionManager::get_sessions_by_user($user_id, true);
if (!empty($list_sessions)) {
foreach ($list_sessions as $session_item) {
echo $session_item['session_name'].'<br />';
echo $session_item['session_name'] . '<br />';
}
} else {
echo get_lang('NoSessionsForThisUser');
@ -107,6 +106,20 @@ switch ($action) {
}
}
break;
case 'get_description':
$sessionId = intval($_GET['session']);
$sessionInfo = api_get_session_info($sessionId);
?>
<h2><?php echo $sessionInfo['name'] ?></h2><br>
<div class="home-course-intro">
<div class="page-course">
<div class="page-course-intro">
<p><?php echo $sessionInfo['show_description'] == 1 ? $sessionInfo['description'] : get_lang('None') ?></p>
</div>
</div>
</div>
<?php
default:
echo '';
}

@ -1,18 +1,3 @@
<?php
/**
* Set up the Chamilo autoload stack. Can be called several time if needed also
* better to avoid it.
*/
require_once dirname(__FILE__) . '/lib/autoload.class.php';
Autoload::register();
/**
use Symfony\Component\ClassLoader\UniversalClassLoader;
$loader = new UniversalClassLoader();
$loader->registerNamespaces(array(
'Symfony\\Component\\HttpFoundation', __DIR__.'/vendor/symfony/http-foundation',
));
$loader->register();
*/
require_once __DIR__ . '/../../vendor/autoload.php';

@ -84,7 +84,7 @@ if (api_get_setting('login_is_email') == 'true') {
define('USERNAME_MAX_LENGTH', $default_username_length);
// Do not over-use this variable. It is only for this script's local use.
$lib_path = api_get_path(LIBRARY_PATH);
$lib_path = dirname(__FILE__).'/../../main/inc/lib/';
// Fix bug in IIS that doesn't fill the $_SERVER['REQUEST_URI'].
api_request_uri();
@ -96,16 +96,20 @@ ini_set('include_path', api_create_include_path_setting());
ini_set('auto_detect_line_endings', '1');
// Include the libraries that are necessary everywhere
require_once dirname(__FILE__).'/autoload.inc.php';
require_once dirname(__FILE__).'/../../vendor/autoload.php';
require_once $lib_path.'database.lib.php';
require_once $lib_path.'text.lib.php';
require_once $lib_path.'array.lib.php';
require_once $lib_path.'events.lib.inc.php';
require_once $lib_path.'model.lib.php';
require_once $lib_path.'course.lib.php';
require_once $lib_path.'online.inc.php';
define('_MPDF_TEMP_PATH', api_get_path(SYS_ARCHIVE_PATH).'mpdf/');
if (!is_dir(_MPDF_TEMP_PATH)) {
mkdir(_MPDF_TEMP_PATH, api_get_permissions_for_new_directories(), true);
}
/* DATABASE CONNECTION */
// @todo: this shouldn't be done here. It should be stored correctly during installation.
@ -115,14 +119,20 @@ if (empty($_configuration['statistics_database']) && $already_installed) {
global $database_connection;
// Connect to the server database and select the main chamilo database.
// When $_configuration['db_persistent_connection'] is set, it is expected to be a boolean type.
if (!($conn_return = @Database::connect(
array(
'server' => $_configuration['db_host'],
'username' => $_configuration['db_user'],
'password' => $_configuration['db_password'],
'persistent' => $_configuration['db_persistent_connection']
)))
) {
$dbPersistConnection = api_get_configuration_value('db_persistent_connection');
// $_configuration['db_client_flags'] can be set in configuration.php to pass
// flags to the DB connection
$dbFlags = api_get_configuration_value('db_client_flags');
$params = array(
'server' => $_configuration['db_host'],
'username' => $_configuration['db_user'],
'password' => $_configuration['db_password'],
'persistent' => $dbPersistConnection,
'client_flags' => $dbFlags,
);
if (!($conn_return = @Database::connect($params))) {
$global_error_code = 3;
// The database server is not available or credentials are invalid.
require $includePath.'/global_error_message.inc.php';

@ -0,0 +1,101 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Library for generate a teacher time report
*
* @author Angel Fernando Quiroz Campos <angel.quiroz@beeznest.com>
* @package chamilo.admin
*/
class TeacherTimeReport
{
/**
* The report data
* @var array
*/
public $data = array();
/**
* Callback for compare sessions names
* @param array $dataA The datab A
* @param array $dataB The data B
* @return int returns -1 if dataA is less than dataB, 1 if dataA is greater than dataB, and 0 if they are equal
*/
public function compareSessions($dataA, $dataB)
{
return strnatcmp($dataA['session']['name'], $dataB['session']['name']);
}
/**
* Callback for compare courses names
* @param array $dataA The datab A
* @param array $dataB The data B
* @return int returns -1 if dataA is less than dataB, 1 if dataA is greater than dataB, and 0 if they are equal
*/
public function compareCourses($dataA, $dataB)
{
return strnatcmp($dataA['course']['name'], $dataB['course']['name']);
}
/**
* Callback for compare coaches names
* @param array $dataA The datab A
* @param array $dataB The data B
* @return int returns -1 if dataA is less than dataB, 1 if dataA is greater than dataB, and 0 if they are equal
*/
public function compareCoaches($dataA, $dataB)
{
return strnatcmp($dataA['coach']['completeName'], $dataB['coach']['completeName']);
}
/**
* Sort the report data
* @param boolean $withFilter Whether sort by sessions and courses
*/
public function sortData($withFilter = false)
{
if ($withFilter) {
uasort($this->data, array($this, 'compareSessions'));
uasort($this->data, array($this, 'compareCourses'));
}
uasort($this->data, array($this, 'compareCoaches'));
}
public function prepareDataToExport($withFilter = false)
{
$dataToExport = array();
if ($withFilter) {
$dataToExport[] = array(
get_lang('Session'),
get_lang('Course'),
get_lang('Coach'),
get_lang('TotalTime')
);
} else {
$dataToExport[] = array(
get_lang('Coach'),
get_lang('TotalTime')
);
}
foreach ($this->data as $row) {
$data = array();
if ($withFilter) {
$data[] = $row['session']['name'];
$data[] = $row['course']['name'];
}
$data[] = $row['coach']['completeName'];
$data[] = $row['totalTime'];
$dataToExport[] = $data;
}
return $dataToExport;
}
}

@ -1759,6 +1759,7 @@ function create_course_tables($course_db_name = null) {
show_form_profile int NOT NULL default 0,
form_fields TEXT NOT NULL,
session_id int unsigned NOT NULL default 0,
visible_results int unsigned DEFAULT 0,
PRIMARY KEY (c_id, survey_id)
)" . $charset_clause;
$result = Database::query($sql);
@ -2015,6 +2016,9 @@ function create_course_tables($course_db_name = null) {
Database::query($sql);
// New course tables for 1.10.x come here
return 0;
}

@ -607,7 +607,7 @@ class Auth
$userId = api_get_user_id();
$limitFilter = getLimitFilterFromArray($limit);
$sql = "SELECT s.id, s.name, s.nbr_courses, s.nbr_users, s.date_start, s.date_end, u.lastname, u.firstname, u.username "
$sql = "SELECT s.id, s.name, s.nbr_courses, s.nbr_users, s.date_start, s.date_end, u.lastname, u.firstname, u.username, description, show_description "
. "FROM $sessionTable AS s "
. "INNER JOIN $userTable AS u "
. "ON s.id_coach = u.user_id "

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save