Browse Source

merge 1.11.x

jmontoyaa 8 years ago
parent
commit
0b54ae207c
100 changed files with 2348 additions and 726 deletions
  1. 5 0
      .github/ISSUE_TEMPLATE.md
  2. 1 1
      README.md
  3. 5 2
      app/Migrations/Schema/V110/Version20150603181728.php
  4. 4 4
      app/Migrations/Schema/V110/Version20151221150100.php
  5. 5 1
      app/Migrations/Schema/V111/Version111.php
  6. 241 0
      app/Migrations/Schema/V111/Version20160907140300.php
  7. 215 0
      app/Migrations/Schema/V111/Version20160907150300.php
  8. 42 0
      app/Migrations/Schema/V111/Version20160929120000.php
  9. 50 0
      app/Migrations/Schema/V111/Version20160930144400.php
  10. 46 0
      app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-cs.js
  11. 70 0
      app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-de.js
  12. 75 0
      app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-en.js
  13. 49 0
      app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-es.js
  14. 53 0
      app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-fr.js
  15. 46 0
      app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-hu.js
  16. 46 0
      app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-it.js
  17. 46 0
      app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-ja.js
  18. 46 0
      app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-ko.js
  19. 46 0
      app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-pl.js
  20. 37 0
      app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-pt-br.js
  21. 46 0
      app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-pt.js
  22. 46 0
      app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-ro.js
  23. 46 0
      app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-ru.js
  24. 46 0
      app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-sk.js
  25. 46 0
      app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-zh-cn.js
  26. 46 0
      app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-zh.js
  27. 15 0
      app/Resources/public/assets/pwstrength-bootstrap/locales/de.json
  28. 15 0
      app/Resources/public/assets/pwstrength-bootstrap/locales/pl.json
  29. 15 0
      app/Resources/public/assets/pwstrength-bootstrap/locales/tr.json
  30. 28 2
      app/Resources/public/css/editor.css
  31. 71 109
      app/Resources/public/css/scorm.css
  32. 3 3
      app/Resources/public/css/themes/academica/default.css
  33. 3 3
      app/Resources/public/css/themes/baby_orange/default.css
  34. 3 3
      app/Resources/public/css/themes/beach/default.css
  35. 3 3
      app/Resources/public/css/themes/blue_lagoon/default.css
  36. 3 3
      app/Resources/public/css/themes/chamilo/default.css
  37. 3 3
      app/Resources/public/css/themes/chamilo_electric_blue/default.css
  38. 3 3
      app/Resources/public/css/themes/chamilo_green/default.css
  39. 3 3
      app/Resources/public/css/themes/chamilo_orange/default.css
  40. 3 3
      app/Resources/public/css/themes/chamilo_red/default.css
  41. 3 3
      app/Resources/public/css/themes/chamilo_sport_red/default.css
  42. 3 3
      app/Resources/public/css/themes/cool_blue/default.css
  43. 3 3
      app/Resources/public/css/themes/corporate/default.css
  44. 3 3
      app/Resources/public/css/themes/cosmic_campus/default.css
  45. 3 3
      app/Resources/public/css/themes/delicious_bordeaux/default.css
  46. 3 3
      app/Resources/public/css/themes/empire_green/default.css
  47. 3 3
      app/Resources/public/css/themes/fruity_orange/default.css
  48. 3 3
      app/Resources/public/css/themes/holi/default.css
  49. 3 3
      app/Resources/public/css/themes/journal/default.css
  50. 3 3
      app/Resources/public/css/themes/kiddy/default.css
  51. 3 3
      app/Resources/public/css/themes/medical/default.css
  52. 3 3
      app/Resources/public/css/themes/readable/default.css
  53. 3 3
      app/Resources/public/css/themes/royal_purple/default.css
  54. 3 3
      app/Resources/public/css/themes/simplex/default.css
  55. 3 3
      app/Resources/public/css/themes/sober_brown/default.css
  56. 3 3
      app/Resources/public/css/themes/spacelab/default.css
  57. 3 3
      app/Resources/public/css/themes/steel_grey/default.css
  58. 3 3
      app/Resources/public/css/themes/tasty_olive/default.css
  59. 1 1
      composer.json
  60. 8 3
      documentation/installation_guide.html
  61. 10 4
      documentation/installation_guide_es_ES.html
  62. 9 3
      documentation/installation_guide_fr_FR.html
  63. 211 211
      main/admin/access_url_edit_usergroup_to_url.php
  64. 2 2
      main/admin/course_edit.php
  65. 1 1
      main/admin/dashboard_add_sessions_to_user.php
  66. 7 9
      main/admin/settings.lib.php
  67. 12 6
      main/admin/settings.php
  68. 2 2
      main/admin/skill.php
  69. 3 1
      main/admin/skill_badge.php
  70. 2 3
      main/admin/skill_badge_create.php
  71. 2 2
      main/admin/skill_badge_list.php
  72. 2 2
      main/admin/skill_level.php
  73. 2 2
      main/admin/skill_list.php
  74. 2 2
      main/admin/skill_profile.php
  75. 2 2
      main/admin/skills.php
  76. 3 2
      main/admin/skills_profile.php
  77. 2 2
      main/admin/skills_wheel.php
  78. 12 15
      main/admin/teacher_time_report.php
  79. 4 3
      main/admin/teachers_time_by_session_report.php
  80. 2 2
      main/admin/user_add.php
  81. 0 8
      main/admin/user_information.php
  82. 6 6
      main/admin/user_list.php
  83. 26 27
      main/announcements/announcements.php
  84. 5 2
      main/announcements/download.php
  85. 1 1
      main/auth/external_login/ldap.inc.php
  86. 15 7
      main/auth/external_login/login.ldap.php
  87. 9 2
      main/blog/download.php
  88. 2 8
      main/calendar/agenda_js.php
  89. 2 5
      main/calendar/agenda_list.php
  90. 4 1
      main/calendar/download.php
  91. 6 4
      main/course_info/delete_course.php
  92. 2 1
      main/coursecopy/import_moodle.php
  93. 291 157
      main/cron/import_csv.php
  94. 24 9
      main/document/create_document.php
  95. 5 2
      main/document/document.php
  96. 1 1
      main/document/document_quota.php
  97. 5 2
      main/document/download.php
  98. 4 1
      main/document/download_scorm.php
  99. 3 0
      main/document/downloadfolder.inc.php
  100. 7 2
      main/document/edit_odf.php

+ 5 - 0
.github/ISSUE_TEMPLATE.md

@@ -0,0 +1,5 @@
+### Expected behavior / Resultado esperado / Résultat attendu
+
+### Actual behavior / Resultado real / Résultat réel
+
+### Steps to reproduce / Pasos para reproducir / Étapes pour reproduire

+ 1 - 1
README.md

@@ -177,4 +177,4 @@ In short, we ask you to send us Pull Requests based on a branch that you create
 with this purpose into your repository forked from the original Chamilo repository.
 
 # Documentation
-For more information on Chamilo, visit https://stable.chamilo.org/documentation
+For more information on Chamilo, visit https://1.11.chamilo.org/documentation/index.html

+ 5 - 2
app/Migrations/Schema/V110/Version20150603181728.php

@@ -56,9 +56,12 @@ class Version20150603181728 extends AbstractMigrationChamilo
         // Remove inconsistencies about non-existing courses
 
         $this->addSql("DELETE FROM c_item_property WHERE session_id IS NOT NULL and session_id <> 0 AND session_id NOT IN (SELECT id FROM session)");
-        $this->addSql("DELETE FROM c_item_property WHERE to_user_id IS NOT NULL and to_user_id <> 0 AND  to_user_id NOT IN (SELECT id FROM user)");
+        $this->addSql("DELETE FROM c_item_property WHERE to_user_id IS NOT NULL and to_user_id <> 0 AND to_user_id NOT IN (SELECT id FROM user)");
         $this->addSql("DELETE FROM c_item_property WHERE to_user_id IS NOT NULL AND to_user_id <> 0 AND to_user_id NOT IN (SELECT id FROM user)");
-        $this->addSql("DELETE FROM c_item_property WHERE insert_user_id IS NOT NULL AND insert_user_id <> 0 AND insert_user_id NOT IN (SELECT id FROM user)");
+
+        // Sometimes the user was deleted but we need to keep the document.
+        // Assuming user.id = 1 (admin)
+        $this->addSql("UPDATE c_item_property SET insert_user_id = 1 WHERE insert_user_id IS NOT NULL AND insert_user_id <> 0 AND insert_user_id NOT IN (SELECT id FROM user)");
 
         // Remove inconsistencies about non-existing users
         $this->addSql("DELETE FROM c_item_property WHERE c_id NOT IN (SELECT id FROM course)");

+ 4 - 4
app/Migrations/Schema/V110/Version20151221150100.php

@@ -29,9 +29,9 @@ class Version20151221150100 extends AbstractMigrationChamilo
         $this->addSql("
             UPDATE track_e_attempt a
             INNER JOIN c_quiz_answer qa
-            ON a.question_id = qa.question_id
+            ON (a.question_id = qa.question_id AND a.c_id = qa.c_id)
             INNER JOIN c_quiz_question q
-            ON qa.question_id = q.id
+            ON (qa.question_id = q.id AND qa.c_id = q.c_id)
             SET a.answer = qa.id_auto
             WHERE
                 a.answer = qa.id AND
@@ -42,9 +42,9 @@ class Version20151221150100 extends AbstractMigrationChamilo
         $this->addSql("
             UPDATE c_quiz_answer a
             INNER JOIN c_quiz_answer b
-            ON a.question_id = b.question_id
+            ON (a.question_id = b.question_id AND b.c_id = a.c_id)
             INNER JOIN c_quiz_question q
-            ON b.question_id = q.id
+            ON (b.question_id = q.id AND b.c_id = q.c_id)
             SET a.correct = b.id_auto
             WHERE
                 a.correct = b.id AND

+ 5 - 1
app/Migrations/Schema/V111/Version111.php

@@ -70,6 +70,8 @@ class Version111 extends AbstractMigrationChamilo
 
         // Needed to update 0000-00-00 00:00:00 values
         $this->addSql('SET sql_mode = ""');
+        // In case this one didn't work, also try this
+        $this->addSql('SET SESSION sql_mode = ""');
 
         $this->addSql('ALTER TABLE c_lp CHANGE publicated_on publicated_on DATETIME');
         $this->addSql('ALTER TABLE c_lp CHANGE expired_on expired_on DATETIME');
@@ -268,7 +270,6 @@ class Version111 extends AbstractMigrationChamilo
         $this->addSql("INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable) VALUES ('show_link_ticket_notification', NULL, 'radio', 'Platform', 'false', 'ShowLinkTicketNotificationTitle', 'ShowLinkTicketNotificationComment', NULL, NULL, 0)");
         $this->addSql("INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, access_url) VALUES ('sso_authentication_subclass', NULL, 'textfield', 'Security', '', 'SSOSubclassTitle', 'SSOSubclassComment', 1)");
 
-
         $this->addSql("INSERT INTO settings_options (variable, value, display_text) VALUES ('ticket_allow_student_add', 'true', 'Yes'), ('ticket_allow_student_add', 'false', 'No')");
         $this->addSql("INSERT INTO settings_options (variable, value, display_text) VALUES ('ticket_allow_category_edition', 'true', 'Yes'), ('ticket_allow_category_edition', 'false', 'No')");
         $this->addSql("INSERT INTO settings_options (variable, value, display_text) VALUES ('ticket_send_warning_to_all_admins', 'true', 'Yes'), ('ticket_send_warning_to_all_admins', 'false', 'No')");
@@ -298,6 +299,7 @@ class Version111 extends AbstractMigrationChamilo
         $this->addSql('ALTER TABLE extra_field_options CHANGE display_text display_text VARCHAR(255) DEFAULT NULL');
         $this->addSql('ALTER TABLE extra_field CHANGE variable variable VARCHAR(255) NOT NULL');
         $this->addSql('ALTER TABLE c_course_setting MODIFY COLUMN value TEXT');
+        $this->addSql("ALTER TABLE session MODIFY COLUMN name VARCHAR(150) NOT NULL DEFAULT ''");
 
         if (!$schema->hasTable('version')) {
             $this->addSql('CREATE TABLE version (id int unsigned NOT NULL AUTO_INCREMENT, version varchar(255), PRIMARY KEY(id), UNIQUE(version));');
@@ -311,6 +313,8 @@ class Version111 extends AbstractMigrationChamilo
         $this->addSql('DELETE FROM settings_current WHERE variable = "course_create_active_tools" AND subkey = "online_conference"');
         $this->addSql('DELETE FROM settings_options WHERE variable = "visio_use_rtmpt"');
         $this->addSql('DELETE FROM course_module WHERE name = "conference"');
+        $this->addSql('ALTER TABLE c_student_publication_assignment CHANGE add_to_calendar add_to_calendar INT NOT NULL;');
+        $this->addSql('ALTER TABLE extra_field ADD visible_to_others TINYINT(1) DEFAULT NULL, CHANGE visible visible_to_self TINYINT(1) DEFAULT NULL');
     }
 
     /**

+ 241 - 0
app/Migrations/Schema/V111/Version20160907140300.php

@@ -0,0 +1,241 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Application\Migrations\Schema\V111;
+
+use Application\Migrations\AbstractMigrationChamilo;
+use Doctrine\DBAL\Schema\Schema;
+use Doctrine\DBAL\Types\Type;
+
+/**
+ * Class Version20160907140300
+ * Change tables engine to InnoDB
+ * @package Application\Migrations\Schema\V111
+ */
+class Version20160907140300 extends AbstractMigrationChamilo
+{
+
+    public function up(Schema $schema)
+    {
+        $data = [
+            'career' => [
+                'created_at',
+                'updated_at',
+            ],
+            'chat' => [
+                'sent',
+
+            ],
+            'course' => [
+                'last_visit',
+                'last_edit',
+                'creation_date',
+                'expiration_date',
+            ],
+            'course_request' => [
+                'request_date',
+            ],
+            'gradebook_certificate' => [
+                'created_at',
+            ],
+            'gradebook_evaluation' => [
+                'created_at',
+            ],
+            'gradebook_link' => [
+                'created_at',
+            ],
+            'gradebook_linkeval_log' => [
+                'created_at',
+            ],
+            'gradebook_result' => [
+                'created_at',
+            ],
+            'gradebook_result_log' => [
+                'created_at',
+            ],
+            'message' => [
+                'send_date',
+            ],
+            'notification' => [
+                'sent_at'
+            ],
+            'promotion' => [
+                'created_at',
+                'updated_at',
+            ],
+            'shared_survey' => [
+                'creation_date',
+            ],
+            'sequence_value' => [
+                'success_date',
+                'available_start_date',
+                'available_end_date',
+            ],
+            'session_rel_user' => [
+                'moved_at',
+                'registered_at',
+            ],
+            'skill' => [
+                'updated_at',
+            ],
+            'sys_announcement' => [
+                'date_start',
+                'date_end',
+            ],
+            'track_e_attempt_recording' => [
+                'insert_date',
+
+            ],
+            'track_e_course_access' => [
+                'login_course_date',
+                'logout_course_date',
+            ],
+            'track_e_downloads' => [
+                'down_date',
+            ],
+            'track_e_exercises' => [
+                'start_date',
+                'exe_date',
+            ],
+            'track_e_hotpotatoes' => [
+                'exe_date',
+            ],
+            'track_e_item_property' => [
+                'lastedit_date',
+            ],
+            'track_e_links' => [
+                'links_date',
+            ],
+            'track_e_login' => [
+                'logout_date',
+            ],
+            'track_e_online' => [
+                'login_date',
+            ],
+            'track_e_open' => [
+                'open_date',
+            ],
+            'track_e_uploads' => [
+                'upload_date',
+            ],
+            'user_api_key' => [
+                'created_date',
+                'validity_start_date',
+                'validity_end_date',
+            ],
+            'user_rel_user' => [
+                'last_edit',
+            ],
+            'c_attendance_calendar' => [
+                'date_time',
+            ],
+            'c_attendance_sheet_log' => [
+                'calendar_date_value',
+            ],
+            'c_blog' => [
+                'date_creation',
+            ],
+            'c_blog_comment' => [
+                'date_creation',
+            ],
+            'c_blog_post' => [
+                'date_creation',
+            ],
+            'c_blog_task_rel_user' => [
+                'target_date',
+            ],
+            'c_chat_connected' => [
+                'last_connection',
+            ],
+            'c_dropbox_feedback' => [
+                'feedback_date',
+            ],
+            'c_dropbox_file' => [
+                'upload_date',
+                'last_upload_date',
+            ],
+            'c_dropbox_post' => [
+                'feedback_date',
+            ],
+            'c_forum_post' => [
+                'post_date',
+            ],
+            'c_forum_thread' => [
+                'thread_date',
+                'thread_close_date',
+            ],
+            'c_forum_thread_qualify' => [
+                'qualify_time',
+            ],
+            'c_forum_thread_qualify_log' => [
+                'qualify_time',
+            ],
+            'c_lp' => [
+                'created_on',
+                'modified_on',
+            ],
+            'c_notebook' => [
+                'creation_date',
+                'update_date',
+            ],
+            'c_online_connected' => [
+                'last_connection',
+            ],
+            'c_survey' => [
+                'creation_date',
+            ],
+            'c_survey_invitation' => [
+                'invitation_date',
+                'reminder_date',
+            ],
+            'c_userinfo_content' => [
+                'edition_time'
+            ],
+            'c_wiki_discuss' => [
+                'dtime',
+            ],
+
+        ];
+        // Needed to update 0000-00-00 00:00:00 values
+        $this->addSql('SET sql_mode = ""');
+        // In case this one didn't work, also try this
+        $this->addSql('SET SESSION sql_mode = ""');
+
+        // The whole point of this version is to ensure that all tricky (or most)
+        // tricky datetime fields are null if = 0000-00-00 00:00:00, because
+        // this value is not tolerated in NO_ZERO_DATE mode nor to convert
+        // the table to InnoDB, and we want all tables to be converted to
+        // InnoDB (that's the point of the following migration)
+        // To try and avoid errors to the maximum, we first convert the fields
+        // to a non-DATETIME type, then change the value of zero-valued times
+        // to NULL, then change the field back to DATETIME
+        foreach ($data as $table => $fields) {
+            foreach ($fields as $field) {
+                $this->addSql("ALTER TABLE $table CHANGE $field $field char(19)");
+                $this->addSql("UPDATE $table SET $field = NULL WHERE $field = '0000-00-00 00:00:00'");
+                $this->addSql("UPDATE $table SET $field = NULL WHERE $field = '0000-00-00 23:59:59'");
+                $this->addSql("ALTER TABLE $table CHANGE $field $field DATETIME");
+            }
+        }
+        // Same with DATE instead of DATETIME
+        $data = [
+            'c_announcement' => [
+                'end_date',
+            ],
+        ];
+        foreach ($data as $table => $fields) {
+            foreach ($fields as $field) {
+                $this->addSql("ALTER TABLE $table CHANGE $field $field char(10)");
+                $this->addSql("UPDATE $table SET $field = NULL WHERE $field = '0000-00-00'");
+                $this->addSql("ALTER TABLE $table CHANGE $field $field DATE");
+            }
+        }
+
+
+    }
+
+    public function down(Schema $schema)
+    {
+
+    }
+}

+ 215 - 0
app/Migrations/Schema/V111/Version20160907150300.php

@@ -0,0 +1,215 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Application\Migrations\Schema\V111;
+
+use Application\Migrations\AbstractMigrationChamilo;
+use Doctrine\DBAL\Schema\Schema;
+use Doctrine\DBAL\Types\Type;
+
+/**
+ * Class Version20160907150300
+ * Change tables engine to InnoDB
+ * @package Application\Migrations\Schema\V111
+ */
+class Version20160907150300 extends AbstractMigrationChamilo
+{
+    private $names = [
+        'access_url_rel_session',
+        'access_url_rel_user',
+        'admin',
+        'announcement_rel_group',
+        'block',
+        'c_announcement',
+        'c_announcement_attachment',
+        'c_attendance',
+        'c_attendance_calendar',
+        'c_attendance_result',
+        'c_attendance_sheet',
+        'c_attendance_sheet_log',
+        'c_blog',
+        'c_blog_attachment',
+        'c_blog_comment',
+        'c_blog_post',
+        'c_blog_rating',
+        'c_blog_rel_user',
+        'c_blog_task',
+        'c_blog_task_rel_user',
+        'c_calendar_event_attachment',
+        'c_calendar_event_repeat',
+        'c_calendar_event_repeat_not',
+        'c_chat_connected',
+        'c_course_description',
+        'c_course_setting',
+        'c_document',
+        'c_dropbox_category',
+        'c_dropbox_feedback',
+        'c_dropbox_file',
+        'c_dropbox_person',
+        'c_dropbox_post',
+        'c_forum_attachment',
+        'c_forum_category',
+        'c_forum_forum',
+        'c_forum_mailcue',
+        'c_forum_notification',
+        'c_forum_post',
+        'c_forum_thread',
+        'c_forum_thread_qualify',
+        'c_forum_thread_qualify_log',
+        'c_glossary',
+        'c_group_category',
+        'c_group_rel_tutor',
+        'c_group_rel_user',
+        'c_link',
+        'c_link_category',
+        'c_lp',
+        'c_lp_item',
+        'c_lp_item_view',
+        'c_lp_iv_interaction',
+        'c_lp_iv_objective',
+        'c_lp_view',
+        'c_notebook',
+        'c_online_connected',
+        'c_online_link',
+        'c_permission_group',
+        'c_permission_task',
+        'c_permission_user',
+        'c_quiz',
+        'c_quiz_question_category',
+        'c_quiz_question_option',
+        'c_quiz_question_rel_category',
+        'c_quiz_rel_question',
+        'c_resource',
+        'c_role',
+        'c_role_group',
+        'c_role_permissions',
+        'c_role_user',
+        'c_student_publication',
+        'c_student_publication_assignment',
+        'c_survey',
+        'c_survey_answer',
+        'c_survey_group',
+        'c_survey_invitation',
+        'c_survey_question',
+        'c_survey_question_option',
+        'c_thematic',
+        'c_thematic_plan',
+        'c_tool',
+        'c_tool_intro',
+        'c_userinfo_content',
+        'c_userinfo_def',
+        'c_wiki',
+        'c_wiki_conf',
+        'c_wiki_discuss',
+        'c_wiki_mailcue',
+        'career',
+        'chat',
+        'class_user',
+        'course_category',
+        'course_module',
+        'course_rel_class',
+        'course_request',
+        'course_type',
+        'event_email_template',
+        'event_sent',
+        'grade_components',
+        'grade_model',
+        'gradebook_category',
+        'gradebook_certificate',
+        'gradebook_evaluation',
+        'gradebook_link',
+        'gradebook_linkeval_log',
+        'gradebook_result',
+        'gradebook_result_log',
+        'gradebook_score_display',
+        'language',
+        'legal',
+        'message',
+        'message_attachment',
+        'notification',
+        'openid_association',
+        'personal_agenda',
+        'personal_agenda_repeat',
+        'personal_agenda_repeat_not',
+        'promotion',
+        'search_engine_ref',
+        'shared_survey',
+        'shared_survey_question',
+        'shared_survey_question_option',
+        'skill',
+        'skill_profile',
+        'skill_rel_gradebook',
+        'skill_rel_profile',
+        'skill_rel_skill',
+        'skill_rel_user',
+        'specific_field',
+        'specific_field_values',
+        'sys_announcement',
+        'sys_calendar',
+        'system_template',
+        'tag',
+        'templates',
+        'track_course_ranking',
+        'track_e_access',
+        'track_e_attempt',
+        'track_e_attempt_coeff',
+        'track_e_attempt_recording',
+        'track_e_course_access',
+        'track_e_default',
+        'track_e_downloads',
+        'track_e_exercises',
+        'track_e_hotpotatoes',
+        'track_e_hotspot',
+        'track_e_item_property',
+        'track_e_lastaccess',
+        'track_e_links',
+        'track_e_login',
+        'track_e_online',
+        'track_e_open',
+        'track_e_uploads',
+        'track_stored_values',
+        'track_stored_values_stack',
+        'user_api_key',
+        'user_course_category',
+        'user_friend_relation_type',
+        'user_rel_course_vote',
+        'user_rel_event_type',
+        'user_rel_tag',
+        'user_rel_user',
+        'usergroup_rel_course',
+        'usergroup_rel_question',
+        'usergroup_rel_session'
+    ];
+
+    /**
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\DBALException
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     */
+    public function up(Schema $schema)
+    {
+        foreach ($this->names as $name) {
+            if (!$schema->hasTable($name)) {
+                continue;
+            }
+
+            $this->addSql("ALTER TABLE $name ENGINE=InnoDB");
+        }
+    }
+
+    /**
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\DBALException
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     */
+    public function down(Schema $schema)
+    {
+        foreach ($this->names as $name) {
+            if (!$schema->hasTable($name)) {
+                continue;
+            }
+
+            $this->addSql("ALTER TABLE $name ENGINE=MyISAM");
+        }
+    }
+}

+ 42 - 0
app/Migrations/Schema/V111/Version20160929120000.php

@@ -0,0 +1,42 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Application\Migrations\Schema\V111;
+
+use Application\Migrations\AbstractMigrationChamilo;
+use Doctrine\DBAL\Schema\Schema;
+use Doctrine\DBAL\Types\Type;
+
+/**
+ * Class Version20160929120000
+ * Change tables engine to InnoDB
+ * @package Application\Migrations\Schema\V111
+ */
+class Version20160929120000 extends AbstractMigrationChamilo
+{
+    /**
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\DBALException
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     */
+    public function up(Schema $schema)
+    {
+        $this->addSql("ALTER TABLE c_tool ADD INDEX idx_ctool_name (name(20))");
+    }
+
+    /**
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\DBALException
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     */
+    public function down(Schema $schema)
+    {
+        foreach ($this->names as $name) {
+            if (!$schema->hasTable($name)) {
+                continue;
+            }
+
+            $this->addSql("ALTER TABLE c_tool DROP INDEX idx_ctool_name");
+        }
+    }
+}

+ 50 - 0
app/Migrations/Schema/V111/Version20160930144400.php

@@ -0,0 +1,50 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Application\Migrations\Schema\V111;
+
+use Application\Migrations\AbstractMigrationChamilo;
+use Doctrine\DBAL\Schema\Schema;
+
+/**
+ * Class Version20160930144400
+ * Fix track_e_hotspot ussing c_quiz_answer iid
+ * @package Application\Migrations\Schema\V111
+ */
+class Version20160930144400 extends AbstractMigrationChamilo
+{
+    /**
+     * @param Schema $schema
+     */
+    public function up(Schema $schema)
+    {
+        $this->addSql('
+            UPDATE track_e_hotspot h 
+            SET h.hotspot_answer_id = (
+                SELECT qa.iid
+                FROM c_quiz_answer qa
+                WHERE h.c_id = qa.c_id AND
+                    h.hotspot_question_id = qa.question_id AND 
+                    h.hotspot_answer_id = qa.id
+            )
+        ');
+    }
+
+    /**
+     * @param Schema $schema
+     */
+    public function down(Schema $schema)
+    {
+        $this->addSql('
+            UPDATE track_e_hotspot h 
+            SET h.hotspot_answer_id = (
+                SELECT qa.id
+                FROM c_quiz_answer qa
+                WHERE
+                    h.c_id = qa.c_id AND
+                    h.hotspot_question_id = qa.question_id AND 
+                    h.hotspot_answer_id = qa.iid
+            )
+        ');
+    }
+}

+ 46 - 0
app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-cs.js

@@ -0,0 +1,46 @@
+/*!
+ * This is a i18n.locale language object.
+ *
+ * Czech translation by Jalios, Twitter: @Jalios
+ *
+ * @author
+ *   Jalios (Twitter: @Jalios)
+ *
+ * @see
+ *   me-i18n.js
+ *
+ * @params
+ *  - exports - CommonJS, window ..
+ */
+;(function(exports, undefined) {
+
+    "use strict";
+
+    if (typeof exports.cs === 'undefined') {
+        exports.cs = {
+
+            'mejs.audio-player' : "Přehrávač hudby",
+            'mejs.captions-subtitles' : "Titulky",
+            'mejs.close' : "Zavřít",
+            'mejs.download-file' : "Stáhnout soubor",
+            'mejs.download-video' : "Stáhnout video",
+            'mejs.fullscreen' : "Celá obrazovka",
+            'mejs.fullscreen-off' : "Vypnout režim celá obrazovka",
+            'mejs.fullscreen-on' : "Na celou obrazovku",
+            'mejs.mute' : "Vypnout zvuk",
+            'mejs.mute-toggle' : "Vypnout/zapnout zvuk",
+            'mejs.none' : "Žádný",
+            'mejs.pause' : "Pozastavit",
+            'mejs.play' : "Přehrát",
+            'mejs.time-help-text' : "Použijte tlačítka se šipkami doleva / doprava pro posun o jednu vteřinu, tlačítka se šipkami nahoru / dolů pro posun o deset vteřin.",
+            'mejs.time-skip-back' : "Zpět o %1 vteřin",
+            'mejs.time-slider' : "Posuvný běžec nastavení času",
+            'mejs.unmute' : "Zapnout zvuk",
+            'mejs.video-player' : "Přehrávač videa",
+            'mejs.volume-help-text' : "Použijte tlačítka se šipkami nahoru / dolů pro zesílení nebo zeslabení hlasitosti.",
+            'mejs.volume-slider' : "Posuvný běžec nastavení hlasitosti"
+
+        };
+    }
+
+}(mejs.i18n.locale.strings));

+ 70 - 0
app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-de.js

@@ -0,0 +1,70 @@
+/*!
+ * This is a i18n.locale language object.
+ *
+ * German
+ *
+ * @author
+ *   Sascha "SoftCreatR" Greuel
+ *
+ * @see
+ *   me-i18n.js
+ *
+ * @params
+ *  - exports - CommonJS, window ..
+ */
+;(function(exports, undefined) {
+
+    "use strict";
+
+    if (typeof exports.de === 'undefined') {
+        exports.de = {
+            // me-shim
+            'mejs.download-file': 'Datei herunterladen',
+
+            // mep-feature-contextmenu
+            'mejs.fullscreen-off': 'Vollbildmodus beenden',
+            'mejs.fullscreen-on' : 'Vollbild',
+            'mejs.download-video' : 'Video herunterladen',
+
+            // mep-feature-fullscreen
+            'mejs.fullscreen' : 'Vollbild',
+
+            // mep-feature-jumpforward
+            'mejs.time-jump-forward': '%1 Sekunde(n) vorspulen',
+
+            // mep-feature-playpause
+            'mejs.play': 'Abspielen',
+            'mejs.pause': 'Pause',
+
+            // mep-feature-postroll
+            'mejs.close' : 'Schließen',
+
+            // mep-feature-progress
+            'mejs.time-slider': 'Zeitschieberegler',
+            'mejs.time-help-text': 'Verwende die Pfeiltaste nach links/rechts, um eine Sekunde zu spulen, hoch/runter um zehn Sekunden zu spulen.',
+
+            // mep-feature-skipback
+            'mejs.time-skip-back': '%1 Sekunde(n) zurückspulen',
+
+            // mep-feature-tracks
+            'mejs.captions-subtitles' : 'Überschriften/Untertitel',
+            'mejs.none' : 'Keine',
+
+            // mep-feature-volume
+            'mejs.mute-toggle' : 'Stummschaltung umschalten',
+            'mejs.volume-help-text': 'Verwende die Pfeiltaste nach oben/nach unten um die Lautstärke zu erhöhen oder zu verringern.',
+            'mejs.unmute' : 'Stummschaltung aufheben',
+            'mejs.mute' : 'Stummschalten',
+            'mejs.volume-slider': 'Lautstärkeregler',
+
+            // mep-player
+            'mejs.video-player': 'Video-Player',
+            'mejs.audio-player': 'Audio-Player',
+            	
+            // mep-feature-ads
+            'mejs.ad-skip': 'Werbung überspringen',
+            'mejs.ad-skip-info': 'Überspringen in %1 Sekunde(n)',
+        };
+    }
+
+}(mejs.i18n.locale.strings));

+ 75 - 0
app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-en.js

@@ -0,0 +1,75 @@
+/*!
+ * This is a i18n.locale language object.
+ *
+ * English; This can serve as a template for other languages to translate
+ *
+ * @author
+ *   TBD
+ *
+ * @see
+ *   me-i18n.js
+ *
+ * @params
+ *  - exports - CommonJS, window ..
+ */
+;(function(exports, undefined) {
+
+    "use strict";
+
+    if (typeof exports.en === 'undefined') {
+        exports.en = {
+            // me-shim
+            'mejs.download-file': 'Download File',
+
+            // mep-feature-contextmenu
+            'mejs.fullscreen-off': 'Turn off Fullscreen',
+            'mejs.fullscreen-on' : 'Go Fullscreen',
+            // Duplicated from mep-feature-volume
+            // 'mejs.unmute' : 'Unmute',
+            // 'mejs.mute' : 'Mute',
+            'mejs.download-video' : 'Download Video',
+
+            // mep-feature-fullscreen
+            'mejs.fullscreen' : 'Fullscreen',
+
+            // mep-feature-jumpforward
+            'mejs.time-jump-forward': 'Jump forward %1 seconds',
+
+            // mep-feature-playpause
+            'mejs.play': 'Play',
+            'mejs.pause': 'Pause',
+
+            // mep-feature-postroll
+            'mejs.close' : 'Close',
+
+            // mep-feature-progress
+            'mejs.time-slider': 'Time Slider',
+            'mejs.time-help-text': 'Use Left/Right Arrow keys to advance one second, Up/Down arrows to advance ten seconds.',
+
+            // mep-feature-skipback
+            'mejs.time-skip-back': 'Skip back %1 seconds',
+
+            // mep-feature-tracks
+            'mejs.captions-subtitles' : 'Captions/Subtitles',
+            'mejs.none' : 'None',
+
+            // mep-feature-volume
+            'mejs.mute-toggle' : 'Mute Toggle',
+            'mejs.volume-help-text': 'Use Up/Down Arrow keys to increase or decrease volume.',
+            'mejs.unmute' : 'Unmute',
+            'mejs.mute' : 'Mute',
+            'mejs.volume-slider': 'Volume Slider',
+
+            // mep-player
+            'mejs.video-player': 'Video Player',
+            'mejs.audio-player': 'Audio Player',
+            	
+            // mep-feature-ads
+            'mejs.ad-skip': 'Skip ad',
+            'mejs.ad-skip-info': 'Skip in %1 seconds',
+
+            'mejs.source-chooser': 'Source Chooser'
+        };
+    }
+
+}(mejs.i18n.locale.strings));

+ 49 - 0
app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-es.js

@@ -0,0 +1,49 @@
+/*!
+ * This is a i18n.locale language object.
+ *
+ * Spanish; Castilian translation by Jalios, Twitter: @Jalios
+ *
+ * @author
+ *   Jalios (Twitter: @Jalios)
+ *
+ * @see
+ *   me-i18n.js
+ *
+ * @params
+ *  - exports - CommonJS, window ..
+ */
+;(function(exports, undefined) {
+
+    "use strict";
+
+    if (typeof exports.es === 'undefined') {
+        exports.es = {
+
+            'mejs.ad-skip': "Salta publicidad",
+            'mejs.ad-skip-info': "Salta en %1 segundos",
+            'mejs.audio-player' : "Reproductor de audio",
+            'mejs.captions-subtitles' : "Leyendas/Subtítulos",
+            'mejs.close' : "Cerrar",
+            'mejs.download-file' : "Descargar archivo",
+            'mejs.download-video' : "Descargar vídeo",
+            'mejs.fullscreen' : "Pantalla completa",
+            'mejs.fullscreen-off' : "Desconectar pantalla completa",
+            'mejs.fullscreen-on' : "Ir a pantalla completa",
+            'mejs.mute' : "Silencio",
+            'mejs.mute-toggle' : "Alternar silencio",
+            'mejs.none' : "Ninguno",
+            'mejs.pause' : "Pausa",
+            'mejs.play' : "Reproducción",
+            'mejs.time-help-text' : "Use las flechas Izquierda/Derecha para avanzar un segundo y las flechas Arriba/Abajo para avanzar diez segundos.",
+            'mejs.time-skip-back' : "Saltar atrás %1 segundos",
+            'mejs.time-slider' : "Control deslizante de tiempo",
+            'mejs.unmute' : "Reactivar silencio",
+            'mejs.video-player' : "Reproductor de video",
+            'mejs.volume-help-text' : "Use las flechas Arriba/Abajo para subir o bajar el volumen.",
+            'mejs.volume-slider' : "Control deslizante de volumen",
+            'mejs.source-chooser': "Selector de media"
+
+        };
+    }
+
+}(mejs.i18n.locale.strings));

+ 53 - 0
app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-fr.js

@@ -0,0 +1,53 @@
+/*!
+ * This is a i18n.locale language object.
+ *
+ * French translation by 
+ *   Luc Poupard, Twitter: @klohFR
+ *   Jalios, Twitter: @Jalios
+ *
+ * @author
+ *   Luc Poupard (Twitter: @klohFR)
+ *   Jalios (Twitter: @Jalios)
+ *
+ * @see
+ *   me-i18n.js
+ *
+ * @params
+ *  - exports - CommonJS, window ..
+ */
+;(function(exports, undefined) {
+
+    "use strict";
+
+    if (typeof exports.fr === 'undefined') {
+        exports.fr = {
+
+            'mejs.ad-skip' : "Passer la publicité",
+            'mejs.ad-skip-info' : "Passer la publicité dans %1 secondes",
+            'mejs.audio-player' : "Lecteur Audio",
+            'mejs.captions-subtitles' : "Sous-titres",
+            'mejs.close' : "Fermer",
+            'mejs.download-file' : "Télécharger le fichier",
+            'mejs.download-video' : "Télécharger la vidéo",
+            'mejs.fullscreen' : "Plein écran",
+            'mejs.fullscreen-off' : "Quitter le mode plein écran",
+            'mejs.fullscreen-on' : "Afficher en plein écran",
+            'mejs.mute' : "Désactiver le son",
+            'mejs.mute-toggle' : "Activer/désactiver le son",
+            'mejs.none' : "Aucun",
+            'mejs.pause' : "Pause",
+            'mejs.play' : "Lecture",
+            'mejs.time-help-text' : "Utilisez les flèches Gauche/Droite du clavier pour avancer d'une seconde, les flèches Haut/Bas pour avancer de 10 secondes.",
+            'mejs.time-jump-forward' : "Avancer de %1 secondes",
+            'mejs.time-skip-back' : "Reculer de %1 secondes",
+            'mejs.time-slider' : "Curseur temporel",
+            'mejs.unmute' : "Activer le son",
+            'mejs.video-player' : "Lecteur Vidéo",
+            'mejs.volume-help-text' : "Utilisez les flèches Haut/Bas du clavier pour augmenter ou diminuer le volume.",
+            'mejs.volume-slider' : "Volume",
+            'mejs.source-chooser': 'Sélecteur de média'
+
+        };
+    }
+
+}(mejs.i18n.locale.strings));

+ 46 - 0
app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-hu.js

@@ -0,0 +1,46 @@
+/*!
+ * This is a i18n.locale language object.
+ *
+ * Hungarian translation by Jalios, Twitter: @Jalios
+ *
+ * @author
+ *   Jalios (Twitter: @Jalios)
+ *
+ * @see
+ *   me-i18n.js
+ *
+ * @params
+ *  - exports - CommonJS, window ..
+ */
+;(function(exports, undefined) {
+
+    "use strict";
+
+    if (typeof exports.hu === 'undefined') {
+        exports.hu = {
+
+            'mejs.audio-player' : "Audiolejátszó",
+            'mejs.captions-subtitles' : "Képaláírás/Feliratok",
+            'mejs.close' : "Bezárás",
+            'mejs.download-file' : "Fájl letöltése",
+            'mejs.download-video' : "Videó letöltése",
+            'mejs.fullscreen' : "Teljes képernyő",
+            'mejs.fullscreen-off' : "Teljes képernyő kikapcsolása",
+            'mejs.fullscreen-on' : "Átlépés teljes képernyős módra",
+            'mejs.mute' : "Némítás",
+            'mejs.mute-toggle' : "Némítás kapcsolója",
+            'mejs.none' : "Nincs",
+            'mejs.pause' : "Szünet",
+            'mejs.play' : "Lejátszás",
+            'mejs.time-help-text' : "Használja a Bal/Jobb nyíl gombokat az egy másodperces léptetéshez, a Fel/Le nyíl gombokat a tíz másodperces léptetéshez.",
+            'mejs.time-skip-back' : "Ugrás vissza %1 másodperccel",
+            'mejs.time-slider' : "Idő csúszka",
+            'mejs.unmute' : "Némítás feloldása",
+            'mejs.video-player' : "Videolejátszó",
+            'mejs.volume-help-text' : "Használja a Fel/Le nyíl gombokat a hangerő növeléséhez vagy csökkentéséhez.",
+            'mejs.volume-slider' : "Hangerőcsúszka"
+
+        };
+    }
+
+}(mejs.i18n.locale.strings));

+ 46 - 0
app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-it.js

@@ -0,0 +1,46 @@
+/*!
+ * This is a i18n.locale language object.
+ *
+ * Italian translation by Jalios, Twitter: @Jalios
+ *
+ * @author
+ *   Jalios (Twitter: @Jalios)
+ *
+ * @see
+ *   me-i18n.js
+ *
+ * @params
+ *  - exports - CommonJS, window ..
+ */
+;(function(exports, undefined) {
+
+    "use strict";
+
+    if (typeof exports.it === 'undefined') {
+        exports.it = {
+
+            'mejs.audio-player' : "Lettore Audio",
+            'mejs.captions-subtitles' : "Acquisizioni/sottotitoli",
+            'mejs.close' : "Chiudere",
+            'mejs.download-file' : "Scaricare il file",
+            'mejs.download-video' : "Scaricare il video",
+            'mejs.fullscreen' : "Schermo intero",
+            'mejs.fullscreen-off' : "Disattivare lo schermo intero",
+            'mejs.fullscreen-on' : "Attivare lo schermo intero",
+            'mejs.mute' : "Muto",
+            'mejs.mute-toggle' : "Toggle muto",
+            'mejs.none' : "Nessuno",
+            'mejs.pause' : "Pausa",
+            'mejs.play' : "Eseguire",
+            'mejs.time-help-text' : "Utilizzare i tasti Freccia sinistra/Freccia destra per avanzare di un secondo, Freccia Su/Giù per avanzare dieci secondi.",
+            'mejs.time-skip-back' : "Riavvolgere %1 secondi",
+            'mejs.time-slider' : "Barra di scorrimento",
+            'mejs.unmute' : "Disattivare muto",
+            'mejs.video-player' : "Lettore Video",
+            'mejs.volume-help-text' : "Utilizzare i tasti Freccia Su/Giù per aumentare o diminuire il volume.",
+            'mejs.volume-slider' : "Barra del volume"
+
+        };
+    }
+
+}(mejs.i18n.locale.strings));

+ 46 - 0
app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-ja.js

@@ -0,0 +1,46 @@
+/*!
+ * This is a i18n.locale language object.
+ *
+ * Japanese translation by Jalios, Twitter: @Jalios
+ *
+ * @author
+ *   Jalios (Twitter: @Jalios)
+ *
+ * @see
+ *   me-i18n.js
+ *
+ * @params
+ *  - exports - CommonJS, window ..
+ */
+;(function(exports, undefined) {
+
+    "use strict";
+
+    if (typeof exports.ja === 'undefined') {
+        exports.ja = {
+
+            'mejs.audio-player' : "オーディオプレーヤー",
+            'mejs.captions-subtitles' : "キャプション/字幕",
+            'mejs.close' : "閉じる",
+            'mejs.download-file' : "ファイルをダウンロードする",
+            'mejs.download-video' : "動画をダウンロードする",
+            'mejs.fullscreen' : "全画面",
+            'mejs.fullscreen-off' : "全画面をオフにする",
+            'mejs.fullscreen-on' : "全画面にする",
+            'mejs.mute' : "ミュート",
+            'mejs.mute-toggle' : "ミュートトグル",
+            'mejs.none' : "なし",
+            'mejs.pause' : "一時停止",
+            'mejs.play' : "再生",
+            'mejs.time-help-text' : "1秒進めるには左/右矢印をキーを、10秒進めるには上/下矢印を使います。",
+            'mejs.time-skip-back' : "%1秒スキップバックする",
+            'mejs.time-slider' : "タイムスライダー",
+            'mejs.unmute' : "ミュートを解除",
+            'mejs.video-player' : "ビデオプレーヤー",
+            'mejs.volume-help-text' : "音量を上げたり下げたりするには、上/下矢印を使います。",
+            'mejs.volume-slider' : "音量スライダー"
+
+        };
+    }
+
+}(mejs.i18n.locale.strings));

+ 46 - 0
app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-ko.js

@@ -0,0 +1,46 @@
+/*!
+ * This is a i18n.locale language object.
+ *
+ * Korean translation by Jalios, Twitter: @Jalios
+ *
+ * @author
+ *   Jalios (Twitter: @Jalios)
+ *
+ * @see
+ *   me-i18n.js
+ *
+ * @params
+ *  - exports - CommonJS, window ..
+ */
+;(function(exports, undefined) {
+
+    "use strict";
+
+    if (typeof exports.ko === 'undefined') {
+        exports.ko = {
+
+            'mejs.audio-player' : "오디오 플레이어",
+            'mejs.captions-subtitles' : "캡션/자막",
+            'mejs.close' : "종료",
+            'mejs.download-file' : "파일 다운로드",
+            'mejs.download-video' : "비디오 다운로드",
+            'mejs.fullscreen' : "전체화면",
+            'mejs.fullscreen-off' : "전체화면 해제",
+            'mejs.fullscreen-on' : "전체화면 가기",
+            'mejs.mute' : "말 없는",
+            'mejs.mute-toggle' : "음소거 전환",
+            'mejs.none' : "없음",
+            'mejs.pause' : "정지",
+            'mejs.play' : "작동",
+            'mejs.time-help-text' : "1초 전진하려면 좌/우측 화살표를 사용하시고 10초 전진하려면 위/아래 화살표를 사용하세요.",
+            'mejs.time-skip-back' : "1초 % 를 뒤로 건너뛰세요",
+            'mejs.time-slider' : "시간 슬라이더",
+            'mejs.unmute' : "음소거 해제",
+            'mejs.video-player' : "비디오 플레이어",
+            'mejs.volume-help-text' : "볼륨을 높이거나 낮추려면 위/아래 화살표를 이용하세요.",
+            'mejs.volume-slider' : "볼륨 슬라이더"
+
+        };
+    }
+
+}(mejs.i18n.locale.strings));

+ 46 - 0
app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-pl.js

@@ -0,0 +1,46 @@
+/*!
+ * This is a i18n.locale language object.
+ *
+ * Polish translation by Jalios, Twitter: @Jalios
+ *
+ * @author
+ *   Jalios (Twitter: @Jalios)
+ *
+ * @see
+ *   me-i18n.js
+ *
+ * @params
+ *  - exports - CommonJS, window ..
+ */
+;(function(exports, undefined) {
+
+    "use strict";
+
+    if (typeof exports.pl === 'undefined') {
+        exports.pl = {
+
+            'mejs.audio-player' : "Odtwarzacz audio",
+            'mejs.captions-subtitles' : "Podpisy/napisy",
+            'mejs.close' : "Zamknij",
+            'mejs.download-file' : "Pobierz plik",
+            'mejs.download-video' : "Pobierz wideo",
+            'mejs.fullscreen' : "Pełny ekran",
+            'mejs.fullscreen-off' : "Wyłącz pełny ekran",
+            'mejs.fullscreen-on' : "Przejdź na pełny ekran",
+            'mejs.mute' : "Wycisz",
+            'mejs.mute-toggle' : "Przełączanie wyciszania",
+            'mejs.none' : "Brak",
+            'mejs.pause' : "Wstrzymaj",
+            'mejs.play' : "Odtwarzaj",
+            'mejs.time-help-text' : "Strzałki w lewo/w prawo powodują przewijanie o sekundę, strzałki w górę/w dół o dziesięć sekund.",
+            'mejs.time-skip-back' : "Cofnij o %1 sek.",
+            'mejs.time-slider' : "Suwak czasu",
+            'mejs.unmute' : "Wyłącz wyciszenie",
+            'mejs.video-player' : "Odtwarzacz wideo",
+            'mejs.volume-help-text' : "Aby zwiększyć lub zmniejszyć głośność, użyj strzałek w górę/w dół.",
+            'mejs.volume-slider' : "Suwak głośności"
+
+        };
+    }
+
+}(mejs.i18n.locale.strings));

+ 37 - 0
app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-pt-br.js

@@ -0,0 +1,37 @@
+/*!
+ * This is a i18n.locale language object.
+ *
+ * Brazilian Portuguese translation by Armando Meziat
+ *
+ * @author
+ *   Armando Meziat 
+ *   - Twitter: @odnamrataizem
+ *   - GitHub: https://github.com/odnamrataizem/
+ *
+ * @see
+ *   me-i18n.js
+ *
+ * @params
+ *  - exports - CommonJS, window ..
+ */
+;(function(exports, undefined) {
+
+    "use strict";
+
+    if (typeof exports['pt-BR'] === 'undefined') {
+        exports.pt = {
+            'mejs.none' : "Sem legendas",
+            'mejs.unmute' : "Tirar silêncio",
+            'mejs.fullscreen' : "Tela inteira",
+            'mejs.download-file' : "Baixar arquivo",
+            'mejs.mute-toggle' : "Alternar silêncio",
+            'mejs.captions-subtitles' : "Legendas",
+            'mejs.download-video' : "Baixar vídeo",
+            'mejs.mute' : "Silenciar",
+            'mejs.fullscreen-off' : "Sair da tela inteira",
+            'mejs.fullscreen-on' : "Ir para tela inteira",
+            'mejs.close' : "Fechar"
+        };
+    }
+
+}(mejs.i18n.locale.strings));

+ 46 - 0
app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-pt.js

@@ -0,0 +1,46 @@
+/*!
+ * This is a i18n.locale language object.
+ *
+ * Portuguese translation by Jalios, Twitter: @Jalios
+ *
+ * @author
+ *   Jalios (Twitter: @Jalios)
+ *
+ * @see
+ *   me-i18n.js
+ *
+ * @params
+ *  - exports - CommonJS, window ..
+ */
+;(function(exports, undefined) {
+
+    "use strict";
+
+    if (typeof exports.pt === 'undefined') {
+        exports.pt = {
+
+            'mejs.audio-player' : "Leitor de áudio",
+            'mejs.captions-subtitles' : "Legendas",
+            'mejs.close' : "Fechar",
+            'mejs.download-file' : "Descarregar o ficheiro",
+            'mejs.download-video' : "Descarregar o vídeo",
+            'mejs.fullscreen' : "Ecrã completo",
+            'mejs.fullscreen-off' : "Desligar ecrã completo",
+            'mejs.fullscreen-on' : "Ir para ecrã completo",
+            'mejs.mute' : "Silêncio",
+            'mejs.mute-toggle' : "Alternar silêncio",
+            'mejs.none' : "Nenhum",
+            'mejs.pause' : "Pausa",
+            'mejs.play' : "Reprodução",
+            'mejs.time-help-text' : "Use as teclas das setas para a esquerda/direita para avançar um segundo, e as setas para cima/baixo para avançar dez segundos.",
+            'mejs.time-skip-back' : "Retroceder %1 segundos",
+            'mejs.time-slider' : "Deslizador do tempo",
+            'mejs.unmute' : "Voltar ao som",
+            'mejs.video-player' : "Leitor de vídeo",
+            'mejs.volume-help-text' : "Use as teclas das setas para cima/baixo para aumentar ou diminuir o volume.",
+            'mejs.volume-slider' : "Deslizador do volume"
+
+        };
+    }
+
+}(mejs.i18n.locale.strings));

+ 46 - 0
app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-ro.js

@@ -0,0 +1,46 @@
+/*!
+ * This is a i18n.locale language object.
+ *
+ * Romanian translation by Jalios, Twitter: @Jalios
+ *
+ * @author
+ *   Jalios (Twitter: @Jalios)
+ *
+ * @see
+ *   me-i18n.js
+ *
+ * @params
+ *  - exports - CommonJS, window ..
+ */
+;(function(exports, undefined) {
+
+    "use strict";
+
+    if (typeof exports.ro === 'undefined') {
+        exports.ro = {
+
+            'mejs.audio-player' : "Player audio",
+            'mejs.captions-subtitles' : "Legende/Subtitrări",
+            'mejs.close' : "Închide",
+            'mejs.download-file' : "Descarcă fişierul",
+            'mejs.download-video' : "Descarcă fişierul video",
+            'mejs.fullscreen' : "Ecran complet",
+            'mejs.fullscreen-off' : "Opreşte ecranul complet",
+            'mejs.fullscreen-on' : "Treci la ecran complet",
+            'mejs.mute' : "Fără sunet",
+            'mejs.mute-toggle' : "Comutare dezactivare sunet",
+            'mejs.none' : "Niciunul",
+            'mejs.pause' : "Pauză",
+            'mejs.play' : "Redare",
+            'mejs.time-help-text' : "Utilizează tastele săgeată Stânga/Dreapta pentru a avansa o secundă şi săgeţile Sus/Jos pentru a avansa zece secunde.",
+            'mejs.time-skip-back' : "Sari înapoi %1 secunde",
+            'mejs.time-slider' : "Cursor timp",
+            'mejs.unmute' : "Cu sunet",
+            'mejs.video-player' : "Player video",
+            'mejs.volume-help-text' : "Utilizează tastele de săgeată Sus/Jos pentru a creşte/micşora volumul",
+            'mejs.volume-slider' : "Cursor volum"
+
+        };
+    }
+
+}(mejs.i18n.locale.strings));

+ 46 - 0
app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-ru.js

@@ -0,0 +1,46 @@
+/*!
+ * This is a i18n.locale language object.
+ *
+ * Russian translation by Jalios, Twitter: @Jalios
+ *
+ * @author
+ *   Jalios (Twitter: @Jalios)
+ *
+ * @see
+ *   me-i18n.js
+ *
+ * @params
+ *  - exports - CommonJS, window ..
+ */
+;(function(exports, undefined) {
+
+    "use strict";
+
+    if (typeof exports.ru === 'undefined') {
+        exports.ru = {
+
+            'mejs.audio-player' : "Аудиоплеер",
+            'mejs.captions-subtitles' : "Титры/Субтитры",
+            'mejs.close' : "Закрыть",
+            'mejs.download-file' : "Скачать файл",
+            'mejs.download-video' : "Скачать видео",
+            'mejs.fullscreen' : "Широкий экран",
+            'mejs.fullscreen-off' : "Выключить широкий экран",
+            'mejs.fullscreen-on' : "Перейти к широкому экрану",
+            'mejs.mute' : "Отключить звук",
+            'mejs.mute-toggle' : "Без звука",
+            'mejs.none' : "Нет",
+            'mejs.pause' : "Пауза",
+            'mejs.play' : "Воспроизвести",
+            'mejs.time-help-text' : "Используйте Левую/Правую клавиши со стрелками, чтобы продвинуться на одну секунду, клавиши со стрелками Вверх/Вниз, чтобы продвинуться на десять секунд.",
+            'mejs.time-skip-back' : "Пропустить назад %1 секунд",
+            'mejs.time-slider' : "Слайдер времени",
+            'mejs.unmute' : "Отменить выключение звука",
+            'mejs.video-player' : "Видеоплеер",
+            'mejs.volume-help-text' : "Используйте клавиши со стрелками Вверх/Вниз, чтобы увеличить или уменьшить громкость.",
+            'mejs.volume-slider' : "Слайдер громкости"
+
+        };
+    }
+
+}(mejs.i18n.locale.strings));

+ 46 - 0
app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-sk.js

@@ -0,0 +1,46 @@
+/*!
+ * This is a i18n.locale language object.
+ *
+ * Slovak translation by Jalios, Twitter: @Jalios
+ *
+ * @author
+ *   Jalios (Twitter: @Jalios)
+ *
+ * @see
+ *   me-i18n.js
+ *
+ * @params
+ *  - exports - CommonJS, window ..
+ */
+;(function(exports, undefined) {
+
+    "use strict";
+
+    if (typeof exports.sk === 'undefined') {
+        exports.sk = {
+
+            'mejs.audio-player' : "Prehrávač zvuku",
+            'mejs.captions-subtitles' : "Skryté titulky/Titulky",
+            'mejs.close' : "Zavrieť",
+            'mejs.download-file' : "Prevziať súbor",
+            'mejs.download-video' : "Prevziať video",
+            'mejs.fullscreen' : "Celá obrazovka",
+            'mejs.fullscreen-off' : "Vypnúť celú obrazovku",
+            'mejs.fullscreen-on' : "Prejsť na celú obrazovku",
+            'mejs.mute' : "Stlmiť",
+            'mejs.mute-toggle' : "Prepínač stlmenia",
+            'mejs.none' : "Žiadne",
+            'mejs.pause' : "Pozastaviť",
+            'mejs.play' : "Prehrať",
+            'mejs.time-help-text' : "Klávesmi so šípkou doľava/doprava posuniete o jednu sekundu, šípkami nahor/ nadol posuniete o desať sekúnd.",
+            'mejs.time-skip-back' : "Preskočiť dozadu o %1 s.",
+            'mejs.time-slider' : "Posúvač času",
+            'mejs.unmute' : "Zrušiť stlmenie",
+            'mejs.video-player' : "Prehrávač videa",
+            'mejs.volume-help-text' : "Klávesmi so šípkou nahor/nadol zvýšite alebo znížite hlasitosť.",
+            'mejs.volume-slider' : "Posúvač hlasitosti"
+
+        };
+    }
+
+}(mejs.i18n.locale.strings));

+ 46 - 0
app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-zh-cn.js

@@ -0,0 +1,46 @@
+/*!
+ * This is a i18n.locale language object.
+ *
+ * Chinese simplified translation by Jalios, Twitter: @Jalios
+ *
+ * @author
+ *   Jalios (Twitter: @Jalios)
+ *
+ * @see
+ *   me-i18n.js
+ *
+ * @params
+ *  - exports - CommonJS, window ..
+ */
+;(function(exports, undefined) {
+
+    "use strict";
+
+    if (typeof exports['zh-CN'] === 'undefined') {
+        exports['zh-CN'] = {
+
+            'mejs.audio-player' : "音频播放器",
+            'mejs.captions-subtitles' : "字幕/标题",
+            'mejs.close' : "关闭",
+            'mejs.download-file' : "下载文件",
+            'mejs.download-video' : "下载视频",
+            'mejs.fullscreen' : "全屏",
+            'mejs.fullscreen-off' : "关闭全屏",
+            'mejs.fullscreen-on' : "转向全屏",
+            'mejs.mute' : "静音",
+            'mejs.mute-toggle' : "静音切换",
+            'mejs.none' : "无",
+            'mejs.pause' : "暂停",
+            'mejs.play' : "播放",
+            'mejs.time-help-text' : "使用作/右箭头快进1秒,使用上/下箭头快进10秒。",
+            'mejs.time-skip-back' : "后退%1秒",
+            'mejs.time-slider' : "时间滑动棒",
+            'mejs.unmute' : "取消静音",
+            'mejs.video-player' : "视频播放器",
+            'mejs.volume-help-text' : "使用上/下箭头提高或降低音量。",
+            'mejs.volume-slider' : "音量选择键"
+
+        };
+    }
+
+}(mejs.i18n.locale.strings));

+ 46 - 0
app/Resources/public/assets/mediaelement/build/lang/me-i18n-locale-zh.js

@@ -0,0 +1,46 @@
+/*!
+ * This is a i18n.locale language object.
+ *
+ * Chinese traditionnal translation by Jalios, Twitter: @Jalios
+ *
+ * @author
+ *   Jalios (Twitter: @Jalios)
+ *
+ * @see
+ *   me-i18n.js
+ *
+ * @params
+ *  - exports - CommonJS, window ..
+ */
+;(function(exports, undefined) {
+
+    "use strict";
+
+    if (typeof exports.zh === 'undefined') {
+        exports.zh = {
+
+            'mejs.audio-player' : "音頻播放器",
+            'mejs.captions-subtitles' : "字幕/標題",
+            'mejs.close' : "關閉",
+            'mejs.download-file' : "下載文件",
+            'mejs.download-video' : "下載視頻",
+            'mejs.fullscreen' : "全屏",
+            'mejs.fullscreen-off' : "關閉全屏",
+            'mejs.fullscreen-on' : "轉向全屏",
+            'mejs.mute' : "靜音",
+            'mejs.mute-toggle' : "靜音切換",
+            'mejs.none' : "沒有",
+            'mejs.pause' : "暫停",
+            'mejs.play' : "播放",
+            'mejs.time-help-text' : "使用左/右箭頭快進1秒,上/下箭頭快進10秒。",
+            'mejs.time-skip-back' : "跳躍式迴繞%1秒",
+            'mejs.time-slider' : "時間滑動棒",
+            'mejs.unmute' : "取消靜音",
+            'mejs.video-player' : "視頻播放器",
+            'mejs.volume-help-text' : "使用上/下箭頭提高或降低音量。",
+            'mejs.volume-slider' : "音量控制鍵"
+
+        };
+    }
+
+}(mejs.i18n.locale.strings));

+ 15 - 0
app/Resources/public/assets/pwstrength-bootstrap/locales/de.json

@@ -0,0 +1,15 @@
+{
+    "wordLength": "Das Passwort ist zu kurz",
+    "wordNotEmail": "Das Passwort darf die E-Mail Adresse nicht enthalten",
+    "wordSimilarToUsername": "Das Passwort darf den Benutzernamen nicht enthalten",
+    "wordTwoCharacterClasses": "Bitte Buchstaben und Ziffern verwenden",
+    "wordRepetitions": "Zu viele Wiederholungen",
+    "wordSequences": "Das Passwort enthält Buchstabensequenzen",
+    "errorList": "Fehler:",
+    "veryWeak": "Sehr schwach",
+    "weak": "Schwach",
+    "normal": "Normal",
+    "medium": "Mittel",
+    "strong": "Stark",
+    "veryStrong": "Sehr stark"
+}

+ 15 - 0
app/Resources/public/assets/pwstrength-bootstrap/locales/pl.json

@@ -0,0 +1,15 @@
+{
+    "wordLength": "Hasło jest zbyt krótkie",
+    "wordNotEmail": "Hasło nie może być Twoim emailem",
+    "wordSimilarToUsername": "Hasło nie może zawierać nazwy użytkownika",
+    "wordTwoCharacterClasses": "Użyj innych klas znaków",
+    "wordRepetitions": "Zbyt wiele powtórzeń",
+    "wordSequences": "Hasło zawiera sekwencje",
+    "errorList": "Błędy:",
+    "veryWeak": "Bardzo słabe",
+    "weak": "Słabe",
+    "normal": "Normalne",
+    "medium": "Średnie",
+    "strong": "Silne",
+    "veryStrong": "Bardzo silne"
+}

+ 15 - 0
app/Resources/public/assets/pwstrength-bootstrap/locales/tr.json

@@ -0,0 +1,15 @@
+{
+    "wordLength": "Girdiğiniz şifre çok Kısa",
+    "wordNotEmail": "E-mail adresinizi şifreniz içerisinde kullanmayınız",
+    "wordSimilarToUsername": "Kullanıcı Adınızı şifreniz içerisinde kullanmayınız",
+    "wordTwoCharacterClasses": "Başka karakter sınıfı kullanınız",
+    "wordRepetitions": "Çok fazla tekrar var",
+    "wordSequences": "Şifreniz Dizi içermektedir",
+    "errorList": "Hatalar:",
+    "veryWeak": "Çok Zayıf",
+    "weak": "Zayıf",
+    "normal": "Normal",
+    "medium": "Orta",
+    "strong": "Güçlü",
+    "veryStrong": "Çok Güçlü"
+}

+ 28 - 2
app/Resources/public/css/editor.css

@@ -9,9 +9,35 @@
 
 @import url(../assets/fontawesome/css/font-awesome.min.css);
 
+@font-face {
+  font-family: 'Open Sans';
+  font-style: normal;
+  font-weight: 300;
+  src: local('Open Sans Light'), local('OpenSans-Light'), url(themes/chamilo/fonts/OpenSans-Light.woff2) format('woff2'), url(themes/chamilo/fonts/OpenSans-Light.woff) format('woff');
+}
+@font-face {
+  font-family: 'Open Sans';
+  font-style: normal;
+  font-weight: 400;
+  src: local('Open Sans'), local('OpenSans'), url(themes/chamilo/fonts/OpenSans.woff2) format('woff2'), url(themes/chamilo/fonts/OpenSans.woff) format('woff');
+}
+@font-face {
+  font-family: 'Open Sans';
+  font-style: normal;
+  font-weight: 600;
+  src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url(themes/chamilo/fonts/OpenSans-Semibold.woff2) format('woff2'), url(themes/chamilo/fonts/OpenSans-Semibold.woff) format('woff');
+}
+@font-face {
+  font-family: 'Open Sans';
+  font-style: normal;
+  font-weight: 700;
+  src: local('Open Sans Bold'), local('OpenSans-Bold'), url(themes/chamilo/fonts/OpenSans-Bold.woff2) format('woff2'), url(themes/chamilo/fonts/OpenSans-Bold.woff) format('woff');
+}
+
+
 body{
     color: #666;
-    font-family: Verdana, Helvetica, Arial, sans-serif;
+    font-family: 'Open Sans', sans-serif;
     line-height: 30px;
    
 }
@@ -203,4 +229,4 @@ blockquote p {
 }
 .alert-danger .alert-link {
   color: #843534;
-}
+}

+ 71 - 109
app/Resources/public/css/scorm.css

@@ -20,7 +20,6 @@ body{
   position: relative;
   width: 100%;
 }
-
 #author_name {
   float: left;
   text-align:center;
@@ -29,11 +28,6 @@ body{
   color: #888;
   margin-top: 2px;
 }
-
-#learning_path_toc {
-  font-size:9pt;
-  margin:0;
-}
 #learning_path_left_zone #scorm-gamification{
 }
 #scorm-gamification .fa-star{
@@ -83,13 +77,6 @@ body{
     text-decoration: none;
     font-weight: bold;
 }
-.inner_lp_toc .scorm_item_section {
-    background:#E8ECEF;
-    color:#666;
-    padding: 5px 0px 5px 0px;
-    font-size: 12px;
-    font-weight: bold;
-}
 .inner_lp_toc .scorm_item {
     font-size: 16px;
     margin-left: 10px;
@@ -104,40 +91,50 @@ body{
 }
 /* learning path's classes for section and item for 5 levels of depth */
 .scorm_section_level_0 {
-    padding : 0 0 0 0;
+    margin: 0 0 0 0;
 }
 .scorm_section_level_1 {
-    padding : 0 0.5em 0 2em;
+    margin: 0 0.5em 0 20px;
 }
 .scorm_section_level_2 {
-    padding : 0 0.5em 0 4em;
+    margin: 0 0.5em 0 40px;
 }
 .scorm_section_level_3 {
-    padding : 0 0.5em 0 6em;
+    margin: 0 0.5em 0 60px;
 }
 .scorm_section_level_4 {
-    padding : 0 0.5em 0 8em;
+    margin: 0 0.5em 0 70px;
 }
 .scorm_section_level_5 {
-    padding : 0 0.5em 0 10em;
+    margin: 0 0.5em 0 10em;
 }
-.scorm_item_level_0 {
-    padding : 0 0 0 0;
+.scorm_item_normal{
+    line-height: 25px;
+    border-bottom: 1px solid #DDD;
+}
+.level_0 {
+    margin: 0;
+    padding-left: 20px;
 }
-.scorm_item_level_1 {
-    padding : 0 0.5em 0 1.5em;
+.level_1 {
+    margin: 0 0.5em 0 20px;
+    padding-left: 20px;
 }
-.scorm_item_level_2 {
-    padding : 0 0.5em 0 3em;
+.level_2 {
+    margin: 0 0.5em 0 40px;
+    padding-left: 20px;
 }
-.scorm_item_level_3 {
-    padding : 0 0.5em 0 4.5em;
+.level_3 {
+    margin: 0 0.5em 0 60px;
+    padding-left: 20px;
 }
-.scorm_item_level_4 {
-    padding : 0 0.5em 0 6em;
+.level_4 {
+    margin: 0 0.5em 0 70px;
+    padding-left: 20px;
 }
-.scorm_item_level_5 {
-    padding : 0 0.5em 0 7.5em;
+.level_5 {
+    margin: 0 0.5em 0 90px;
+    padding-left: 20px;
 }
 #learning_path_breadcrumb_zone .breadcrumb{
   background-color: #2b3d53;
@@ -193,10 +190,6 @@ body{
   margin-top: .5em;
   font-size: 12px;
 }
-#lp_navigation_elem .buttons {
-
-}
-
 #learning_path_left_zone .scorm_title{
   font-size: 20px;
   color: #666;
@@ -204,80 +197,59 @@ body{
   margin-top: .5em;
 }
 /* for section */
-.scorm_item_section.scorm_completed{
-  color: #ffffff;
-  padding-right: 1.5em;
-  background-color: #AAB3B8;
-}
 .scorm_item_section{
-  background: #2b3d53; /* Old browsers */
-  background: -moz-linear-gradient(top, #2b3d53 0%, #2c3d4d 100%); /* FF3.6+ */
-  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#2b3d53), color-stop(100%,#2c3d4d)); /* Chrome,Safari4+ */
-  background: -webkit-linear-gradient(top, #2b3d53 0%,#2c3d4d 100%); /* Chrome10+,Safari5.1+ */
-  background: -o-linear-gradient(top, #2b3d53 0%,#2c3d4d 100%); /* Opera 11.10+ */
-  background: -ms-linear-gradient(top, #2b3d53 0%,#2c3d4d 100%); /* IE10+ */
-  background: linear-gradient(to bottom, #2b3d53 0%,#2c3d4d 100%); /* W3C */
-  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#2b3d53', endColorstr='#2c3d4d',GradientType=0 ); /* IE6-9 */
-  padding-top: 10px;
-  padding-bottom: 10px;
-  font-size: 14px;
-  color: #ffffff;
-  /* border-top-left-radius:5px;
-  border-top-right-radius: 5px;*/
-}
-.scorm_item_section .scorm_section_level_0{
-  padding-left: .5em;
-  padding-right: .5em;
-}
-.scorm_item_section .scorm_section_level_1{
-  padding-left: 1.5em;
-  padding-right: .5em;
-}
-.scorm_item_section .scorm_section_level_2{
-  padding-left: 2.5em;
-  padding-right: .5em;
+    border-bottom: 1px solid #DDD;
+    font-size: 12px;
+    font-weight: bold;
 }
-.scorm_item_section .scorm_section_level_3{
-  padding-left: 3.5em;
-  padding-right: .5em;
+.scorm_item_section .section{
+    background:url("../../main/img/scorm/folder-item-closed.png") no-repeat left center;
 }
-
-.scorm_item_normal .scorm_item_level_0{
-  padding-left: 1.5em;
-}
-.scorm_item_normal{
-  padding:5px;
-  margin-left: 10px;
+.scorm_item_section.scorm_completed .section{
+  background:url("../../main/img/scorm/folder-item-open.png") no-repeat left center;
+  padding-right: 1.5em;
 }
 .scorm_item_normal a.items-list{
   color: #666666;
+  font-size: 12px;
 }
 .scorm_item_normal a:hover{
    text-decoration: none;
 }
-.scorm_item_normal.scorm_completed {
+.scorm_item_normal.scorm_completed{
+   background-color: #F5F5F5;
+}
+.scorm_item_section.scorm_completed{
+   background-color: #F5F5F5;
+   color: #000;
+}
+.scorm_completed .item {
   background:url("../../main/img/scorm/scorm_completed.png") no-repeat left center;
 }
-.scorm_item_normal.scorm_failed{
+.scorm_completed .item a{
+  color: #000;
+}
+.scorm_failed .item{
   background:url("../../main/img/scorm/scorm_failed.png") no-repeat left center;
 }
-.scorm_item_normal.scorm_not_attempted{
+.scorm_not_attempted .item{
   background:url("../../main/img/scorm/scorm_not_attempted.png") no-repeat left center;	
 }
-.scorm_item_normal.scorm_highlight{
+.scorm_highlight .item{
   background:url("../../main/img/scorm/scorm_highlight.png") no-repeat left center !important;
   color: #009AB8;
 }
-.scorm_item_normal.scorm_highlight.scorm_completed{
+.scorm_highlight.scorm_completed .item{
   background:url("../../main/img/scorm/scorm_current.png") no-repeat left center !important;
-  color: #009AB8;
 }
-.scorm_item_normal.scorm_highlight.scorm_failed{
+.scorm_highlight.scorm_failed .item{
     background:url("../../main/img/scorm/scorm_failed.png") no-repeat left center !important;
-    color: #009AB8;
 }
-.scorm_item_normal.scorm_highlight a{
-  color: #009AB8 !important;
+.scorm_highlight a{
+  color: #FFFFFF !important;
+}
+.scorm_item_normal.scorm_highlight{
+    background-color: #00AAD4;
 }
 
 /* END SCORM CSS BASE*/
@@ -311,29 +283,25 @@ body{
     padding-bottom: 10px;
 }
 .scorm-title{
-    color: #666;
-    font-size: 16px;
-    font-weight: 700;
+    color: #333;
+    font-size: 18px;
+    font-weight: bold;
     line-height: 1.5em;
-    margin: 0 0 10px;
+    margin: 0 0 15px;
     overflow: hidden;
     text-overflow: ellipsis;
     white-space: nowrap;
+    padding-bottom: 5px;
+    border-bottom: 1px solid #DDD;
 }
-
 #learning_path_right_zone .lp-view-tabs li a {
     padding: 5px 10px;
 }
-
-
-
-/* Extra small devices (mobiles, 767px and down) */
 #learning_path_main {
     height: 100%;
     margin: 0;
     overflow: hidden;
 }
-
 #learning_path_left_zone,
 #learning_path_right_zone {
     bottom: 0;
@@ -347,7 +315,6 @@ body{
     transition-property: left width;
     transition-duration: 0.5s;
 }
-
 #learning_path_left_zone .lp-view-zone-container,
 #learning_path_right_zone .lp-view-zone-container {
     bottom: 0;
@@ -357,7 +324,6 @@ body{
     right: 0;
     top: 0;
 }
-
 #learning_path_toc {
     bottom: 5px;
     left: 5px;
@@ -368,12 +334,10 @@ body{
     transition-property: top;
     transition-duration: 0.1s;
 }
-
 #learning_path_right_zone {
     left: 100%;
     width: 100%;
 }
-
 #learning_path_right_zone .lp-view-tabs .tab-content {
     bottom: 5px;
     left: 5px;
@@ -390,11 +354,9 @@ body{
     height: 100%;
     width: 100%;
 }
-
 #learning_path_main.lp-view-collapsed #learning_path_left_zone {
     left: -100%;
 }
-
 #learning_path_main.lp-view-collapsed #learning_path_right_zone {
     left: 0;
     width: 100%;
@@ -451,13 +413,13 @@ body{
     color: #ffffff;
 }
 #learning_path_toc {
-        bottom: 10px;
-        left: 10px;
-        right: 5px;
-        margin-top:20px;
-        border: 1px solid #ddd;
-        padding: 10px;
-        border-radius: 5px;
+    bottom: 10px;
+    left: 10px;
+    right: 5px;
+    margin-top:20px;
+    border: 1px solid #ddd;
+    padding: 10px;
+    border-radius: 5px;
 }
 /* Small devices (tablets, 768px and up) */
 @media (min-width: 768px) {

+ 3 - 3
app/Resources/public/css/themes/academica/default.css

@@ -125,7 +125,7 @@ header{
 .panel-default .panel-heading{
     background-color: #ddecef;
 }
-footer{
+footer.bgfooter{
   background: #004455; /* Old browsers */
   background: -moz-linear-gradient(top, #004455 0%, #272727 100%); /* FF3.6+ */
   background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#004455), color-stop(100%,#272727)); /* Chrome,Safari4+ */
@@ -137,9 +137,9 @@ footer{
   color: #9DD0F1;
   border-top: 2px solid #364753;
 }
-footer a{
+footer.bgfooter a{
   color: #ffffff;
 }
-footer a:hover{
+footer.bgfooter a:hover{
   color: #CCC;
 }

+ 3 - 3
app/Resources/public/css/themes/baby_orange/default.css

@@ -123,14 +123,14 @@ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#e83b10', end
 .panel-default .panel-heading{
     background-color: #F9F9F9;
 }
-footer{
+footer.bgfooter{
   background: #3D3D3D;
   color: #9DD0F1;
   border-top: 4px solid #CCC;
 }
-footer a{
+footer.bgfooter a{
   color: #ffffff;
 }
-footer a:hover{
+footer.bgfooter a:hover{
   color: #CCC;
 }

+ 3 - 3
app/Resources/public/css/themes/beach/default.css

@@ -194,7 +194,7 @@ a:focus {
  border-color: #ECF0F1;
 }
 /* End Jquery UI */
-footer{
+footer.bgfooter{
   background-color:#181D20;
   border-bottom: 1px solid #181D20;
   -webkit-filter: none;
@@ -202,10 +202,10 @@ footer{
   -webkit-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
   box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
 }
-footer{
+footer.bgfooter{
   color: #ffffff;
 }
-footer a{
+footer.bgfooter a{
   color: #ffffff;
 }
 

+ 3 - 3
app/Resources/public/css/themes/blue_lagoon/default.css

@@ -104,14 +104,14 @@ header{
 .nav li a:hover{
     background: transparent;
 }
-footer{
+footer.bgfooter{
   background: #2E75A3;
   color: #9DD0F1;
   border-top: 2px solid #0099C0;
 }
-footer a{
+footer.bgfooter a{
   color: #ffffff;
 }
-footer a:hover{
+footer.bgfooter a:hover{
   color: #CCC;
 }

+ 3 - 3
app/Resources/public/css/themes/chamilo/default.css

@@ -139,13 +139,13 @@ a:focus {
   padding-left: 0.2em;
 }
 /* End Jquery UI */
-footer{
+.bgfooter{
   background-color:#1A2226;
 }
-footer{
+.bgfooter{
   color: #ffffff;
 }
-footer a{
+.bgfooter a{
   color: #ffffff;
 }
 .page-header{

+ 3 - 3
app/Resources/public/css/themes/chamilo_electric_blue/default.css

@@ -112,13 +112,13 @@ border-radius: 0px;
 .nav li a:hover{
     background: transparent;
 }
-footer{
+footer.bgfooter{
   background: #004455;
   color: #37abc8;
 }
-footer a{
+footer.bgfooter a{
   color: #ffffff;
 }
-footer a:hover{
+footer.bgfooter a:hover{
   color: #CCC;
 }

+ 3 - 3
app/Resources/public/css/themes/chamilo_green/default.css

@@ -120,7 +120,7 @@ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#008000', end
 .nav li a:hover{
     background: transparent;
 }
-footer{
+footer.bgfooter{
   background: #1c1c1c; /* Old browsers */
   background: -moz-linear-gradient(top, #1c1c1c 0%, #272727 99%); /* FF3.6+ */
   background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#1c1c1c), color-stop(99%,#272727)); /* Chrome,Safari4+ */
@@ -131,9 +131,9 @@ footer{
   filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#1c1c1c', endColorstr='#272727',GradientType=0 ); /* IE6-9 */
   color: #88aa00;
 }
-footer a{
+footer.bgfooter a{
   color: #ffffff;
 }
-footer a:hover{
+footer.bgfooter a:hover{
   color: #CCC;
 }

+ 3 - 3
app/Resources/public/css/themes/chamilo_orange/default.css

@@ -116,7 +116,7 @@ header{
 .nav li a:hover{
     background: transparent;
 }
-footer{
+footer.bgfooter{
   background: #4b4139; /* Old browsers */
   background: -moz-linear-gradient(top, #4b4139 0%, #655f4e 100%); /* FF3.6+ */
   background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#4b4139), color-stop(100%,#655f4e)); /* Chrome,Safari4+ */
@@ -127,9 +127,9 @@ footer{
   filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#4b4139', endColorstr='#655f4e',GradientType=0 ); /* IE6-9 */
   color: #ccc;
 }
-footer a{
+footer.bgfooter a{
   color: #ffffff;
 }
-footer a:hover{
+footer.bgfooter a:hover{
   color: #FF813A;
 }

+ 3 - 3
app/Resources/public/css/themes/chamilo_red/default.css

@@ -121,7 +121,7 @@ border-radius: 0;
 .nav li a:hover{
     background: transparent;
 }
-footer{
+footer.bgfooter{
   background: #1c1c1c; /* Old browsers */
   background: -moz-linear-gradient(top, #1c1c1c 0%, #272727 99%); /* FF3.6+ */
   background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#1c1c1c), color-stop(99%,#272727)); /* Chrome,Safari4+ */
@@ -132,10 +132,10 @@ footer{
   filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#1c1c1c', endColorstr='#272727',GradientType=0 ); /* IE6-9 */
   color: #d4707f;
 }
-footer a{
+footer.bgfooter a{
   color: #ffffff;
 }
-footer a:hover{
+footer.bgfooter a:hover{
   color: #CCC;
 }
 #carousel-announcement .left, #carousel-announcement .right{

+ 3 - 3
app/Resources/public/css/themes/chamilo_sport_red/default.css

@@ -153,15 +153,15 @@ background: #020202;
     background-color: #0099c0;
   }
 }
-footer{
+footer.bgfooter{
   background: #000000;
   color: #FF0000;
   border-top: 4px solid #FF0000;
 }
-footer a{
+footer.bgfooter a{
   color: #ffffff;
 }
-footer a:hover{
+footer.bgfooter a:hover{
   color: #CCC;
 }
 .nav li a:hover{

+ 3 - 3
app/Resources/public/css/themes/cool_blue/default.css

@@ -166,7 +166,7 @@ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fe9700', end
 .panel-default .panel-heading{
     background-color: #F9F9F9;
 }
-footer{
+footer.bgfooter{
 background: #04638a; /* Old browsers */
 background: -moz-linear-gradient(top, #04638a 0%, #041759 100%); /* FF3.6+ */
 background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#04638a), color-stop(100%,#041759)); /* Chrome,Safari4+ */
@@ -178,9 +178,9 @@ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#04638a', end
   color: #9DD0F1;
   border-top: 4px solid #CCC;
 }
-footer a{
+footer.bgfooter a{
   color: #ffffff;
 }
-footer a:hover{
+footer.bgfooter a:hover{
   color: #CCC;
 }

+ 3 - 3
app/Resources/public/css/themes/corporate/default.css

@@ -137,14 +137,14 @@ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#2eaebb', end
 .panel-default .panel-heading{
     background-color: #F9F9F9;
 }
-footer{
+footer.bgfooter{
   background: #258B96;
   color: #9DD0F1;
   border-top: 4px solid #CCC;
 }
-footer a{
+footer.bgfooter a{
   color: #ffffff;
 }
-footer a:hover{
+footer.bgfooter a:hover{
   color: #CCC;
 }

+ 3 - 3
app/Resources/public/css/themes/cosmic_campus/default.css

@@ -155,15 +155,15 @@ header{
 .panel-default .panel-heading{
     background-color: #ddecef;
 }
-footer{
+footer.bgfooter{
   background: #272727;
   color: #9DD0F1;
   border-top: 4px solid #546667;
   height: auto;
 }
-footer a{
+footer.bgfooter a{
   color: #ffffff;
 }
-footer a:hover{
+footer.bgfooter a:hover{
   color: #CCC;
 }

+ 3 - 3
app/Resources/public/css/themes/delicious_bordeaux/default.css

@@ -143,7 +143,7 @@ background: #800020;
 .panel-default{
     border-color: #F3F3F4;
 }
-footer{
+footer.bgfooter{
 background: #890226; /* Old browsers */
 background: -moz-linear-gradient(top, #890226 0%, #6d0019 100%); /* FF3.6+ */
 background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#890226), color-stop(100%,#6d0019)); /* Chrome,Safari4+ */
@@ -155,9 +155,9 @@ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#890226', end
 color: #9DD0F1;
 border-top: 4px solid #720033;
 }
-footer a{
+footer.bgfooter a{
   color: #ffffff;
 }
-footer a:hover{
+footer.bgfooter a:hover{
   color: #CCC;
 }

+ 3 - 3
app/Resources/public/css/themes/empire_green/default.css

@@ -158,14 +158,14 @@ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#7b8392', end
 .panel-default .panel-heading{
     background-color: #F9F9F9;
 }
-footer{
+footer.bgfooter{
   background: #444444;
   color: #9DD0F1;
   border-top: 4px solid #C2DF44;
 }
-footer a{
+footer.bgfooter a{
   color: #ffffff;
 }
-footer a:hover{
+footer.bgfooter a:hover{
   color: #CCC;
 }

+ 3 - 3
app/Resources/public/css/themes/fruity_orange/default.css

@@ -157,14 +157,14 @@ background: #FF650D;
 .panel-default{
     border-color: #F3F3F4;
 }
-footer{
+footer.bgfooter{
 background: #000000;
 color: #FF6700;
 border-top: 4px solid #FF6700;
 }
-footer a{
+footer.bgfooter a{
   color: #ffffff;
 }
-footer a:hover{
+footer.bgfooter a:hover{
   color: #CCC;
 }

+ 3 - 3
app/Resources/public/css/themes/holi/default.css

@@ -217,7 +217,7 @@ a:focus {
  border-color: #ECF0F1;
 }
 /* End Jquery UI */
-footer{
+footer.bgfooter{
   background-color:#6B77B8;
   border-bottom: 1px solid #6B77B8;
   -webkit-filter: none;
@@ -225,10 +225,10 @@ footer{
   -webkit-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
   box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
 }
-footer{
+footer.bgfooter{
   color: #ffffff;
 }
-footer a{
+footer.bgfooter a{
   color: #ffffff;
 }
 

+ 3 - 3
app/Resources/public/css/themes/journal/default.css

@@ -181,14 +181,14 @@ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#6fc4af', end
 .panel-default{
     border-color: #F3F3F4;
 }
-footer{
+footer.bgfooter{
 background: #34495E;
 color: #50B387;
 border-top: 4px solid #50B387;
 }
-footer a{
+footer.bgfooter a{
   color: #ffffff;
 }
-footer a:hover{
+footer.bgfooter a:hover{
   color: #CCC;
 }

+ 3 - 3
app/Resources/public/css/themes/kiddy/default.css

@@ -199,7 +199,7 @@ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fc8a00', end
 .panel-default{
     border-color: #F3F3F4;
 }
-footer{
+footer.bgfooter{
 background: #01a1ff;
 background: -moz-linear-gradient(top, #01a1ff 0%, #0266ef 100%);
 background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#01a1ff), color-stop(100%,#0266ef));
@@ -211,10 +211,10 @@ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#01a1ff', end
 color: #FFB500;
 border: none;
 }
-footer a{
+footer.bgfooter a{
   color: #ffffff;
 }
-footer a:hover{
+footer.bgfooter a:hover{
   color: #CCC;
 }
 .menu-column .panel-heading{

+ 3 - 3
app/Resources/public/css/themes/medical/default.css

@@ -169,16 +169,16 @@ background: #F38A1E;
 .panel-default{
     border-color: #F3F3F4;
 }
-footer{
+footer.bgfooter{
 background: #2C9BB6;
 color: #FFF;
 border-top: 10px solid #EFEFEF;
 }
-footer a{
+footer.bgfooter a{
   color: #FFFF00;
   font-weight: bold;
 }
-footer a:hover{
+footer.bgfooter a:hover{
   color: #CCC;
 }
 .menu-column .panel-body{

+ 3 - 3
app/Resources/public/css/themes/readable/default.css

@@ -160,15 +160,15 @@ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#8fc400', end
 .panel-default .panel-heading{
     background-color: #F9F9F9;
 }
-footer{
+footer.bgfooter{
   background: #232323;
   color: #837E76;
   border-top: 2px solid #79B72C;
 }
-footer a{
+footer.bgfooter a{
   color: #63AC0C;
 }
-footer a:hover{
+footer.bgfooter a:hover{
   color: #63AC0C;
 }
 .menu-column .panel-default .panel-heading{

+ 3 - 3
app/Resources/public/css/themes/royal_purple/default.css

@@ -158,7 +158,7 @@ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f7a400', end
 .panel-default .panel-heading{
     background-color: #F9F9F9;
 }
-footer{
+footer.bgfooter{
   background: #663872; /* Old browsers */
 background: -moz-linear-gradient(top, #663872 0%, #36254f 100%); /* FF3.6+ */
 background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#663872), color-stop(100%,#36254f)); /* Chrome,Safari4+ */
@@ -170,9 +170,9 @@ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#663872', end
   color: #FFFFFF;
   border-top: 4px solid #FE7400;
 }
-footer a{
+footer.bgfooter a{
   color: #F79F00;
 }
-footer a:hover{
+footer.bgfooter a:hover{
   color: #CCC;
 }

+ 3 - 3
app/Resources/public/css/themes/simplex/default.css

@@ -148,15 +148,15 @@ background: #111111;
 .panel-default{
     border-color: #F3F3F4;
 }
-footer{
+footer.bgfooter{
 background: #111111;
 color: #FBD232;
 border-top: 5px solid #FBD232;
 }
-footer a{
+footer.bgfooter a{
   color: #ffffff;
 }
-footer a:hover{
+footer.bgfooter a:hover{
   color: #CCC;
 }
 .menu-column .panel-heading{

+ 3 - 3
app/Resources/public/css/themes/sober_brown/default.css

@@ -129,15 +129,15 @@ background: #F7490C;
 .panel-default .panel-heading{
     background-color: #F9F9F9;
 }
-footer{
+footer.bgfooter{
   background: #782306;
   color: #F7490C;
   border-top: 4px solid #F7490C;
 }
-footer a{
+footer.bgfooter a{
   color: #ffffff;
 }
-footer a:hover{
+footer.bgfooter a:hover{
   color: #CCC;
 }
 .badge{

+ 3 - 3
app/Resources/public/css/themes/spacelab/default.css

@@ -147,14 +147,14 @@ border:none;
 .panel-default .panel-heading{
     background-color: #ddecef;
 }
-footer{
+footer.bgfooter{
   background: #272727;
   color: #9DD0F1;
   border-top: 4px solid #4A8480;
 }
-footer a{
+footer.bgfooter a{
   color: #ffffff;
 }
-footer a:hover{
+footer.bgfooter a:hover{
   color: #CCC;
 }

+ 3 - 3
app/Resources/public/css/themes/steel_grey/default.css

@@ -132,15 +132,15 @@ background: #F7490C;
 .menu-column .panel-default .panel-heading a:hover{
     color: #111;
 }
-footer{
+footer.bgfooter{
   background: #465251;
   color: #111;
   border:none;
 }
-footer a{
+footer.bgfooter a{
   color: #ffffff;
 }
-footer a:hover{
+footer.bgfooter a:hover{
   color: #CCC;
 }
 .badge{

+ 3 - 3
app/Resources/public/css/themes/tasty_olive/default.css

@@ -158,14 +158,14 @@ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#7b8392', end
 .panel-default .panel-heading{
     background-color: #F9F9F9;
 }
-footer{
+footer.bgfooter{
   background: #444444;
   color: #9DD0F1;
   border-top: 4px solid #C2DF44;
 }
-footer a{
+footer.bgfooter a{
   color: #ffffff;
 }
-footer a:hover{
+footer.bgfooter a:hover{
   color: #CCC;
 }

+ 1 - 1
composer.json

@@ -150,7 +150,7 @@
         "knplabs/doctrine-behaviors": "~1.1",
         "lunetics/locale-bundle": "^2.4",
         "theodo-evolution/session-bundle": "1.0.*",
-        "jimmiw/php-time-ago": "^0.4.11",
+        "jimmiw/php-time-ago": "^0.4.14",
         "phpoffice/phpword": "^0.12.1",
         "facebook/php-sdk-v4" : "~5.0",
         "kigkonsult/icalcreator" : "0.1.0",

+ 8 - 3
documentation/installation_guide.html

@@ -36,7 +36,7 @@
 </nav>
 
 <div class="container">
-<h1>Chamilo 1.10 - Installation Guide</h1>
+<h1>Chamilo 1.11 - Installation Guide</h1>
 
 <p>Thank you for downloading Chamilo</p>
 <ul>
@@ -678,7 +678,7 @@ If you have issues with files taking a long time to download, make sure you reco
 	RewriteCond %{QUERY_STRING} ^id=(.*)$
 	RewriteRule ^([^/.]+)/?$ user.php?$1 [L]
 	RewriteRule ^certificates/$ certificates/index.php?id=%1 [L]
-	RewriteRule ^courses/([^/]+)/$ app/course_home/course_home.php?cDir=$1 [QSA,L]
+	RewriteRule ^courses/([^/]+)/$ main/course_home/course_home.php?cDir=$1 [QSA,L]
 	RewriteRule ^courses/([^/]+)/index.php$ main/course_home/course_home.php?cDir=$1 [QSA,L]
 	RewriteRule ^courses/([^/]+)/document/(.*)$ main/document/download.php?doc_url=/$2&cDir=$1 [QSA,L]
 	RewriteRule ^courses/([^/]+)/work/(.*)$ main/work/download.php?file=work/$2&cDir=$1 [QSA,L]
@@ -701,10 +701,13 @@ If you have issues with files taking a long time to download, make sure you reco
 
   location @rewrite{
     rewrite ^/courses/([^/]+)/scorm/(.*)$ /main/document/download_scorm.php?doc_url=/$2&cDir=$1 last;
+    # Alternatively, you can choose to give direct access to all SCORM files, which is much faster but less secure
+    # rewrite "^/courses/([^/]+)/scorm/(.*)$" /app/courses/$1/scorm/$2 break;
     rewrite "^/courses/([^/]+)/document/certificates/(.*)$" /app/courses/$1/document/certificates/$2 last;
     rewrite ^/courses/([^/]+)/document/(.*)$ /main/document/download.php?doc_url=/$2&cDir=$1 last;
     rewrite ^/courses/([^/]+)/work/(.*)$ /main/work/download.php?file=work/$2&cDir=$1 last;
     rewrite ^/courses/([^/]+)/upload/(.*)$ /app/courses/$1/upload/$2 last;
+    rewrite ^/main/upload/users/(.*)/(.*)/my_files/(.*)$ /app/upload/users/$1/$2/my_files/$3 last;
     try_files $uri /index.php;
     break;
   }
@@ -741,7 +744,7 @@ If you have issues with files taking a long time to download, make sure you reco
   }
 
   # Serve static files directly
-  location ~* \.(png|jpe?g|gif|ico|js)$ {
+  location ~* \.(png|jpe?g|gif|ico|js|css|mp3|swf|flv|mp4|ogg)$ {
     expires 1y;
     access_log off;
     rewrite ^/courses/([^/]+)/course-pic85x85.png$ /app/courses/$1/course-pic85x85.png last;
@@ -750,6 +753,8 @@ If you have issues with files taking a long time to download, make sure you reco
     rewrite ^/courses/([^/]+)/document/(.*)$ /main/document/download.php?doc_url=/$2&cDir=$1 last;
     rewrite ^/courses/([^/]+)/work/(.*)$ /main/work/download.php?file=work/$2&cDir=$1 last;
     rewrite ^/courses/([^/]+)/upload/(.*)$ /app/courses/$1/upload/$2 last;
+    # For all these media resources not treated by previous rewrites, give direct access (no permission check)
+    rewrite ^/courses/(.*)$ /app/courses/$1 break;
     try_files $uri @rewrite;
   }
   location ~ ~\.(ht|git){

+ 10 - 4
documentation/installation_guide_es_ES.html

@@ -1,7 +1,7 @@
 <html lang="es">
 <head>
     <meta charset="utf-8" />
-	<title>Guia de Instalación de Chamilo 1.10</title>
+	<title>Guia de Instalación de Chamilo 1.11</title>
     <link rel="stylesheet" href="../web/assets/bootstrap/dist/css/bootstrap.css" type="text/css" media="screen,projection" />
     <link rel="stylesheet" href="default.css" type="text/css" media="screen,projection" />
     <link rel="stylesheet" href="default.css" type="text/css" media="screen,projection" />
@@ -41,7 +41,7 @@
     </li>
     <li>Guía de Instalación</li>
 </ul>
-<h1>Chamilo 1.10 - Guía de Instalación</h1>
+<h1>Chamilo 1.11 - Guía de Instalación</h1>
 
 <p>Gracias por descargar Chamilo, la suite de aprendizaje de código abierto profesional.</p>
 <ul>
@@ -686,9 +686,13 @@ por ejemplo. El efecto debería ser inmediato.
 
   location @rewrite{
     rewrite ^/courses/([^/]+)/scorm/(.*)$ /main/document/download_scorm.php?doc_url=/$2&cDir=$1 last;
+    # Alternatively, you can choose to give direct access to all SCORM files, which is much faster but less secure
+    # rewrite "^/courses/([^/]+)/scorm/(.*)$" /app/courses/$1/scorm/$2 break;
+    rewrite "^/courses/([^/]+)/document/certificates/(.*)$" /app/courses/$1/document/certificates/$2 last;
     rewrite ^/courses/([^/]+)/document/(.*)$ /main/document/download.php?doc_url=/$2&cDir=$1 last;
     rewrite ^/courses/([^/]+)/work/(.*)$ /main/work/download.php?file=work/$2&cDir=$1 last;
     rewrite ^/courses/([^/]+)/upload/(.*)$ /app/courses/$1/upload/$2 last;
+    rewrite ^/main/upload/users/(.*)/(.*)/my_files/(.*)$ /app/upload/users/$1/$2/my_files/$3 last;
     try_files $uri /index.php;
     break;
   }
@@ -723,7 +727,7 @@ por ejemplo. El efecto debería ser inmediato.
   }
 
   # Serve static files directly
-  location ~* \.(png|jpe?g|gif|ico)$ {
+  location ~* \.(png|jpe?g|gif|ico|js|css|mp3|swf|flv|mp4|ogg)$ {
     expires 1y;
     access_log off;
     rewrite ^/courses/([^/]+)/course-pic85x85.png$ /app/courses/$1/course-pic85x85.png last;
@@ -732,6 +736,8 @@ por ejemplo. El efecto debería ser inmediato.
     rewrite ^/courses/([^/]+)/document/(.*)$ /main/document/download.php?doc_url=/$2&cDir=$1 last;
     rewrite ^/courses/([^/]+)/work/(.*)$ /main/work/download.php?file=work/$2&cDir=$1 last;
     rewrite ^/courses/([^/]+)/upload/(.*)$ /app/courses/$1/upload/$2 last;
+    # For all these media resources not treated by previous rewrites, give direct access (no permission check)
+    rewrite ^/courses/(.*)$ /app/courses/$1 break;
     try_files $uri @rewrite;
   }
   location ~ ~\.(ht|git){
@@ -771,7 +777,7 @@ Apache2: La configuración para nuestro sitio de ejemplo my.chamilo10.net sería
 	RewriteCond %{QUERY_STRING} ^id=(.*)$
 	RewriteRule ^([^/.]+)/?$ user.php?$1 [L]
 	RewriteRule ^certificates/$ certificates/index.php?id=%1 [L]
-	RewriteRule ^courses/([^/]+)/$ app/course_home/course_home.php?cDir=$1 [QSA,L]
+	RewriteRule ^courses/([^/]+)/$ main/course_home/course_home.php?cDir=$1 [QSA,L]
 	RewriteRule ^courses/([^/]+)/index.php$ main/course_home/course_home.php?cDir=$1 [QSA,L]
 	RewriteRule ^courses/([^/]+)/document/(.*)$ main/document/download.php?doc_url=/$2&cDir=$1 [QSA,L]
 	RewriteRule ^courses/([^/]+)/work/(.*)$ main/work/download.php?file=work/$2&cDir=$1 [QSA,L]

+ 9 - 3
documentation/installation_guide_fr_FR.html

@@ -36,7 +36,7 @@
         </nav>
 
         <div class="container">
-            <h1>Guide d'installation de Chamilo LMS 1.10</h1>
+            <h1>Guide d'installation de Chamilo LMS 1.11</h1>
 
             <p>Merci d'avoir téléchargé Chamilo</p>
             <ul>
@@ -732,7 +732,7 @@ ou, si vous travaillez avec Apache 2.4, la syntaxe est légèrement différente
 	RewriteCond %{QUERY_STRING} ^id=(.*)$
 	RewriteRule ^([^/.]+)/?$ user.php?$1 [L]
 	RewriteRule ^certificates/$ certificates/index.php?id=%1 [L]
-	RewriteRule ^courses/([^/]+)/$ app/course_home/course_home.php?cDir=$1 [QSA,L]
+	RewriteRule ^courses/([^/]+)/$ main/course_home/course_home.php?cDir=$1 [QSA,L]
 	RewriteRule ^courses/([^/]+)/index.php$ main/course_home/course_home.php?cDir=$1 [QSA,L]
 	RewriteRule ^courses/([^/]+)/document/(.*)$ main/document/download.php?doc_url=/$2&cDir=$1 [QSA,L]
 	RewriteRule ^courses/([^/]+)/work/(.*)$ main/work/download.php?file=work/$2&cDir=$1 [QSA,L]
@@ -755,9 +755,13 @@ Ce sont uniquement les redirections à placer dans un bloc server{}, comme les a
 
   location @rewrite{
     rewrite ^/courses/([^/]+)/scorm/(.*)$ /main/document/download_scorm.php?doc_url=/$2&cDir=$1 last;
+    # Alternatively, you can choose to give direct access to all SCORM files, which is much faster but less secure
+    # rewrite "^/courses/([^/]+)/scorm/(.*)$" /app/courses/$1/scorm/$2 break;
+    rewrite "^/courses/([^/]+)/document/certificates/(.*)$" /app/courses/$1/document/certificates/$2 last;
     rewrite ^/courses/([^/]+)/document/(.*)$ /main/document/download.php?doc_url=/$2&cDir=$1 last;
     rewrite ^/courses/([^/]+)/work/(.*)$ /main/work/download.php?file=work/$2&cDir=$1 last;
     rewrite ^/courses/([^/]+)/upload/(.*)$ /app/courses/$1/upload/$2 last;
+    rewrite ^/main/upload/users/(.*)/(.*)/my_files/(.*)$ /app/upload/users/$1/$2/my_files/$3 last;
     try_files $uri /index.php;
     break;
   }
@@ -792,7 +796,7 @@ Ce sont uniquement les redirections à placer dans un bloc server{}, comme les a
   }
 
   # Serve static files directly
-  location ~* \.(png|jpe?g|gif|ico)$ {
+  location ~* \.(png|jpe?g|gif|ico|js|css|mp3|swf|flv|mp4|ogg)$ {
     expires 1y;
     access_log off;
     rewrite ^/courses/([^/]+)/course-pic85x85.png$ /app/courses/$1/course-pic85x85.png last;
@@ -801,6 +805,8 @@ Ce sont uniquement les redirections à placer dans un bloc server{}, comme les a
     rewrite ^/courses/([^/]+)/document/(.*)$ /main/document/download.php?doc_url=/$2&cDir=$1 last;
     rewrite ^/courses/([^/]+)/work/(.*)$ /main/work/download.php?file=work/$2&cDir=$1 last;
     rewrite ^/courses/([^/]+)/upload/(.*)$ /app/courses/$1/upload/$2 last;
+    # For all these media resources not treated by previous rewrites, give direct access (no permission check)
+    rewrite ^/courses/(.*)$ /app/courses/$1 break;
     try_files $uri @rewrite;
   }
   location ~ ~\.(ht|git){

+ 211 - 211
main/admin/access_url_edit_usergroup_to_url.php

@@ -1,9 +1,9 @@
 <?php
 /* For licensing terms, see /license.txt */
 /**
-*	@package chamilo.admin
-*	@author Julio Montoya <gugli100@gmail.com>
-*/
+ * @package chamilo.admin
+ * @author Julio Montoya <gugli100@gmail.com>
+ */
 // resetting the course id
 $cidReset = true;
 
@@ -25,8 +25,8 @@ if (!api_get_multiple_access_url()) {
 
 // setting breadcrumbs
 $tool_name = get_lang('EditUserGroupToURL');
-$interbreadcrumb[] = array ('url' => 'index.php', 'name' => get_lang('PlatformAdmin'));
-$interbreadcrumb[] = array ('url' => 'access_urls.php', 'name' => get_lang('MultipleAccessURLs'));
+$interbreadcrumb[] = array('url' => 'index.php', 'name' => get_lang('PlatformAdmin'));
+$interbreadcrumb[] = array('url' => 'access_urls.php', 'name' => get_lang('MultipleAccessURLs'));
 
 $add_type = 'multiple';
 if (isset($_REQUEST['add_type']) && $_REQUEST['add_type'] != '') {
@@ -43,7 +43,6 @@ $htmlHeadXtra[] = $xajax->getJavascript('../inc/lib/xajax/');
 $htmlHeadXtra[] = '
 <script>
 function add_user_to_url(code, content) {
-
 	document.getElementById("course_to_add").value = "";
 	document.getElementById("ajax_list_courses").innerHTML = "";
 
@@ -55,10 +54,9 @@ function add_user_to_url(code, content) {
 }
 
 function send() {
-
 	if (document.formulaire.access_url_id.value!=0) {
 		document.formulaire.form_sent.value=0;
-		document.formulaire.add_type.value=\''.$add_type.'\';
+		document.formulaire.add_type.value=\'' . $add_type . '\';
 		document.formulaire.submit();
 	}
 }
@@ -73,10 +71,10 @@ function remove_item(origin) {
 }
 </script>';
 
-$form_sent=0;
-$errorMsg='';
-$UserList=$SessionList=array();
-$users=$sessions=array();
+$form_sent = 0;
+$errorMsg = '';
+$UserList = $SessionList = array();
+$users = $sessions = array();
 
 if (isset($_POST['form_sent']) && $_POST['form_sent']) {
     $form_sent = $_POST['form_sent'];
@@ -104,7 +102,7 @@ Display::display_header($tool_name);
 echo '<div class="actions">';
 echo Display::url(
     Display::return_icon('view_more_stats.gif', get_lang('AddUserGroupToURL'), ''),
-    api_get_path(WEB_CODE_PATH).'admin/access_url_add_usergroup_to_url.php'
+    api_get_path(WEB_CODE_PATH) . 'admin/access_url_add_usergroup_to_url.php'
 );
 echo '</div>';
 
@@ -119,224 +117,226 @@ if ($ajax_search) {
         $userGroupList[$item['id']] = $item;
     }
 } else {
-	$userGroups = UrlManager::get_url_rel_usergroup_data();
+    $userGroups = UrlManager::get_url_rel_usergroup_data();
 
     foreach ($userGroups as $item) {
         if ($item['access_url_id'] == $access_url_id) {
-            $userGroupList[$item['id']] = $item ;
+            $userGroupList[$item['id']] = $item;
         }
     }
     $noUserGroupList = $userGroup->getUserGroupNotInList(array_keys($userGroupList));
 }
 
+$link_add_type_unique = ['class' => 'disabled'];
+$link_add_type_multiple = [];
+
 if ($add_type == 'multiple') {
-	$link_add_type_unique = '<a href="'.api_get_self().'?add_type=unique&access_url_id='.$access_url_id.'">'.get_lang('SessionAddTypeUnique').'</a>';
-	$link_add_type_multiple = get_lang('SessionAddTypeMultiple');
-} else {
-	$link_add_type_unique = get_lang('SessionAddTypeUnique');
-	$link_add_type_multiple = '<a href="'.api_get_self().'?add_type=multiple&access_url_id='.$access_url_id.'">'.get_lang('SessionAddTypeMultiple').'</a>';
+    $link_add_type_unique = [];
+    $link_add_type_multiple = ['class' => 'disabled'];
 }
-
+?>
+    <div class="btn-toolbar">
+        <div class="btn-group">
+            <?php
+            echo Display::toolbarButton(
+                get_lang('SessionAddTypeUnique'),
+                api_get_self() . '?' . http_build_query([
+                    'add_type' => 'unique',
+                    'access_url_id' => $access_url_id
+                ]),
+                'file-o',
+                'default',
+                $link_add_type_unique
+            );
+            echo Display::toolbarButton(
+                get_lang('SessionAddTypeMultiple'),
+                api_get_self() . '?' . http_build_query([
+                    'add_type' => 'multiple',
+                    'access_url_id' => $access_url_id
+                ]),
+                'files-o',
+                'default',
+                $link_add_type_multiple
+            );
+            ?>
+        </div>
+    </div>
+<?php
 $url_list = UrlManager::get_url_data();
 ?>
-<div style="text-align: left;">
-	<?php echo $link_add_type_unique ?>&nbsp;|&nbsp;<?php echo $link_add_type_multiple ?>
-</div>
-<br /><br />
-<form
-    name="formulaire"
-    method="post"
-    action="<?php echo api_get_self(); ?>"
-    style="margin:0px;" <?php if ($ajax_search){ echo ' onsubmit="valide();"'; } ?>
->
-<?php echo get_lang('SelectUrl').' : '; ?>
-<select name="access_url_id" onchange="javascript:send();">
-<option value="0">-- <?php echo get_lang('SelectUrl')?> -- </option>
-	<?php
-    $url_selected = '';
-    foreach ($url_list as $url_obj) {
-        $checked = '';
-        if (!empty($access_url_id)) {
-            if ($url_obj[0] == $access_url_id) {
-                $checked = 'selected=true';
-                $url_selected=$url_obj[1];
-            }
-        }
-        if ($url_obj['active']==1) { ?>
-            <option <?php echo $checked;?> value="<?php echo $url_obj[0]; ?>"> <?php echo $url_obj[1]; ?>
-            </option>
+    <form
+        name="formulaire"
+        method="post"
+        action="<?php echo api_get_self(); ?>"
+        style="margin:0px;" <?php if ($ajax_search) {
+        echo ' onsubmit="valide();"';
+    } ?>
+    >
+        <div class="row">
+            <div class="col-xs-2">
+                <label for="access_url_id"><?php echo get_lang('SelectUrl') ?></label>
+            </div>
+            <div class="col-xs-5">
+                <select name="access_url_id" id="access_url_id" onchange="javascript:send();" class="form-control">
+                    <option value="0">-- <?php echo get_lang('SelectUrl') ?> --</option>
+                    <?php
+                    $url_selected = '';
+                    foreach ($url_list as $url_obj) {
+                        $checked = '';
+                        if (!empty($access_url_id)) {
+                            if ($url_obj[0] == $access_url_id) {
+                                $checked = 'selected=true';
+                                $url_selected = $url_obj[1];
+                            }
+                        }
+                        if ($url_obj['active'] == 1) { ?>
+                            <option <?php echo $checked; ?>
+                                value="<?php echo $url_obj[0]; ?>"> <?php echo $url_obj[1]; ?>
+                            </option>
+                            <?php
+                        }
+                    }
+                    ?>
+                </select>
+            </div>
+        </div>
+        <input type="hidden" name="form_sent" value="1"/>
+        <input type="hidden" name="add_type" value="<?php echo $add_type ?>"/>
         <?php
+        if (!empty($errorMsg)) {
+            Display::display_normal_message($errorMsg); //main API
+        }
+        ?>
+        <div class="row">
+            <div class="col-sm-5">
+                <label for="<?php echo $ajax_search ? 'course_to_add' : 'origin_users' ?>"><?php echo get_lang('UserGroupListInPlatform') ?></label>
+                <div id="content_source">
+                    <?php if ($ajax_search) { ?>
+                        <input type="text" id="course_to_add" class="form-control"
+                               onkeyup="xajax_searchUserGroupAjax(this.value,document.formulaire.access_url_id.options[document.formulaire.access_url_id.selectedIndex].value)"/>
+                        <div id="ajax_list_courses"></div>
+                    <?php } else { ?>
+                        <select id="origin_users" name="no_course_list[]" multiple="multiple" size="15" class="form-control">
+                            <?php foreach ($noUserGroupList as $noItem) { ?>
+                                <option value="<?php echo $noItem['id']; ?>"><?php echo $noItem['name']; ?></option>
+                            <?php } ?>
+                        </select>
+                    <?php } ?>
+                </div>
+            </div>
+            <div class="col-sm-2 text-center">
+                <br><br><br><br>
+                <?php if ($ajax_search) { ?>
+                    <button class="btn btn-default" type="button"
+                            onclick="remove_item(document.getElementById('destination_users'))">
+                        <em class="fa fa-arrow-left"></em>
+                    </button>
+                <?php } else { ?>
+                    <button class="btn btn-default" type="button"
+                            onclick="moveItem(document.getElementById('origin_users'), document.getElementById('destination_users'))">
+                        <em class="fa fa-arrow-right"></em>
+                    </button>
+                    <br/><br/>
+                    <button class="btn btn-default" type="button"
+                            onclick="moveItem(document.getElementById('destination_users'), document.getElementById('origin_users'))">
+                        <em class="fa fa-arrow-left"></em>
+                    </button>
+                <?php } ?>
+            </div>
+            <div class="col-sm-5">
+                <label for="destination_users"><?php printf(get_lang('UserGroupListInX'), $url_selected); ?></label>
+                <select id="destination_users" name="course_list[]" multiple="multiple" size="15" class="form-control">
+                    <?php foreach ($userGroupList as $item) { ?>
+                        <option value="<?php echo $item['id']; ?>">
+                            <?php echo $item['name']; ?>
+                        </option>
+                    <?php } ?>
+                </select>
+            </div>
+        </div>
+        <div class="row">
+            <div class="col-xs-12 text-center">
+                <button class="save btn btn-primary" onclick="valide()">
+                    <span class="fa fa-save fa-fw" aria-hidden="true"></span>
+                    <?php echo isset($_GET['add']) ? get_lang('AddUserGroupToURL') : get_lang('EditUserGroupToURL') ?>
+                </button>
+            </div>
+        </div>
+    </form>
+    <script>
+        function moveItem(origin, destination) {
+            for (var i = 0; i < origin.options.length; i++) {
+                if (origin.options[i].selected) {
+                    destination.options[destination.length] = new Option(origin.options[i].text, origin.options[i].value);
+                    origin.options[i] = null;
+                    i = i - 1;
+                }
+            }
+            destination.selectedIndex = -1;
+            sortOptions(destination.options);
         }
-    }
-?>
-</select>
-<br /><br />
-<input type="hidden" name="form_sent" value="1" />
-<input type="hidden" name="add_type" value = "<?php echo $add_type ?>" />
-
-<?php
-if (!empty($errorMsg)) {
-    Display::display_normal_message($errorMsg); //main API
-}
-?>
-
-<table border="0" cellpadding="5" cellspacing="0" width="100%">
-<!-- Users -->
-<tr>
-  <td align="center"><b><?php echo get_lang('UserGroupListInPlatform') ?> :</b>
-  </td>
-  <td></td>
-  <td align="center"><b><?php printf(get_lang('UserGroupListInX'),$url_selected); ?></b></td>
-</tr>
-
-<tr>
-  <td align="center">
-  <div id="content_source">
-    <?php if ($ajax_search) { ?>
-		<input type="text" id="course_to_add" onkeyup="xajax_searchUserGroupAjax(this.value,document.formulaire.access_url_id.options[document.formulaire.access_url_id.selectedIndex].value)" />
-		<div id="ajax_list_courses"></div>
-    <?php } else { ?>
-	  <select id="origin_users" name="no_course_list[]" multiple="multiple" size="15" style="width:380px;">
-		<?php
-		foreach ($noUserGroupList as $noItem) {
-		?>
-			<option value="<?php echo $noItem['id']; ?>">
-                <?php echo $noItem['name']; ?>
-            </option>
-		<?php
-		}
-		?>
-	  </select>
-	<?php
-  	  }
-  	 ?>
-  </div>
-  </td>
-  <td width="10%" valign="middle" align="center">
-  <?php
-  if ($ajax_search) {
-	?>
-	<button class="btn btn-default" type="button" onclick="remove_item(document.getElementById('destination_users'))" >
-        <em class="fa fa-arrow-left"></em>
-	</button>
-  	<?php
-  } else {
-  	?>
-	<button class="btn btn-default" type="button" onclick="moveItem(document.getElementById('origin_users'), document.getElementById('destination_users'))" >
-        <em class="fa fa-arrow-right"></em>
-	</button>
-	<br /><br />
-	<button class="btn btn-default" type="button" onclick="moveItem(document.getElementById('destination_users'), document.getElementById('origin_users'))" >
-        <em class="fa fa-arrow-left"></em>
-	</button>
-	<?php
-  }
-  ?>
-	<br /><br /><br /><br /><br /><br />
-  </td>
-  <td align="center">
-  <select id="destination_users" name="course_list[]" multiple="multiple" size="15" style="width:380px;">
-<?php
-foreach($userGroupList as $item) {
-?>
-	<option value="<?php echo $item['id']; ?>">
-        <?php echo $item['name']; ?>
-    </option>
-<?php
-}
-?>
-  </select>
-  </td>
-</tr>
-<tr>
-	<td colspan="3" align="center">
-		<br />
-		<?php
-		if(isset($_GET['add']))
-			echo '<button class="save" onclick="valide()" >'.get_lang('AddUserGroupToURL').'</button>';
-		else
-			echo '<button class="save" onclick="valide()" >'.get_lang('EditUserGroupToURL').'</button>';
-		?>
-	</td>
-</tr>
-</table>
-</form>
-<script>
-
-function moveItem(origin , destination) {
-	for(var i = 0 ; i<origin.options.length ; i++) {
-		if(origin.options[i].selected) {
-			destination.options[destination.length] = new Option(origin.options[i].text,origin.options[i].value);
-			origin.options[i]=null;
-			i = i-1;
-		}
-	}
-	destination.selectedIndex = -1;
-	sortOptions(destination.options);
-}
-
-function sortOptions(options) {
-	newOptions = new Array();
-	for (i = 0 ; i<options.length ; i++)
-		newOptions[i] = options[i];
-
-	newOptions = newOptions.sort(mysort);
-	options.length = 0;
-	for(i = 0 ; i < newOptions.length ; i++)
-		options[i] = newOptions[i];
-
-}
-
-function mysort(a, b) {
-	if(a.text.toLowerCase() > b.text.toLowerCase()){
-		return 1;
-	}
-	if(a.text.toLowerCase() < b.text.toLowerCase()){
-		return -1;
-	}
-	return 0;
-}
 
-function valide(){
-	var options = document.getElementById('destination_users').options;
-	for (i = 0 ; i<options.length ; i++)
-		options[i].selected = true;
-	document.forms.formulaire.submit();
-}
+        function sortOptions(options) {
+            newOptions = new Array();
+            for (i = 0; i < options.length; i++)
+                newOptions[i] = options[i];
 
-function loadUsersInSelect(select){
+            newOptions = newOptions.sort(mysort);
+            options.length = 0;
+            for (i = 0; i < newOptions.length; i++)
+                options[i] = newOptions[i];
 
-	var xhr_object = null;
+        }
 
-	if(window.XMLHttpRequest) // Firefox
-		xhr_object = new XMLHttpRequest();
-	else if(window.ActiveXObject) // Internet Explorer
-		xhr_object = new ActiveXObject("Microsoft.XMLHTTP");
-	else  // XMLHttpRequest non supporté par le navigateur
-	alert("Votre navigateur ne supporte pas les objets XMLHTTPRequest...");
+        function mysort(a, b) {
+            if (a.text.toLowerCase() > b.text.toLowerCase()) {
+                return 1;
+            }
+            if (a.text.toLowerCase() < b.text.toLowerCase()) {
+                return -1;
+            }
+            return 0;
+        }
 
-	xhr_object.open("POST", "loadUsersInSelect.ajax.php");
-	xhr_object.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
-	nosessionUsers = makepost(document.getElementById('origin_users'));
-	sessionUsers = makepost(document.getElementById('destination_users'));
-	nosessionClasses = makepost(document.getElementById('origin_classes'));
-	sessionClasses = makepost(document.getElementById('destination_classes'));
-	xhr_object.send("nosessionusers="+nosessionUsers+"&sessionusers="+sessionUsers+"&nosessionclasses="+nosessionClasses+"&sessionclasses="+sessionClasses);
+        function valide() {
+            var options = document.getElementById('destination_users').options;
+            for (i = 0; i < options.length; i++)
+                options[i].selected = true;
+            document.forms.formulaire.submit();
+        }
 
-	xhr_object.onreadystatechange = function() {
-		if(xhr_object.readyState == 4) {
-			document.getElementById('content_source').innerHTML = result = xhr_object.responseText;
-		}
-	}
-}
+        function loadUsersInSelect(select) {
+            var xhr_object = null;
+
+            if (window.XMLHttpRequest) // Firefox
+                xhr_object = new XMLHttpRequest();
+            else if (window.ActiveXObject) // Internet Explorer
+                xhr_object = new ActiveXObject("Microsoft.XMLHTTP");
+            else  // XMLHttpRequest non supporté par le navigateur
+                alert("Votre navigateur ne supporte pas les objets XMLHTTPRequest...");
+
+            xhr_object.open("POST", "loadUsersInSelect.ajax.php");
+            xhr_object.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+            nosessionUsers = makepost(document.getElementById('origin_users'));
+            sessionUsers = makepost(document.getElementById('destination_users'));
+            nosessionClasses = makepost(document.getElementById('origin_classes'));
+            sessionClasses = makepost(document.getElementById('destination_classes'));
+            xhr_object.send("nosessionusers=" + nosessionUsers + "&sessionusers=" + sessionUsers + "&nosessionclasses=" + nosessionClasses + "&sessionclasses=" + sessionClasses);
+
+            xhr_object.onreadystatechange = function () {
+                if (xhr_object.readyState == 4) {
+                    document.getElementById('content_source').innerHTML = result = xhr_object.responseText;
+                }
+            }
+        }
 
-function makepost(select){
-	var options = select.options;
-	var ret = "";
-	for (i = 0 ; i<options.length ; i++)
-		ret = ret + options[i].value +'::'+options[i].text+";;";
-	return ret;
-}
-</script>
+        function makepost(select) {
+            var options = select.options;
+            var ret = "";
+            for (i = 0; i < options.length; i++)
+                ret = ret + options[i].value + '::' + options[i].text + ";;";
+            return ret;
+        }
+    </script>
 <?php
 Display::display_footer();

+ 2 - 2
main/admin/course_edit.php

@@ -344,10 +344,10 @@ if ($form->validate()) {
             }
         }
 
-        CourseManager::updateTeachers($courseId, $teachers, true, true, false);
+        CourseManager::updateTeachers($courseInfo, $teachers, true, true, false);
     } else {
         // Normal behaviour
-        CourseManager::updateTeachers($courseId, $teachers, true, false);
+        CourseManager::updateTeachers($courseInfo, $teachers, true, false);
 
         // Updating session coaches
         $sessionCoaches = $course['session_coaches'];

+ 1 - 1
main/admin/dashboard_add_sessions_to_user.php

@@ -155,7 +155,7 @@ $UserList = array();
 if (isset($_POST['formSent']) && intval($_POST['formSent']) == 1) {
     $sessions_list = $_POST['SessionsList'];
     $userInfo = api_get_user_info($user_id);
-    $affected_rows = SessionManager::suscribe_sessions_to_hr_manager(
+    $affected_rows = SessionManager::subscribeSessionsToDrh(
         $userInfo,
         $sessions_list
     );

+ 7 - 9
main/admin/settings.lib.php

@@ -402,16 +402,14 @@ function handleStylesheets()
             . '</script>';
         }
     } elseif (isset($_POST['logo_upload'])) {
-
         $logoForm->addRule('new_logo', get_lang('InvalidExtension').' ('.implode(',', $allowedFileTypes).')', 'filetype', $allowedFileTypes);
         $logoForm->addRule('new_logo', get_lang('ThisFieldIsRequired'), 'required');
 
         if ($logoForm->validate()) {
-
             $imageInfo = getimagesize($_FILES['new_logo']['tmp_name']);
             $width = $imageInfo[0];
             $height = $imageInfo[1];
-            if ($width <= 250 && $height <= 70 ) {
+            if ($width <= 250 && $height <= 70) {
                 if (is_file($dir.$newLogoFileName)) {
                     unlink($dir.$newLogoFileName);
                 }
@@ -1219,7 +1217,7 @@ function generateSettingsForm($settings, $settings_by_access_list)
     );
 
     $url_id = api_get_current_access_url_id();
-    /* 
+    /*
     if (!empty($_configuration['multiple_access_urls']) && api_is_global_platform_admin() && $url_id == 1) {
         $group = array();
         $group[] = $form->createElement('button', 'mark_all', get_lang('MarkAll'));
@@ -1297,11 +1295,11 @@ function generateSettingsForm($settings, $settings_by_access_list)
                 if (empty($row['category'])) {
                     $row['category'] = 0;
                 }
-
-                if (is_array($settings_by_access_list[ $row['variable'] ] [ $row['subkey'] ] [ $row['category'] ])) {
+                if (isset($settings_by_access_list[$row['variable']]) &&
+                    is_array($settings_by_access_list[$row['variable']][$row['subkey']][$row['category']])) {
                     // We are sure that the other site have a selected value.
-                    if ($settings_by_access_list[$row['variable']] [$row['subkey']] [$row['category']]['selected_value'] != '') {
-                        $row['selected_value'] = $settings_by_access_list[$row['variable']] [$row['subkey']] [$row['category']]['selected_value'];
+                    if ($settings_by_access_list[$row['variable']][$row['subkey']][$row['category']]['selected_value'] != '') {
+                        $row['selected_value'] = $settings_by_access_list[$row['variable']][$row['subkey']][$row['category']]['selected_value'];
                     }
                 }
                 // There is no else{} statement because we load the default $row['selected_value'] of the main Chamilo site.
@@ -1523,7 +1521,7 @@ function generateSettingsForm($settings, $settings_by_access_list)
                 if (empty($timezone)) {
                     $timezone = _api_get_timezone();
                 }
-                $form->addElement('html', sprintf(get_lang('LocalTimeUsingPortalTimezoneXIsY'), $timezone, api_get_local_time()));
+                $form->addLabel('', sprintf(get_lang('LocalTimeUsingPortalTimezoneXIsY'), $timezone, api_get_local_time()));
                 break;
         }
     } // end for

+ 12 - 6
main/admin/settings.php

@@ -84,22 +84,28 @@ $form_search_html = $form_search->returnForm();
 $url_id = api_get_current_access_url_id();
 
 $settings = null;
-
-function get_settings($category = null)
+/**
+ * @param string $category
+ * @return array
+ */
+function get_settings($category = '')
 {
     $url_id = api_get_current_access_url_id();
     $settings_by_access_list = array();
 
     if ($url_id == 1) {
         $settings = api_get_settings($category, 'group', $url_id);
-
     } else {
         $url_info = api_get_access_url($url_id);
         if ($url_info['active'] == 1) {
+            $categoryToSearch = $category;
+            if ($category == 'search_setting') {
+                $categoryToSearch = '';
+            }
             // The default settings of Chamilo
-            $settings = api_get_settings($category, 'group', 1, 0);
+            $settings = api_get_settings($categoryToSearch, 'group', 1, 0);
             // The settings that are changeable from a particular site.
-            $settings_by_access = api_get_settings($category, 'group', $url_id, 1);
+            $settings_by_access = api_get_settings($categoryToSearch, 'group', $url_id, 1);
 
             foreach ($settings_by_access as $row) {
                 if (empty($row['variable'])) {
@@ -122,7 +128,7 @@ function get_settings($category = null)
         }
     }
 
-    if (isset($category) && $category== 'search_setting') {
+    if (isset($category) && $category == 'search_setting') {
         if (!empty($_REQUEST['search_field'])) {
             $settings = searchSetting($_REQUEST['search_field']);
         }

+ 2 - 2
main/admin/skill.php

@@ -88,7 +88,7 @@ switch ($action) {
 }
 
 $tpl->assign('list', $list);
-
-$contentTemplate = $tpl->fetch('default/admin/skill.tpl');
+$view = $tpl->get_template('admin/skill.tpl');
+$contentTemplate = $tpl->fetch($view);
 $tpl->assign('content', $contentTemplate);
 $tpl->display_one_col_template();

+ 3 - 1
main/admin/skill_badge.php

@@ -38,7 +38,9 @@ $toolbar = Display::toolbarButton(
 
 $tpl = new Template(get_lang('Badges'));
 $tpl->assign('backpack', $backpack);
-$contentTemplate = $tpl->fetch('default/skill/badge.tpl');
+
+$templateName = $tpl->get_template('skill/badge.tpl');
+$contentTemplate = $tpl->fetch($templateName);
 
 $tpl->assign('actions', $toolbar);
 $tpl->assign('content', $contentTemplate);

+ 2 - 3
main/admin/skill_badge_create.php

@@ -120,9 +120,8 @@ $tpl = new Template(get_lang('CreateBadge'));
 $tpl->assign('platformAdminEmail', api_get_setting('emailAdministrator'));
 $tpl->assign('skill', $skill);
 $tpl->assign('badge_studio', $badgeStudio);
-
-$contentTemplate = $tpl->fetch('default/skill/badge_create.tpl');
-
+$templateName = $tpl->get_template('skill/badge_create.tpl');
+$contentTemplate = $tpl->fetch($templateName);
 $tpl->assign('actions', $toolbar);
 $tpl->assign('content', $contentTemplate);
 $tpl->display_one_col_template();

+ 2 - 2
main/admin/skill_badge_list.php

@@ -50,8 +50,8 @@ $toolbar = Display::toolbarButton(
 $tpl = new Template(get_lang('Skills'));
 $tpl->assign('errorMessage', $errorMessage);
 $tpl->assign('skills', $skills);
-
-$contentTemplate = $tpl->fetch('default/skill/badge_list.tpl');
+$templateName = $tpl->get_template('skill/badge_list.tpl');
+$contentTemplate = $tpl->fetch($templateName);
 
 $tpl->assign('actions', $toolbar);
 $tpl->assign('content', $contentTemplate);

+ 2 - 2
main/admin/skill_level.php

@@ -106,7 +106,7 @@ switch ($action) {
 }
 
 $tpl->assign('list', $list);
-
-$contentTemplate = $tpl->fetch('default/admin/skill_level.tpl');
+$templateName = $tpl->get_template('admin/skill_level.tpl');
+$contentTemplate = $tpl->fetch($templateName);
 $tpl->assign('content', $contentTemplate);
 $tpl->display_one_col_template();

+ 2 - 2
main/admin/skill_list.php

@@ -176,8 +176,8 @@ switch ($action) {
         $tpl->assign('skills', $skillList);
         $tpl->assign('current_tag_id', $extraFieldSearchTagId);
         $tpl->assign('tags', $tags);
-
-        $content = $tpl->fetch('default/skill/list.tpl');
+        $templateName = $tpl->get_template('skill/list.tpl');
+        $content = $tpl->fetch($templateName);
 
         $tpl->assign('actions', $toolbar);
         $tpl->assign('content', $content);

+ 2 - 2
main/admin/skill_profile.php

@@ -116,7 +116,7 @@ switch ($action) {
 }
 
 $tpl->assign('list', $list);
-
-$contentTemplate = $tpl->fetch('default/admin/skill_profile.tpl');
+$templateName = $tpl->get_template('admin/skill_profile.tpl');
+$contentTemplate = $tpl->fetch($templateName);
 $tpl->assign('content', $contentTemplate);
 $tpl->display_one_col_template();

+ 2 - 2
main/admin/skills.php

@@ -35,7 +35,7 @@ $tpl->assign('url', $url);
 $tpl->assign('html', $html);
 $tpl->assign('skill_visualizer', $skill_visualizer);
 $tpl->assign('js', $skill_visualizer->return_js());
-
-$content = $tpl->fetch('default/skill/skill_tree.tpl');
+$templateName = $tpl->get_template('skill/skill_tree.tpl');
+$content = $tpl->fetch($templateName);
 $tpl->assign('content', $content);
 $tpl->display_no_layout_template();

+ 3 - 2
main/admin/skills_profile.php

@@ -143,9 +143,10 @@ foreach ($total_skills_to_search as $skill_info) {
 
 $tpl->assign('skill_list', $skill_list);
 $tpl->assign('search_skill_list', $skills);
-$form_to_html = $form->return_form();
+$form_to_html = $form->returnForm();
 $tpl->assign('form', $form_to_html);
 $tpl->assign('url', $url);
-$content = $tpl->fetch('default/skill/profile.tpl');
+$templateName = $tpl->get_template('skill/profile.tpl');
+$content = $tpl->fetch($templateName);
 $tpl->assign('content', $content);
 $tpl->display_one_col_template();

+ 2 - 2
main/admin/skills_wheel.php

@@ -70,7 +70,7 @@ $saveProfileForm->addHidden('profile_id', null);
 $saveProfileForm->addText('name', get_lang('Name'), true, ['id' => 'name_profile']);
 $saveProfileForm->addTextarea('description', get_lang('Description'), ['id' => 'description_profile', 'rows' => 6]);
 $tpl->assign('saveProfileForm', $saveProfileForm->returnForm());
-
-$content = $tpl->fetch('default/skill/skill_wheel.tpl');
+$templateName = $tpl->get_template('skill/skill_wheel.tpl');
+$content = $tpl->fetch($templateName);
 $tpl->assign('content', $content);
 $tpl->display_no_layout_template();

+ 12 - 15
main/admin/teacher_time_report.php

@@ -368,25 +368,22 @@ $form->setDefaults([
 ]);
 
 $tpl = new Template($toolName);
-$tpl->assign('reportTitle', $reportTitle);
-$tpl->assign('reportSubTitle', $reportSubTitle);
-
-$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('report_title', $reportTitle);
+$tpl->assign('report_sub_title', $reportSubTitle);
+$tpl->assign('selected_course', $selectedCourse);
+$tpl->assign('selected_session', $selectedSession);
+$tpl->assign('selected_teacher', $selectedTeacher);
+$tpl->assign('selected_from', $selectedFrom);
+$tpl->assign('selected_until', $selectedUntil);
+$tpl->assign('with_filter', $withFilter);
 $tpl->assign('courses', $courseList);
 $tpl->assign('sessions', $sessionsList);
-$tpl->assign('courseCoaches', $teacherList);
-
+//$tpl->assign('courseCoaches', $teacherList);
 $tpl->assign('form', $form->returnForm());
-
 $tpl->assign('rows', $timeReport->data);
 
-$contentTemplate = $tpl->fetch('default/admin/teacher_time_report.tpl');
+$templateName = $tpl->get_template('admin/teacher_time_report.tpl');
+
+$contentTemplate = $tpl->fetch($templateName);
 $tpl->assign('content', $contentTemplate);
 $tpl->display_one_col_template();

+ 4 - 3
main/admin/teachers_time_by_session_report.php

@@ -3,6 +3,7 @@
 
 use \Chamilo\CoreBundle\Entity\Session;
 use \Doctrine\Common\Collections\Criteria;
+use \Chamilo\CourseBundle\Entity\Repository\CStudentPublicationRepository;
 
 /**
  * Generate a teacher time report in platform by session only
@@ -79,9 +80,9 @@ if ($session) {
                 continue;
             }
 
-            $works = $em
-                ->getRepository('ChamiloCourseBundle:CStudentPublication')
-                ->findWorksByTeacher($user, $course, $session);
+            /** @var \Chamilo\CourseBundle\Entity\Repository\CStudentPublicationRepository $studentPubRepo */
+            $studentPubRepo = $em->getRepository('ChamiloCourseBundle:CStudentPublication');
+            $works = $studentPubRepo->findWorksByTeacher($user, $course, $session);
 
             $usersInfo[$user->getId()][$course->getId() . '_number_of_students'] = $sessionCourse->getNbrUsers();
             $usersInfo[$user->getId()][$course->getId() . '_number_of_works'] = count($works);

+ 2 - 2
main/admin/user_add.php

@@ -126,7 +126,7 @@ $form->addElement('text', 'official_code', get_lang('OfficialCode'), array('size
 $form->applyFilter('official_code', 'html_filter');
 $form->applyFilter('official_code', 'trim');
 // Email
-$form->addElement('text', 'email', get_lang('Email'), array('size' => '40'));
+$form->addElement('text', 'email', get_lang('Email'), array('size' => '40', 'autocomplete' => 'off'));
 $form->addRule('email', get_lang('EmailWrong'), 'email');
 if (api_get_setting('registration', 'email') == 'true') {
     $form->addRule('email', get_lang('EmailWrong'), 'required');
@@ -138,7 +138,7 @@ if (api_get_setting('login_is_email') == 'true') {
 }
 
 // Phone
-$form->addElement('text', 'phone', get_lang('PhoneNumber'));
+$form->addElement('text', 'phone', get_lang('PhoneNumber'), ['autocomplete' => 'off']);
 // Picture
 $form->addFile(
     'picture',

+ 0 - 8
main/admin/user_information.php

@@ -333,14 +333,6 @@ if (count($sessions) > 0) {
             }
         }
 
-        if ($session_item['access_start_date'] == '0000-00-00') {
-            $session_item['access_start_date'] = null;
-        }
-
-        if ($session_item['access_end_date'] == '0000-00-00') {
-            $session_item['access_end_date'] = null;
-        }
-
         $dates = array_filter(
             array($session_item['access_start_date'], $session_item['access_end_date'])
         );

+ 6 - 6
main/admin/user_list.php

@@ -579,21 +579,21 @@ function modify_filter($user_id, $url_params, $row)
     if (api_is_platform_admin() || (api_is_session_admin() && $current_user_status_label == $statusname[STUDENT])) {
         if (!$user_is_anonymous) {
             if (api_global_admin_can_edit_admin($user_id)) {
-                $result .= '<a href="user_list.php?action=login_as&user_id='.$user_id.'&sec_token='.$_SESSION['sec_token'].'">'.Display::return_icon('login_as.png', get_lang('LoginAs')).'</a>&nbsp;&nbsp;';
+                $result .= '<a href="user_list.php?action=login_as&user_id='.$user_id.'&sec_token='.$_SESSION['sec_token'].'">'.Display::return_icon('login_as.png', get_lang('LoginAs')).'</a>&nbsp;';
             } else {
-                $result .= Display::return_icon('login_as_na.png', get_lang('LoginAs')).'&nbsp;&nbsp;';
+                $result .= Display::return_icon('login_as_na.png', get_lang('LoginAs')).'&nbsp;';
             }
         } else {
-            $result .= Display::return_icon('login_as_na.png', get_lang('LoginAs')).'&nbsp;&nbsp;';
+            $result .= Display::return_icon('login_as_na.png', get_lang('LoginAs')).'&nbsp;';
         }
     } else {
-        $result .= Display::return_icon('login_as_na.png', get_lang('LoginAs')).'&nbsp;&nbsp;';
+        $result .= Display::return_icon('login_as_na.png', get_lang('LoginAs')).'&nbsp;';
     }
 
     if ($current_user_status_label != $statusname[STUDENT]) {
-        $result .= Display::return_icon('statistics_na.gif', get_lang('Reporting')).'&nbsp;&nbsp;';
+        $result .= Display::return_icon('statistics_na.gif', get_lang('Reporting')).'&nbsp;';
     } else {
-        $result .= '<a href="../mySpace/myStudents.php?student='.$user_id.'">'.Display::return_icon('statistics.gif', get_lang('Reporting')).'</a>&nbsp;&nbsp;';
+        $result .= '<a href="../mySpace/myStudents.php?student='.$user_id.'">'.Display::return_icon('statistics.gif', get_lang('Reporting')).'</a>&nbsp;';
     }
 
     if (api_is_platform_admin(true)) {

+ 26 - 27
main/announcements/announcements.php

@@ -28,6 +28,18 @@ $current_course_tool = TOOL_ANNOUNCEMENT;
 $this_section = SECTION_COURSES;
 $nameTools = get_lang('ToolAnnouncement');
 
+$allowToEdit = (
+    api_is_allowed_to_edit(false, true) ||
+    (api_get_course_setting('allow_user_edit_announcement') && !api_is_anonymous())
+);
+
+$sessionId = api_get_session_id();
+$drhHasAccessToSessionContent = api_get_configuration_value('drh_can_access_all_session_content');
+
+if (!empty($sessionId) && $drhHasAccessToSessionContent) {
+    $allowToEdit = $allowToEdit || api_is_drh();
+}
+
 /* ACCESS RIGHTS */
 api_protect_course_script(true);
 
@@ -53,6 +65,10 @@ $_course = api_get_course_info_by_id($course_id);
 $group_id = api_get_group_id();
 $sessionId = api_get_session_id();
 
+if (!empty($group_id)) {
+    $group_properties = GroupManager:: get_group_properties($group_id);
+}
+
 api_protect_course_group(GroupManager::GROUP_TOOL_ANNOUNCEMENT);
 
 /*	Tracking	*/
@@ -197,17 +213,15 @@ switch ($action) {
                 'width' => '150',
                 'align' => 'left',
                 //'formatter' => 'action_formatter',
-                'sortable' => 'false',
-            ),
+                'sortable' => 'false'
+            )
         );
 
         // Autowidth
         $extra_params['autowidth'] = 'true';
         // height auto
         $extra_params['height'] = 'auto';
-
         $editOptions = '';
-
         if (api_is_allowed_to_edit()) {
             $extra_params['multiselect'] = true;
             $editOptions = '
@@ -242,10 +256,7 @@ switch ($action) {
 
         if (empty($count)) {
             $html = '';
-            if ((api_is_allowed_to_edit(false, true) ||
-                    (api_get_course_setting('allow_user_edit_announcement') && !api_is_anonymous())) &&
-                (empty($_GET['origin']) || $_GET['origin'] !== 'learnpath')
-            ) {
+            if ($allowToEdit && (empty($_GET['origin']) or $_GET['origin'] !== 'learnpath')) {
                 $html .= '<div id="no-data-view">';
                 $html .= '<h3>'.get_lang('Announcements').'</h3>';
                 $html .= Display::return_icon('valves.png', '', array(), 64);
@@ -406,12 +417,7 @@ switch ($action) {
                 $announcement_to_modify = '';
             }
 
-            $form->addElement(
-                'checkbox',
-                'email_ann',
-                null,
-                get_lang('EmailOption')
-            );
+            $form->addCheckBox('email_ann', '', get_lang('EmailOption'));
         } else {
             if (!isset($announcement_to_modify)) {
                 $announcement_to_modify = '';
@@ -419,12 +425,7 @@ switch ($action) {
 
             $element = CourseManager::addGroupMultiSelect($form, $group_properties['iid'], array());
             $form->setRequired($element);
-            $form->addElement(
-                'checkbox',
-                'email_ann',
-                null,
-                get_lang('EmailOption')
-            );
+            $form->addCheckBox('email_ann', '', get_lang('EmailOption'));
         }
 
         $announcementInfo = AnnouncementManager::get_by_id($course_id, $id);
@@ -445,6 +446,8 @@ switch ($action) {
             }
         }
 
+        $defaults['email_ann'] = true;
+
         $form->addElement('text', 'title', get_lang('EmailTitle'));
         $form->addElement('hidden', 'id');
         $htmlTags = "<b>".get_lang('Tags')."</b><br /><br />";
@@ -573,16 +576,14 @@ switch ($action) {
 if (!empty($_GET['remind_inactive'])) {
     $to[] = 'USER:'.intval($_GET['remind_inactive']);
 }
-
 if (!empty($group_id)) {
-    $group_properties = GroupManager:: get_group_properties($group_id);
     $interbreadcrumb[] = array(
         "url" => api_get_path(WEB_CODE_PATH)."group/group.php?".api_get_cidreq(),
         "name" => get_lang('Groups'),
     );
     $interbreadcrumb[] = array(
         "url" => api_get_path(WEB_CODE_PATH)."group/group_space.php?".api_get_cidreq(),
-        "name" => get_lang('GroupSpace').' '.$group_properties['name'],
+        "name" => get_lang('GroupSpace').' '.$group_properties['name']
     );
 }
 
@@ -599,9 +600,7 @@ if (empty($_GET['origin']) || $_GET['origin'] !== 'learnpath') {
 // Actions
 $show_actions = false;
 $actionsLeft = '';
-if ((api_is_allowed_to_edit(false, true) ||
-    (api_get_course_setting('allow_user_edit_announcement') && !api_is_anonymous())) &&
-    (empty($_GET['origin']) || $_GET['origin'] !== 'learnpath')
+if ($allowToEdit && (empty($_GET['origin']) || $_GET['origin'] !== 'learnpath')
 ) {
     if (in_array($action, array('add', 'modify', 'view'))) {
         $actionsLeft .= "<a href='".api_get_self()."?".api_get_cidreq()."'>".
@@ -618,7 +617,7 @@ if ((api_is_allowed_to_edit(false, true) ||
     }
 }
 
-if (api_is_allowed_to_edit() && $announcement_number > 1) {
+if ($allowToEdit) {
     if (api_get_group_id() == 0) {
         if (!isset($_GET['action'])) {
             $actionsLeft .= "<a href=\"".api_get_self()."?".api_get_cidreq()."&action=delete_all\" onclick=\"javascript:if(!confirm('".get_lang("ConfirmYourChoice")."')) return false;\">".

+ 5 - 2
main/announcements/download.php

@@ -62,14 +62,17 @@ $doc_url = Database::escape_string($doc_url);
 $sql = "SELECT filename FROM $tbl_announcement_attachment
   	  	WHERE c_id = $course_id AND path LIKE BINARY '$doc_url'";
 
-$result= Database::query($sql);
+$result = Database::query($sql);
 if (Database::num_rows($result) > 0) {
     $row= Database::fetch_array($result);
     $title = str_replace(' ','_', $row['filename']);
     if (Security::check_abs_path($full_file_name,
         api_get_path(SYS_COURSE_PATH) . api_get_course_path() . '/upload/announcements/')
     ) {
-        DocumentManager::file_send_for_download($full_file_name, true, $title);
+        $result = DocumentManager::file_send_for_download($full_file_name, true, $title);
+        if ($result === false) {
+            api_not_allowed(true);
+        }
     }
 }
 exit;

+ 1 - 1
main/auth/external_login/ldap.inc.php

@@ -182,7 +182,7 @@ function extldap_get_chamilo_user($ldap_user, $cor = null)
                 if (isset($ldap_user[$ldap_field][0])) {
                     $chamilo_user[$chamilo_field] = extldap_purify_string($ldap_user[$ldap_field][0]);
                 } else {
-                    error_log('EXTLDAP WARNING : '.$ldap_field.'[0] field is not set in ldap array');
+                    //error_log('EXTLDAP WARNING : '.$ldap_field.'[0] field is not set in ldap array');
                 }
                 break;
         }

+ 15 - 7
main/auth/external_login/login.ldap.php

@@ -1,5 +1,7 @@
 <?php
 
+use ChamiloSession as Session;
+
 // External login module : LDAP
 /**
  *
@@ -38,24 +40,30 @@
  *
  * */
 
-use ChamiloSession as Session;
-
 require_once dirname(__FILE__) . '/ldap.inc.php';
 require_once dirname(__FILE__) . '/functions.inc.php';
-error_log('Entering login.ldap.php');
+$debug = false;
+if ($debug) {
+    error_log('Entering login.ldap.php');
+}
 $ldap_user = extldap_authenticate($login, $password);
 if ($ldap_user !== false) {
-    error_log('extldap_authenticate works');
+    if ($debug) {
+        error_log('extldap_authenticate works');
+    }
     $chamilo_user = extldap_get_chamilo_user($ldap_user);
     //userid is not on the ldap, we have to use $uData variable from local.inc.php
     $chamilo_user['user_id'] = $uData['user_id'];
-
-    error_log("chamilo_user found user_id: {$uData['user_id']}");
+    if ($debug) {
+        error_log("chamilo_user found user_id: {$uData['user_id']}");
+    }
 
     //Update user info
     if (isset($extldap_config['update_userinfo']) && $extldap_config['update_userinfo']) {
         external_update_user($chamilo_user);
-        error_log("Calling external_update_user");
+        if ($debug) {
+            error_log("Calling external_update_user");
+        }
     }
 
     $loginFailed = false;

+ 9 - 2
main/blog/download.php

@@ -58,12 +58,19 @@ $sql = 'SELECT filename FROM '.$tbl_blogs_attachment.'
 $result = Database::query($sql);
 if (Database::num_rows($result) > 0) {
     $row = Database::fetch_array($result);
-    if (Security::check_abs_path($full_file_name, api_get_path(SYS_COURSE_PATH).api_get_course_path().'/upload/blog/')) {
-        DocumentManager::file_send_for_download(
+    if (Security::check_abs_path(
+        $full_file_name,
+        api_get_path(SYS_COURSE_PATH).api_get_course_path().'/upload/blog/')
+    ) {
+        $result = DocumentManager::file_send_for_download(
             $full_file_name,
             true,
             $row['filename']
         );
+
+        if ($result === false) {
+            api_not_allowed(true);
+        }
     }
 }
 exit;

+ 2 - 8
main/calendar/agenda_js.php

@@ -1,8 +1,6 @@
 <?php
 /* For licensing terms, see /license.txt */
 
-use ChamiloSession as Session;
-
 /**
  * @package chamilo.calendar
  */
@@ -248,11 +246,7 @@ if ($agenda->type === 'course') {
 }
 
 $tpl->assign('form_add', $form->returnForm());
-
-// Loading Agenda template.
-$content = $tpl->fetch('default/agenda/month.tpl');
-
+$templateName = $tpl->get_template('agenda/month.tpl');
+$content = $tpl->fetch($templateName);
 $tpl->assign('content', $content);
-
-// Loading main Chamilo 1 col template
 $tpl->display_one_col_template();

+ 2 - 5
main/calendar/agenda_list.php

@@ -79,10 +79,7 @@ if (api_is_allowed_to_edit()) {
     }
 }
 
-// Loading Agenda template
-$content = $tpl->fetch('default/agenda/event_list.tpl');
-
+$templateName = $tpl->get_template('agenda/event_list.tpl');
+$content = $tpl->fetch($templateName);
 $tpl->assign('content', $content);
-
-// Loading main Chamilo 1 col template
 $tpl->display_one_col_template();

+ 4 - 1
main/calendar/download.php

@@ -82,7 +82,10 @@ if (Database::num_rows($result)) {
         $full_file_name,
         api_get_path(SYS_COURSE_PATH).$course_info['path'].'/upload/calendar/'
     )) {
-        DocumentManager::file_send_for_download($full_file_name, true, $title);
+        $result = DocumentManager::file_send_for_download($full_file_name, true, $title);
+        if ($result === false) {
+            api_not_allowed(true);
+        }
     }
 }
 

+ 6 - 4
main/course_info/delete_course.php

@@ -46,7 +46,9 @@ if (isset($_GET['delete']) && $_GET['delete'] === 'yes') {
         get_lang('Yes').'</a></p>';
 	$interbreadcrumb[] = array('url' => 'maintenance.php', 'name' => get_lang('Maintenance'));
 }
-Display :: display_header($tool_name, 'Settings');
-echo Display::page_header($tool_name);
-Display::display_warning_message($message, false);
-Display :: display_footer();
+
+$tpl = new Template($tool_name);
+
+$tpl->assign('content', Display::return_message($message, 'warning', false));
+$tpl->display_one_col_template();
+

+ 2 - 1
main/coursecopy/import_moodle.php

@@ -59,7 +59,8 @@ $template = new Template($templateName);
 $infoMsg = Display::return_message(get_lang('ImportFromMoodleInstructions'), 'normal', false);
 $template->assign('info_msg', $infoMsg);
 $template->assign('form', $form->returnForm());
-$content = $template->fetch('default/coursecopy/import_moodle.tpl');
+$templateName = $template->get_template('coursecopy/import_moodle.tpl');
+$content = $template->fetch($templateName);
 
 $template->assign('header', $templateName);
 $template->assign('content', $content);

+ 291 - 157
main/cron/import_csv.php

@@ -1,7 +1,7 @@
 <?php
 /* For licensing terms, see /license.txt */
 
-if (PHP_SAPI !='cli') {
+if (PHP_SAPI != 'cli') {
     die('Run this script through the command line or comment this line in the code');
 }
 
@@ -27,7 +27,7 @@ class ImportCsv
         'session' => 'external_session_id',
         'course' => 'external_course_id',
         'user' => 'external_user_id',
-        'calendar_event' => 'external_calendar_event_id'
+        'calendar_event' => 'external_calendar_event_id',
     );
     public $defaultAdminId = 1;
     public $defaultSessionVisibility = 1;
@@ -38,6 +38,8 @@ class ImportCsv
      */
     public $expirationDateInUserCreation = 1;
 
+    public $batchSize = 20;
+
     /**
      * When updating a user the expiration date is set to update date + this value
      * @var int number of years
@@ -107,7 +109,7 @@ class ImportCsv
         if (!empty($files)) {
             foreach ($files as $file) {
                 $fileInfo = pathinfo($file);
-                if ($fileInfo['extension'] == 'csv') {
+                if (isset($fileInfo['extension']) && $fileInfo['extension'] === 'csv') {
                     // Checking teachers_yyyymmdd.csv, courses_yyyymmdd.csv, students_yyyymmdd.csv and sessions_yyyymmdd.csv
                     $parts = explode('_', $fileInfo['filename']);
                     $preMethod = ucwords($parts[1]);
@@ -191,7 +193,12 @@ class ImportCsv
                         echo 'File: '.$file.PHP_EOL;
                         $this->logger->addInfo("Reading file: $file");
                         if ($method == 'importSessions') {
-                            $this->$method($file, true, $teacherBackup, $groupBackup);
+                            $this->$method(
+                                $file,
+                                true,
+                                $teacherBackup,
+                                $groupBackup
+                            );
                         } else {
                             $this->$method($file, true);
                         }
@@ -224,7 +231,12 @@ class ImportCsv
                         $file = $fileInfo['file'];
                         echo 'Static file: '.$file.PHP_EOL;
                         $this->logger->addInfo("Reading static file: $file");
-                        $this->$method($file, true, $teacherBackup, $groupBackup);
+                        $this->$method(
+                            $file,
+                            true,
+                            $teacherBackup,
+                            $groupBackup
+                        );
                     }
                 }
             }
@@ -261,11 +273,13 @@ class ImportCsv
 
         // Create calendar_event extra field extra_external_session_id
         $extraField = new ExtraField('calendar_event');
-        $extraField->save(array(
-            'field_type' => ExtraField::FIELD_TYPE_TEXT,
-            'variable' => $this->extraFieldIdNameList['calendar_event'],
-            'display_text' => 'External calendar event id'
-        ));
+        $extraField->save(
+            array(
+                'field_type' => ExtraField::FIELD_TYPE_TEXT,
+                'variable' => $this->extraFieldIdNameList['calendar_event'],
+                'display_text' => 'External calendar event id',
+            )
+        );
     }
 
     /**
@@ -284,7 +298,9 @@ class ImportCsv
         if ($result) {
             $this->logger->addInfo("Moving file to the treated folder: $file");
         } else {
-            $this->logger->addError("Error - Cant move file to the treated folder: $file");
+            $this->logger->addError(
+                "Error - Cant move file to the treated folder: $file"
+            );
         }
     }
 
@@ -330,12 +346,14 @@ class ImportCsv
 
         $row['teachers'] = array();
         if (isset($row['Teacher']) && !empty($row['Teacher'])) {
+            //$this->logger->addInfo("Teacher list found: ".$row['Teacher']);
             $teachers = explode(',', $row['Teacher']);
             if (!empty($teachers)) {
                 foreach ($teachers as $teacherUserName) {
                     $teacherUserName = trim($teacherUserName);
                     $userInfo = api_get_user_info_from_username($teacherUserName);
                     if (!empty($userInfo)) {
+                        //$this->logger->addInfo("Username found: $teacherUserName");
                         $row['teachers'][] = $userInfo['user_id'];
                     }
                 }
@@ -380,23 +398,27 @@ class ImportCsv
 
         if (!empty($data)) {
             $this->logger->addInfo(count($data)." records found.");
+            $expirationDateOnCreation = api_get_utc_datetime(strtotime("+".intval($this->expirationDateInUserCreation)."years"));
+            $expirationDateOnUpdate = api_get_utc_datetime(strtotime("+".intval($this->expirationDateInUserUpdate)."years"));
+
+            $batchSize = $this->batchSize;
+            $em = Database::getManager();
+            $counter = 1;
             foreach ($data as $row) {
                 $row = $this->cleanUserRow($row);
 
                 $user_id = UserManager::get_user_id_from_original_id(
-                    $row['extra_' . $this->extraFieldIdNameList['user']],
+                    $row['extra_'.$this->extraFieldIdNameList['user']],
                     $this->extraFieldIdNameList['user']
                 );
-                $userInfo  = array();
-                $userInfoByOfficialCode  = null;
+                $userInfo = array();
+                $userInfoByOfficialCode = null;
 
                 if (!empty($user_id)) {
                     $userInfo = api_get_user_info($user_id);
                     $userInfoByOfficialCode = api_get_user_info_from_official_code($row['official_code']);
                 }
 
-                $expirationDate = api_get_utc_datetime(strtotime("+".intval($this->expirationDateInUserCreation)."years"));
-
                 if (empty($userInfo) && empty($userInfoByOfficialCode)) {
                     // Create user
                     $userId = UserManager::create_user(
@@ -411,7 +433,7 @@ class ImportCsv
                         $row['phone'],
                         null, //$row['picture'], //picture
                         $row['auth_source'], // ?
-                        $expirationDate, //'0000-00-00 00:00:00', //$row['expiration_date'], //$expiration_date = '0000-00-00 00:00:00',
+                        $expirationDateOnCreation, //'0000-00-00 00:00:00', //$row['expiration_date'], //$expiration_date = '0000-00-00 00:00:00',
                         1, //active
                         0,
                         null, // extra
@@ -423,12 +445,18 @@ class ImportCsv
                         foreach ($row as $key => $value) {
                             if (substr($key, 0, 6) == 'extra_') {
                                 //an extra field
-                                UserManager::update_extra_field_value($userId, substr($key, 6), $value);
+                                UserManager::update_extra_field_value(
+                                    $userId,
+                                    substr($key, 6),
+                                    $value
+                                );
                             }
                         }
                         $this->logger->addInfo("Teachers - User created: ".$row['username']);
                     } else {
                         $this->logger->addError("Teachers - User NOT created: ".$row['username']." ".$row['firstname']." ".$row['lastname']);
+                        $this->logger->addError(strip_tags(Display::getFlashToString()));
+                        Display::cleanFlashMessages();
                     }
                 } else {
                     if (empty($userInfo)) {
@@ -436,8 +464,6 @@ class ImportCsv
                         continue;
                     }
 
-                    $expirationDate = api_get_utc_datetime(strtotime("+".intval($this->expirationDateInUserUpdate)."years"));
-
                     // Update user
                     $result = UserManager::update_user(
                         $userInfo['user_id'],
@@ -451,7 +477,7 @@ class ImportCsv
                         $userInfo['official_code'],
                         $userInfo['phone'],
                         $userInfo['picture_uri'],
-                        $expirationDate,
+                        $expirationDateOnUpdate,
                         $userInfo['active'],
                         null, //$creator_id = null,
                         0, //$hr_dept_id = 0,
@@ -478,7 +504,15 @@ class ImportCsv
                         $this->logger->addError("Teachers - User not updated: ".$row['username']);
                     }
                 }
+
+                if (($counter % $batchSize) === 0) {
+                    $em->flush();
+                    $em->clear(); // Detaches all objects from Doctrine!
+                }
+                $counter++;
             }
+
+            $em->clear(); // Detaches all objects from Doctrine!
         }
 
         if ($moveFile) {
@@ -515,10 +549,20 @@ class ImportCsv
         So I presume you’ll just update the expiration date.
         We want to grant access to courses up to a year after deletion.
          */
+        $timeStart = microtime(true);
+
+        $batchSize = $this->batchSize;
+        $em = Database::getManager();
 
         if (!empty($data)) {
             $language = $this->defaultLanguage;
             $this->logger->addInfo(count($data)." records found.");
+
+            $expirationDateOnCreate = api_get_utc_datetime(strtotime("+".intval($this->expirationDateInUserCreation)."years"));
+            $expirationDateOnUpdate = api_get_utc_datetime(strtotime("+".intval($this->expirationDateInUserUpdate)."years"));
+
+            $counter = 1;
+
             foreach ($data as $row) {
                 $row = $this->cleanUserRow($row);
                 $user_id = UserManager::get_user_id_from_original_id(
@@ -533,8 +577,6 @@ class ImportCsv
                     $userInfoByOfficialCode = api_get_user_info_from_official_code($row['official_code']);
                 }
 
-                $expirationDate = api_get_utc_datetime(strtotime("+".intval($this->expirationDateInUserCreation)."years"));
-
                 if (empty($userInfo) && empty($userInfoByOfficialCode)) {
                     // Create user
                     $result = UserManager::create_user(
@@ -549,7 +591,7 @@ class ImportCsv
                         $row['phone'],
                         null, //$row['picture'], //picture
                         $row['auth_source'], // ?
-                        $expirationDate, //'0000-00-00 00:00:00', //$row['expiration_date'], //$expiration_date = '0000-00-00 00:00:00',
+                        $expirationDateOnCreate, //'0000-00-00 00:00:00', //$row['expiration_date'], //$expiration_date = '0000-00-00 00:00:00',
                         1, //active
                         0,
                         null, // extra
@@ -559,14 +601,20 @@ class ImportCsv
 
                     if ($result) {
                         foreach ($row as $key => $value) {
-                            if (substr($key, 0, 6) == 'extra_') {
+                            if (substr($key, 0, 6) === 'extra_') {
                                 //an extra field
-                                UserManager::update_extra_field_value($result, substr($key, 6), $value);
+                                UserManager::update_extra_field_value(
+                                    $result,
+                                    substr($key, 6),
+                                    $value
+                                );
                             }
                         }
                         $this->logger->addInfo("Students - User created: ".$row['username']);
                     } else {
                         $this->logger->addError("Students - User NOT created: ".$row['username']." ".$row['firstname']." ".$row['lastname']);
+                        $this->logger->addError(strip_tags(Display::getFlashToString()));
+                        Display::cleanFlashMessages();
                     }
                 } else {
                     if (empty($userInfo)) {
@@ -584,7 +632,6 @@ class ImportCsv
                     $resetPassword = 2; // allow password change
 
                     // Conditions that disables the update of password and email:
-
                     if (isset($this->conditions['importStudents'])) {
                         if (isset($this->conditions['importStudents']['update']) &&
                             isset($this->conditions['importStudents']['update']['avoid'])
@@ -609,19 +656,17 @@ class ImportCsv
                             }
 
                             // Blocking password update
-                            $avoidUsersWithPassword = $this->conditions['importStudents']['update']['avoid']['password'];
+                            //$avoidUsersWithPassword = $this->conditions['importStudents']['update']['avoid']['password'];
 
-                            if (isset($row['password'])) {
+                            /*if (isset($row['password'])) {
                                 $user = api_get_user_entity($userInfo['id']);
                                 $encoded = UserManager::encryptPassword(
                                     $row['password'],
                                     $user
                                 );
 
-                                if ($userInfo['password'] != $encoded && in_array(
-                                        $row['password'],
-                                        $avoidUsersWithPassword
-                                    )
+                                if ($userInfo['password'] != $encoded &&
+                                    in_array($row['password'], $avoidUsersWithPassword)
                                 ) {
                                     $this->logger->addInfo(
                                         "Students - User password is not updated: ".$row['username']." because the avoid conditions (password)."
@@ -629,11 +674,13 @@ class ImportCsv
                                     $password = null;
                                     $resetPassword = 0; // disallow password change
                                 }
-                            }
+                            }*/
                         }
                     }
 
-                    $expirationDate = api_get_utc_datetime(strtotime("+".intval($this->expirationDateInUserUpdate)."years"));
+                    // Always disallow password change during update
+                    $password = null;
+                    $resetPassword = 0; // disallow password change
 
                     // Update user
                     $result = UserManager::update_user(
@@ -648,7 +695,7 @@ class ImportCsv
                         $userInfo['official_code'],
                         $userInfo['phone'],
                         $userInfo['picture_uri'],
-                        $expirationDate,
+                        $expirationDateOnUpdate,
                         $userInfo['active'],
                         null, //$creator_id = null,
                         0, //$hr_dept_id = 0,
@@ -660,12 +707,11 @@ class ImportCsv
                     );
 
                     if ($result) {
-
                         if ($row['username'] != $userInfo['username']) {
                             $this->logger->addInfo("Students - Username was changes from '".$userInfo['username']."' to '".$row['username']."' ");
                         }
                         foreach ($row as $key => $value) {
-                            if (substr($key, 0, 6) == 'extra_') {
+                            if (substr($key, 0, 6) === 'extra_') {
                                 //an extra field
                                 UserManager::update_extra_field_value(
                                     $userInfo['user_id'],
@@ -680,9 +726,21 @@ class ImportCsv
                         $this->logger->addError("Students - User NOT updated: ".$row['username']." ".$row['firstname']." ".$row['lastname']);
                     }
                 }
+
+                if (($counter % $batchSize) === 0) {
+                    $em->flush();
+                    $em->clear(); // Detaches all objects from Doctrine!
+                    $this->logger->addInfo("Detaches all objects");
+                }
+                $counter++;
             }
+            $em->clear(); // Detaches all objects from Doctrine!
         }
 
+        $timeEnd = microtime(true);
+        $executionTime = round(($timeEnd - $timeStart)/60, 2);
+        $this->logger->addInfo("Execution Time for process students: $executionTime Min");
+
         if ($moveFile) {
             $this->moveFile($file);
         }
@@ -698,7 +756,7 @@ class ImportCsv
 
     /**
      * @param string $file
-     * @param bool   $moveFile
+     * @param bool $moveFile
      *
      * @return int
      */
@@ -708,7 +766,7 @@ class ImportCsv
         $data = Import::csvToArray($file);
 
         if (!empty($data)) {
-            $this->logger->addInfo(count($data) . " records found.");
+            $this->logger->addInfo(count($data)." records found.");
             $eventsToCreate = array();
             $errorFound = false;
             foreach ($data as $row) {
@@ -722,7 +780,7 @@ class ImportCsv
                     );
                 }
 
-                $courseCode  = null;
+                $courseCode = null;
                 if (isset($row['coursecode'])) {
                     $courseCode = $row['coursecode'];
                 }
@@ -776,7 +834,7 @@ class ImportCsv
                 }
 
                 $date = $row['date'];
-                $startTime  = $row['time_start'];
+                $startTime = $row['time_start'];
                 $endTime = $row['time_end'];
                 $title = $row['title'];
                 $comment = $row['comment'];
@@ -811,9 +869,10 @@ class ImportCsv
                         'session_id' => $sessionId,
                         'comment' => $comment,
                         'color' => $color,
-                        $this->extraFieldIdNameList['calendar_event'] => $row['external_calendar_itemID']
+                        $this->extraFieldIdNameList['calendar_event'] => $row['external_calendar_itemID'],
                     );
                 }
+                $errorFound = false;
             }
 
             if (empty($eventsToCreate)) {
@@ -835,7 +894,9 @@ class ImportCsv
             $externalEventId = null;
 
             $extraField = new ExtraField('calendar_event');
-            $extraFieldInfo = $extraField->get_handler_field_info_by_field_variable($extraFieldName);
+            $extraFieldInfo = $extraField->get_handler_field_info_by_field_variable(
+                $extraFieldName
+            );
 
             if (empty($extraFieldInfo)) {
                 $this->logger->addInfo(
@@ -989,8 +1050,12 @@ class ImportCsv
      * @param array $teacherBackup
      * @param array $groupBackup
      */
-    private function importCourses($file, $moveFile = true, &$teacherBackup = array(), &$groupBackup = array())
-    {
+    private function importCourses(
+        $file,
+        $moveFile = true,
+        &$teacherBackup = array(),
+        &$groupBackup = array()
+    ) {
         $this->fixCSVFile($file);
         $data = Import::csvToArray($file);
 
@@ -1001,7 +1066,7 @@ class ImportCsv
                 $row = $this->cleanCourseRow($row);
 
                 $courseId = CourseManager::get_course_id_from_original_id(
-                    $row['extra_' . $this->extraFieldIdNameList['course']],
+                    $row['extra_'.$this->extraFieldIdNameList['course']],
                     $this->extraFieldIdNameList['course']
                 );
 
@@ -1017,7 +1082,10 @@ class ImportCsv
                     $params['course_language'] = $row['language'];
                     $params['teachers'] = $row['teachers'];
 
-                    $courseInfo = CourseManager::create_course($params, $this->defaultAdminId);
+                    $courseInfo = CourseManager::create_course(
+                        $params,
+                        $this->defaultAdminId
+                    );
 
                     if (!empty($courseInfo)) {
                         CourseManager::update_course_extra_field_value(
@@ -1051,7 +1119,7 @@ class ImportCsv
 
                     if ($addTeacherToSession) {
                         CourseManager::updateTeachers(
-                            $courseInfo['id'],
+                            $courseInfo,
                             $row['teachers'],
                             false,
                             true,
@@ -1060,9 +1128,9 @@ class ImportCsv
                         );
                     } else {
                         CourseManager::updateTeachers(
-                            $courseInfo['id'],
+                            $courseInfo,
                             $row['teachers'],
-                            false,
+                            true,
                             false,
                             false,
                             $teacherBackup
@@ -1118,7 +1186,8 @@ class ImportCsv
     {
         $data = Import::csv_reader($file);
         if (!empty($data)) {
-            $this->logger->addInfo(count($data) . " records found.");
+            $this->logger->addInfo(count($data)." records found.");
+            $userIdList = [];
             foreach ($data as $row) {
                 $chamiloUserName = $row['UserName'];
                 $chamiloCourseCode = $row['CourseCode'];
@@ -1169,19 +1238,26 @@ class ImportCsv
                         );
                         break;
                     case 'drh':
+                        $removeAllSessionsFromUser = true;
+
+                        if (in_array($userId, $userIdList)) {
+                            $removeAllSessionsFromUser = false;
+                        } else {
+                            $userIdList[] = $userId;
+                        }
+
                         $userInfo = api_get_user_info($userId);
-                        SessionManager::suscribe_sessions_to_hr_manager(
+                        SessionManager::subscribeSessionsToDrh(
                             $userInfo,
                             [$chamiloSessionId],
                             false,
-                            false
+                            $removeAllSessionsFromUser
                         );
-
                         break;
                 }
 
                 $this->logger->addError(
-                    "User '$chamiloUserName' was added as '$status' to Session: #$chamiloSessionId - Course: " . $courseInfo['code']
+                    "User '$chamiloUserName' was added as '$status' to Session: #$chamiloSessionId - Course: ".$courseInfo['code']
                 );
 
             }
@@ -1196,7 +1272,7 @@ class ImportCsv
         $data = Import::csv_reader($file);
 
         if (!empty($data)) {
-            $this->logger->addInfo(count($data) . " records found.");
+            $this->logger->addInfo(count($data)." records found.");
             foreach ($data as $row) {
                 $chamiloUserName = $row['UserName'];
                 $chamiloCourseCode = $row['CourseCode'];
@@ -1255,7 +1331,7 @@ class ImportCsv
         $data = Import::csv_reader($file);
 
         if (!empty($data)) {
-            $this->logger->addInfo(count($data) . " records found.");
+            $this->logger->addInfo(count($data)." records found.");
             foreach ($data as $row) {
                 $chamiloUserName = $row['UserName'];
                 $chamiloCourseCode = $row['CourseCode'];
@@ -1323,40 +1399,36 @@ class ImportCsv
     {
         $content = file($file);
         $sessions = array();
-
-        if (!api_strstr($content[0], ';')) {
-            $error_message = get_lang('NotCSV');
-        } else {
-            $tag_names = array();
-
-            foreach ($content as $key => $enreg) {
-                $enreg = explode(';', trim($enreg));
-                if ($key) {
-                    foreach ($tag_names as $tag_key => $tag_name) {
-                        if (isset($enreg[$tag_key])) {
-                            $sessions[$key - 1][$tag_name] = $enreg[$tag_key];
-                        }
-                    }
-                } else {
-                    foreach ($enreg as $tag_name) {
-                        $tag_names[] = api_preg_replace(
-                            '/[^a-zA-Z0-9_\-]/',
-                            '',
-                            $tag_name
-                        );
-                    }
-                    if (!in_array('SessionName', $tag_names) || !in_array(
-                            'DateStart',
-                            $tag_names
-                        ) || !in_array('DateEnd', $tag_names)
-                    ) {
-                        $error_message = get_lang('NoNeededData');
-                        break;
+        $tag_names = array();
+
+        foreach ($content as $key => $enreg) {
+            $enreg = explode(';', trim($enreg));
+            if ($key) {
+                foreach ($tag_names as $tag_key => $tag_name) {
+                    if (isset($enreg[$tag_key])) {
+                        $sessions[$key - 1][$tag_name] = $enreg[$tag_key];
                     }
                 }
+            } else {
+                foreach ($enreg as $tag_name) {
+                    $tag_names[] = api_preg_replace(
+                        '/[^a-zA-Z0-9_\-]/',
+                        '',
+                        $tag_name
+                    );
+                }
+                if (!in_array('SessionName', $tag_names) || !in_array(
+                        'DateStart',
+                        $tag_names
+                    ) || !in_array('DateEnd', $tag_names)
+                ) {
+                    $error_message = get_lang('NoNeededData');
+                    break;
+                }
             }
         }
 
+
         if (!empty($sessions)) {
             // Looping the sessions.
             foreach ($sessions as $session) {
@@ -1414,6 +1486,7 @@ class ImportCsv
 
                         if (is_numeric($result)) {
                             $sessionId = $result;
+                            $this->logger->addInfo("Session #$sessionId created: ".$session['SessionName']);
                             SessionManager::update_session_extra_field_value(
                                 $sessionId,
                                 $this->extraFieldIdNameList['session'],
@@ -1461,6 +1534,7 @@ class ImportCsv
                         );
 
                         if (is_numeric($result)) {
+                            $this->logger->addInfo("Session #$sessionId updated: ".$session['SessionName']);
                             $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
                             $params = array(
                                 'description' => $session['SessionDescription']
@@ -1473,79 +1547,104 @@ class ImportCsv
                         }
                     }
 
-                    // Courses
-                    $courses = explode('|', $session['Courses']);
-                    $courseList = array();
-                    foreach ($courses as $course) {
-                        $courseArray = bracketsToArray($course);
-                        $courseCode = $courseArray[0];
-                        if (CourseManager::course_exists($courseCode)) {
-                            $courseInfo = api_get_course_info($courseCode);
-                            $courseList[] = $courseInfo['real_id'];
-                        }
-                    }
-
-                    SessionManager::add_courses_to_session(
-                        $sessionId,
-                        $courseList,
-                        true
-                    );
-
                     if (!empty($sessionId)) {
+                        // Courses
                         $courses = explode('|', $session['Courses']);
+                        $courseList = [];
+                        $courseListWithCoach = [];
                         foreach ($courses as $course) {
                             $courseArray = bracketsToArray($course);
                             $courseCode = $courseArray[0];
                             if (CourseManager::course_exists($courseCode)) {
-                                // Coaches
+                                $courseInfo = api_get_course_info($courseCode);
+                                $courseList[] = $courseInfo['real_id'];
+                                // Extracting course coaches
                                 $courseCoaches = isset($courseArray[1]) ? $courseArray[1] : null;
                                 $courseCoaches = explode(',', $courseCoaches);
 
-                                if (!empty($courseCoaches)) {
-                                    $coachList = array();
-                                    foreach ($courseCoaches as $courseCoach) {
-                                        $courseCoachId = UserManager::get_user_id_from_username($courseCoach);
-                                        if ($courseCoachId !== false) {
-                                            // Just insert new coaches
-                                            $coachList[] = $courseCoachId;
-                                        }
-                                    }
-                                    SessionManager::updateCoaches(
-                                        $sessionId,
-                                        $courseCode,
-                                        $coachList,
-                                        true
-                                    );
-                                }
-
-                                // Students
+                                // Extracting students
                                 $courseUsers = isset($courseArray[2]) ? $courseArray[2] : null;
                                 $courseUsers = explode(',', $courseUsers);
-                                if (!empty($courseUsers)) {
-                                    $userList = array();
-                                    foreach ($courseUsers as $username) {
-                                        $userInfo = api_get_user_info_from_username(trim($username));
-                                        if (!empty($userInfo)) {
-                                            $userList[] = $userInfo['user_id'];
-                                        }
-                                    }
 
-                                    SessionManager::subscribe_users_to_session_course(
-                                        $userList,
-                                        $sessionId,
-                                        $courseCode,
-                                        SESSION_VISIBLE_READ_ONLY,
-                                        true
+                                $courseListWithCoach[] = [
+                                    'course_info' => $courseInfo,
+                                    'coaches' => $courseCoaches,
+                                    'course_users' => $courseUsers
+                                ];
+                            }
+                        }
+
+                        SessionManager::add_courses_to_session(
+                            $sessionId,
+                            $courseList,
+                            true
+                        );
+
+                        $this->logger->addInfo("Session #$sessionId: Courses added: '".implode(', ', $courseList)."'");
+
+                        if (empty($courseListWithCoach)) {
+                            $this->logger->addInfo("No users/coaches to update");
+                            continue;
+                        }
+
+                        foreach ($courseListWithCoach as $courseData) {
+                            $courseInfo = $courseData['course_info'];
+                            $courseCode = $courseInfo['code'];
+                            $courseId = $courseInfo['real_id'];
+                            $courseCoaches = $courseData['coaches'];
+                            $courseUsers = $courseData['course_users'];
+
+                            // Coaches
+                            if (!empty($courseCoaches)) {
+                                $coachList = array();
+                                foreach ($courseCoaches as $courseCoach) {
+                                    $courseCoachId = UserManager::get_user_id_from_username(
+                                        $courseCoach
                                     );
-                                } else {
-                                    $this->logger->addInfo("No users to register.");
+                                    if ($courseCoachId !== false) {
+                                        // Just insert new coaches
+                                        $coachList[] = $courseCoachId;
+                                    }
                                 }
+
+                                $this->logger->addInfo("Session #$sessionId: course '$courseCode' coaches added: '".implode(', ', $coachList)."'");
+
+                                SessionManager::updateCoaches(
+                                    $sessionId,
+                                    $courseId,
+                                    $coachList,
+                                    true
+                                );
                             } else {
-                                $this->logger->addInfo("Course does not exists $courseCode");
+                                $this->logger->addInfo("No coaches added");
+                            }
+
+                            // Students
+                            if (!empty($courseUsers)) {
+                                $userList = array();
+                                foreach ($courseUsers as $username) {
+                                    $userInfo = api_get_user_info_from_username(trim($username));
+                                    if (!empty($userInfo)) {
+                                        $userList[] = $userInfo['user_id'];
+                                    }
+                                }
+
+                                $this->logger->addInfo("Session #$sessionId: course '$courseCode': Students added '".implode(', ', $userList)."'");
+                                SessionManager::subscribe_users_to_session_course(
+                                    $userList,
+                                    $sessionId,
+                                    $courseCode,
+                                    SESSION_VISIBLE_READ_ONLY,
+                                    true
+                                );
+                            } else {
+                                $this->logger->addInfo("No users to register.");
                             }
                         }
                     } else {
-                        $this->logger->addInfo('SessionID not found in system.');
+                        $this->logger->addInfo(
+                            'SessionID not found in system.'
+                        );
                     }
                 } else {
                     $this->logger->addInfo('SessionID does not exists');
@@ -1558,13 +1657,17 @@ class ImportCsv
 
     /**
      * @param string $file
-     * @param bool   $moveFile
+     * @param bool $moveFile
      * @param array $teacherBackup
      * @param array $groupBackup
      */
-    private function importSessions($file, $moveFile = true, &$teacherBackup = array(), &$groupBackup = array())
-    {
-        $avoid =  null;
+    private function importSessions(
+        $file,
+        $moveFile = true,
+        &$teacherBackup = array(),
+        &$groupBackup = array()
+    ) {
+        $avoid = null;
         if (isset($this->conditions['importSessions']) &&
             isset($this->conditions['importSessions']['update'])
         ) {
@@ -1681,19 +1784,31 @@ class ImportCsv
                 $courseInfo = api_get_course_info($chamiloCourseCode);
 
                 if (empty($courseInfo)) {
-                    $this->logger->addError('Course does not exists: '.$chamiloCourseCode);
+                    $this->logger->addError(
+                        'Course does not exists: '.$chamiloCourseCode
+                    );
                     continue;
                 }
 
-                $userId = UserManager::get_user_id_from_username($chamiloUserName);
+                $userId = UserManager::get_user_id_from_username(
+                    $chamiloUserName
+                );
 
                 if (empty($userId)) {
-                    $this->logger->addError('User does not exists: '.$chamiloUserName);
+                    $this->logger->addError(
+                        'User does not exists: '.$chamiloUserName
+                    );
                     continue;
                 }
 
-                CourseManager::subscribe_user($userId, $courseInfo['code'], $status);
-                $this->logger->addInfo("User $userId added to course $chamiloCourseCode as $status");
+                CourseManager::subscribe_user(
+                    $userId,
+                    $courseInfo['code'],
+                    $status
+                );
+                $this->logger->addInfo(
+                    "User $userId added to course $chamiloCourseCode as $status"
+                );
             }
         }
     }
@@ -1701,8 +1816,12 @@ class ImportCsv
     /**
      * @param string $file
      */
-    private function importUnsubscribeStatic($file, $moveFile = false, &$teacherBackup = array(), &$groupBackup = array())
-    {
+    private function importUnsubscribeStatic(
+        $file,
+        $moveFile = false,
+        &$teacherBackup = array(),
+        &$groupBackup = array()
+    ) {
         $data = Import::csv_reader($file);
 
         if (!empty($data)) {
@@ -1742,7 +1861,9 @@ class ImportCsv
                 $userCourseData = Database::fetch_array($result, 'ASSOC');
                 $teacherBackup[$userId][$courseInfo['code']] = $userCourseData;
 
-                $sql = "SELECT * FROM ".Database::get_course_table(TABLE_GROUP_USER)."
+                $sql = "SELECT * FROM ".Database::get_course_table(
+                        TABLE_GROUP_USER
+                    )."
                         WHERE
                             user_id = ".$userId." AND
                             c_id = '".$courseInfo['real_id']."'
@@ -1886,6 +2007,11 @@ class ImportCsv
             Database::query($sql);
             echo $sql.PHP_EOL;
         }
+
+        $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
+        $sql = "DELETE FROM $table WHERE tool = 'calendar_event'";
+        Database::query($sql);
+        echo $sql.PHP_EOL;
     }
 
     /**
@@ -1894,7 +2020,7 @@ class ImportCsv
      */
     private function fixCSVFile($file)
     {
-        $f = fopen($file, 'r+');
+        /*$f = fopen($file, 'r+');
         $cursor = -1;
 
         fseek($f, $cursor, SEEK_END);
@@ -1907,7 +2033,7 @@ class ImportCsv
         if ($char === "\"") {
             fseek($f, -1, SEEK_CUR);
             fwrite($f, '";');
-        }
+        }*/
     }
 }
 
@@ -1935,7 +2061,10 @@ if (!empty($emails)) {
     }
 }*/
 
-$stream = new StreamHandler(api_get_path(SYS_ARCHIVE_PATH).'import_csv.log', $minLevel);
+$stream = new StreamHandler(
+    api_get_path(SYS_ARCHIVE_PATH).'import_csv.log',
+    $minLevel
+);
 $logger->pushHandler(new BufferHandler($stream, 0, $minLevel));
 $logger->pushHandler(new RotatingFileHandler('import_csv', 5, $minLevel));
 
@@ -1970,8 +2099,13 @@ if (isset($_configuration['import_csv_test'])) {
     $import->test = true;
 }
 
+$timeStart = microtime(true);
 $import->run();
 
+$timeEnd = microtime(true);
+$executionTime = round(($timeEnd - $timeStart) / 60, 2);
+$logger->addInfo("Total execution Time $executionTime Min");
+
 if (isset($_configuration['import_csv_fix_permissions']) &&
     $_configuration['import_csv_fix_permissions'] == true
 ) {

+ 24 - 9
main/document/create_document.php

@@ -98,10 +98,15 @@ if (!empty($sessionId) && empty($document_data)) {
         $sessionId
     );
 }
+$groupIid = 0;
+
+if (!empty($groupId)) {
+    $group_properties = GroupManager::get_group_properties($groupId);
+    $groupIid = $group_properties['iid'];
+}
 
 if (empty($document_data)) {
     if (api_is_in_group()) {
-        $group_properties = GroupManager::get_group_properties($groupId);
         $document_id = DocumentManager::get_document_id($_course, $group_properties['directory']);
         $document_data = DocumentManager::get_document_data_by_id($document_id, api_get_course_id());
         $dir = $document_data['path'];
@@ -191,7 +196,6 @@ if (!is_dir($filepath)) {
 }
 
 $to_group_id = 0;
-
 if (!$is_certificate_mode) {
 	if (api_is_in_group()) {
         $interbreadcrumb[] = array(
@@ -199,7 +203,7 @@ if (!$is_certificate_mode) {
             "name" => get_lang('GroupSpace'),
         );
 		$noPHP_SELF = true;
-		$to_group_id = api_get_group_id();
+		$to_group_id = $group_properties['iid'];
 		$path = explode('/', $dir);
 		if ('/'.$path[1] != $group_properties['directory']) {
 			api_not_allowed(true);
@@ -300,7 +304,11 @@ $current_session_id = api_get_session_id();
 $form->addHtmlEditor('content', get_lang('Content'), true, true, $editorConfig, true);
 
 // Comment-field
-$folders = DocumentManager::get_all_document_folders($_course, $to_group_id, $is_allowed_to_edit);
+$folders = DocumentManager::get_all_document_folders(
+    $_course,
+    $groupIid,
+    $is_allowed_to_edit
+);
 
 // If we are not in the certificates creation, display a folder chooser for the
 // new document created
@@ -308,13 +316,20 @@ $folders = DocumentManager::get_all_document_folders($_course, $to_group_id, $is
 if (!$is_certificate_mode &&
 	!DocumentManager::is_my_shared_folder($userId, $dir, $current_session_id)
 ) {
-	$folders = DocumentManager::get_all_document_folders($_course, $to_group_id, $is_allowed_to_edit);
+    $folders = DocumentManager::get_all_document_folders(
+        $_course,
+        $groupIid,
+        $is_allowed_to_edit
+    );
 
-	//$parent_select = $form->addElement('select', 'curdirpath', array(null, get_lang('DestinationDirectory')));
-        $parent_select = $form->addSelect('curdirpath', get_lang('DestinationDirectory'),null, array('cols-size' => [2, 10, 0]) );
-	// Following two conditions copied from document.inc.php::build_directory_selector()
-	$folder_titles = array();
+    $parent_select = $form->addSelect(
+        'curdirpath',
+        get_lang('DestinationDirectory'),
+        null,
+        array('cols-size' => [2, 10, 0])
+    );
 
+	$folder_titles = array();
     if (is_array($folders)) {
         $escaped_folders = array();
         foreach ($folders as $key => & $val) {

+ 5 - 2
main/document/document.php

@@ -315,7 +315,10 @@ switch ($action) {
         }
         $full_file_name = $base_work_dir.$document_data['path'];
         if (Security::check_abs_path($full_file_name, $base_work_dir.'/')) {
-            DocumentManager::file_send_for_download($full_file_name, true);
+            $result = DocumentManager::file_send_for_download($full_file_name, true);
+            if ($result === false) {
+                api_not_allowed(true);
+            }
         }
         exit;
         break;
@@ -1303,7 +1306,7 @@ if ($is_allowed_to_edit ||
                 $courseInfo,
                 api_get_user_id(),
                 $sessionId,
-                $groupIid,
+                $groupId,
                 $to_user_id,
                 $base_work_dir,
                 $dir_name,

+ 1 - 1
main/document/document_quota.php

@@ -76,7 +76,7 @@ if (!empty($group_list)) {
         $session[] = array(addslashes(get_lang('Group').': '.$group_data['name']).' ('.format_file_size($quota_bytes).')', $quota_percentage);
     }
 }
-//Showing weight of documents uploaded by user
+// Showing weight of documents uploaded by user
 $document_list = DocumentManager::get_all_document_data($_course);
 if (is_array($document_list)) {
     foreach ($document_list as $document_data) {

+ 5 - 2
main/document/download.php

@@ -59,10 +59,10 @@ if (substr($refer_script, 0, 15) == '/fillsurvey.php') {
         $document_explorer = api_get_path(WEB_CODE_PATH).'document/document.php?curdirpath='.urlencode($doc_url).'&'.api_get_cidreq_params(Security::remove_XSS($_GET['cidReq'], 0, $gid_req));
         // Redirect
         header('Location: '.$document_explorer);
+        exit;
     }
 }
 
-
 //Fixes swf upload problem in chamilo 1.8.x. When uploading a file with
 //the character "-" the filename was changed from "-" to "_" in the DB for no reason
 $path_info = pathinfo($doc_url);
@@ -101,6 +101,9 @@ if (Security::check_abs_path($sys_course_path.$doc_url, $sys_course_path.'/')) {
     // Launch event
     Event::event_download($doc_url);
     $download = (!empty($_GET['dl']) ? true : false);
-    DocumentManager::file_send_for_download($full_file_name, $download);
+    $result = DocumentManager::file_send_for_download($full_file_name, $download);
+    if ($result === false) {
+        api_not_allowed(true);
+    }
 }
 exit;

+ 4 - 1
main/document/download_scorm.php

@@ -55,6 +55,9 @@ if (Security::check_abs_path($sys_course_path.$doc_url, $sys_course_path.'/')) {
     Event::event_download($doc_url);
 
     $fixLinks = api_get_configuration_value('lp_replace_http_to_https');
-    DocumentManager::file_send_for_download($full_file_name, false, '', $fixLinks);
+    $result = DocumentManager::file_send_for_download($full_file_name, false, '', $fixLinks);
+    if ($result === false) {
+        api_not_allowed(true);
+    }
 }
 exit;

+ 3 - 0
main/document/downloadfolder.inc.php

@@ -314,6 +314,9 @@ $name = ($path == '/') ? 'documents.zip' : $documentInfo['title'].'.zip';
 
 if (Security::check_abs_path($tempZipFile, api_get_path(SYS_ARCHIVE_PATH))) {
     $result = DocumentManager::file_send_for_download($tempZipFile, true, $name);
+    if ($result === false) {
+        api_not_allowed(true);
+    }
     @unlink($tempZipFile);
     exit;
 } else {

+ 7 - 2
main/document/edit_odf.php

@@ -20,8 +20,13 @@ if ($document_id) {
 }
 
 //Check user visibility
-//$is_visible = DocumentManager::is_visible_by_id($document_id, $course_info, api_get_session_id(), api_get_user_id());
-$is_visible = DocumentManager::check_visibility_tree($document_id, api_get_course_id(), api_get_session_id(), api_get_user_id(), api_get_group_id());
+$is_visible = DocumentManager::check_visibility_tree(
+    $document_id,
+    api_get_course_id(),
+    api_get_session_id(),
+    api_get_user_id(),
+    api_get_group_id()
+);
 
 if (!api_is_allowed_to_edit() && !$is_visible) {
     api_not_allowed(true);

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