ソースを参照

Partial merge with 1.11.x see BT#15952

Julio Montoya 5 年 前
コミット
f5dfcef3a1
100 ファイル変更2655 行追加2026 行削除
  1. 2 9
      main/lp/aicc.class.php
  2. 0 7
      main/lp/aicc_hacp.php
  3. 1 0
      main/lp/download.php
  4. 2 0
      main/lp/embed.php
  5. 199 192
      main/lp/learnpath.class.php
  6. 102 343
      main/lp/learnpathItem.class.php
  7. 15 22
      main/lp/learnpathList.class.php
  8. 9 13
      main/lp/lp_add.php
  9. 17 11
      main/lp/lp_add_audio.php
  10. 1 1
      main/lp/lp_add_category.php
  11. 1 2
      main/lp/lp_add_item.php
  12. 2 0
      main/lp/lp_ajax_initialize.php
  13. 21 10
      main/lp/lp_ajax_save_item.php
  14. 58 2
      main/lp/lp_ajax_switch_item.php
  15. 58 128
      main/lp/lp_controller.php
  16. 8 13
      main/lp/lp_edit.php
  17. 31 64
      main/lp/lp_final_item.php
  18. 1 1
      main/lp/lp_impress.php
  19. 145 199
      main/lp/lp_list.php
  20. 0 1
      main/lp/lp_save.php
  21. 2 2
      main/lp/lp_stats.php
  22. 15 2
      main/lp/lp_upload.php
  23. 54 10
      main/lp/lp_view.php
  24. 0 4
      main/lp/openoffice_document.class.php
  25. 0 3
      main/lp/openoffice_presentation.class.php
  26. 9 2
      main/lp/scorm.class.php
  27. 0 3
      main/lp/scormItem.class.php
  28. 38 11
      main/lp/scorm_api.php
  29. 6 1
      main/messages/download.php
  30. 11 16
      main/messages/inbox.php
  31. 13 20
      main/messages/new_message.php
  32. 0 3
      main/messages/outbox.php
  33. 0 2
      main/messages/view_message.php
  34. 7 6
      main/mySpace/access_details.php
  35. 5 3
      main/mySpace/admin_view.php
  36. 1 1
      main/mySpace/company_reports.php
  37. 7 15
      main/mySpace/index.php
  38. 219 29
      main/mySpace/lp_tracking.php
  39. 107 142
      main/mySpace/myStudents.php
  40. 204 39
      main/mySpace/session.php
  41. 4 7
      main/mySpace/student.php
  42. 1 0
      main/mySpace/teachers.php
  43. 7 2
      main/mySpace/users.php
  44. 6 4
      main/mySpace/works_in_session_report.php
  45. 7 3
      main/search/search_suggestions.php
  46. 2 4
      main/session/about.php
  47. 29 25
      main/session/add_courses_to_session.php
  48. 4 1
      main/session/add_edit_users_to_session.php
  49. 1 1
      main/session/add_teachers_to_session.php
  50. 16 16
      main/session/add_users_to_session.php
  51. 1 1
      main/session/add_users_to_session_course.php
  52. 40 31
      main/session/index.php
  53. 85 50
      main/session/resume_session.php
  54. 15 19
      main/session/scheduled_announcement.php
  55. 168 114
      main/session/session_category_list.php
  56. 1 1
      main/session/session_course_edit.php
  57. 1 1
      main/session/session_course_list.php
  58. 3 4
      main/session/session_course_user.php
  59. 1 1
      main/session/session_course_user_list.php
  60. 2 3
      main/session/session_edit.php
  61. 1 0
      main/session/session_export.php
  62. 7 27
      main/session/session_list.php
  63. 1 1
      main/social/download.php
  64. 14 15
      main/social/group_view.php
  65. 2 4
      main/social/groups.php
  66. 9 6
      main/social/home.php
  67. 0 1
      main/social/map.php
  68. 20 4
      main/social/my_skills_report.php
  69. 9 1
      main/social/personal_data.php
  70. 8 44
      main/social/profile.php
  71. 1 1
      main/social/search.php
  72. 14 2
      main/survey/fillsurvey.php
  73. 163 4
      main/survey/survey.lib.php
  74. 331 198
      main/survey/surveyUtil.class.php
  75. 11 7
      main/survey/survey_invite.php
  76. 1 1
      main/template/default/admin/teacher_time_report.tpl
  77. 2 2
      main/template/default/auth/session_catalog.tpl
  78. 1 1
      main/template/default/blog/blog.tpl
  79. 1 1
      main/template/default/blog/post.tpl
  80. 1 1
      main/template/default/chat/chat.tpl
  81. 1 1
      main/template/default/chat/video.tpl
  82. 2 0
      main/template/default/javascript/editor/ckeditor/config_js.tpl
  83. 9 3
      main/template/default/layout/hot_course_item.tpl
  84. 3 1
      main/template/default/layout/main.js.tpl
  85. 1 1
      main/template/default/layout/menu.tpl
  86. 3 6
      main/template/default/learnpath/list.tpl
  87. 9 12
      main/template/default/learnpath/view.tpl
  88. 99 0
      main/template/default/macro/macro.tpl
  89. 1 5
      main/template/default/my_space/accessoverview.tpl
  90. 1 8
      main/template/default/my_space/index.tpl
  91. 19 3
      main/template/default/my_space/pdf_export_student.tpl
  92. 104 0
      main/template/default/session/resume_session.tpl
  93. 1 1
      main/template/default/skill/issued.tpl
  94. 8 7
      main/template/default/skill/issued_all.tpl
  95. 1 1
      main/template/default/skill/list.tpl
  96. 21 26
      main/template/default/skill/student_boss_report.tpl
  97. 4 0
      main/template/default/skill/student_report.tpl
  98. 2 7
      main/template/default/social/home.tpl
  99. 2 2
      main/template/default/social/profile.tpl
  100. 2 1
      main/template/default/social/skills_block.tpl

+ 2 - 9
main/lp/aicc.class.php

@@ -72,10 +72,6 @@ class aicc extends learnpath
      */
     public function open($id)
     {
-        // Redefine parent method.
-        if ($this->debug > 0) {
-            error_log('In aicc::open()', 0);
-        }
     }
 
     /**
@@ -675,9 +671,6 @@ class aicc extends learnpath
     public function set_author($author = '')
     {
         $course_id = api_get_course_int_id();
-        if ($this->debug > 0) {
-            error_log('In aicc::set_author('.$author.') method', 0);
-        }
         $lp = $this->get_id();
         if ($lp != 0) {
             $tbl_lp = Database::get_course_table(TABLE_LP_MAIN);
@@ -686,9 +679,9 @@ class aicc extends learnpath
             Database::query($sql);
 
             return true;
-        } else {
-            return false;
         }
+
+        return false;
     }
 
     /**

+ 0 - 7
main/lp/aicc_hacp.php

@@ -161,22 +161,18 @@ if (!empty($_REQUEST['command'])) {
                         break;
                 }
             }
-            //error_log('In '.__FILE__.', '.__LINE__.' - aicc data is '.$hacp_aicc_data, 0);
             // Treat the incoming request:
             $aicc = new aicc();
             $msg_array = $aicc->parse_ini_string_quotes_safe($hacp_aicc_data, ['core_lesson', 'core_vendor']);
-            //error_log('Message is now in this form: '.print_r($msg_array, true), 0);
             foreach ($msg_array as $key => $dummy) {
                 switch (strtolower($key)) {
                     case 'core':
                         foreach ($msg_array[$key] as $subkey => $value) {
                             switch (strtolower($subkey)) {
                                 case 'lesson_location':
-                                    //error_log('Setting lesson_location to '.$value, 0);
                                     $oItem->set_lesson_location($value);
                                     break;
                                 case 'lesson_status':
-                                    //error_log('Setting lesson_status to '.$value, 0);
                                     // Sometimes values are sent abbreviated
                                     switch ($value) {
                                         case 'C':
@@ -201,11 +197,9 @@ if (!empty($_REQUEST['command'])) {
                                     $oItem->set_status($value);
                                     break;
                                 case 'score':
-                                    //error_log('Setting lesson_score to '.$value, 0);
                                     $oItem->set_score($value);
                                     break;
                                 case 'time':
-                                    //error_log('Setting lesson_time to '.$value, 0);
                                     if (strpos($value, ':') !== false) {
                                         $oItem->set_time($value, 'scorm');
                                     } else {
@@ -216,7 +210,6 @@ if (!empty($_REQUEST['command'])) {
                         }
                         break;
                     case 'core_lesson':
-                        //error_log('Setting suspend_data to '.print_r($msg_array[$key], true), 0);
                         $oItem->current_data = $msg_array[$key];
                         break;
                     case 'comments':

+ 1 - 0
main/lp/download.php

@@ -14,6 +14,7 @@ $this_section = SECTION_COURSES;
 
 // Protection
 api_protect_course_script();
+$_course = api_get_course_info();
 
 if (!isset($_course)) {
     api_not_allowed(true);

+ 2 - 0
main/lp/embed.php

@@ -5,6 +5,8 @@ use ChamiloSession as Session;
 
 require_once __DIR__.'/../inc/global.inc.php';
 
+api_protect_course_script(true);
+
 $type = $_REQUEST['type'];
 $src = Security::remove_XSS($_REQUEST['source']);
 if (empty($type) || empty($src)) {

ファイルの差分が大きいため隠しています
+ 199 - 192
main/lp/learnpath.class.php


ファイルの差分が大きいため隠しています
+ 102 - 343
main/lp/learnpathItem.class.php


+ 15 - 22
main/lp/learnpathList.class.php

@@ -28,7 +28,7 @@ class LearnpathList
      * (only displays) items if he has enough permissions to view them.
      *
      * @param int    $user_id
-     * @param string $course_code             Optional course code (otherwise we use api_get_course_id())
+     * @param array  $courseInfo              Optional course code (otherwise we use api_get_course_id())
      * @param int    $session_id              Optional session id (otherwise we use api_get_session_id())
      * @param string $order_by
      * @param bool   $check_publication_dates
@@ -38,7 +38,7 @@ class LearnpathList
      */
     public function __construct(
         $user_id,
-        $course_code = '',
+        $courseInfo = [],
         $session_id = 0,
         $order_by = null,
         $check_publication_dates = false,
@@ -46,23 +46,16 @@ class LearnpathList
         $ignoreCategoryFilter = false,
         $ignoreLpVisibility = false
     ) {
-        $course_info = api_get_course_info($course_code);
-
-        if (empty($course_info['real_id'])) {
-            return false;
+        if (empty($courseInfo)) {
+            $courseInfo = api_get_course_info();
         }
 
-        $this->course_code = $course_info['code'];
+        $this->course_code = $courseInfo['code'];
+        $course_id = $courseInfo['real_id'];
         $this->user_id = $user_id;
-        $course_id = $course_info['real_id'];
 
         // Condition for the session.
-        if (!empty($session_id)) {
-            $session_id = intval($session_id);
-        } else {
-            $session_id = api_get_session_id();
-        }
-
+        $session_id = empty($session_id) ? api_get_session_id() : (int) $session_id;
         $condition_session = api_get_session_condition(
             $session_id,
             true,
@@ -72,14 +65,14 @@ class LearnpathList
 
         $tbl_tool = Database::get_course_table(TABLE_TOOL_LIST);
 
-        $order = "ORDER BY lp.displayOrder ASC, lp.name ASC";
+        $order = ' ORDER BY lp.displayOrder ASC, lp.name ASC';
         if (isset($order_by)) {
             $order = Database::parse_conditions(['order' => $order_by]);
         }
 
         $now = api_get_utc_datetime();
-        $time_conditions = '';
 
+        $time_conditions = '';
         if ($check_publication_dates) {
             $time_conditions = " AND (
                 (lp.publicatedOn IS NOT NULL AND lp.publicatedOn < '$now' AND lp.expiredOn IS NOT NULL AND lp.expiredOn > '$now') OR
@@ -95,7 +88,7 @@ class LearnpathList
                 $categoryId = (int) $categoryId;
                 $categoryFilter = " AND lp.categoryId = $categoryId";
             } else {
-                $categoryFilter = " AND (lp.categoryId = 0 OR lp.categoryId IS NULL) ";
+                $categoryFilter = ' AND (lp.categoryId = 0 OR lp.categoryId IS NULL) ';
             }
         }
 
@@ -107,10 +100,10 @@ class LearnpathList
                     $categoryFilter
                     $order
                 ";
-
         $learningPaths = Database::getManager()->createQuery($dql)->getResult();
         $showBlockedPrerequisite = api_get_configuration_value('show_prerequisite_as_blocked');
         $names = [];
+        $isAllowToEdit = api_is_allowed_to_edit();
         /** @var CLp $row */
         foreach ($learningPaths as $row) {
             // Use domesticate here instead of Database::escape_string because
@@ -120,7 +113,7 @@ class LearnpathList
             $link = 'lp/lp_controller.php?action=view&lp_id='.$row->getId().'&id_session='.$session_id;
             $oldLink = 'newscorm/lp_controller.php?action=view&lp_id='.$row->getId().'&id_session='.$session_id;
 
-            $sql2 = "SELECT * FROM $tbl_tool
+            $sql2 = "SELECT visibility FROM $tbl_tool
                      WHERE
                         c_id = $course_id AND 
                         name = '$name' AND
@@ -139,7 +132,7 @@ class LearnpathList
 
             // Check if visible.
             $visibility = api_get_item_visibility(
-                api_get_course_info($course_code),
+                $courseInfo,
                 'learnpath',
                 $row->getId(),
                 $session_id
@@ -147,11 +140,11 @@ class LearnpathList
 
             // If option is not true then don't show invisible LP to user
             if ($ignoreLpVisibility === false) {
-                if ($showBlockedPrerequisite !== true && !api_is_allowed_to_edit()) {
+                if ($showBlockedPrerequisite !== true && !$isAllowToEdit) {
                     $lpVisibility = learnpath::is_lp_visible_for_student(
                         $row->getId(),
                         $user_id,
-                        $course_code
+                        $courseInfo
                     );
                     if ($lpVisibility === false) {
                         continue;

+ 9 - 13
main/lp/lp_add.php

@@ -42,16 +42,10 @@ $isStudentView = isset($_REQUEST['isStudentView']) ? $_REQUEST['isStudentView']
 $learnpath_id = isset($_REQUEST['lp_id']) ? $_REQUEST['lp_id'] : null;
 
 /* MAIN CODE */
-if ((!$is_allowed_to_edit) || ($isStudentView)) {
-    header('location:lp_controller.php?action=view&lp_id='.$learnpath_id);
+if ((!$is_allowed_to_edit) || $isStudentView) {
+    header('location:lp_controller.php?action=view&lp_id='.$learnpath_id.'&'.api_get_cidreq());
     exit;
 }
-// From here on, we are admin because of the previous condition, so don't check anymore.
-
-/*
-    Course admin section
-    - all the functions not available for students - always available in this case (page only shown to admin)
-*/
 
 if (api_is_in_gradebook()) {
     $interbreadcrumb[] = [
@@ -61,7 +55,7 @@ if (api_is_in_gradebook()) {
 }
 
 $interbreadcrumb[] = [
-    'url' => 'lp_controller.php?action=list',
+    'url' => 'lp_controller.php?action=list&'.api_get_cidreq(),
     'name' => get_lang('LearningPaths'),
 ];
 
@@ -150,16 +144,19 @@ $form->addElement('html', '<div id="end_date_div" style="display:none;">');
 $form->addDatePicker('expired_on', get_lang('ExpirationDate'));
 $form->addElement('html', '</div>');
 
+$extraField = new ExtraField('lp');
+
+$extra = $extraField->addElements($form, 0, ['lp_icon']);
+
 Skill::addSkillsToForm($form, ITEM_TYPE_LEARNPATH, 0);
 
 $form->addElement('html', '</div>');
 
 $defaults['activate_start_date_check'] = 1;
 
+$defaults['accumulate_scorm_time'] = 0;
 if (api_get_setting('scorm_cumulative_session_time') == 'true') {
     $defaults['accumulate_scorm_time'] = 1;
-} else {
-    $defaults['accumulate_scorm_time'] = 0;
 }
 
 $defaults['publicated_on'] = date('Y-m-d 08:00:00');
@@ -167,7 +164,6 @@ $defaults['expired_on'] = date('Y-m-d 08:00:00', time() + 86400);
 
 $form->setDefaults($defaults);
 $form->addButtonCreate(get_lang('CreateLearningPath'));
-
 $form->display();
-// Footer
+
 Display::display_footer();

+ 17 - 11
main/lp/lp_add_audio.php

@@ -87,6 +87,10 @@ $suredel = trim(get_lang('AreYouSureToDeleteJS'));
 
 $lpPathInfo = $lp->generate_lp_folder(api_get_course_info());
 
+DocumentManager::createDefaultAudioFolder($courseInfo);
+
+$audioFolderId = DocumentManager::get_document_id($courseInfo, '/audio');
+
 $file = null;
 if (isset($lp_item->audio) && !empty($lp_item->audio)) {
     $file = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document/audio/'.$lp_item->audio;
@@ -106,7 +110,7 @@ $page .= $lp->return_new_tree(null, true);
 // Show the template list.
 $page .= '</div>';
 
-$recordVoiceForm = Display::page_subheader(get_lang('RecordYourVoice'));
+$recordVoiceForm = '<h3 class="page-header">'.get_lang('RecordYourVoice').'</h3>';
 
 $page .= '<div id="doc_form" class="col-md-8">';
 
@@ -125,8 +129,7 @@ $tpl->assign('lp_item_id', $lp_item_id);
 $tpl->assign('lp_dir', api_remove_trailing_slash($lpPathInfo['dir']));
 $template = $tpl->get_template('learnpath/record_voice.tpl');
 $recordVoiceForm .= $tpl->fetch($template);
-$form->addElement('header', get_lang('Or'));
-$form->addElement('header', get_lang('AudioFile'));
+$form->addElement('header', '<small class="text-muted">'.get_lang('Or').'</small> '.get_lang('AudioFile'));
 $form->addLabel(null, sprintf(get_lang('AudioFileForItemX'), $lp_item->get_title()));
 
 if (!empty($file)) {
@@ -149,30 +152,33 @@ if (!empty($file)) {
     $form->addElement('hidden', 'id', $lp_item_id);
     $form->addButtonSave(get_lang('Save'));
 }
-$form->addElement('header', get_lang('Or'));
 
 $courseInfo = api_get_course_info();
 $documentTree = DocumentManager::get_document_preview(
     $courseInfo,
-    false,
+    $lp->get_id(),
     null,
     api_get_session_id(),
     false,
     '',
     api_get_path(WEB_CODE_PATH).'lp/lp_controller.php?action=add_audio&lp_id='.$lp->get_id().'&id='.$lp_item_id,
     false,
-    true
-    //$folderId = false
+    true,
+    $audioFolderId
 );
 
 $page .= $recordVoiceForm;
+$page .= '<br>';
 $page .= $form->returnForm();
-$page .= '<legend>'.get_lang('SelectAnAudioFileFromDocuments').'</legend>';
-$page .= $documentTree;
+$page .= '<h3 class="page-header"><small>'.get_lang('Or').'</small> '.get_lang('SelectAnAudioFileFromDocuments').'</h3>';
+$page .= '<ul class="lp_resource">';
+$page .= '<li class="doc_folder" style="margin-left: 36px;">'.get_lang('Audio').'</li>';
+$page .= '<li class="doc_folder">';
+$page .= '<ul class="lp_resource">'.$documentTree.'</ul>';
+$page .= '</div>';
+$page .= '</ul>';
 $page .= '</div>';
 $page .= '</div>';
 
 $tpl->assign('content', $page);
-$template = $tpl->get_template('learnpath/lp_upload_audio.tpl');
-$content = $tpl->fetch($template);
 $tpl->display_one_col_template();

+ 1 - 1
main/lp/lp_add_category.php

@@ -37,7 +37,7 @@ if (api_get_configuration_value('save_titles_as_html')) {
         get_lang('Name'),
         true,
         false,
-        ['ToolbarSet' => 'Minimal']
+        ['ToolbarSet' => 'Minimal', 'Height' => '100']
     );
 } else {
     $form->addText('name', get_lang('Name'), true);

+ 1 - 2
main/lp/lp_add_item.php

@@ -121,7 +121,7 @@ switch ($type) {
         break;
 }
 
-if ($action == 'add_item' && $type == 'document') {
+if ($action === 'add_item' && $type === 'document') {
     $interbreadcrumb[] = ['url' => '#', 'name' => get_lang('NewDocumentCreated')];
 }
 
@@ -216,7 +216,6 @@ if (($type == 'document' || $type == 'step') && !isset($_GET['file'])) {
     echo '<div id="frmModel" class="scrollbar-inner lp-add-item">';
     echo '</div>';
 }
-
 echo '</div>';
 
 echo '<div id="doc_form" class="col-md-8">';

+ 2 - 0
main/lp/lp_ajax_initialize.php

@@ -15,6 +15,8 @@
 $use_anonymous = true;
 require_once __DIR__.'/../inc/global.inc.php';
 
+api_protect_course_script();
+
 /**
  * Get one item's details.
  *

+ 21 - 10
main/lp/lp_ajax_save_item.php

@@ -16,6 +16,8 @@ use ChamiloSession as Session;
 $use_anonymous = true;
 require_once __DIR__.'/../inc/global.inc.php';
 
+api_protect_course_script();
+
 /**
  * Writes an item's new values into the database and returns the operation result.
  *
@@ -119,6 +121,15 @@ function save_item(
             error_log('Prerequisites are OK');
         }
 
+        $logInfo = [
+            'tool' => TOOL_LEARNPATH,
+            'tool_id' => $lp_id,
+            'tool_id_detail' => $item_id,
+            'action' => 'view',
+            'action_details' => $myLP->getCurrentAttempt(),
+        ];
+        Event::registerLog($logInfo);
+
         if (isset($max) && $max != -1) {
             $myLPI->max_score = $max;
             $myLPI->set_max_score($max);
@@ -488,18 +499,9 @@ function save_item(
     }
 
     if ($myLP->get_type() == 2) {
-        $return .= "update_stats();";
+        $return .= 'update_stats();';
     }
 
-    $logInfo = [
-        'tool' => TOOL_LEARNPATH,
-        'tool_id' => $myLP->get_id(),
-        'tool_id_detail' => $myLP->get_current_item_id(),
-        'action' => 'save_item',
-        'info' => '',
-    ];
-    Event::registerLog($logInfo);
-
     // To be sure progress is updated.
     $myLP->save_last();
 
@@ -510,6 +512,15 @@ function save_item(
         error_log('---------------- lp_ajax_save_item.php : save_item end ----- ');
     }
 
+    $logInfo = [
+        'tool' => TOOL_LEARNPATH,
+        'tool_id' => $myLP->get_id(),
+        'action_details' => $myLP->getCurrentAttempt(),
+        'tool_id_detail' => $myLP->get_current_item_id(),
+        'action' => 'save_item',
+    ];
+    Event::registerLog($logInfo);
+
     return $return;
 }
 

+ 58 - 2
main/lp/lp_ajax_switch_item.php

@@ -217,10 +217,66 @@ function switch_item_details($lp_id, $user_id, $view_id, $current_item, $next_it
         "olms.lms_item_core_exit = '".$mycore_exit."';".
         "olms.asset_timer = 0;";
 
-    $return .= "update_toc('unhighlight','".$current_item."');".
+    $updateMinTime = '';
+    if (Tracking::minimumTimeAvailable(api_get_session_id(), api_get_course_int_id())) {
+        $timeLp = $mylp->getAccumulateWorkTime();
+        $timeTotalCourse = $mylp->getAccumulateWorkTimeTotalCourse();
+        // Minimum connection percentage
+        $perc = 100;
+        // Time from the course
+        $tc = $timeTotalCourse;
+        $sessionId = api_get_session_id();
+        if (!empty($sessionId) && $sessionId != 0) {
+            /*$sql = "SELECT hours, perc FROM plugin_licences_course_session WHERE session_id = $sessionId";
+            $res = Database::query($sql);
+            if (Database::num_rows($res) > 0) {
+                $aux = Database::fetch_assoc($res);
+                $perc = $aux['perc'];
+                $tc = $aux['hours'] * 60;
+            }*/
+        }
+
+        // Percentage of the learning paths
+        $pl = 0;
+        if (!empty($timeTotalCourse)) {
+            $pl = $timeLp / $timeTotalCourse;
+        }
+
+        // Minimum time for each learning path
+        $time_total = intval($pl * $tc * $perc / 100) * 60;
+
+        //$time_total = $mylp->getAccumulateWorkTime() * 60;
+        /*$lpTime = Tracking::get_time_spent_in_lp(
+            $user_id,
+            api_get_course_id(),
+            [$lp_id],
+            api_get_session_id()
+        );*/
+
+        $lpTimeList = Tracking::getCalculateTime($user_id, api_get_course_int_id(), api_get_session_id());
+        $lpTime = isset($lpTimeList[TOOL_LEARNPATH][$lp_id]) ? $lpTimeList[TOOL_LEARNPATH][$lp_id] : 0;
+
+        if ($lpTime >= $time_total) {
+            $time_spent = $time_total;
+        } else {
+            $time_spent = $lpTime;
+        }
+
+        $hour = (intval($lpTime / 3600)) < 10 ? '0'.intval($lpTime / 3600) : intval($lpTime / 3600);
+        $minute = date('i', $lpTime);
+        $second = date('s', $lpTime);
+        $updateMinTime = "update_time_bar('$time_spent','$time_total','%');".
+                         "update_chronometer('$hour','$minute','$second');";
+    }
+
+    $return .=
+        "update_toc('unhighlight','".$current_item."');".
         "update_toc('highlight','".$new_item_id."');".
         "update_toc('$mylesson_status','".$new_item_id."');".
-        "update_progress_bar('$mycomplete','$mytotal','$myprogress_mode');";
+        "update_progress_bar('$mycomplete','$mytotal','$myprogress_mode');".
+        $updateMinTime
+    ;
+
     $return .= 'updateGamificationValues(); ';
     // Ofaj
     $return .= "$('#item-parent-names').load('"

+ 58 - 128
main/lp/lp_controller.php

@@ -18,11 +18,10 @@ use ChamiloSession as Session;
 $use_anonymous = true;
 $debug = 0;
 
-if ($debug) {
-    error_log('Entering lp_controller.php. Checking if LP exist in current session');
-}
-
 require_once __DIR__.'/../inc/global.inc.php';
+
+api_protect_course_script(true);
+
 $current_course_tool = TOOL_LEARNPATH;
 $_course = api_get_course_info();
 
@@ -56,18 +55,7 @@ $htmlHeadXtra[] = '
     /*
     Script to manipulate Learning Path items with Drag and drop
      */
-    var newOrderData = "";
-    var lptree_debug = "";  // for debug
-    var lp_id_list = "";    // for debug
-
-    // uncomment for some debug display utility
-    /*
-    $(function() {
-        buildLPtree_debug($("#lp_item_list"), 0, 0);
-        alert(lp_id_list+"\n\n"+lptree_debug);
-    });
-    */
-
+    var newOrderData = "";    
     function buildLPtree(in_elem, in_parent_id) {
         var item_tag = in_elem.get(0).tagName;
         var item_id =  in_elem.attr("id");
@@ -83,26 +71,6 @@ $htmlHeadXtra[] = '
         });
     }
 
-    // same than buildLPtree with some text display for debug in string lptree_debug
-    function buildLPtree_debug(in_elem, in_lvl, in_parent_id) {
-        var item_tag = in_elem.get(0).tagName;
-        var item_id =  in_elem.attr("id");
-        var parent_id = item_id;
-
-        if (item_tag == "LI" && item_id != undefined) {
-            for (i=0; i < 4 * in_lvl; i++) {
-                lptree_debug += " ";
-            }
-            lptree_debug += " Lvl="+(in_lvl - 1)/2+" ("+item_tag+" "+item_id+" Fils de="+in_parent_id+") \n";
-            // in_parent_id de la forme UL_x
-            lp_id_list += item_id+"|"+get_UL_integer_id(in_parent_id)+"^";
-        }
-
-        in_elem.children().each(function () {
-            buildLPtree_debug($(this), in_lvl + 1, parent_id);
-        });
-    }
-
     // return the interge part of an UL id
     // (0 for lp_item_list)
     function get_UL_integer_id(in_ul_id) {
@@ -120,7 +88,7 @@ $htmlHeadXtra[] = '
             connectWith: "#lp_item_list",
             placeholder: "ui-state-highlight", //defines the yellow highlight
             start: function(event, ui) {
-                $(ui.item).css("width", "160px");
+                $(ui.item).css("width", "350px");
                 $(ui.item).find(".item_data").attr("style", "");
             },
             stop: function(event, ui) {
@@ -185,7 +153,6 @@ $htmlHeadXtra[] = '
 </script>';
 
 $session_id = api_get_session_id();
-api_protect_course_script(true);
 
 $lpfound = false;
 $myrefresh = 0;
@@ -203,10 +170,6 @@ if ($debug > 0) {
     error_log(' $myrefresh: '.$myrefresh);
 }
 
-if (!empty($_REQUEST['dialog_box'])) {
-    $dialog_box = stripslashes(urldecode($_REQUEST['dialog_box']));
-}
-
 $lp_controller_touched = 1;
 $lp_found = false;
 $lpObject = Session::read('lpobject');
@@ -258,9 +221,6 @@ if (!$lp_found || (!empty($_REQUEST['lp_id']) && $_SESSION['oLP']->get_id() != $
     }
     // Regenerate a new lp object? Not always as some pages don't need the object (like upload?)
     if (!empty($_REQUEST['lp_id']) || !empty($myrefresh_id)) {
-        if ($debug > 0) {
-            error_log(' lp_id is defined');
-        }
         // Select the lp in the database and check which type it is (scorm/chamilo/aicc) to generate the
         // right object.
         if (!empty($_REQUEST['lp_id'])) {
@@ -298,32 +258,24 @@ if (!$lp_found || (!empty($_REQUEST['lp_id']) && $_SESSION['oLP']->get_id() != $
                         $oLP = new learnpath(api_get_course_id(), $lpIid, api_get_user_id());
                         if ($oLP !== false) {
                             $lp_found = true;
-                        } else {
-                            error_log($oLP->error);
                         }
                         break;
                     case 2:
                         $oLP = new scorm(api_get_course_id(), $lpIid, api_get_user_id());
                         if ($oLP !== false) {
                             $lp_found = true;
-                        } else {
-                            error_log($oLP->error);
                         }
                         break;
                     case 3:
                         $oLP = new aicc(api_get_course_id(), $lpIid, api_get_user_id());
                         if ($oLP !== false) {
                             $lp_found = true;
-                        } else {
-                            error_log($oLP->error);
                         }
                         break;
                     default:
                         $oLP = new learnpath(api_get_course_id(), $lpIid, api_get_user_id());
                         if ($oLP !== false) {
                             $lp_found = true;
-                        } else {
-                            error_log($oLP->error);
                         }
                         break;
                 }
@@ -344,35 +296,16 @@ if (!$lp_found || (!empty($_REQUEST['lp_id']) && $_SESSION['oLP']->get_id() != $
 }
 
 if ($debug > 0) {
-    error_log('Passed oLP creation check', 0);
+    error_log('Passed oLP creation check');
 }
 
 $is_allowed_to_edit = api_is_allowed_to_edit(false, true, false, false);
 
 if (isset($_SESSION['oLP'])) {
-    $_SESSION['oLP']->update_queue = [];
     // Reinitialises array used by javascript to update items in the TOC.
+    $_SESSION['oLP']->update_queue = [];
 }
 
-/*$studentView = api_is_student_view_active();
-if ($studentView) {
-    if (isset($_REQUEST['action']) && !in_array($_REQUEST['action'], ['list', 'view', 'view_category'])) {
-        if (!empty($_REQUEST['lp_id'])) {
-            $_REQUEST['action'] = 'view';
-        } elseif ($_REQUEST['action'] == 'view_category') {
-            $_REQUEST['action'] = 'view_category';
-        } else {
-            $_REQUEST['action'] = 'list';
-        }
-    }
-} else {
-    if ($is_allowed_to_edit) {
-        if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'view' && !isset($_REQUEST['exeId'])) {
-            $_REQUEST['action'] = 'build';
-        }
-    }
-}*/
-
 $action = !empty($_REQUEST['action']) ? $_REQUEST['action'] : '';
 
 if ($debug) {
@@ -387,6 +320,7 @@ if (empty($lp_id)) {
 }
 
 $lp_detail_id = 0;
+$attemptId = 0;
 switch ($action) {
     case '':
     case 'list':
@@ -394,7 +328,8 @@ switch ($action) {
         break;
     case 'view':
     case 'content':
-        $lp_detail_id = $_SESSION['oLP']->get_current_item_id();
+        $lp_detail_id = $oLP->get_current_item_id();
+        $attemptId = $oLP->getCurrentAttempt();
         break;
     default:
         $lp_detail_id = (!empty($_REQUEST['id']) ? (int) $_REQUEST['id'] : 0);
@@ -405,6 +340,7 @@ $logInfo = [
     'tool' => TOOL_LEARNPATH,
     'tool_id' => $eventLpId,
     'tool_id_detail' => $lp_detail_id,
+    'action_details' => $attemptId,
     'action' => !empty($action) ? $action : 'list',
 ];
 Event::registerLog($logInfo);
@@ -425,50 +361,44 @@ if (isset($_POST['title'])) {
 $redirectTo = '';
 if ($debug > 0) {
     error_log('action "'.$action.'" triggered');
-    if (!$lp_found) {
-        //check if the learnpath ID was defined, otherwise send back to list
-        error_log('No learnpath given');
-    }
 }
 
 switch ($action) {
     case 'send_notify_teacher':
-        // Enviar correo al profesor
+        // Send notification to the teacher
         $studentInfo = api_get_user_info();
         $course_info = api_get_course_info();
+        $sessionId = api_get_session_id();
 
-        global $_configuration;
-        $root_web = $_configuration['root_web'];
-
-        if (api_get_session_id() > 0) {
-            $session_info = api_get_session_info(api_get_session_id());
-            $course_name = $session_info['name'];
-            $course_url = $root_web.'courses/'.$course_info['code'].'/index.php?id_session='.api_get_session_id();
-        } else {
-            $course_name = $course_info['title'];
-            $course_url = $root_web.'courses/'.$course_info['code'].'/index.php?';
+        $courseName = $course_info['title'];
+        $courseUrl = $course_info['course_public_url'];
+        if (!empty($sessionId)) {
+            $sessionInfo = api_get_session_info($sessionId);
+            $courseName = $sessionInfo['name'];
+            $courseUrl .= '?id_session='.$sessionId;
         }
-        $url = Display::url($course_name, $course_url, ['title' => get_lang('GoToCourse')]);
-        $coachList = CourseManager::get_coachs_from_course(api_get_session_id(), api_get_course_int_id());
-        foreach ($coachList as $coach_course) {
-            $recipient_name = $coach_course['full_name'];
 
+        $url = Display::url($courseName, $courseUrl, ['title' => get_lang('GoToCourse')]);
+        $coachList = CourseManager::get_coachs_from_course($sessionId, api_get_course_int_id());
+        foreach ($coachList as $coach_course) {
+            $recipientName = $coach_course['full_name'];
             $coachInfo = api_get_user_info($coach_course['user_id']);
+
+            if (empty($coachInfo)) {
+                continue;
+            }
             $email = $coachInfo['email'];
 
             $tplContent = new Template(null, false, false, false, false, false);
-            // variables for the default template
-            $tplContent->assign('name_teacher', $recipient_name);
+            $tplContent->assign('name_teacher', $recipientName);
             $tplContent->assign('name_student', $studentInfo['complete_name']);
-            $tplContent->assign('course_name', $course_name);
+            $tplContent->assign('course_name', $courseName);
             $tplContent->assign('course_url', $url);
-            //$tplContent->assign('telefono', $telefono);
-            //$tplContent->assign('prefix', $prefix);
             $layoutContent = $tplContent->get_template('mail/content_ending_learnpath.tpl');
             $emailBody = $tplContent->fetch($layoutContent);
 
             api_mail_html(
-                $recipient_name,
+                $recipientName,
                 $email,
                 sprintf(get_lang('StudentXFinishedLp'), $studentInfo['complete_name']),
                 $emailBody,
@@ -478,7 +408,9 @@ switch ($action) {
             );
         }
         Display::addFlash(Display::return_message(get_lang('MessageSent')));
-        require 'lp_list.php';
+        $url = api_get_self().'?action=list&'.api_get_cidreq();
+        header('Location: '.$url);
+        exit;
         break;
     case 'add_item':
         if (!$is_allowed_to_edit) {
@@ -660,8 +592,10 @@ switch ($action) {
             api_not_allowed(true);
         }
         if (isset($_REQUEST['id'])) {
-            learnpath::deleteCategory($_REQUEST['id']);
-            Display::addFlash(Display::return_message(get_lang('Deleted')));
+            $result = learnpath::deleteCategory($_REQUEST['id']);
+            if ($result) {
+                Display::addFlash(Display::return_message(get_lang('Deleted')));
+            }
         }
         require 'lp_list.php';
         break;
@@ -678,20 +612,18 @@ switch ($action) {
             } else {
                 Session::write('post_time', $_POST['post_time']);
 
+                $publicated_on = null;
                 if (isset($_REQUEST['activate_start_date_check']) &&
                     $_REQUEST['activate_start_date_check'] == 1
                 ) {
                     $publicated_on = $_REQUEST['publicated_on'];
-                } else {
-                    $publicated_on = null;
                 }
 
+                $expired_on = null;
                 if (isset($_REQUEST['activate_end_date_check']) &&
                     $_REQUEST['activate_end_date_check'] == 1
                 ) {
                     $expired_on = $_REQUEST['expired_on'];
-                } else {
-                    $expired_on = null;
                 }
 
                 $new_lp_id = learnpath::add_lp(
@@ -712,6 +644,10 @@ switch ($action) {
                     $form->addSelect('skills', 'skills');
                     Skill::saveSkills($form, ITEM_TYPE_LEARNPATH, $new_lp_id);
 
+                    $extraFieldValue = new ExtraFieldValue('lp');
+                    $_REQUEST['item_id'] = $new_lp_id;
+                    $extraFieldValue->saveFieldValues($_REQUEST);
+
                     // TODO: Maybe create a first directory directly to avoid bugging the user with useless queries
                     $_SESSION['oLP'] = new learnpath(
                         api_get_course_id(),
@@ -743,7 +679,8 @@ switch ($action) {
         }
         break;
     case 'auto_launch':
-        if (api_get_course_setting('enable_lp_auto_launch') == 1) { //Redirect to a specific LP
+        // Redirect to a specific LP
+        if (api_get_course_setting('enable_lp_auto_launch') == 1) {
             if (!$is_allowed_to_edit) {
                 api_not_allowed(true);
             }
@@ -764,7 +701,6 @@ switch ($action) {
             require 'lp_list.php';
         } else {
             Session::write('refresh', 1);
-            //require 'lp_build.php';
             $url = api_get_self().'?action=add_item&type=step&lp_id='.intval($_SESSION['oLP']->lp_id).'&'.api_get_cidreq();
             header('Location: '.$url);
             exit;
@@ -779,7 +715,7 @@ switch ($action) {
         } else {
             Session::write('refresh', 1);
             if (isset($_POST['submit_button']) && !empty($post_title)) {
-                //Updating the lp.modified_on
+                // Updating the lp.modified_on
                 $_SESSION['oLP']->set_modified_on();
 
                 // TODO: mp3 edit
@@ -808,15 +744,12 @@ switch ($action) {
                 if (isset($_POST['content_lp'])) {
                     $_SESSION['oLP']->edit_document($_course);
                 }
-                $is_success = true;
-
                 Display::addFlash(Display::return_message(get_lang('Updated')));
-
                 $url = api_get_self().'?action=add_item&type=step&lp_id='.intval($_SESSION['oLP']->lp_id).'&'.api_get_cidreq();
                 header('Location: '.$url);
                 exit;
             }
-            if (isset($_GET['view']) && $_GET['view'] == 'build') {
+            if (isset($_GET['view']) && $_GET['view'] === 'build') {
                 require 'lp_edit_item.php';
             } else {
                 require 'lp_admin_view.php';
@@ -844,10 +777,6 @@ switch ($action) {
                     $max
                 );
 
-                if ($editPrerequisite) {
-                    $is_success = true;
-                }
-
                 Display::addFlash(Display::return_message(get_lang('Updated')));
                 $url = api_get_self().'?action=add_item&type=step&lp_id='.intval($_SESSION['oLP']->lp_id).'&'.api_get_cidreq();
                 header('Location: '.$url);
@@ -876,7 +805,6 @@ switch ($action) {
                     $post_title,
                     $_POST['description']
                 );
-                $is_success = true;
                 $url = api_get_self().'?action=add_item&type=step&lp_id='.intval($_SESSION['oLP']->lp_id).'&'.api_get_cidreq();
                 header('Location: '.$url);
                 exit;
@@ -948,14 +876,18 @@ switch ($action) {
         }
         break;
     case 'export_to_pdf':
-        if (!learnpath::is_lp_visible_for_student($_SESSION['oLP']->lp_id, api_get_user_id())) {
-            api_not_allowed();
-        }
         $hideScormPdfLink = api_get_setting('hide_scorm_pdf_link');
         if ($hideScormPdfLink === 'true') {
             api_not_allowed(true);
         }
 
+        // Teachers can export to PDF
+        if (!$is_allowed_to_edit) {
+            if (!learnpath::is_lp_visible_for_student($_SESSION['oLP']->lp_id, api_get_user_id(), $_course)) {
+                api_not_allowed();
+            }
+        }
+
         if (!$lp_found) {
             require 'lp_list.php';
         } else {
@@ -1123,23 +1055,20 @@ switch ($action) {
             $_SESSION['oLP']->set_prerequisite(isset($_POST['prerequisites']) ? (int) $_POST['prerequisites'] : 0);
             $_SESSION['oLP']->setAccumulateWorkTime(isset($_REQUEST['accumulate_work_time']) ? $_REQUEST['accumulate_work_time'] : 0);
             $_SESSION['oLP']->set_use_max_score(isset($_POST['use_max_score']) ? 1 : 0);
-
             $subscribeUsers = isset($_REQUEST['subscribe_users']) ? 1 : 0;
             $_SESSION['oLP']->setSubscribeUsers($subscribeUsers);
 
             $accumulateScormTime = isset($_REQUEST['accumulate_scorm_time']) ? $_REQUEST['accumulate_scorm_time'] : 'true';
             $_SESSION['oLP']->setAccumulateScormTime($accumulateScormTime);
 
+            $publicated_on = null;
             if (isset($_REQUEST['activate_start_date_check']) && $_REQUEST['activate_start_date_check'] == 1) {
                 $publicated_on = $_REQUEST['publicated_on'];
-            } else {
-                $publicated_on = null;
             }
 
+            $expired_on = null;
             if (isset($_REQUEST['activate_end_date_check']) && $_REQUEST['activate_end_date_check'] == 1) {
                 $expired_on = $_REQUEST['expired_on'];
-            } else {
-                $expired_on = null;
             }
             $_SESSION['oLP']->setCategoryId($_REQUEST['category_id']);
             $_SESSION['oLP']->set_modified_on();
@@ -1197,7 +1126,8 @@ switch ($action) {
             exit;
         }
         break;
-    case 'add_sub_item': // Add an item inside a dir/chapter.
+    case 'add_sub_item':
+        // Add an item inside a dir/chapter.
         // @todo check if this is @deprecated
         if (!$is_allowed_to_edit) {
             api_not_allowed(true);

+ 8 - 13
main/lp/lp_edit.php

@@ -159,7 +159,7 @@ $form->addElement('html', '</div>');
 $form->addElement('html', '<div class="col-md-2"></div>');
 $form->addElement('html', '</div>');
 // Time Control
-if (Tracking::minimunTimeAvailable(api_get_session_id(), api_get_course_int_id())) {
+if (Tracking::minimumTimeAvailable(api_get_session_id(), api_get_course_int_id())) {
     $accumulateTime = $_SESSION['oLP']->getAccumulateWorkTime();
     $form->addText('accumulate_work_time', [get_lang('LpMinTime'), get_lang('LpMinTimeDescription')]);
     $defaults['accumulate_work_time'] = $accumulateTime;
@@ -236,11 +236,8 @@ if (!empty($options)) {
     $defaults['extra_lp_icon'] = learnpath::getSelectedIcon($lpId);
 }
 
-$enableLpExtraFields = false;
-if ($enableLpExtraFields) {
-    $extraField = new ExtraField('lp');
-    $extra = $extraField->addElements($form, $lpId);
-}
+$extraField = new ExtraField('lp');
+$extra = $extraField->addElements($form, $lpId, ['lp_icon']);
 
 $skillList = Skill::addSkillsToForm($form, ITEM_TYPE_LEARNPATH, $lpId);
 
@@ -251,13 +248,11 @@ $form->addButtonSave(get_lang('SaveLPSettings'));
 $form->addElement('hidden', 'action', 'update_lp');
 $form->addElement('hidden', 'lp_id', $lpId);
 
-if ($enableLpExtraFields) {
-    $htmlHeadXtra[] = '<script>
-    $(function() {
-        '.$extra['jquery_ready_content'].'
-    });
-    </script>';
-}
+$htmlHeadXtra[] = '<script>
+$(function() {
+    '.$extra['jquery_ready_content'].'
+});
+</script>';
 
 $htmlHeadXtra[] = '<script>'.$learnPath->get_js_dropdown_array().'</script>';
 

+ 31 - 64
main/lp/lp_final_item.php

@@ -137,47 +137,41 @@ if ($accessGranted == false) {
             $catCourseCode = CourseManager::get_course_by_category($categoryId);
             $show_message = $cat->show_message_resource_delete($catCourseCode);
 
-            if ($show_message == '') {
-                if (!api_is_allowed_to_edit() && !api_is_excluded_user_type()) {
-                    $certificate = Category::generateUserCertificate(
-                        $categoryId,
-                        $userId
-                    );
+            if (false === $show_message && !api_is_allowed_to_edit() && !api_is_excluded_user_type()) {
+                $certificate = Category::generateUserCertificate(
+                    $categoryId,
+                    $userId
+                );
 
-                    if (!empty($certificate['pdf_url']) ||
-                        !empty($certificate['badge_link'])
-                    ) {
-                        if (is_array($certificate) &&
-                            isset($certificate['pdf_url'])
-                        ) {
-                            $downloadCertificateLink = generateLPFinalItemTemplateCertificateLinks(
-                                $certificate
-                            );
-                        }
-
-                        if (is_array($certificate) &&
-                            isset($certificate['badge_link'])
-                        ) {
-                            $courseId = api_get_course_int_id();
-                            $badgeLink = generateLPFinalItemTemplateBadgeLinks(
-                                $userId,
-                                $courseId,
-                                $sessionId
-                            );
-                        }
+                if (!empty($certificate['pdf_url']) ||
+                    !empty($certificate['badge_link'])
+                ) {
+                    if (is_array($certificate)) {
+                        $downloadCertificateLink = Category::getDownloadCertificateBlock($certificate);
                     }
 
-                    $currentScore = Category::getCurrentScore(
-                        $userId,
-                        $category,
-                        true
-                    );
-                    Category::registerCurrentScore(
-                        $currentScore,
-                        $userId,
-                        $categoryId
-                    );
+                    if (is_array($certificate) &&
+                        isset($certificate['badge_link'])
+                    ) {
+                        $courseId = api_get_course_int_id();
+                        $badgeLink = generateLPFinalItemTemplateBadgeLinks(
+                            $userId,
+                            $courseId,
+                            $sessionId
+                        );
+                    }
                 }
+
+                $currentScore = Category::getCurrentScore(
+                    $userId,
+                    $category,
+                    true
+                );
+                Category::registerCurrentScore(
+                    $currentScore,
+                    $userId,
+                    $categoryId
+                );
             }
         }
 
@@ -289,30 +283,3 @@ function generateLPFinalItemTemplateBadgeLinks($userId, $courseId, $sessionId =
 
     return $badgeLink;
 }
-
-/**
- * Return HTML string with certificate links.
- *
- * @param array $certificate
- *
- * @return string HTML string for certificates
- */
-function generateLPFinalItemTemplateCertificateLinks($certificate)
-{
-    $downloadCertificateLink = Display::url(
-        Display::returnFontAwesomeIcon('file-pdf-o').get_lang('DownloadCertificatePdf'),
-        $certificate['pdf_url'],
-        ['class' => 'btn btn-default']
-    );
-    $viewCertificateLink = $certificate['certificate_link'];
-    $downloadCertificateLink = "
-        <div class='panel panel-default'>
-            <div class='panel-body'>
-                <h3 class='text-center'>".get_lang('NowDownloadYourCertificateClickHere')."</h3>
-                <div class='text-center'>$downloadCertificateLink $viewCertificateLink</div>
-            </div>
-        </div>
-    ";
-
-    return $downloadCertificateLink;
-}

+ 1 - 1
main/lp/lp_impress.php

@@ -19,7 +19,7 @@ $lp_id = intval($_GET['lp_id']);
 
 // Check if the learning path is visible for student - (LP requisites)
 if (!api_is_allowed_to_edit(null, true) &&
-    !learnpath::is_lp_visible_for_student($lp_id, api_get_user_id())
+    !learnpath::is_lp_visible_for_student($lp_id, api_get_user_id(), api_get_course_info())
 ) {
     api_not_allowed();
 }

+ 145 - 199
main/lp/lp_list.php

@@ -16,11 +16,14 @@ use ChamiloSession as Session;
 $this_section = SECTION_COURSES;
 //@todo who turns on $lp_controller_touched?
 if (empty($lp_controller_touched) || $lp_controller_touched != 1) {
-    header('location: lp_controller.php?action=list');
+    header('Location: lp_controller.php?action=list&'.api_get_cidreq());
     exit;
 }
 
 require_once __DIR__.'/../inc/global.inc.php';
+
+api_protect_course_script();
+
 $courseDir = api_get_course_path().'/scorm';
 $baseWordDir = $courseDir;
 
@@ -28,8 +31,7 @@ $baseWordDir = $courseDir;
  * Display initialisation and security checks.
  */
 // Extra javascript functions for in html head:
-$htmlHeadXtra[]
-    = "<script>
+$htmlHeadXtra[] = "<script>
 function confirmation(name) {
     if (confirm(\" ".trim(get_lang('AreYouSureToDeleteJS'))." \"+name+\"?\")) {
         return true;
@@ -40,17 +42,16 @@ function confirmation(name) {
 </script>";
 $nameTools = get_lang('LearningPaths');
 Event::event_access_tool(TOOL_LEARNPATH);
-api_protect_course_script();
 
-/**
- * Display.
- */
 /* Require the search widget and prepare the header with its stuff. */
 if (api_get_setting('search_enabled') === 'true') {
     require api_get_path(LIBRARY_PATH).'search/search_widget.php';
     search_widget_prepare($htmlHeadXtra);
 }
+$courseId = api_get_course_int_id();
 $sessionId = api_get_session_id();
+$is_allowed_to_edit = api_is_allowed_to_edit(null, true);
+$courseInfo = api_get_course_info();
 
 $subscriptionSettings = learnpath::getSubscriptionSettings();
 
@@ -67,11 +68,8 @@ $introduction = Display::return_introduction_section(
     ]
 );
 
-$is_allowed_to_edit = api_is_allowed_to_edit(null, true);
-$courseInfo = api_get_course_info();
 $message = '';
 $actions = '';
-
 if ($is_allowed_to_edit) {
     $actionLeft = '';
     $actionLeft .= Display::url(
@@ -121,8 +119,7 @@ if ($is_allowed_to_edit) {
 
 $token = Security::get_token();
 
-/* DISPLAY SCORM LIST */
-$categoriesTempList = learnpath::getCategories(api_get_course_int_id());
+$categoriesTempList = learnpath::getCategories($courseId);
 $categoryTest = new CLpCategory();
 $categoryTest->setId(0);
 $categoryTest->setName(get_lang('WithOutCategory'));
@@ -134,7 +131,6 @@ $categories = [
 if (!empty($categoriesTempList)) {
     $categories = array_merge($categories, $categoriesTempList);
 }
-
 $userId = api_get_user_id();
 $userInfo = api_get_user_info();
 $lpIsShown = false;
@@ -155,15 +151,48 @@ if ($filteredCategoryId) {
 $test_mode = api_get_setting('server_type');
 $showBlockedPrerequisite = api_get_configuration_value('show_prerequisite_as_blocked');
 $allowLpChamiloExport = api_get_configuration_value('allow_lp_chamilo_export');
-$allowMinTime = Tracking::minimunTimeAvailable(api_get_session_id(), api_get_course_int_id());
+$allowMinTime = Tracking::minimumTimeAvailable($sessionId, $courseId);
+$accumulateWorkTimeTotal = 0;
+if ($allowMinTime) {
+    $accumulateWorkTimeTotal = learnpath::getAccumulateWorkTimeTotal($courseId);
+}
+
 $user = api_get_user_entity($userId);
 $ending = true;
+$isInvitee = api_is_invitee();
+$hideScormExportLink = api_get_setting('hide_scorm_export_link');
+$hideScormCopyLink = api_get_setting('hide_scorm_copy_link');
+$hideScormPdfLink = api_get_setting('hide_scorm_pdf_link');
+$options = learnpath::getIconSelect();
+$cidReq = api_get_cidreq();
+
+$defaultLpIcon = Display::return_icon(
+    'learnpath.png',
+    get_lang('LPName')
+);
+
+$defaultDisableLpIcon = Display::return_icon(
+    'learnpath_na.png',
+    get_lang('LPName')
+);
+
+$courseSettingsIcon = Display::return_icon(
+    'settings.png',
+    get_lang('CourseSettings')
+);
+
+$courseSettingsDisableIcon = Display::return_icon(
+    'settings_na.png',
+    get_lang('CourseSettings')
+);
+
+$enableAutoLaunch = api_get_course_setting('enable_lp_auto_launch');
+$gameMode = api_get_setting('gamification_mode');
 
 $data = [];
 /** @var CLpCategory $item */
 foreach ($categories as $item) {
     $categoryId = $item->getId();
-
     if ($categoryId !== 0 && $subscriptionSettings['allow_add_users_to_lp_category'] == true) {
         // "Without category" has id = 0
         $categoryVisibility = api_get_item_visibility(
@@ -174,7 +203,7 @@ foreach ($categories as $item) {
         );
 
         if (!$is_allowed_to_edit) {
-            if ((int) $categoryVisibility !== 1 && $categoryVisibility != -1) {
+            if ($categoryVisibility !== 1 && $categoryVisibility != -1) {
                 continue;
             }
         }
@@ -185,9 +214,9 @@ foreach ($categories as $item) {
     }
 
     $list = new LearnpathList(
-        api_get_user_id(),
-        api_get_course_id(),
-        api_get_session_id(),
+        $userId,
+        $courseInfo,
+        $sessionId,
         null,
         false,
         $categoryId
@@ -196,64 +225,65 @@ foreach ($categories as $item) {
     $flat_list = $list->get_flat_list();
 
     // Hiding categories with out LPs (only for student)
-    if (empty($flat_list) && !api_is_allowed_to_edit()) {
+    if (empty($flat_list) && !$is_allowed_to_edit) {
         continue;
     }
 
     $listData = [];
     $lpTimeList = [];
     if ($allowMinTime) {
-        $lpTimeList = Tracking::getCalculateTime($userId, api_get_course_int_id(), api_get_session_id());
+        $lpTimeList = Tracking::getCalculateTime($userId, $courseId, $sessionId);
     }
 
-    $options = learnpath::getIconSelect();
-
     if (!empty($flat_list)) {
         $max = count($flat_list);
         $counter = 0;
         $current = 0;
         $autolaunch_exists = false;
-        $accumulateWorkTimeTotal = 0;
-        if ($allowMinTime) {
-            $accumulateWorkTimeTotal = learnpath::getAccumulateWorkTimeTotal(api_get_course_int_id());
-        }
 
+        $progressList = learnpath::getProgressFromLpList(
+            array_column($flat_list, 'lp_old_id'),
+            $userId,
+            $courseId,
+            $sessionId
+        );
+
+        $now = time();
         foreach ($flat_list as $id => $details) {
             $id = $details['lp_old_id'];
-            // Validation when belongs to a session.
-            $session_img = api_get_session_image(
-                $details['lp_session'],
-                $userInfo['status']
-            );
 
             if (!$is_allowed_to_edit && $details['lp_visibility'] == 0) {
                 // This is a student and this path is invisible, skip.
                 continue;
             }
 
-            $lpVisibility = learnpath::is_lp_visible_for_student($id, $userId);
-            $isBlocked = learnpath::isBlockedByPrerequisite(
-                $userId,
-                $details['prerequisite'],
-                $courseInfo,
-                api_get_session_id()
-            );
+            $lpVisibility = learnpath::is_lp_visible_for_student($id, $userId, $courseInfo);
 
             // Check if the learnpath is visible for student.
-            if (!$is_allowed_to_edit && $lpVisibility === false
-                && ($isBlocked && $showBlockedPrerequisite === false)
-            ) {
-                continue;
+            if (!$is_allowed_to_edit) {
+                $isBlocked = learnpath::isBlockedByPrerequisite(
+                    $userId,
+                    $details['prerequisite'],
+                    $courseInfo,
+                    $sessionId
+                );
+                if ($lpVisibility === false && $isBlocked && $showBlockedPrerequisite === false) {
+                    continue;
+                }
             }
 
             $start_time = $end_time = '';
-            if (!$is_allowed_to_edit) {
+            if ($is_allowed_to_edit) {
+                if (!empty($details['publicated_on'])) {
+                    $start_time = api_convert_and_format_date($details['publicated_on'], DATE_TIME_FORMAT_LONG_24H);
+                }
+                if (!empty($details['expired_on'])) {
+                    $end_time = api_convert_and_format_date($details['expired_on'], DATE_TIME_FORMAT_LONG_24H);
+                }
+            } else {
                 $time_limits = false;
-
                 // This is an old LP (from a migration 1.8.7) so we do nothing
-                if (empty($details['created_on']) &&
-                    empty($details['modified_on'])
-                ) {
+                if (empty($details['created_on']) && empty($details['modified_on'])) {
                     $time_limits = false;
                 }
 
@@ -264,18 +294,9 @@ foreach ($categories as $item) {
 
                 if ($time_limits) {
                     // Check if start time
-                    if (!empty($details['publicated_on']) &&
-                        !empty($details['expired_on'])
-                    ) {
-                        $start_time = api_strtotime(
-                            $details['publicated_on'],
-                            'UTC'
-                        );
-                        $end_time = api_strtotime(
-                            $details['expired_on'],
-                            'UTC'
-                        );
-                        $now = time();
+                    if (!empty($details['publicated_on']) && !empty($details['expired_on'])) {
+                        $start_time = api_strtotime($details['publicated_on'], 'UTC');
+                        $end_time = api_strtotime($details['expired_on'], 'UTC');
                         $is_actived_time = false;
                         if ($now > $start_time && $end_time > $now) {
                             $is_actived_time = true;
@@ -286,30 +307,15 @@ foreach ($categories as $item) {
                         }
                     }
                 }
-                $start_time = $end_time = '';
-            } else {
-                if (!empty($details['publicated_on'])) {
-                    $start_time = api_convert_and_format_date(
-                        $details['publicated_on'],
-                        DATE_TIME_FORMAT_LONG_24H
-                    );
-                }
-                if (!empty($details['expired_on'])) {
-                    $end_time = api_convert_and_format_date(
-                        $details['expired_on'],
-                        DATE_TIME_FORMAT_LONG_24H
-                    );
-                }
             }
 
             $counter++;
+            $oddclass = 'row_even';
             if (($counter % 2) == 0) {
                 $oddclass = 'row_odd';
-            } else {
-                $oddclass = 'row_even';
             }
 
-            $url_start_lp = 'lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.$id;
+            $url_start_lp = 'lp_controller.php?'.$cidReq.'&action=view&lp_id='.$id;
             $name = Security::remove_XSS($details['lp_name']);
             $extra = null;
 
@@ -322,26 +328,18 @@ foreach ($categories as $item) {
                     .($lpVisibility
                         ? ''
                         : ' - ('.get_lang('LPNotVisibleToStudent').')');
-                $extra = '<div class ="lp_content_type_label">'.$dsp_desc
-                    .'</div>';
+                $extra = '<div class ="lp_content_type_label">'.$dsp_desc.'</div>';
             }
 
             $my_title = $name;
-            $icon_learnpath = Display::return_icon(
-                'learnpath.png',
-                get_lang('LPName')
-            );
-
+            $icon_learnpath = $defaultLpIcon;
             if ($details['lp_visibility'] == 0) {
                 $my_title = Display::tag(
                     'font',
                     $name,
                     ['class' => 'text-muted']
                 );
-                $icon_learnpath = Display::return_icon(
-                    'learnpath_na.png',
-                    get_lang('LPName')
-                );
+                $icon_learnpath = $defaultDisableLpIcon;
             }
 
             if (!empty($options)) {
@@ -360,10 +358,7 @@ foreach ($categories as $item) {
                     $name,
                     ['class' => 'text-muted']
                 );
-                $icon_learnpath = Display::return_icon(
-                    'learnpath_na.png',
-                    get_lang('LPName')
-                );
+                $icon_learnpath = $defaultDisableLpIcon;
                 $url_start_lp = '#';
             }
 
@@ -376,22 +371,17 @@ foreach ($categories as $item) {
             $dsp_default_view = '';
             $dsp_debug = '';
             $dsp_order = '';
-            $progress = 0;
 
-            if (!api_is_invitee()) {
-                $progress = learnpath::getProgress(
-                    $id,
-                    $userId,
-                    api_get_course_int_id(),
-                    api_get_session_id()
-                );
+            $progress = 0;
+            if (!$isInvitee) {
+                $progress = isset($progressList[$id]) && !empty($progressList[$id]) ? $progressList[$id] : 0;
             }
 
             if ($is_allowed_to_edit) {
                 $dsp_progress = '<center>'.$progress.'%</center>';
             } else {
                 $dsp_progress = '';
-                if (!api_is_invitee()) {
+                if (!$isInvitee) {
                     $dsp_progress = learnpath::get_progress_bar($progress, '%');
                 }
             }
@@ -404,7 +394,7 @@ foreach ($categories as $item) {
             $linkMinTime = '';
             if ($allowMinTime) {
                 // Minimum time (in minutes) to pass the learning path
-                $accumulateWorkTime = learnpath::getAccumulateWorkTimePrerequisite($id, api_get_course_int_id());
+                $accumulateWorkTime = learnpath::getAccumulateWorkTimePrerequisite($id, $courseId);
                 if ($accumulateWorkTime > 0) {
                     $lpTime = isset($lpTimeList[TOOL_LEARNPATH][$id]) ? $lpTimeList[TOOL_LEARNPATH][$id] : 0;
 
@@ -444,7 +434,7 @@ foreach ($categories as $item) {
                         $time_progress_perc = '100%';
                         $time_progress_value = 100;
                     } else {
-                        $time_progress_value = intval(($lpTime * 100) / ($accumulateWorkTime * 60));
+                        $time_progress_value = (int) (($lpTime * 100) / ($accumulateWorkTime * 60));
                     }
 
                     if ($time_progress_value < 100) {
@@ -472,18 +462,11 @@ foreach ($categories as $item) {
                 // EDIT LP
                 if ($sessionId == $details['lp_session']) {
                     $dsp_edit_lp = Display::url(
-                        Display::return_icon(
-                            'settings.png',
-                            get_lang('CourseSettings')
-                        ),
-                        "lp_controller.php?".api_get_cidreq()
-                            ."&action=edit&lp_id=$id"
+                        $courseSettingsIcon,
+                        'lp_controller.php?'.$cidReq."&action=edit&lp_id=$id"
                     );
                 } else {
-                    $dsp_edit_lp = Display::return_icon(
-                        'settings_na.png',
-                        get_lang('CourseSettings')
-                    );
+                    $dsp_edit_lp = $courseSettingsDisableIcon;
                 }
 
                 // BUILD
@@ -494,7 +477,7 @@ foreach ($categories as $item) {
                                 'edit.png',
                                 get_lang('LearnpathEditLearnpath')
                             ),
-                            'lp_controller.php?'.api_get_cidreq().'&'
+                            'lp_controller.php?'.$cidReq.'&'
                                 .http_build_query(
                                     [
                                         'action' => 'add_item',
@@ -531,22 +514,20 @@ foreach ($categories as $item) {
                                 'invisible.png',
                                 get_lang('Show')
                             ),
-                            api_get_self().'?'.api_get_cidreq()
-                                ."&lp_id=$id&action=toggle_visible&new_status=1"
+                            api_get_self().'?'.$cidReq."&lp_id=$id&action=toggle_visible&new_status=1"
                         );
                     } else {
                         $dsp_visible = Display::url(
                             Display::return_icon('visible.png', get_lang('Hide')),
-                            api_get_self().'?'.api_get_cidreq()
-                                ."&lp_id=$id&action=toggle_visible&new_status=0"
+                            api_get_self().'?'.$cidReq."&lp_id=$id&action=toggle_visible&new_status=0"
                         );
                     }
                 }
 
                 // Tracking command
-                $trackingActionUrl = 'lp_controller.php?'
-                    .api_get_cidreq().'&'
-                    .http_build_query(['action' => 'report', 'lp_id' => $id]);
+                $trackingActionUrl = 'lp_controller.php?'.$cidReq.'&'.http_build_query(
+                    ['action' => 'report', 'lp_id' => $id]
+                );
 
                 $trackingAction = Display::url(
                     Display::return_icon(
@@ -558,14 +539,13 @@ foreach ($categories as $item) {
 
                 /* PUBLISH COMMAND */
                 if ($sessionId == $details['lp_session']) {
-                    if ($details['lp_published'] == "i") {
+                    if ($details['lp_published'] == 'i') {
                         $dsp_publish = Display::url(
                             Display::return_icon(
                                 'lp_publish_na.png',
                                 get_lang('LearnpathPublish')
                             ),
-                            api_get_self().'?'.api_get_cidreq()
-                                ."&lp_id=$id&action=toggle_publish&new_status=v"
+                            api_get_self().'?'.$cidReq."&lp_id=$id&action=toggle_publish&new_status=v"
                         );
                     } else {
                         $dsp_publish = Display::url(
@@ -573,8 +553,7 @@ foreach ($categories as $item) {
                                 'lp_publish.png',
                                 get_lang('LearnpathDoNotPublish')
                             ),
-                            api_get_self().'?'.api_get_cidreq()
-                                ."&lp_id=$id&action=toggle_publish&new_status=i"
+                            api_get_self().'?'.$cidReq."&lp_id=$id&action=toggle_publish&new_status=i"
                         );
                     }
                 } else {
@@ -591,17 +570,14 @@ foreach ($categories as $item) {
                  * It is thus a mix betwenn multiple attempt and mono attempt
                  */
                 if ($sessionId == $details['lp_session']) {
-                    if ($details['seriousgame_mode'] == 1
-                        && $details['lp_prevent_reinit'] == 1
-                    ) {
+                    if ($details['seriousgame_mode'] == 1 && $details['lp_prevent_reinit'] == 1) {
                         // seriousgame mode | next = single
                         $dsp_reinit = Display::url(
                             Display::return_icon(
                                 'reload.png',
                                 get_lang('PreventMultipleAttempts')
                             ),
-                            "lp_controller.php?".api_get_cidreq()
-                                ."&action=switch_attempt_mode&lp_id=$id"
+                            'lp_controller.php?'.$cidReq."&action=switch_attempt_mode&lp_id=$id"
                         );
                     }
                     if ($details['seriousgame_mode'] == 0 &&
@@ -613,8 +589,7 @@ foreach ($categories as $item) {
                                 'reload_na.png',
                                 get_lang('AllowMultipleAttempts')
                             ),
-                            "lp_controller.php?".api_get_cidreq()
-                                ."&action=switch_attempt_mode&lp_id=$id"
+                            'lp_controller.php?'.$cidReq."&action=switch_attempt_mode&lp_id=$id"
                         );
                     }
                     if ($details['seriousgame_mode'] == 0 &&
@@ -626,8 +601,7 @@ foreach ($categories as $item) {
                                 'reload.png',
                                 get_lang('AllowMultipleAttempts')
                             ),
-                            "lp_controller.php?".api_get_cidreq()
-                                ."&action=switch_attempt_mode&lp_id=$id"
+                            'lp_controller.php?'.$cidReq."&action=switch_attempt_mode&lp_id=$id"
                         );
                     }
                 } else {
@@ -646,9 +620,7 @@ foreach ($categories as $item) {
                                     'view_fullscreen.png',
                                     get_lang('ViewModeFullScreen')
                                 ),
-                                'lp_controller.php?'.api_get_cidreq()
-                                    .'&action=switch_view_mode&lp_id='.$id
-                                    .$token_parameter
+                                'lp_controller.php?'.$cidReq.'&action=switch_view_mode&lp_id='.$id.$token_parameter
                             );
                             break;
                         case 'embedded':
@@ -657,9 +629,7 @@ foreach ($categories as $item) {
                                     'view_left_right.png',
                                     get_lang('ViewModeEmbedded')
                                 ),
-                                'lp_controller.php?'.api_get_cidreq()
-                                    .'&action=switch_view_mode&lp_id='.$id
-                                    .$token_parameter
+                                'lp_controller.php?'.$cidReq.'&action=switch_view_mode&lp_id='.$id.$token_parameter
                             );
                             break;
                         case 'embedframe':
@@ -668,9 +638,7 @@ foreach ($categories as $item) {
                                     'view_nofullscreen.png',
                                     get_lang('ViewModeEmbedFrame')
                                 ),
-                                'lp_controller.php?'.api_get_cidreq()
-                                    .'&action=switch_view_mode&lp_id='.$id
-                                    .$token_parameter
+                                'lp_controller.php?'.$cidReq.'&action=switch_view_mode&lp_id='.$id.$token_parameter
                             );
                             break;
                         case 'impress':
@@ -679,14 +647,12 @@ foreach ($categories as $item) {
                                     'window_list_slide.png',
                                     get_lang('ViewModeImpress')
                                 ),
-                                'lp_controller.php?'.api_get_cidreq()
-                                    .'&action=switch_view_mode&lp_id='.$id
-                                    .$token_parameter
+                                'lp_controller.php?'.$cidReq.'&action=switch_view_mode&lp_id='.$id.$token_parameter
                             );
                             break;
                     }
                 } else {
-                    if ($details['lp_view_mode'] == 'fullscreen') {
+                    if ($details['lp_view_mode'] === 'fullscreen') {
                         $dsp_default_view = Display::return_icon(
                             'view_fullscreen_na.png',
                             get_lang('ViewModeEmbedded')
@@ -700,15 +666,14 @@ foreach ($categories as $item) {
                 }
 
                 /*  DEBUG  */
-                if ($test_mode == 'test' || api_is_platform_admin()) {
+                if ($test_mode === 'test' || api_is_platform_admin()) {
                     if ($details['lp_scorm_debug'] == 1) {
                         $dsp_debug = Display::url(
                             Display::return_icon(
                                 'bug.png',
                                 get_lang('HideDebug')
                             ),
-                            "lp_controller.php?".api_get_cidreq()
-                                ."&action=switch_scorm_debug&lp_id=$id"
+                            "lp_controller.php?$cidReq&action=switch_scorm_debug&lp_id=$id"
                         );
                     } else {
                         $dsp_debug = Display::url(
@@ -716,8 +681,7 @@ foreach ($categories as $item) {
                                 'bug_na.png',
                                 get_lang('ShowDebug')
                             ),
-                            "lp_controller.php?".api_get_cidreq()
-                                ."&action=switch_scorm_debug&lp_id=$id"
+                            'lp_controller.php?'.$cidReq."&action=switch_scorm_debug&lp_id=$id"
                         );
                     }
                 }
@@ -726,15 +690,13 @@ foreach ($categories as $item) {
                 if ($details['lp_type'] == 1) {
                     $dsp_disk = Display::url(
                         Display::return_icon('cd.png', get_lang('ExportShort')),
-                        api_get_self()."?".api_get_cidreq()
-                            ."&action=export&lp_id=$id"
+                        api_get_self()."?$cidReq&action=export&lp_id=$id"
                     );
                 } elseif ($details['lp_type'] == 2) {
                     $dsp_disk = Display::url(
                         Display::return_icon('cd.png', get_lang('ExportShort')),
-                        api_get_self()."?".api_get_cidreq()
-                            ."&action=export&lp_id=$id&export_name="
-                            .api_replace_dangerous_char($name).".zip"
+                        api_get_self()."?$cidReq&action=export&lp_id=$id&export_name="
+                            .api_replace_dangerous_char($name).'.zip'
                     );
                 } else {
                     $dsp_disk = Display::return_icon(
@@ -746,7 +708,7 @@ foreach ($categories as $item) {
                 // Copy
                 $copy = Display::url(
                     Display::return_icon('cd_copy.png', get_lang('Copy')),
-                    api_get_self()."?".api_get_cidreq()."&action=copy&lp_id=$id"
+                    api_get_self().'?'.$cidReq."&action=copy&lp_id=$id"
                 );
 
                 // Subscribe users
@@ -759,12 +721,12 @@ foreach ($categories as $item) {
                             'user.png',
                             get_lang('SubscribeUsersToLp')
                         ),
-                        api_get_path(WEB_CODE_PATH)."lp/lp_subscribe_users.php?lp_id=$id&".api_get_cidreq()
+                        api_get_path(WEB_CODE_PATH)."lp/lp_subscribe_users.php?lp_id=$id&".$cidReq
                     );
                 }
 
                 /* Auto launch LP code */
-                if (api_get_course_setting('enable_lp_auto_launch') == 1) {
+                if ($enableAutoLaunch == 1) {
                     if ($details['autolaunch'] == 1 &&
                         $autolaunch_exists == false
                     ) {
@@ -774,8 +736,7 @@ foreach ($categories as $item) {
                                 'launch.png',
                                 get_lang('DisableLPAutoLaunch')
                             ),
-                            api_get_self().'?'.api_get_cidreq()
-                            ."&action=auto_launch&status=0&lp_id=$id"
+                            api_get_self().'?'.$cidReq."&action=auto_launch&status=0&lp_id=$id"
                         );
                     } else {
                         $lp_auto_launch_icon = Display::url(
@@ -783,8 +744,7 @@ foreach ($categories as $item) {
                                 'launch_na.png',
                                 get_lang('EnableLPAutoLaunch')
                             ),
-                            api_get_self().'?'.api_get_cidreq()
-                            ."&action=auto_launch&status=1&lp_id=$id"
+                            api_get_self().'?'.$cidReq."&action=auto_launch&status=1&lp_id=$id"
                         );
                     }
                 }
@@ -795,8 +755,7 @@ foreach ($categories as $item) {
                         'pdf.png',
                         get_lang('ExportToPDFOnlyHTMLAndImages')
                     ),
-                    api_get_self().'?'.api_get_cidreq()
-                    ."&action=export_to_pdf&lp_id=$id"
+                    api_get_self().'?'.$cidReq."&action=export_to_pdf&lp_id=$id"
                 );
 
                 /* Delete */
@@ -806,11 +765,9 @@ foreach ($categories as $item) {
                             'delete.png',
                             get_lang('LearnpathDeleteLearnpath')
                         ),
-                        'lp_controller.php?'.api_get_cidreq()
-                        ."&action=delete&lp_id=$id",
+                        'lp_controller.php?'.$cidReq."&action=delete&lp_id=$id",
                         [
-                            'onclick' => "javascript: return confirmation('"
-                                .addslashes($name)."');",
+                            'onclick' => "javascript: return confirmation('".addslashes($name)."');",
                         ]
                     );
                 } else {
@@ -826,33 +783,29 @@ foreach ($categories as $item) {
                     if ($details['lp_display_order'] == 1 && $max != 1) {
                         $dsp_order .= Display::url(
                             Display::return_icon('down.png', get_lang('MoveDown')),
-                            "lp_controller.php?".api_get_cidreq()
-                                ."&action=move_lp_down&lp_id=$id&category_id=$categoryId"
+                            "lp_controller.php?$cidReq&action=move_lp_down&lp_id=$id&category_id=$categoryId"
                         );
                     } elseif ($current == $max - 1 && $max != 1) {
                         $dsp_order .= Display::url(
                             Display::return_icon('up.png', get_lang('MoveUp')),
-                            "lp_controller.php?".api_get_cidreq()
-                                ."&action=move_lp_up&lp_id=$id&category_id=$categoryId"
+                            "lp_controller.php?$cidReq&action=move_lp_up&lp_id=$id&category_id=$categoryId"
                         );
                     } elseif ($max == 1) {
                         $dsp_order = '';
                     } else {
                         $dsp_order .= Display::url(
                             Display::return_icon('down.png', get_lang('MoveDown')),
-                            "lp_controller.php?".api_get_cidreq()
-                                ."&action=move_lp_down&lp_id=$id&category_id=$categoryId"
+                            "lp_controller.php?$cidReq&action=move_lp_down&lp_id=$id&category_id=$categoryId"
                         );
                         $dsp_order .= Display::url(
                             Display::return_icon('up.png', get_lang('MoveUp')),
-                            "lp_controller.php?".api_get_cidreq()
-                                ."&action=move_lp_up&lp_id=$id&category_id=$categoryId"
+                            "lp_controller.php?$cidReq&action=move_lp_up&lp_id=$id&category_id=$categoryId"
                         );
                     }
                 }
 
                 if ($details['lp_type'] == 2) {
-                    $url = api_get_path(WEB_CODE_PATH)."lp/lp_update_scorm.php?".api_get_cidreq()."&lp_id=$id";
+                    $url = api_get_path(WEB_CODE_PATH).'lp/lp_update_scorm.php?'.$cidReq."&lp_id=$id";
                     $actionUpdateScormFile = Display::url(
                         Display::return_icon('upload_file.png', get_lang('Update')),
                         $url
@@ -865,23 +818,15 @@ foreach ($categories as $item) {
                             'backup.png',
                             get_lang('ExportToChamiloFormat')
                         ),
-                        api_get_self().'?'.api_get_cidreq()
-                        ."&action=export_to_course_build&lp_id=$id"
+                        api_get_self().'?'.$cidReq."&action=export_to_course_build&lp_id=$id"
                     );
                 }
 
-                if ($is_allowed_to_edit) {
-                    $start_time = $start_time;
-                    $end_time = $end_time;
-                } else {
-                    $start_time = $end_time = '';
-                }
-
-                if (api_get_setting('gamification_mode') == 1) {
+                if ($gameMode == 1) {
                     if ($details['seriousgame_mode'] == 0) {
                         $actionSeriousGame = Display::toolbarButton(
                             null,
-                            api_get_self().'?'.api_get_cidreq()
+                            api_get_self().'?'.$cidReq
                                 ."&lp_id=$id&action=toggle_seriousgame",
                             'trophy',
                             'default',
@@ -893,7 +838,7 @@ foreach ($categories as $item) {
                     } else {
                         $actionSeriousGame = Display::toolbarButton(
                             null,
-                            api_get_self().'?'.api_get_cidreq()
+                            api_get_self().'?'.$cidReq
                                 ."&lp_id=$id&action=toggle_seriousgame",
                             'trophy',
                             'warning',
@@ -908,31 +853,32 @@ foreach ($categories as $item) {
                 // Student
                 $export_icon = Display::url(
                     Display::return_icon('pdf.png', get_lang('ExportToPDF')),
-                    api_get_self().'?'.api_get_cidreq()
-                        ."&action=export_to_pdf&lp_id=$id"
+                    api_get_self().'?'.$cidReq."&action=export_to_pdf&lp_id=$id"
                 );
             }
 
-            $hideScormExportLink = api_get_setting('hide_scorm_export_link');
             if ($hideScormExportLink === 'true') {
                 $dsp_disk = null;
             }
 
-            $hideScormCopyLink = api_get_setting('hide_scorm_copy_link');
             if ($hideScormCopyLink === 'true') {
                 $copy = null;
             }
 
-            $hideScormPdfLink = api_get_setting('hide_scorm_pdf_link');
             if ($hideScormPdfLink === 'true') {
                 $export_icon = null;
             }
 
+            $sessionImage = api_get_session_image(
+                $details['lp_session'],
+                $userInfo['status']
+            );
+
             $listData[] = [
                 'learnpath_icon' => $icon_learnpath,
                 'url_start' => $url_start_lp,
                 'title' => $my_title,
-                'session_image' => $session_img,
+                'session_image' => $sessionImage,
                 'extra' => $extra,
                 'start_time' => $start_time,
                 'end_time' => $end_time,
@@ -995,7 +941,7 @@ DocumentManager::removeGeneratedAudioTempFile();
 $template = new Template($nameTools);
 $template->assign('subscription_settings', $subscriptionSettings);
 $template->assign('is_allowed_to_edit', $is_allowed_to_edit);
-$template->assign('is_invitee', api_is_invitee());
+$template->assign('is_invitee', $isInvitee);
 $template->assign('is_ending', $ending);
 $template->assign('actions', $actions);
 $template->assign('categories', $categories);

+ 0 - 1
main/lp/lp_save.php

@@ -15,7 +15,6 @@ use ChamiloSession as Session;
  * Initialization is to be done by lp_controller.php.
  * Switching within the field to update.
  */
-error_log('New LP - Loaded lp_save : '.$_SERVER['REQUEST_URI'].' from '.$_SERVER['HTTP_REFERER'], 0);
 ?>
 <!DOCTYPE html
      PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

+ 2 - 2
main/lp/lp_stats.php

@@ -25,7 +25,7 @@ $extendId = isset($_GET['extend_id']) ? $_GET['extend_id'] : null;
 $extendAttemptId = isset($_GET['extend_attempt_id']) ? $_GET['extend_attempt_id'] : null;
 $extendedAttempt = isset($_GET['extend_attempt']) ? $_GET['extend_attempt'] : null;
 $extendedAll = isset($_GET['extend_all']) ? $_GET['extend_all'] : null;
-$export = isset($_GET['export']) && $_GET['export'] === 'csv' ? true : false;
+$export = isset($_GET['export']) && $_GET['export'] === 'csv';
 $allowExtend = isset($_GET['allow_extend']) ? $_GET['allow_extend'] : 1;
 
 $lpReportType = api_get_setting('lp_show_reduced_report');
@@ -51,7 +51,7 @@ $output = Tracking::getLpStats(
 );
 
 // Origin = tracking means that teachers see that info in the Reporting tool
-if ($origin != 'tracking') {
+if ($origin !== 'tracking') {
     Display::display_reduced_header();
     $output .= '</body></html>';
 }

+ 15 - 2
main/lp/lp_upload.php

@@ -22,6 +22,11 @@ if (empty($_POST['current_dir'])) {
 }
 $uncompress = 1;
 
+$allowHtaccess = false;
+if (api_get_configuration_value('allow_htaccess_import_from_scorm') && isset($_POST['allow_htaccess'])) {
+    $allowHtaccess = true;
+}
+
 /*
  * Check the request method in place of a variable from POST
  * because if the file size exceed the maximum file upload
@@ -59,6 +64,7 @@ if (isset($_POST) && $is_error) {
     if (!empty($_REQUEST['content_proximity'])) {
         $proximity = Database::escape_string($_REQUEST['content_proximity']);
     }
+
     $maker = 'Scorm';
     if (!empty($_REQUEST['content_maker'])) {
         $maker = Database::escape_string($_REQUEST['content_maker']);
@@ -80,7 +86,14 @@ if (isset($_POST) && $is_error) {
             break;
         case 'scorm':
             $oScorm = new scorm();
-            $manifest = $oScorm->import_package($_FILES['user_file'], $current_dir);
+            $manifest = $oScorm->import_package(
+                $_FILES['user_file'],
+                $current_dir,
+                [],
+                false,
+                null,
+                $allowHtaccess
+            );
             if (!empty($manifest)) {
                 $oScorm->parse_manifest($manifest);
                 $oScorm->import_manifest(api_get_course_id(), $_REQUEST['use_max_score']);
@@ -144,7 +157,7 @@ if (isset($_POST) && $is_error) {
     $new_dir = api_replace_dangerous_char(trim($file_base_name));
 
     $result = learnpath::verify_document_size($s);
-    if ($result == true) {
+    if ($result) {
         Display::addFlash(
             Display::return_message(get_lang('UplFileTooBig'))
         );

+ 54 - 10
main/lp/lp_view.php

@@ -26,15 +26,14 @@ if ($lp_controller_touched != 1) {
 
 require_once __DIR__.'/../inc/global.inc.php';
 
+api_protect_course_script();
+
 if (isset($_REQUEST['origin']) && $_REQUEST['origin'] === 'learnpath') {
     $_REQUEST['origin'] = '';
 }
 
-//To prevent the template class
+// To prevent the template class
 $show_learnpath = true;
-
-api_protect_course_script();
-
 $lp_id = !empty($_GET['lp_id']) ? (int) $_GET['lp_id'] : 0;
 $sessionId = api_get_session_id();
 $course_code = api_get_course_id();
@@ -250,7 +249,6 @@ if (!isset($src)) {
                 }
 
                 $src = $lp->fixBlockedLinks($src);
-
                 $lp->start_current_item(); // starts time counter manually if asset
             } else {
                 $src = 'blank.php?error=prerequisites';
@@ -313,9 +311,7 @@ if (!empty($_REQUEST['exeId']) &&
     $safe_id = $lp_id;
     $safe_exe_id = (int) $_REQUEST['exeId'];
 
-    if ($safe_id == strval(intval($safe_id)) &&
-        $safe_item_id == strval(intval($safe_item_id))
-    ) {
+    if (!empty($safe_id) && !empty($safe_item_id)) {
         $sql = 'SELECT start_date, exe_date, exe_result, exe_weighting, exe_exo_id, exe_duration
                 FROM '.$TBL_TRACK_EXERCICES.'
                 WHERE exe_id = '.$safe_exe_id;
@@ -335,7 +331,7 @@ if (!empty($_REQUEST['exeId']) &&
                 WHERE
                     c_id = $course_id AND
                     lp_item_id = $safe_item_id AND
-                    lp_view_id = ".$lp->lp_view_id."
+                    lp_view_id = ".$lp->get_view_id()."
                 ORDER BY id DESC
                 LIMIT 1";
         $res_last_attempt = Database::query($sql);
@@ -376,7 +372,7 @@ if (!empty($_REQUEST['exeId']) &&
             Database::query($sql);
         }
     }
-    if (intval($_GET['fb_type']) > 0) {
+    if (intval($_GET['fb_type']) != EXERCISE_FEEDBACK_TYPE_END) {
         $src = 'blank.php?msg=exerciseFinished';
     } else {
         $src = api_get_path(WEB_CODE_PATH).'exercise/result.php?id='.$safe_exe_id.'&'.api_get_cidreq(true, true, 'learnpath');
@@ -556,6 +552,51 @@ if ($gamificationMode == 1) {
 }
 
 $template->assign('lp_author', $lp->get_author());
+
+$lpMinTime = '';
+if (Tracking::minimumTimeAvailable(api_get_session_id(), api_get_course_int_id())) {
+    // Calulate minimum and accumulated time
+    $timeLp = $_SESSION['oLP']->getAccumulateWorkTime();
+    $timeTotalCourse = $_SESSION['oLP']->getAccumulateWorkTimeTotalCourse();
+    // Minimum connection percentage
+    $perc = 100;
+    // Time from the course
+    $tc = $timeTotalCourse;
+    // Percentage of the learning paths
+    $pl = 0;
+    if (!empty($timeTotalCourse)) {
+        $pl = $timeLp / $timeTotalCourse;
+    }
+
+    // Minimum time for each learning path
+    $time_min = intval($pl * $tc * $perc / 100);
+
+    if ($_SESSION['oLP']->getAccumulateWorkTime() > 0) {
+        $lpMinTime = '('.$time_min.' min)';
+    }
+
+    $lpTimeList = Tracking::getCalculateTime($user_id, api_get_course_int_id(), api_get_session_id());
+    $lpTime = isset($lpTimeList[TOOL_LEARNPATH][$lp_id]) ? (int) $lpTimeList[TOOL_LEARNPATH][$lp_id] : 0;
+
+    if ($lpTime >= ($time_min * 60)) {
+        $time_progress_perc = '100%';
+        $time_progress_value = 100;
+    } else {
+        $time_progress_value = intval(($lpTime * 100) / ($time_min * 60));
+        $time_progress_perc = $time_progress_value.'%';
+    }
+
+    $template->assign('time_progress_perc', $time_progress_perc);
+    $template->assign('time_progress_value', $time_progress_value);
+    // Cronometro
+    $hour = (intval($lpTime / 3600)) < 10 ? '0'.intval($lpTime / 3600) : intval($lpTime / 3600);
+    $template->assign('hour', $hour);
+    $template->assign('minute', date('i', $lpTime));
+    $template->assign('second', date('s', $lpTime));
+    $template->assign('hour_min', api_time_to_hms($timeLp * 60, '</div><div class="divider">:</div><div>'));
+}
+
+$template->assign('lp_accumulate_work_time', $lpMinTime);
 $template->assign('lp_mode', $lp->mode);
 $template->assign('lp_title_scorm', $lp->name);
 // ofaj
@@ -581,6 +622,9 @@ $template->assign(
     )
 );
 
+$frameReady = Display::getFrameReadyBlock('#content_id, #content_id_blank');
+$template->assign('frame_ready', $frameReady);
+
 // Ofaj
 $template->assign('lp_id', $lp->lp_id);
 $template->assign('lp_current_item_id', $lp->get_current_item_id());

+ 0 - 4
main/lp/openoffice_document.class.php

@@ -33,9 +33,6 @@ abstract class OpenofficeDocument extends learnpath
      */
     public function __construct($course_code = null, $resource_id = null, $user_id = null)
     {
-        if ($this->debug > 0) {
-            error_log('In OpenofficeDocument::OpenofficeDocument()', 0);
-        }
         if (!empty($course_code) && !empty($resource_id) && !empty($user_id)) {
             parent::__construct($course_code, $resource_id, $user_id);
         }
@@ -378,7 +375,6 @@ abstract class OpenofficeDocument extends learnpath
         ];
 
         try {
-            //error_log('['.time().'] Calling wsConvertPpt webservice on ' . $ppt2lp_host);
             $result = $client->__call('wsConvertPpt', ['pptData' => $params]);
         } catch (Exception $e) {
             error_log('['.time().'] Chamilo SOAP call error: '.$e->getMessage());

+ 0 - 3
main/lp/openoffice_presentation.class.php

@@ -50,8 +50,6 @@ class OpenofficePresentation extends OpenofficeDocument
                 slide name (with accents) || file name (without accents) || all slide text (to be indexed).
             */
             list($slide_name, $file_name, $slide_body) = explode('||', $file);
-            //error_log('Treating '.$file_name.' from '.__FUNCTION__);
-
             // Filename is utf8 encoded, but when we decode, some chars are not translated (like quote &rsquo;).
             // so we remove these chars by translating it in htmlentities and the reconvert it in want charset.
             $slide_name = api_htmlentities($slide_name, ENT_COMPAT, $this->original_charset);
@@ -67,7 +65,6 @@ class OpenofficePresentation extends OpenofficeDocument
             }
 
             if (!is_file($this->base_work_dir.$dir.$file_name) or filesize($this->base_work_dir.$dir.$file_name) == 0) {
-                //error_log($this->base_work_dir.$dir.$file_name . ' is not a file or is 0');
                 continue;
             }
 

+ 9 - 2
main/lp/scorm.class.php

@@ -597,6 +597,7 @@ class scorm extends learnpath
      * @param array     $courseInfo
      * @param bool      $updateDirContents
      * @param learnpath $lpToCheck
+     * @param bool      $allowHtaccess
      *
      * @return string $current_dir Absolute path to the imsmanifest.xml file or empty string on error
      */
@@ -605,7 +606,8 @@ class scorm extends learnpath
         $currentDir = '',
         $courseInfo = [],
         $updateDirContents = false,
-        $lpToCheck = null
+        $lpToCheck = null,
+        $allowHtaccess = false
     ) {
         if ($this->debug > 0) {
             error_log(
@@ -745,9 +747,14 @@ class scorm extends learnpath
 
             chdir($courseSysDir.$newDir);
 
+            $callBack = 'clean_up_files_in_zip';
+            if ($allowHtaccess) {
+                $callBack = 'cleanZipFilesAllowHtaccess';
+            }
+
             $zipFile->extract(
                 PCLZIP_CB_PRE_EXTRACT,
-                'clean_up_files_in_zip'
+                $callBack
             );
 
             if (!empty($newDir)) {

+ 0 - 3
main/lp/scormItem.class.php

@@ -189,8 +189,5 @@ class scormItem extends learnpathItem
         parent::save($from_outside, $prereqs_complete);
         // Under certain conditions, the scorm_contact should not be set, because no scorm signal was sent.
         $this->scorm_contact = true;
-        if (!$this->scorm_contact) {
-            //error_log('New LP - was expecting SCORM message but none received', 0);
-        }
     }
 }

+ 38 - 11
main/lp/scorm_api.php

@@ -210,8 +210,8 @@ if (olms.score == 0 && olms.lms_item_type == 'sco' && olms.lesson_status == 'not
 }
 
 olms.asset_timer = 0;
-olms.userfname = '<?php echo str_replace("'", "\\'", $user['firstname']); ?>';
-olms.userlname = '<?php echo str_replace("'", "\\'", $user['lastname']); ?>';
+olms.userfname = '<?php echo addslashes(trim($user['firstname'])); ?>';
+olms.userlname = '<?php echo addslashes(trim($user['lastname'])); ?>';
 olms.execute_stats = false;
 
 var courseUrl = '?cidReq='+olms.lms_course_code+'&id_session='+olms.lms_session_id;
@@ -238,7 +238,6 @@ $(function() {
     olms.info_lms_item[0] = '<?php echo $oItem->get_id(); ?>';
     olms.info_lms_item[1] = '<?php echo $oItem->get_id(); ?>';
 
-
     $("#content_id").load(function() {
         logit_lms('#content_id load event starts');
         olms.info_lms_item[0] = olms.info_lms_item[1];
@@ -337,7 +336,12 @@ function LMSInitialize() {
 
         logit_scorm('LMSInitialize() with params: '+log);
 
-    if (olms.lms_lp_type == 1 || olms.lms_item_type == 'asset' || olms.lms_item_type == 'document') {
+        if(olms.lms_item_type == 'sco'){
+            $("#tab-iframe").removeClass();
+            $("#tab-iframe").addClass("tab-content iframe_"+olms.lms_item_type);
+        }
+
+        if (olms.lms_lp_type == 1 || olms.lms_item_type == 'asset' || olms.lms_item_type == 'document') {
             xajax_start_timer();
         }
 
@@ -471,7 +475,7 @@ function LMSGetValue(param) {
     } else if(param == 'cmi.core.student_name'){
         // ---- cmi.core.student_name
         <?php
-          $who = addslashes($user['lastname']).', '.addslashes($user['firstname']);
+          $who = addslashes(trim($user['lastname']).', '.trim($user['firstname']));
           echo "result='$who';";
         ?>
     } else if(param == 'cmi.core.lesson_location'){
@@ -867,7 +871,7 @@ function savedata(item_id) {
 
     // Status is NOT modified here see the lp_ajax_save_item.php file
     if (olms.lesson_status != '') {
-        olms.updatable_vars_list['cmi.core.lesson_status'] = true;
+        //olms.updatable_vars_list['cmi.core.lesson_status'] = true;
     }
 
     old_item_id = olms.info_lms_item[0];
@@ -1439,7 +1443,25 @@ function reinit_updatable_vars_list() {
  * @param	string		This parameter can be a string specifying the next
  *						item (like 'next', 'previous', 'first' or 'last') or the id to the next item
  */
-function switch_item(current_item, next_item){
+function switch_item(current_item, next_item)
+{
+    logit_lms('switch_item() called with params '+olms.lms_item_id+' and '+next_item+'',2);
+
+    if (olms.lms_initialized == 0) {
+        // Fix error when flash is not loaded and SCO is not started BT#14944
+        olms.G_LastError = G_NotInitialized;
+        olms.G_LastErrorMessage = G_NotInitializedMessage;
+        logit_scorm('Error '+ G_NotInitialized + G_NotInitializedMessage, 0);
+        //window.location.reload(false);
+
+        var url = window.location.href + '&item_id='  + parseInt(next_item);
+        window.location.replace(url);
+
+        return false;
+    }
+
+    olms.switch_finished = 0; //only changed back once LMSInitialize() happens
+
     // backup these params
     var orig_current_item   = current_item;
     var orig_next_item      = next_item;
@@ -1452,8 +1474,6 @@ function switch_item(current_item, next_item){
         olms.statusSignalReceived = 1;
     }
 
-    logit_lms('switch_item() called with params '+olms.lms_item_id+' and '+next_item+'',2);
-
     /*
      There are four "cases" for switching items:
      (1) asset switching to asset
@@ -1685,9 +1705,10 @@ function switch_item(current_item, next_item){
             if ($("#lp_media_file").length != 0) {
                 $("#lp_media_file").html(tmp_data);
             }
+
+            LPViewUtils.setHeightLPToc();
         }
     });
-    olms.switch_finished = 0; //only changed back once LMSInitialize() happens
 
     loadForumThread(olms.lms_lp_id, next_item);
     checkCurrentItemPosition(olms.lms_item_id);
@@ -1740,11 +1761,15 @@ var loadForumThread = function(lpId, lpItemId) {
         var tabForumLink = $('.lp-view-tabs a[href="#lp-view-forum"]'),
             tabForum = tabForumLink.parent();
             $("#navTabs").show();
+            $("#tab-iframe").removeClass("tab-none-forum");
+            $("#btn-menu-float").removeClass("none-forum");
 
         if (forumThreadData.error) {
             tabForumLink.removeAttr('data-toggle');
             tabForum.addClass('disabled');
             $("#navTabs").hide();
+            $("#tab-iframe").addClass("tab-none-forum");
+            $("#btn-menu-float").addClass("none-forum");
             $('#lp-view-forum').html('');
 
             return;
@@ -1915,7 +1940,9 @@ function xajax_save_item_scorm(
         } else if (my_scorm_values[k]=='cmi.completion_status') {
         } else if (my_scorm_values[k]=='cmi.score.scaled') {
         } else if (my_scorm_values[k]=='cmi.suspend_data') {
-            params += '&suspend='+olms.suspend_data;
+            // params += '&suspend='+olms.suspend_data;
+            // Fixes error when scorm sends text with "+" sign
+            params += '&suspend='+encodeURIComponent(olms.suspend_data);
         } else if (my_scorm_values[k]=='cmi.completion_status') {
         } else if (my_scorm_values[k]=='cmi.core.exit') {
             params += '&core_exit='+olms.lms_item_core_exit;

+ 6 - 1
main/messages/download.php

@@ -13,12 +13,17 @@ session_cache_limiter('public');
 
 require_once __DIR__.'/../inc/global.inc.php';
 
+$file_url = isset($_GET['file']) ? $_GET['file'] : '';
+
+if (empty($file_url)) {
+    api_not_allowed();
+}
+
 // IMPORTANT to avoid caching of documents
 header('Expires: Wed, 01 Jan 1990 00:00:00 GMT');
 header('Cache-Control: public');
 header('Pragma: no-cache');
 
-$file_url = $_GET['file'];
 //change the '&' that got rewritten to '///' by mod_rewrite back to '&'
 $file_url = str_replace('///', '&', $file_url);
 //still a space present? it must be a '+' (that got replaced by mod_rewrite)

+ 11 - 16
main/messages/inbox.php

@@ -16,10 +16,7 @@ if (api_get_setting('allow_message_tool') != 'true') {
 
 $logInfo = [
     'tool' => 'Messages',
-    'tool_id' => 0,
-    'tool_id_detail' => 0,
     'action' => isset($_GET['action']) ? $_GET['action'] : 'inbox',
-    'action_details' => '',
 ];
 Event::registerLog($logInfo);
 
@@ -54,7 +51,7 @@ if (isset($_GET['form_reply']) || isset($_GET['form_delete'])) {
 
     if (isset($button_sent)) {
         $title = urldecode($info_reply[0]);
-        $content = str_replace("\\", "", urldecode($info_reply[1]));
+        $content = str_replace("\\", '', urldecode($info_reply[1]));
 
         $user_reply = $info_reply[2];
         $user_email_base = str_replace(')', '(', $info_reply[5]);
@@ -72,12 +69,12 @@ if (isset($_GET['form_reply']) || isset($_GET['form_delete'])) {
         if (isset($user_reply) && !is_null($user_id_by_email) && strlen($info_reply[0]) > 0) {
             MessageManager::send_message($user_id_by_email, $title, $content);
             $show_message .= MessageManager::return_message($user_id_by_email, 'confirmation');
-            $social_right_content .= MessageManager::inbox_display();
+            $social_right_content .= MessageManager::inboxDisplay();
             exit;
         } elseif (is_null($user_id_by_email)) {
             $message_box = get_lang('ErrorSendingMessage');
             $show_message .= Display::return_message(api_xml_http_response_encode($message_box), 'error');
-            $social_right_content .= MessageManager::inbox_display();
+            $social_right_content .= MessageManager::inboxDisplay();
             exit;
         }
     } elseif (trim($info_delete[0]) == 'delete') {
@@ -89,7 +86,7 @@ if (isset($_GET['form_reply']) || isset($_GET['form_delete'])) {
         }
         $message_box = get_lang('SelectedMessagesDeleted');
         $show_message .= Display::return_message(api_xml_http_response_encode($message_box));
-        $social_right_content .= MessageManager::inbox_display();
+        $social_right_content .= MessageManager::inboxDisplay();
         exit;
     }
 }
@@ -115,9 +112,8 @@ $interbreadcrumb[] = [
 $interbreadcrumb[] = ['url' => '#', 'name' => get_lang('Inbox')];
 
 $actions = '';
-
 // Comes from normal profile
-if ($allowSocial == false && $allowMessage) {
+if ($allowSocial === false && $allowMessage) {
     $actions .= '<a href="'.api_get_path(WEB_PATH).'main/messages/new_message.php">'.
         Display::return_icon('message_new.png', get_lang('ComposeMessage')).'</a>';
     $actions .= '<a href="'.api_get_path(WEB_PATH).'main/messages/inbox.php">'.
@@ -136,7 +132,7 @@ if ($allowSocial) {
 // Right content
 $social_right_content = '';
 $keyword = '';
-if (api_get_setting('allow_social_tool') === 'true') {
+if ($allowSocial) {
     $actionsLeft = '<a href="'.api_get_path(WEB_PATH).'main/messages/new_message.php">'.
         Display::return_icon('new-message.png', get_lang('ComposeMessage'), [], 32).'</a>';
     $actionsLeft .= '<a href="'.api_get_path(WEB_PATH).'main/messages/outbox.php">'.
@@ -150,22 +146,21 @@ if (api_get_setting('allow_social_tool') === 'true') {
     $actionsRight = $form->returnForm();
     $social_right_content .= Display::toolbarAction('toolbar', [$actionsLeft, $actionsRight]);
 }
-//MAIN CONTENT
 
 if (!isset($_GET['del_msg'])) {
-    $social_right_content .= MessageManager::inbox_display($keyword);
+    $social_right_content .= MessageManager::inboxDisplay($keyword);
 } else {
-    $num_msg = intval($_POST['total']);
+    $num_msg = (int) $_POST['total'];
     for ($i = 0; $i < $num_msg; $i++) {
         if ($_POST[$i]) {
-            //the user_id was necessary to delete a message??
+            // The user_id was necessary to delete a message??
             $show_message .= MessageManager::delete_message_by_user_receiver(
                 api_get_user_id(),
                 $_POST['_'.$i]
             );
         }
     }
-    $social_right_content .= MessageManager::inbox_display();
+    $social_right_content .= MessageManager::inboxDisplay();
 }
 
 $tpl = new Template(null);
@@ -175,7 +170,7 @@ if ($actions) {
 }
 // Block Social Avatar
 SocialManager::setSocialUserBlock($tpl, api_get_user_id(), 'messages');
-if (api_get_setting('allow_social_tool') == 'true') {
+if ($allowSocial) {
     $tpl->assign('social_menu_block', $social_menu_block);
     $tpl->assign('social_right_content', $social_right_content);
     $social_layout = $tpl->get_template('social/inbox.tpl');

+ 13 - 20
main/messages/new_message.php

@@ -24,14 +24,12 @@ if (api_get_setting('allow_message_tool') !== 'true') {
 
 $logInfo = [
     'tool' => 'Messages',
-    'tool_id' => 0,
-    'tool_id_detail' => 0,
     'action' => 'new_message',
     'action_details' => isset($_GET['re_id']) ? 're_id' : '',
 ];
 Event::registerLog($logInfo);
 
-$allowSocial = api_get_setting('allow_social_tool') == 'true';
+$allowSocial = api_get_setting('allow_social_tool') === 'true';
 $nameTools = api_xml_http_response_encode(get_lang('Messages'));
 
 $htmlHeadXtra[] = '<script>
@@ -59,7 +57,6 @@ function add_image_form() {
 }
 </script>';
 $nameTools = get_lang('ComposeMessage');
-
 $tpl = new Template(get_lang('ComposeMessage'));
 
 /**
@@ -173,7 +170,7 @@ function manageForm($default, $select_from_user_list = null, $sent_to = '', $tpl
         $form->addElement('hidden', 'parent_id', $message_id);
     }
 
-    $form->addText('title', get_lang('Subject'));
+    $form->addText('title', get_lang('Subject'), true);
     $form->addHtmlEditor(
         'content',
         get_lang('Message'),
@@ -190,15 +187,11 @@ function manageForm($default, $select_from_user_list = null, $sent_to = '', $tpl
 
         // Adding reply mail
         $user_reply_info = api_get_user_info($message_reply_info['user_sender_id']);
-        $default['content'] = '<link href="';
-        $default['content'] .= api_get_cdn_path(api_get_path(WEB_CSS_PATH).'themes/'.api_get_visual_theme().'/document.css');
-        $default['content'] .= '" media="screen" rel="stylesheet" type="text/css" />';
-        $default['content'] .= '<p><br/></p>'.sprintf(
+        $default['content'] = '<p><br/></p>'.sprintf(
             get_lang('XWroteY'),
             $user_reply_info['complete_name'],
             Security::filter_terms($message_reply_info['content'])
         );
-
     }
 
     if (isset($_GET['forward_id'])) {
@@ -319,7 +312,7 @@ function manageForm($default, $select_from_user_list = null, $sent_to = '', $tpl
             }
         }
         Security::clear_token();
-        header('Location: '.api_get_path(WEB_PATH).'main/messages/inbox.php');
+        header('Location: '.api_get_path(WEB_CODE_PATH).'messages/inbox.php');
         exit;
     } else {
         $token = Security::get_token();
@@ -334,19 +327,19 @@ function manageForm($default, $select_from_user_list = null, $sent_to = '', $tpl
 if ($allowSocial) {
     $this_section = SECTION_SOCIAL;
     $interbreadcrumb[] = [
-        'url' => api_get_path(WEB_PATH).'main/social/home.php',
+        'url' => api_get_path(WEB_CODE_PATH).'social/home.php',
         'name' => get_lang('SocialNetwork'),
     ];
 } else {
     $this_section = SECTION_MYPROFILE;
     $interbreadcrumb[] = [
-        'url' => api_get_path(WEB_PATH).'main/auth/profile.php',
+        'url' => api_get_path(WEB_CODE_PATH).'auth/profile.php',
         'name' => get_lang('Profile'),
     ];
 }
 
 $interbreadcrumb[] = [
-    'url' => api_get_path(WEB_PATH).'main/messages/inbox.php',
+    'url' => api_get_path(WEB_CODE_PATH).'messages/inbox.php',
     'name' => get_lang('Messages'),
 ];
 
@@ -354,9 +347,9 @@ $group_id = isset($_REQUEST['group_id']) ? (int) $_REQUEST['group_id'] : 0;
 $social_right_content = null;
 if ($group_id != 0) {
     $social_right_content .= '<div class=actions>';
-    $social_right_content .= '<a href="'.api_get_path(WEB_PATH).'main/social/group_view.php?id='.$group_id.'">'.
+    $social_right_content .= '<a href="'.api_get_path(WEB_CODE_PATH).'social/group_view.php?id='.$group_id.'">'.
         Display::return_icon('back.png', api_xml_http_response_encode(get_lang('ComposeMessage'))).'</a>';
-    $social_right_content .= '<a href="'.api_get_path(WEB_PATH).'main/messages/new_message.php?group_id='.$group_id.'">'.
+    $social_right_content .= '<a href="'.api_get_path(WEB_CODE_PATH).'messages/new_message.php?group_id='.$group_id.'">'.
         Display::return_icon('message_new.png', api_xml_http_response_encode(get_lang('ComposeMessage'))).'</a>';
     $social_right_content .= '</div>';
 } else {
@@ -364,11 +357,11 @@ if ($group_id != 0) {
     } else {
         $social_right_content .= '<div class=actions>';
         if (api_get_setting('allow_message_tool') === 'true') {
-            $social_right_content .= '<a href="'.api_get_path(WEB_PATH).'main/messages/new_message.php">'.
+            $social_right_content .= '<a href="'.api_get_path(WEB_CODE_PATH).'messages/new_message.php">'.
                 Display::return_icon('message_new.png', get_lang('ComposeMessage')).'</a>';
-            $social_right_content .= '<a href="'.api_get_path(WEB_PATH).'main/messages/inbox.php">'.
+            $social_right_content .= '<a href="'.api_get_path(WEB_CODE_PATH).'messages/inbox.php">'.
                 Display::return_icon('inbox.png', get_lang('Inbox')).'</a>';
-            $social_right_content .= '<a href="'.api_get_path(WEB_PATH).'main/messages/outbox.php">'.
+            $social_right_content .= '<a href="'.api_get_path(WEB_CODE_PATH).'messages/outbox.php">'.
                 Display::return_icon('outbox.png', get_lang('Outbox')).'</a>';
         }
         $social_right_content .= '</div>';
@@ -383,7 +376,7 @@ if ($allowSocial) {
     $social_right_content .= '<div class="row">';
     $social_right_content .= '<div class="col-md-12">';
     $social_right_content .= '<div class="actions">';
-    $social_right_content .= '<a href="'.api_get_path(WEB_PATH).'main/messages/inbox.php">'.
+    $social_right_content .= '<a href="'.api_get_path(WEB_CODE_PATH).'messages/inbox.php">'.
         Display::return_icon('back.png', get_lang('Back'), [], 32).'</a>';
     $social_right_content .= '</div>';
     $social_right_content .= '</div>';

+ 0 - 3
main/messages/outbox.php

@@ -15,10 +15,7 @@ if (api_get_setting('allow_message_tool') != 'true') {
 
 $logInfo = [
     'tool' => 'Messages',
-    'tool_id' => 0,
-    'tool_id_detail' => 0,
     'action' => isset($_GET['action']) ? $_GET['action'] : 'outbox',
-    'action_details' => '',
 ];
 Event::registerLog($logInfo);
 

+ 0 - 2
main/messages/view_message.php

@@ -49,8 +49,6 @@ $message = '';
 
 $logInfo = [
     'tool' => 'Messages',
-    'tool_id' => 0,
-    'tool_id_detail' => 0,
     'action' => $source,
     'action_details' => 'view-message',
 ];

+ 7 - 6
main/mySpace/access_details.php

@@ -30,12 +30,14 @@ if (!$is_allowedToTrack) {
 // the section (for the tabs)
 $this_section = SECTION_TRACKING;
 
-/* MAIN */
-$user_id = intval($_REQUEST['student']);
-$session_id = intval($_GET['id_session']);
+$user_id = isset($_REQUEST['student']) ? (int) $_REQUEST['student'] : 0;
+$session_id = (int) $_GET['id_session'];
 $type = isset($_REQUEST['type']) ? Security::remove_XSS($_REQUEST['type']) : '';
 $course_code = isset($_REQUEST['course']) ? Security::remove_XSS($_REQUEST['course']) : '';
 $courseInfo = api_get_course_info($course_code);
+if (empty($courseInfo)) {
+    api_not_allowed(true);
+}
 $courseId = (!empty($courseInfo['real_id']) ? $courseInfo['real_id'] : null);
 $quote_simple = "'";
 
@@ -127,10 +129,9 @@ $(function() {
 });
 </script>';
 
-//Changes END
 $interbreadcrumb[] = ['url' => '#', 'name' => get_lang('AccessDetails')];
 
-Display :: display_header('');
+Display::display_header('');
 $userInfo = api_get_user_info($user_id);
 $result_to_print = '';
 $sql_result = MySpace::get_connections_to_course($user_id, $courseInfo);
@@ -178,4 +179,4 @@ $form->display();
 </div>
 
 <?php
-Display:: display_footer();
+Display::display_footer();

+ 5 - 3
main/mySpace/admin_view.php

@@ -11,6 +11,8 @@ $exportCSV = isset($_GET['export']) && $_GET['export'] === 'csv' ? true : false;
 $display = isset($_GET['display']) ? Security::remove_XSS($_GET['display']) : null;
 
 $htmlHeadXtra[] = api_get_jqgrid_js();
+$htmlHeadXtra[] = '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'assets/jquery.easy-pie-chart/dist/jquery.easypiechart.js"></script>';
+
 // the section (for the tabs)
 $this_section = SECTION_TRACKING;
 
@@ -23,13 +25,13 @@ if (!$allowToTrack) {
 }
 
 if ($exportCSV) {
-    if ($display == 'user') {
+    if ($display === 'user') {
         MySpace::export_tracking_user_overview();
         exit;
-    } elseif ($display == 'session') {
+    } elseif ($display === 'session') {
         MySpace::export_tracking_session_overview();
         exit;
-    } elseif ($display == 'course') {
+    } elseif ($display === 'course') {
         MySpace::export_tracking_course_overview();
         exit;
     }

+ 1 - 1
main/mySpace/company_reports.php

@@ -34,7 +34,7 @@ $columns = [
     get_lang('Email'),
     get_lang('ManHours'),
     get_lang('CertificateGenerated'),
-    get_lang('Approved'),
+    get_lang('LearnpathsDone'),
     get_lang('CourseAdvance'),
 ];
 

+ 7 - 15
main/mySpace/index.php

@@ -12,17 +12,17 @@ $cidReset = true;
 
 require_once __DIR__.'/../inc/global.inc.php';
 
+// Access control
+api_block_anonymous_users();
+
 $htmlHeadXtra[] = api_get_jqgrid_js();
-$htmlHeadXtra[] = '<script type="text/javascript" src="'
-    .api_get_path(WEB_PUBLIC_PATH).'assets/jquery.easy-pie-chart/dist/jquery.easypiechart.js"></script>';
-// the section (for the tabs)
+$htmlHeadXtra[] = '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'assets/jquery.easy-pie-chart/dist/jquery.easypiechart.js"></script>';
+
 $this_section = SECTION_TRACKING;
-//for HTML editor repository
-//Session::erase('this_section');
 
 ob_start();
 $nameTools = get_lang('MySpace');
-$export_csv = isset($_GET['export']) && $_GET['export'] == 'csv' ? true : false;
+$export_csv = isset($_GET['export']) && $_GET['export'] === 'csv' ? true : false;
 $display = isset($_GET['display']) ? Security::remove_XSS($_GET['display']) : null;
 $csv_content = [];
 $user_id = api_get_user_id();
@@ -31,18 +31,12 @@ $is_coach = api_is_coach($session_id);
 $is_platform_admin = api_is_platform_admin();
 $is_drh = api_is_drh();
 $is_session_admin = api_is_session_admin();
-$title = '';
 $skipData = api_get_configuration_value('tracking_skip_generic_data');
 
-// Access control
-api_block_anonymous_users();
-
 $logInfo = [
     'tool' => SECTION_TRACKING,
     'tool_id' => 0,
     'tool_id_detail' => 0,
-    'action' => '',
-    'action_details' => '',
 ];
 Event::registerLog($logInfo);
 
@@ -70,7 +64,6 @@ $calendarMenuAdded = false;
 
 if ($is_platform_admin) {
     if ($view == 'admin') {
-        $title = get_lang('CoachList');
         $menu_items[] = Display::url(
             Display::return_icon('teacher.png', get_lang('TeacherInterface'), [], ICON_SIZE_MEDIUM),
             api_get_self().'?view=teacher'
@@ -312,13 +305,12 @@ $form = new FormValidator(
     api_get_path(WEB_CODE_PATH).'mySpace/student.php'
 );
 $form = Tracking::setUserSearchForm($form);
-$skipData = api_get_configuration_value('tracking_skip_generic_data');
 
 $totalTimeSpent = null;
 $averageScore = null;
 $posts = null;
 
-if ($skipData == false) {
+if ($skipData === false) {
     if (!empty($students)) {
         // Students
         $studentIds = array_values($students);

+ 219 - 29
main/mySpace/lp_tracking.php

@@ -1,5 +1,9 @@
 <?php
 /* For licensing terms, see /license.txt */
+
+use Chamilo\CoreBundle\Component\Utils\ChamiloApi;
+use Chamilo\CourseBundle\Entity\CLpItemView;
+
 /**
  * Learning paths reporting.
  *
@@ -7,7 +11,6 @@
  */
 require_once __DIR__.'/../inc/global.inc.php';
 
-// resetting the course id
 $cidReset = true;
 $from_myspace = false;
 $from_link = '';
@@ -18,69 +21,256 @@ if (isset($_GET['from']) && $_GET['from'] == 'myspace') {
     $this_section = SECTION_COURSES;
 }
 
-$session_id = isset($_REQUEST['id_session']) && !empty($_REQUEST['id_session'])
-    ? intval($_REQUEST['id_session'])
-    : api_get_session_id();
-$export_csv = isset($_GET['export']) && $_GET['export'] == 'csv' ? true : false;
-$user_id = isset($_GET['student_id']) ? intval($_GET['student_id']) : api_get_user_id();
+$session_id = isset($_REQUEST['id_session']) ? (int) $_REQUEST['id_session'] : api_get_session_id();
+$export_csv = isset($_GET['export']) && $_GET['export'] == 'csv';
+$user_id = isset($_GET['student_id']) ? (int) $_GET['student_id'] : api_get_user_id();
 $courseCode = isset($_GET['course']) ? Security::remove_XSS($_GET['course']) : api_get_course_id();
 $origin = api_get_origin();
-$lp_id = intval($_GET['lp_id']);
+$lp_id = (int) $_GET['lp_id'];
 $csv_content = [];
-$course_info = api_get_course_info($courseCode);
+$courseInfo = api_get_course_info($courseCode);
 
-if (empty($course_info) || empty($lp_id)) {
+if (empty($courseInfo) || empty($lp_id)) {
     api_not_allowed(api_get_origin() !== 'learnpath');
 }
 $userInfo = api_get_user_info($user_id);
 $name = $userInfo['complete_name'];
 $isBoss = UserManager::userIsBossOfStudent(api_get_user_id(), $user_id);
 
-if (!api_is_platform_admin(true) &&
-    !CourseManager::is_course_teacher(api_get_user_id(), $courseCode) &&
-    !$isBoss &&
-    !Tracking::is_allowed_to_coach_student(api_get_user_id(), $user_id) &&
+if (!$isBoss &&
+    !api_is_platform_admin(true) &&
     !api_is_drh() &&
-    !api_is_course_tutor()
+    !api_is_course_tutor() &&
+    !CourseManager::is_course_teacher(api_get_user_id(), $courseCode) &&
+    !Tracking::is_allowed_to_coach_student(api_get_user_id(), $user_id)
 ) {
-    api_not_allowed(
-        api_get_origin() !== 'learnpath'
-    );
+    api_not_allowed(api_get_origin() !== 'learnpath');
 }
 
-if ($origin == 'user_course') {
+if ($origin === 'user_course') {
     $interbreadcrumb[] = [
-        'url' => api_get_path(WEB_COURSE_PATH).$course_info['directory'],
-        'name' => $course_info['name'],
+        'url' => api_get_path(WEB_COURSE_PATH).$courseInfo['directory'],
+        'name' => $courseInfo['name'],
     ];
     $interbreadcrumb[] = [
         'url' => "../user/user.php?cidReq=$courseCode",
-        'name' => get_lang("Users"),
+        'name' => get_lang('Users'),
     ];
-} elseif ($origin == 'tracking_course') {
+} elseif ($origin === 'tracking_course') {
     $interbreadcrumb[] = [
         'url' => "../tracking/courseLog.php?cidReq=$courseCode&id_session=$session_id",
-        'name' => get_lang("Tracking"),
+        'name' => get_lang('Tracking'),
     ];
 } else {
     $interbreadcrumb[] = ['url' => 'index.php', 'name' => get_lang('MySpace')];
-    $interbreadcrumb[] = ['url' => 'student.php', 'name' => get_lang("MyStudents")];
-    $interbreadcrumb[] = ['url' => "myStudents.php?student=$user_id", 'name' => get_lang("StudentDetails")];
-    $nameTools = get_lang("DetailsStudentInCourse");
+    $interbreadcrumb[] = ['url' => 'student.php', 'name' => get_lang('MyStudents')];
+    $interbreadcrumb[] = ['url' => "myStudents.php?student=$user_id", 'name' => get_lang('StudentDetails')];
+    $nameTools = get_lang('DetailsStudentInCourse');
 }
 
 $interbreadcrumb[] = [
     'url' => "myStudents.php?student=$user_id&course=$courseCode&details=true&origin=$origin",
-    'name' => get_lang("DetailsStudentInCourse"),
+    'name' => get_lang('DetailsStudentInCourse'),
 ];
 $nameTools = get_lang('LearningPathDetails');
 $sql = 'SELECT name	FROM '.Database::get_course_table(TABLE_LP_MAIN).' 
-        WHERE c_id = '.$course_info['real_id'].' AND id='.$lp_id;
+        WHERE c_id = '.$courseInfo['real_id'].' AND id='.$lp_id;
 $rs = Database::query($sql);
 $lp_title = Database::result($rs, 0, 0);
 
 $origin = 'tracking';
 
+$action = isset($_REQUEST['action']) ? $_REQUEST['action'] : '';
+switch ($action) {
+    case 'export_stats':
+        if (!api_is_allowed_to_edit(false, false, true)) {
+            api_not_allowed();
+        }
+        $tpl = new Template(null, false, false);
+        $itemId = isset($_REQUEST['extend_id']) ? $_REQUEST['extend_id'] : 0;
+        $itemViewId = isset($_REQUEST['extend_attempt_id']) ? $_REQUEST['extend_attempt_id'] : 0;
+        $em = Database::getManager();
+
+        $repo = $em->getRepository('ChamiloCourseBundle:CLpItemView');
+        /** @var CLpItemView $itemView */
+        $itemView = $repo->find($itemViewId);
+
+        if (!$itemView) {
+            api_not_allowed();
+        }
+
+        $view = $em->getRepository('ChamiloCourseBundle:CLpView')->find($itemView->getLpViewId());
+        $lp = $em->getRepository('ChamiloCourseBundle:CLp')->find($view->getLpId());
+
+        $duration = learnpathItem::getScormTimeFromParameter('js', $itemView->getTotalTime());
+        $endTime = $itemView->getStartTime() + $itemView->getTotalTime();
+
+        $list1 = learnpath::get_iv_interactions_array($itemViewId, $courseInfo['real_id']);
+        $counter = 0;
+        $table = new HTML_Table();
+
+        $total = 0;
+        $numberChoices = 0;
+        $questionCounter = 0;
+
+        $studentName = '';
+        $questions = [];
+        $categories = [];
+        foreach ($list1 as $id => $interaction) {
+            $counter++;
+            if ($counter === 1) {
+                continue;
+            } elseif ($counter === 2) {
+                $studentName = $interaction['student_response_formatted'];
+            } else {
+                $data = $interaction['student_response_formatted'];
+
+                switch ($interaction['type']) {
+                    case 'fill-in':
+                        $questionCounter++;
+                        $questions[$questionCounter]['question'] = $data;
+                        break;
+                    case 'choice':
+                        $questions[$questionCounter]['options'][] = $interaction;
+                        $numberChoices++;
+                        break;
+                    case 'matching':
+                        $list = explode(',', $data);
+                        if (!empty($list)) {
+                            foreach ($list as &$item) {
+                                $item = cut($item, 30);
+                            }
+                            $interaction['student_response_formatted'] = implode('<br />', $list);
+                        }
+                        $questions[$questionCounter]['options'][] = $interaction;
+                        $numberChoices++;
+                        break;
+                }
+            }
+        }
+
+        $counter = 1;
+        $table = new HTML_Table(['class' => 'table data_table']);
+        $row = 0;
+        $scoreDisplay = new ScoreDisplay();
+        $globalTotal = 0;
+        $globalTotalCount = 0;
+        foreach ($questions as $data) {
+            // Question title
+            $table->setCellContents($row, 0, $data['question']);
+            $table->setCellAttributes($row, 0, ['colspan' => '3', 'style' => 'text-align:center; font-weight:bold']);
+            $choiceCounter = 1;
+            $row++;
+            $total = 0;
+            // Question options
+            foreach ($data['options'] as $option) {
+                if ($option['result'] === 'correct') {
+                    $total++;
+                    $globalTotal++;
+                }
+                $table->setCellContents($row, 0, 'Q'.$choiceCounter);
+                $table->setCellContents($row, 1, $option['student_response_formatted']);
+                $result = Display::return_icon('icon_check.png', null, [], ICON_SIZE_SMALL);
+                if ($option['result'] === 'wrong') {
+                    $result = Display::return_icon('icon_error.png', null, [], ICON_SIZE_SMALL);
+                }
+
+                $table->setCellContents($row, 2, $result);
+                $choiceCounter++;
+                $row++;
+            }
+
+            // Question total
+            $table->setCellContents($row, 0, get_lang('Total'));
+            $table->setCellContents($row, 1, $data['question']);
+
+            $totalOptions = count($data['options']);
+            $arrayScore = [0 => $total, 1 => $totalOptions];
+            $scoreToString = $scoreDisplay->display_score($arrayScore);
+            $table->setCellContents($row, 2, $scoreToString);
+
+            $table->setCellAttributes($row, 0, ['style' => 'font-weight:bold']);
+            $table->setCellAttributes($row, 1, ['style' => 'font-weight:bold']);
+            $table->setCellAttributes($row, 2, ['style' => 'font-weight:bold']);
+
+            $categories[] = [
+                'name' => $data['question'],
+                'score' => $scoreDisplay->display_score($arrayScore, SCORE_DIV),
+                'score_numeric' => $scoreDisplay->display_score($arrayScore, SCORE_NUMERIC),
+                'score_percentage' => $scoreDisplay->display_score($arrayScore, SCORE_PERCENT),
+            ];
+            $tpl->assign('categories', $categories);
+
+            $globalTotalCount += $totalOptions;
+            $row++;
+        }
+
+        $globalScoreTotal = [0 => $globalTotal, 1 => $globalTotalCount];
+        $score = $scoreDisplay->display_score($globalScoreTotal);
+        $generalScore[] = [
+            'score' => $scoreDisplay->display_score($globalScoreTotal, SCORE_DIV),
+            'score_numeric' => $scoreDisplay->display_score($globalScoreTotal, SCORE_NUMERIC),
+            'score_percentage' => $scoreDisplay->display_score($globalScoreTotal, SCORE_PERCENT),
+        ];
+        $tpl->assign('general_score', $generalScore);
+        $tpl->assign('global_total', $score);
+
+        $tableToString = $table->toHtml();
+
+        $duration = learnpathItem::getScormTimeFromParameter('js', $itemView->getTotalTime());
+
+        $dataLpInfo = [
+            'name' => $lp->getName(),
+            'attempt' => $itemView->getViewCount(),
+            'score' => $score,
+            'duration' => $duration,
+            'start_time' => api_get_local_time($itemView->getStartTime()),
+            'start_date' => api_get_local_time($itemView->getStartTime(), null, null, null, false),
+            'end_time' => api_get_local_time($endTime),
+            'candidate' => $studentName,
+        ];
+
+        $tpl->assign('data', $dataLpInfo);
+        $contentText = $tpl->fetch($tpl->get_template('my_space/pdf_tracking_lp.tpl'));
+
+        $content = $contentText.'<pagebreak>'.$tableToString;
+
+        $pdf = new PDF('A4', 'P', ['margin_footer' => 4, 'top' => 40, 'bottom' => 25]);
+
+        $table = new HTML_Table(['class' => 'table', 'style' => 'display: block; margin-bottom: 50px;']);
+        $logo = ChamiloApi::getPlatformLogo(
+            $theme,
+            [
+                'title' => '',
+                'style' => 'max-width:180px, margin-bottom: 100px;',
+                'id' => 'header-logo',
+            ]
+        );
+        $table->setCellContents(0, 0, $logo);
+
+        $secondLogo = api_get_path(SYS_PATH).'custompages/url-images/'.api_get_current_access_url_id().'_url_image_2.png';
+        $logo2 = Display::img($secondLogo, null, ['style' => 'height:70px;']);
+        $table->setCellContents(0, 1, $logo2);
+        $table->setCellAttributes(0, 1, ['style' => 'display:block;float:right;text-align:right']);
+        $pdf->set_custom_header($table->toHtml());
+
+        $background = api_get_path(SYS_PATH).'custompages/url-images/'.api_get_current_access_url_id().'_pdf_background.png';
+        $content = '<html><body style="background-image-resize: 5; background-position: top left; background-image: url('.$background.');">'.$content.'</body></html>';
+
+        $pdf->content_to_pdf(
+            $content,
+            null,
+            $courseInfo['code'].'_'.$lp->getName().'_'.api_get_local_time(),
+            $courseInfo['code'],
+            'D',
+            false,
+            null,
+            false,
+            true
+        );
+        break;
+}
+
 $output = require_once api_get_path(SYS_CODE_PATH).'lp/lp_stats.php';
 
 $actions = [];
@@ -106,7 +296,7 @@ echo Display::toolbarAction(
 $table_title = $session_id
     ? Display::return_icon('session.png', get_lang('Session')).PHP_EOL.api_get_session_name($session_id).PHP_EOL
     : PHP_EOL;
-$table_title .= Display::return_icon('course.png', get_lang('Course')).PHP_EOL.$course_info['name'].PHP_EOL
+$table_title .= Display::return_icon('course.png', get_lang('Course')).PHP_EOL.$courseInfo['name'].PHP_EOL
     .Display::return_icon('user.png', get_lang('User')).' '.$name;
 
 echo Display::page_header($table_title);

+ 107 - 142
main/mySpace/myStudents.php

@@ -1,7 +1,6 @@
 <?php
 /* For licensing terms, see /license.txt */
 
-use Chamilo\CoreBundle\Entity\Message;
 use Chamilo\CourseBundle\Entity\CLpCategory;
 use ChamiloSession as Session;
 
@@ -13,6 +12,7 @@ use ChamiloSession as Session;
 require_once __DIR__.'/../inc/global.inc.php';
 
 api_block_anonymous_users();
+$htmlHeadXtra[] = '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'assets/jquery.easy-pie-chart/dist/jquery.easypiechart.js"></script>';
 
 $export = isset($_GET['export']) ? $_GET['export'] : false;
 $sessionId = isset($_GET['id_session']) ? (int) $_GET['id_session'] : 0;
@@ -94,12 +94,10 @@ if ($export) {
 }
 $csv_content = [];
 $from_myspace = false;
-
-if (isset($_GET['from']) && $_GET['from'] == 'myspace') {
+$this_section = SECTION_COURSES;
+if (isset($_GET['from']) && $_GET['from'] === 'myspace') {
     $from_myspace = true;
     $this_section = SECTION_TRACKING;
-} else {
-    $this_section = SECTION_COURSES;
 }
 
 $nameTools = get_lang('StudentDetails');
@@ -114,14 +112,14 @@ if (!empty($details)) {
             ];
         }
         $interbreadcrumb[] = [
-            'url' => "../user/user.php?cidReq=".$course_code,
-            'name' => get_lang("Users"),
+            'url' => '../user/user.php?cidReq='.$course_code,
+            'name' => get_lang('Users'),
         ];
     } else {
         if ($origin === 'tracking_course') {
             $interbreadcrumb[] = [
-                'url' => "../tracking/courseLog.php?cidReq=".$course_code.'&id_session='.api_get_session_id(),
-                'name' => get_lang("Tracking"),
+                'url' => '../tracking/courseLog.php?cidReq='.$course_code.'&id_session='.api_get_session_id(),
+                'name' => get_lang('Tracking'),
             ];
         } else {
             if ($origin === 'resume_session') {
@@ -130,30 +128,30 @@ if (!empty($details)) {
                     'name' => get_lang('SessionList'),
                 ];
                 $interbreadcrumb[] = [
-                    'url' => "../session/resume_session.php?id_session=".$sessionId,
+                    'url' => '../session/resume_session.php?id_session='.$sessionId,
                     'name' => get_lang('SessionOverview'),
                 ];
             } else {
                 $interbreadcrumb[] = [
-                    'url' => api_is_student_boss() ? "#" : "index.php",
+                    'url' => api_is_student_boss() ? '#' : 'index.php',
                     'name' => get_lang('MySpace'),
                 ];
                 if (!empty($coachId)) {
                     $interbreadcrumb[] = [
-                        'url' => "student.php?id_coach=".$coachId,
-                        'name' => get_lang("CoachStudents"),
+                        'url' => 'student.php?id_coach='.$coachId,
+                        'name' => get_lang('CoachStudents'),
                     ];
                     $interbreadcrumb[] = [
-                        'url' => "myStudents.php?student=".$student_id.'&id_coach='.$coachId,
-                        'name' => get_lang("StudentDetails"),
+                        'url' => 'myStudents.php?student='.$student_id.'&id_coach='.$coachId,
+                        'name' => get_lang('StudentDetails'),
                     ];
                 } else {
                     $interbreadcrumb[] = [
-                        'url' => "student.php",
+                        'url' => 'student.php',
                         'name' => get_lang('MyStudents'),
                     ];
                     $interbreadcrumb[] = [
-                        'url' => "myStudents.php?student=".$student_id,
+                        'url' => 'myStudents.php?student='.$student_id,
                         'name' => get_lang('StudentDetails'),
                     ];
                 }
@@ -162,43 +160,43 @@ if (!empty($details)) {
     }
     $nameTools = get_lang('DetailsStudentInCourse');
 } else {
-    if ($origin == 'resume_session') {
+    if ($origin === 'resume_session') {
         $interbreadcrumb[] = [
-            'url' => "../session/session_list.php",
+            'url' => '../session/session_list.php',
             'name' => get_lang('SessionList'),
         ];
         if (!empty($sessionId)) {
             $interbreadcrumb[] = [
-                'url' => "../session/resume_session.php?id_session=".$sessionId,
+                'url' => '../session/resume_session.php?id_session='.$sessionId,
                 'name' => get_lang('SessionOverview'),
             ];
         }
     } elseif ($origin === 'teacher_details') {
         $this_section = SECTION_TRACKING;
-        $interbreadcrumb[] = ['url' => "index.php", 'name' => get_lang('MySpace')];
-        $interbreadcrumb[] = ['url' => "teachers.php", 'name' => get_lang('Teachers')];
+        $interbreadcrumb[] = ['url' => 'index.php', 'name' => get_lang('MySpace')];
+        $interbreadcrumb[] = ['url' => 'teachers.php', 'name' => get_lang('Teachers')];
         $nameTools = $user_info['complete_name'];
     } else {
         $interbreadcrumb[] = [
-            'url' => api_is_student_boss() ? "#" : "index.php",
+            'url' => api_is_student_boss() ? '#' : 'index.php',
             'name' => get_lang('MySpace'),
         ];
         if (!empty($coachId)) {
             if ($sessionId) {
                 $interbreadcrumb[] = [
-                    'url' => "student.php?id_coach=".$coachId."&id_session=".$sessionId,
-                    'name' => get_lang("CoachStudents"),
+                    'url' => 'student.php?id_coach='.$coachId.'&id_session='.$sessionId,
+                    'name' => get_lang('CoachStudents'),
                 ];
             } else {
                 $interbreadcrumb[] = [
-                    'url' => "student.php?id_coach=".$coachId,
-                    'name' => get_lang("CoachStudents"),
+                    'url' => 'student.php?id_coach='.$coachId,
+                    'name' => get_lang('CoachStudents'),
                 ];
             }
         } else {
             $interbreadcrumb[] = [
-                'url' => "student.php",
-                'name' => get_lang("MyStudents"),
+                'url' => 'student.php',
+                'name' => get_lang('MyStudents'),
             ];
         }
     }
@@ -336,13 +334,6 @@ switch ($action) {
                         $totalScore += $bestScore;
                     }
 
-                    /*$score = Tracking::get_avg_student_score(
-                        $user_info['user_id'],
-                        $courseCodeItem,
-                        [],
-                        $sId
-                    );*/
-
                     $progress = empty($progress) ? '0%' : $progress.'%';
                     $score = empty($bestScore) ? '0%' : $bestScore.'%';
 
@@ -386,13 +377,10 @@ switch ($action) {
             $sessionInfo['name']
         ));
         $tpl->assign('table_course', $courseTable);
-        $template = $tpl->fetch($tpl->get_template('my_space/pdf_export_student.tpl'));
-
-        $content = ''.$template;
+        $content = $tpl->fetch($tpl->get_template('my_space/pdf_export_student.tpl'));
 
         $params = [
             'pdf_title' => get_lang('Resume'),
-            //'course_code' => api_get_course_id(),
             'session_info' => $sessionInfo,
             'course_info' => '',
             'pdf_date' => '',
@@ -402,38 +390,21 @@ switch ($action) {
             'show_teacher_as_myself' => false,
             'orientation' => 'P',
         ];
-
         $pdf = new PDF('A4', $params['orientation'], $params);
-        try {
-            $theme = $tpl->theme;
-            $themeName = empty($theme) ? api_get_visual_theme() : $theme;
-            $themeDir = \Template::getThemeDir($theme);
-            $customLetterhead = $themeDir.'images/letterhead.png';
-            $urlPathLetterhead = api_get_path(SYS_CSS_PATH).$customLetterhead;
-
-            $urlWebLetterhead = '#FFFFFF';
-            $fullPage = false;
-            if (file_exists($urlPathLetterhead)) {
-                $fullPage = true;
-                $urlWebLetterhead = 'url('.api_get_path(WEB_CSS_PATH).$customLetterhead.')';
-            }
 
-            if ($fullPage) {
-                $pdf->pdf->SetDisplayMode('fullpage');
-                $pdf->pdf->SetDefaultBodyCSS('background', $urlWebLetterhead);
-                $pdf->pdf->SetDefaultBodyCSS('background-image-resize', '6');
-            }
-
-            @$pdf->content_to_pdf($content,
-                $css = '',
-                $pdf_name = '',
-                $course_code = null,
-                $outputMode = 'D',
-                $saveInFile = false,
-                $fileToSave = null,
-                $returnHtml = false,
-                $addDefaultCss = true,
-                $completeHeader = false
+        try {
+            $pdf->setBackground($tpl->theme);
+            @$pdf->content_to_pdf(
+                $content,
+                '',
+                '',
+                null,
+                'D',
+                false,
+                null,
+                false,
+                true,
+                false
             );
         } catch (MpdfException $e) {
             error_log($e);
@@ -553,12 +524,12 @@ switch ($action) {
         }
         break;
     case 'reset_lp':
-        $lp_id = isset($_GET['lp_id']) ? intval($_GET['lp_id']) : '';
+        $lp_id = isset($_GET['lp_id']) ? (int) $_GET['lp_id'] : '';
         $check = true;
 
-        if (api_is_allowed_to_edit() &&
-            !empty($lp_id) &&
+        if (!empty($lp_id) &&
             !empty($student_id) &&
+            api_is_allowed_to_edit() &&
             Security::check_token('get')
         ) {
             Event::delete_student_lp_events(
@@ -570,15 +541,14 @@ switch ($action) {
 
             // @todo delete the stats.track_e_exercises records.
             // First implement this http://support.chamilo.org/issues/1334
-            Display::addFlash(
-                Display::return_message(get_lang('LPWasReset'), 'success')
-            );
+            Display::addFlash(Display::return_message(get_lang('LPWasReset'), 'success'));
             Security::clear_token();
         }
         break;
     default:
         break;
 }
+
 $courses_in_session = [];
 
 // See #4676
@@ -658,23 +628,14 @@ while ($row = Database::fetch_array($rs, 'ASSOC')) {
 
 $isDrhOfCourse = CourseManager::isUserSubscribedInCourseAsDrh(
     api_get_user_id(),
-    api_get_course_info()
+    $courseInfo
 );
 
 if (api_is_drh() && !api_is_platform_admin()) {
     if (!empty($student_id)) {
         if (api_drh_can_access_all_session_content()) {
-            //@todo securize drh with student id
-            /*$users = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus('drh_all', api_get_user_id());
-            $userList = array();
-            foreach ($users as $user) {
-                $userList[] = $user['user_id'];
-            }
-            if (!in_array($student_id, $userList)) {
-                api_not_allowed(true);
-            }*/
         } else {
-            if (!($isDrhOfCourse)) {
+            if (!$isDrhOfCourse) {
                 if (api_is_drh() &&
                    !UserManager::is_user_followed_by_drh($student_id, api_get_user_id())
                 ) {
@@ -771,10 +732,9 @@ if ($isAllow) {
 echo '</div>';
 
 // is the user online ?
+$online = get_lang('No');
 if (user_is_online($student_id)) {
     $online = get_lang('Yes');
-} else {
-    $online = get_lang('No');
 }
 
 // get average of score and average of progress by student
@@ -865,6 +825,7 @@ $table_title = Display::return_icon('user.png', get_lang('User')).$user_info['co
 
 echo Display::page_subheader($table_title);
 $userPicture = UserManager::getUserPicture($user_info['user_id'], USER_IMAGE_SIZE_BIG);
+
 $userGroupManager = new UserGroup();
 $userGroups = $userGroupManager->getNameListByUser(
     $user_info['user_id'],
@@ -1518,13 +1479,13 @@ if (empty($details)) {
     ];
 
     $timeCourse = null;
-    if (Tracking::minimunTimeAvailable($session_id, $courseInfo['real_id'])) {
-        $timeCourse = Tracking::getCalculateTime($student_id, $courseInfo['real_id'], $session_id);
+    if (Tracking::minimumTimeAvailable($sessionId, $courseInfo['real_id'])) {
+        $timeCourse = Tracking::getCalculateTime($student_id, $courseInfo['real_id'], $sessionId);
     }
 
     if ($user_info['status'] != INVITEE) {
         $csv_content[] = [];
-        $csv_content[] = [str_replace('&nbsp;', '', strip_tags($table_title))];
+        $csv_content[] = [str_replace('&nbsp;', '', strip_tags($userInfo['complete_name']))];
         $trackingColumns = api_get_configuration_value('tracking_columns');
         if (isset($trackingColumns['my_students_lp'])) {
             foreach ($columnHeaders as $key => $value) {
@@ -1566,13 +1527,13 @@ if (empty($details)) {
         /** @var CLpCategory $item */
         foreach ($categories as $item) {
             $categoryId = $item->getId();
-            if (!learnpath::categoryIsVisibleForStudent($item, $userEntity)) {
+            if (!learnpath::categoryIsVisibleForStudent($item, $userEntity, $courseInfo['real_id'], $sessionId)) {
                 continue;
             }
 
             $list = new LearnpathList(
                 api_get_user_id(),
-                $courseInfo['code'],
+                $courseInfo,
                 $sessionId,
                 null,
                 false,
@@ -1598,7 +1559,6 @@ if (empty($details)) {
 
             foreach ($flat_list as $learnpath) {
                 $lpIdList[] = $learnpath['iid'];
-
                 $lp_id = $learnpath['lp_old_id'];
                 $lp_name = $learnpath['lp_name'];
                 $any_result = false;
@@ -1687,9 +1647,9 @@ if (empty($details)) {
                 }
 
                 if ($i % 2 == 0) {
-                    $css_class = "row_even";
+                    $css_class = 'row_even';
                 } else {
-                    $css_class = "row_odd";
+                    $css_class = 'row_odd';
                 }
 
                 $i++;
@@ -1829,7 +1789,7 @@ if (empty($details)) {
         $i = 0;
         if (Database::num_rows($result_exercices) > 0) {
             while ($exercices = Database::fetch_array($result_exercices)) {
-                $exercise_id = intval($exercices['id']);
+                $exercise_id = (int) $exercices['id'];
                 $count_attempts = Tracking::count_student_exercise_attempts(
                     $student_id,
                     $courseInfo['real_id'],
@@ -1864,10 +1824,9 @@ if (empty($details)) {
                 }
                 $lp_name = !empty($lp_name) ? $lp_name : get_lang('NoLearnpath');
 
+                $css_class = 'row_even';
                 if ($i % 2) {
                     $css_class = 'row_odd';
-                } else {
-                    $css_class = 'row_even';
                 }
 
                 echo '<tr class="'.$css_class.'"><td>'.$exercices['title'].'</td>';
@@ -1894,23 +1853,29 @@ if (empty($details)) {
                 echo '<td>';
 
                 $sql = 'SELECT exe_id FROM '.$tbl_stats_exercices.'
-                     WHERE
-                        exe_exo_id = "'.$exercise_id.'" AND
-                        exe_user_id ="'.$student_id.'" AND
-                        c_id = '.$courseInfo['real_id'].' AND
-                        session_id = "'.$sessionId.'" AND
-                        status = ""
-                    ORDER BY exe_date DESC
-                    LIMIT 1';
+                         WHERE
+                            exe_exo_id = "'.$exercise_id.'" AND
+                            exe_user_id ="'.$student_id.'" AND
+                            c_id = '.$courseInfo['real_id'].' AND
+                            session_id = "'.$sessionId.'" AND
+                            status = ""
+                        ORDER BY exe_date DESC
+                        LIMIT 1';
                 $result_last_attempt = Database::query($sql);
                 if (Database::num_rows($result_last_attempt) > 0) {
                     $id_last_attempt = Database::result($result_last_attempt, 0, 0);
                     if ($count_attempts > 0) {
-                        echo '<a href="../exercise/exercise_show.php?id='.$id_last_attempt.'&cidReq='.$course_code
+                        $qualifyLink = '';
+                        if ($allowToQualify) {
+                            $qualifyLink = '&action=qualify';
+                        }
+                        $attemptLink = '../exercise/exercise_show.php?id='.$id_last_attempt.'&cidReq='.$course_code
                             .'&id_session='.$sessionId.'&session_id='.$sessionId.'&student='.$student_id.'&origin='
-                            .(empty($origin) ? 'tracking' : $origin).'">'
-                            .Display::return_icon('quiz.png')
-                            .'</a>';
+                            .(empty($origin) ? 'tracking' : $origin).$qualifyLink;
+                        echo Display::url(
+                            Display::return_icon('quiz.png', get_lang('Exercise')),
+                            $attemptLink
+                        );
                     }
                 }
                 echo '</td>';
@@ -1953,42 +1918,42 @@ if (empty($details)) {
     // @when using sessions we do not show the survey list
     if (empty($sessionId)) {
         $survey_list = SurveyManager::get_surveys($course_code, $sessionId);
-        $survey_data = [];
-        foreach ($survey_list as $survey) {
-            $user_list = SurveyManager::get_people_who_filled_survey(
-                $survey['survey_id'],
-                false,
-                $courseInfo['real_id']
-            );
-            $survey_done = Display::return_icon(
-                "accept_na.png",
-                get_lang('NoAnswer'),
-                [],
-                ICON_SIZE_SMALL
-            );
-            if (in_array($student_id, $user_list)) {
+        if (!empty($survey_list)) {
+            $survey_data = [];
+            foreach ($survey_list as $survey) {
+                $user_list = SurveyManager::get_people_who_filled_survey(
+                    $survey['survey_id'],
+                    false,
+                    $courseInfo['real_id']
+                );
                 $survey_done = Display::return_icon(
-                    "accept.png",
-                    get_lang('Answered'),
+                    "accept_na.png",
+                    get_lang('NoAnswer'),
                     [],
                     ICON_SIZE_SMALL
                 );
+                if (in_array($student_id, $user_list)) {
+                    $survey_done = Display::return_icon(
+                        "accept.png",
+                        get_lang('Answered'),
+                        [],
+                        ICON_SIZE_SMALL
+                    );
+                }
+                $data = ['title' => $survey['title'], 'done' => $survey_done];
+                $survey_data[] = $data;
             }
-            $data = ['title' => $survey['title'], 'done' => $survey_done];
-            $survey_data[] = $data;
-        }
 
-        if (!empty($survey_list)) {
-            $table = new HTML_Table(['class' => 'data_table']);
-            $header_names = [get_lang('Survey'), get_lang('Answered')];
-            $row = 0;
-            $column = 0;
-            foreach ($header_names as $item) {
-                $table->setHeaderContents($row, $column, $item);
-                $column++;
-            }
-            $row = 1;
             if (!empty($survey_data)) {
+                $table = new HTML_Table(['class' => 'data_table']);
+                $header_names = [get_lang('Survey'), get_lang('Answered')];
+                $row = 0;
+                $column = 0;
+                foreach ($header_names as $item) {
+                    $table->setHeaderContents($row, $column, $item);
+                    $column++;
+                }
+                $row = 1;
                 foreach ($survey_data as $data) {
                     $column = 0;
                     $table->setCellContents($row, $column, $data);
@@ -2000,8 +1965,8 @@ if (empty($details)) {
                     $column++;
                     $row++;
                 }
+                echo $table->toHtml();
             }
-            echo $table->toHtml();
         }
     }
 

+ 204 - 39
main/mySpace/session.php

@@ -14,13 +14,13 @@ api_block_anonymous_users();
 
 $this_section = SECTION_TRACKING;
 $export_csv = false;
-if (isset($_GET['export']) && $_GET['export'] == 'csv') {
+if (isset($_REQUEST['export']) && $_REQUEST['export'] == 'csv') {
     $export_csv = true;
 }
 
 $id_coach = api_get_user_id();
-if (isset($_GET['id_coach']) && $_GET['id_coach'] != '') {
-    $id_coach = (int) $_GET['id_coach'];
+if (isset($_REQUEST['id_coach']) && $_REQUEST['id_coach'] != '') {
+    $id_coach = (int) $_REQUEST['id_coach'];
 }
 
 $allowToTrack = api_is_platform_admin(true, true) || api_is_teacher();
@@ -121,59 +121,224 @@ if (api_is_platform_admin(true, true)) {
 
 $form = new FormValidator(
     'search_course',
-    'get',
+    'post',
     api_get_path(WEB_CODE_PATH).'mySpace/session.php'
 );
 $form->addElement('text', 'keyword', get_lang('Keyword'));
+
+$extraFieldSession = new ExtraField('session');
+$extraFieldSession->addElements(
+    $form,
+    null,
+    [], //exclude
+    true
+);
+
 $form->addButtonSearch(get_lang('Search'));
 $keyword = '';
+$result = SessionManager::getGridColumns('my_space');
+
+$columns = $result['columns'];
+$columnModel = $result['column_model'];
+
+$filterToString = '';
 if ($form->validate()) {
-    $keyword = $form->getSubmitValue('keyword');
+    $values = $form->getSubmitValues();
+    $keyword = Security::remove_XSS($form->getSubmitValue('keyword'));
+    $extraField = new ExtraField('session');
+    $extraFields = $extraField->get_all(null, 'option_order');
+    $extraFields = array_column($extraFields, 'variable');
+    $filter = new stdClass();
+    $filter->groupOp = 'AND';
+
+    foreach ($columnModel as $col) {
+        if (isset($values[$col['index']]) && !empty($values[$col['index']]) &&
+            in_array(str_replace('extra_', '', $col['index']), $extraFields)
+        ) {
+            $rule = new stdClass();
+            $rule->field = $col['index'];
+            $rule->op = 'in';
+            $rule->data = Security::remove_XSS($values[$col['index']]);
+            $filter->rules[] = $rule;
+            $filter->groupOp = 'AND';
+        }
+    }
+    $filterToString = json_encode($filter);
 }
 $form->setDefaults(['keyword' => $keyword]);
 
-$url = api_get_path(WEB_AJAX_PATH).'model.ajax.php?a=get_sessions_tracking&keyword='.Security::remove_XSS($keyword);
-
-$columns = [
-    get_lang('Title'),
-    get_lang('Date'),
-    get_lang('NbCoursesPerSession'),
-    get_lang('NbStudentPerSession'),
-    get_lang('Details'),
-];
+$url = api_get_path(WEB_AJAX_PATH).
+    'model.ajax.php?a=get_sessions_tracking&_search=true&_force_search=true&filters='.$filterToString.'&keyword='.$keyword;
 
 // Column config
-$columnModel = [
-    ['name' => 'name', 'index' => 'name', 'width' => '255', 'align' => 'left'],
-    ['name' => 'date', 'index' => 'access_start_date', 'width' => '150', 'align' => 'left'],
-    ['name' => 'course_per_session', 'index' => 'course_per_session', 'width' => '150', 'sortable' => 'false'],
-    ['name' => 'student_per_session', 'index' => 'student_per_session', 'width' => '100', 'sortable' => 'false'],
-    ['name' => 'details', 'index' => 'details', 'width' => '100', 'sortable' => 'false'],
-];
-
 $extraParams = [
     'autowidth' => 'true',
     'height' => 'auto',
 ];
 
-$js = '<script>
-    $(function() {
-        '.Display::grid_js(
-        'session_tracking',
-        $url,
-        $columns,
-        $columnModel,
-        $extraParams,
-        [],
-        null,
-        true
-    ).'
-    });
-</script>';
-
-echo $js;
+/*$extraParams['postData'] = [
+    'filters' => [
+        'groupOp' => 'AND',
+        'rules' => $result['rules'],
+    ],
+];*/
+
+$urlAjaxExtraField = api_get_path(WEB_AJAX_PATH).'extra_field.ajax.php?1=1';
+$allowOrder = api_get_configuration_value('session_list_order');
+$orderUrl = api_get_path(WEB_AJAX_PATH).'session.ajax.php?a=order';
+
+?>
+    <script>
+        function setSearchSelect(columnName) {
+            $("#sessions").jqGrid('setColProp', columnName, {
+            });
+        }
+        var added_cols = [];
+        var original_cols = [];
+        function clean_cols(grid, added_cols) {
+            // Cleaning
+            for (key in added_cols) {
+                grid.hideCol(key);
+            };
+            grid.showCol('name');
+            grid.showCol('display_start_date');
+            grid.showCol('display_end_date');
+            grid.showCol('course_title');
+        }
+
+        function show_cols(grid, added_cols) {
+            grid.showCol('name').trigger('reloadGrid');
+            for (key in added_cols) {
+                grid.showCol(key);
+            };
+        }
+
+        var second_filters = [];
+
+        $(function() {
+            date_pick_today = function(elem) {
+                $(elem).datetimepicker({dateFormat: "yy-mm-dd"});
+                $(elem).datetimepicker('setDate', (new Date()));
+            }
+            date_pick_one_month = function(elem) {
+                $(elem).datetimepicker({dateFormat: "yy-mm-dd"});
+                next_month = Date.today().next().month();
+                $(elem).datetimepicker('setDate', next_month);
+            }
+
+            // Great hack
+            register_second_select = function(elem) {
+                second_filters[$(elem).val()] = $(elem);
+            }
+
+            fill_second_select = function(elem) {
+                $(elem).on("change", function() {
+                    composed_id = $(this).val();
+                    field_id = composed_id.split("#")[0];
+                    id = composed_id.split("#")[1];
+                    $.ajax({
+                        url: "<?php echo $urlAjaxExtraField; ?>&a=get_second_select_options",
+                        dataType: "json",
+                        data: "type=session&field_id="+field_id+"&option_value_id="+id,
+                        success: function(data) {
+                            my_select = second_filters[field_id];
+                            my_select.empty();
+                            $.each(data, function(index, value) {
+                                my_select.append($("<option/>", {
+                                    value: index,
+                                    text: value
+                                }));
+                            });
+                        }
+                    });
+                });
+            }
+
+            <?php
+            echo Display::grid_js(
+                'sessions',
+                $url,
+                $columns,
+                $columnModel,
+                $extraParams,
+                [],
+                null,
+                true
+            );
+            ?>
+
+            setSearchSelect("status");
+
+            var grid = $("#sessions"),
+                prmSearch = {
+                    multipleSearch : true,
+                    overlay : false,
+                    width: 'auto',
+                    caption: '<?php echo addslashes(get_lang('Search')); ?>',
+                    formclass:'data_table',
+                    onSearch : function() {
+                        var postdata = grid.jqGrid('getGridParam', 'postData');
+                        if (postdata && postdata.filters) {
+                            filters = jQuery.parseJSON(postdata.filters);
+                            clean_cols(grid, added_cols);
+                            added_cols = [];
+                            $.each(filters, function(key, value) {
+                                if (key == 'rules') {
+                                    $.each(value, function(subkey, subvalue) {
+                                        added_cols[subvalue.field] = subvalue.field;
+                                    });
+                                }
+                            });
+                            show_cols(grid, added_cols);
+                        }
+                    },
+                    onReset: function() {
+                        clean_cols(grid, added_cols);
+                    }
+                };
+
+            original_cols = grid.jqGrid('getGridParam', 'colModel');
+
+            grid.jqGrid('navGrid','#sessions_pager',
+                {edit:false,add:false,del:false},
+                {height:280,reloadAfterSubmit:false}, // edit options
+                {height:280,reloadAfterSubmit:false}, // add options
+                {reloadAfterSubmit:false},// del options
+                prmSearch
+            );
+
+            <?php
+            // Create the searching dialog.
+            //echo 'grid.searchGrid(prmSearch);';
+            ?>
+            // Fixes search table.
+            var searchDialogAll = $("#fbox_"+grid[0].id);
+            searchDialogAll.addClass("table");
+            var searchDialog = $("#searchmodfbox_"+grid[0].id);
+            searchDialog.addClass("ui-jqgrid ui-widget ui-widget-content ui-corner-all");
+            searchDialog.css({position:"adsolute", "z-index":"100", "float":"left", "top":"55%", "left" : "25%", "padding" : "5px", "border": "1px solid #CCC"})
+            var gbox = $("#gbox_"+grid[0].id);
+            gbox.before(searchDialog);
+            gbox.css({clear:"left"});
+
+            // Select first elements by default
+            $('.input-elm').each(function() {
+                $(this).find('option:first').attr('selected', 'selected');
+            });
+
+            $('.delete-rule').each(function(){
+                $(this).click(function(){
+                    $('.input-elm').each(function(){
+                        $(this).find('option:first').attr('selected', 'selected');
+                    });
+                });
+            });
+        });
+    </script>
+<?php
+
 $form->display();
 
-echo Display::grid_html('session_tracking');
+echo Display::grid_html('sessions');
 
 Display::display_footer();

+ 4 - 7
main/mySpace/student.php

@@ -130,6 +130,8 @@ function get_users($from, $limit, $column, $direction)
     $all_datas = [];
     foreach ($students as $student_data) {
         $student_id = $student_data['user_id'];
+        $student_data = api_get_user_info($student_id);
+
         if (isset($_GET['id_session'])) {
             $courses = Tracking :: get_course_list_in_session_from_student($student_id, $sessionId);
         }
@@ -252,12 +254,7 @@ if (api_is_drh()) {
         ),
     ];
 
-    $nb_menu_items = count($menu_items);
-    if ($nb_menu_items > 1) {
-        foreach ($menu_items as $key => $item) {
-            $actionsLeft .= $item;
-        }
-    }
+    $actionsLeft .= implode('', $menu_items);
 } elseif (api_is_student_boss()) {
     $actionsLeft .= Display::url(
         Display::return_icon('statistics.png', get_lang('MyStats'), '', ICON_SIZE_MEDIUM),
@@ -267,7 +264,7 @@ if (api_is_drh()) {
         Display::return_icon('user_na.png', get_lang('Students'), [], ICON_SIZE_MEDIUM),
         '#'
     );
-    $actions .= Display::url(
+    $actionsLeft .= Display::url(
         Display::return_icon('skills.png', get_lang('Skills'), [], ICON_SIZE_MEDIUM),
         $webCodePath.'social/my_skills_report.php'
     );

+ 1 - 0
main/mySpace/teachers.php

@@ -116,6 +116,7 @@ function get_users($from, $limit, $column, $direction)
     $url = api_get_path(WEB_CODE_PATH).'mySpace/myStudents.php';
     foreach ($students as $student_data) {
         $student_id = $student_data['user_id'];
+        $student_data = api_get_user_info($student_id);
         if (isset($_GET['id_session'])) {
             $courses = Tracking::get_course_list_in_session_from_student($student_id, $_GET['id_session']);
         }

+ 7 - 2
main/mySpace/users.php

@@ -127,8 +127,9 @@ function get_users($from, $limit, $column, $direction)
     $all_datas = [];
     foreach ($students as $student_data) {
         $student_id = $student_data['user_id'];
+        $student_data = api_get_user_info($student_id);
         if (isset($_GET['id_session'])) {
-            $courses = Tracking :: get_course_list_in_session_from_student($student_id, $sessionId);
+            $courses = Tracking::get_course_list_in_session_from_student($student_id, $sessionId);
         }
 
         $avg_time_spent = $avg_student_score = $avg_student_progress = 0;
@@ -139,7 +140,11 @@ function get_users($from, $limit, $column, $direction)
                 $courseId = $courseInfo['real_id'];
 
                 if (CourseManager::is_user_subscribed_in_course($student_id, $course_code, true)) {
-                    $avg_time_spent += Tracking::get_time_spent_on_the_course($student_id, $courseId, $_GET['id_session']);
+                    $avg_time_spent += Tracking::get_time_spent_on_the_course(
+                        $student_id,
+                        $courseId,
+                        $_GET['id_session']
+                    );
                     $my_average = Tracking::get_avg_student_score($student_id, $course_code);
                     if (is_numeric($my_average)) {
                         $avg_student_score += $my_average;

+ 6 - 4
main/mySpace/works_in_session_report.php

@@ -38,10 +38,12 @@ foreach ($sessionList as $sessionInfo) {
     $selectSession->addOption($sessionInfo['name'], $sessionInfo['id']);
 }
 
-if (isset($_GET['session']) && intval($_GET['session'])) {
-    $form->setDefaults(['session' => intval($_GET['session'])]);
+$sessionId = isset($_GET['session']) ? (int) $_GET['session'] : 0;
+$session = null;
+if (!empty($sessionId)) {
+    $form->setDefaults(['session' => $sessionId]);
     /** @var Session $session */
-    $session = $em->find('ChamiloCoreBundle:Session', intval($_GET['session']));
+    $session = $em->find('ChamiloCoreBundle:Session', $sessionId);
 }
 
 $coursesInfo = [];
@@ -62,7 +64,7 @@ if ($session) {
             if (!array_key_exists($user->getId(), $usersInfo)) {
                 $usersInfo[$user->getId()] = [
                     'code' => $user->getOfficialCode(),
-                    'complete_name' => $user->getCompleteName(),
+                    'complete_name' => UserManager::formatUserFullName($user),
                     'time_in_platform' => api_time_to_hms(
                         Tracking::get_time_spent_on_the_platform($user->getId(), 'ever')
                     ),

+ 7 - 3
main/search/search_suggestions.php

@@ -115,9 +115,13 @@ function get_suggestions_from_search_engine($q)
     echo json_encode($json);
 }
 
-$q = strtolower($_GET["term"]);
-if (!$q) {
-    return;
+if (isset($_GET['term'])) {
+    $q = strtolower($_GET['term']);
+    if (!$q) {
+        return;
+    }
+
+    get_suggestions_from_search_engine($q);
 }
 //echo $q . "| value\n";
 get_suggestions_from_search_engine($q);

+ 2 - 4
main/session/about.php

@@ -5,7 +5,6 @@ use Chamilo\CoreBundle\Entity\Course;
 use Chamilo\CoreBundle\Entity\ExtraField;
 use Chamilo\CoreBundle\Entity\Repository\SequenceRepository;
 use Chamilo\CoreBundle\Entity\SequenceResource;
-use Chamilo\CoreBundle\Entity\Session;
 use Chamilo\CourseBundle\Entity\CCourseDescription;
 use Chamilo\UserBundle\Entity\User;
 
@@ -26,8 +25,7 @@ $sessionId = isset($_GET['session_id']) ? (int) $_GET['session_id'] : 0;
 
 $em = Database::getManager();
 
-/** @var Session $session */
-$session = $em->find('ChamiloCoreBundle:Session', $sessionId);
+$session = api_get_session_entity($sessionId);
 
 if (!$session) {
     api_not_allowed(true);
@@ -63,7 +61,7 @@ foreach ($sessionCourses as $sessionCourse) {
     /** @var User $courseCoach */
     foreach ($courseCoaches as $courseCoach) {
         $coachData = [
-            'complete_name' => $courseCoach->getCompleteName(),
+            'complete_name' => UserManager::formatUserFullName($courseCoach),
             'image' => UserManager::getUserPicture(
                 $courseCoach->getId(),
                 USER_IMAGE_SIZE_ORIGINAL

+ 29 - 25
main/session/add_courses_to_session.php

@@ -6,8 +6,6 @@
  *
  * @todo use formvalidator
  */
-
-// resetting the course id.
 $cidReset = true;
 
 require_once __DIR__.'/../inc/global.inc.php';
@@ -29,7 +27,7 @@ $interbreadcrumb[] = [
     'name' => get_lang('SessionList'),
 ];
 $interbreadcrumb[] = [
-    'url' => "resume_session.php?id_session=".$sessionId,
+    'url' => "resume_session.php?id_session=$sessionId",
     'name' => get_lang('SessionOverview'),
 ];
 
@@ -85,29 +83,32 @@ $courses = $sessions = [];
 if (isset($_POST['formSent']) && $_POST['formSent']) {
     $courseList = $_POST['SessionCoursesList'];
     $copyEvaluation = isset($_POST['copy_evaluation']);
+    $copyCourseTeachersAsCoach = isset($_POST['import_teachers_as_course_coach']);
 
     SessionManager::add_courses_to_session(
         $sessionId,
         $courseList,
         true,
-        $copyEvaluation
+        $copyEvaluation,
+        $copyCourseTeachersAsCoach
     );
 
     Display::addFlash(Display::return_message(get_lang('Updated')));
 
+    $url = api_get_path(WEB_CODE_PATH).'session/';
     if (isset($add)) {
-        header('Location: add_users_to_session.php?id_session='.$sessionId.'&add=true');
+        header('Location: '.$url.'add_users_to_session.php?id_session='.$sessionId.'&add=true');
     } else {
-        header('Location: resume_session.php?id_session='.$sessionId);
+        header('Location: '.$url.'resume_session.php?id_session='.$sessionId);
     }
 
     exit;
 }
 
-// display the header
+// Display the header
 Display::display_header($tool_name);
 
-if ($add_type == 'multiple') {
+if ($add_type === 'multiple') {
     $link_add_type_unique = '<a href="'.api_get_self().'?id_session='.$sessionId.'&add='.$add.'&add_type=unique">'.
         Display::return_icon('single.gif').get_lang('SessionAddTypeUnique').'</a>';
     $link_add_type_multiple = Display::return_icon('multiple.gif').get_lang('SessionAddTypeMultiple').' ';
@@ -123,7 +124,7 @@ echo '<div class="actions">';
 echo $link_add_type_unique.$link_add_type_multiple;
 echo '</div>';
 
-$ajax_search = $add_type == 'unique' ? true : false;
+$ajax_search = $add_type === 'unique' ? true : false;
 $nosessionCourses = $sessionCourses = [];
 if ($ajax_search) {
     $sql = "SELECT course.id, code, title, visual_code, session_id
@@ -131,8 +132,8 @@ if ($ajax_search) {
 			INNER JOIN $tbl_session_rel_course session_rel_course
             ON
                 course.id = session_rel_course.c_id AND
-                session_rel_course.session_id = ".$sessionId."
-			ORDER BY ".(sizeof($courses) ? "(code IN(".implode(',', $courses).")) DESC," : "")." title";
+                session_rel_course.session_id = $sessionId
+			ORDER BY ".(count($courses) ? "(code IN (".implode(',', $courses).")) DESC," : '')." title";
 
     if (api_is_multiple_url_enabled()) {
         $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
@@ -141,12 +142,11 @@ if ($ajax_search) {
             $sql = "SELECT course.id, code, title, visual_code, session_id
                     FROM $tbl_course course
                     INNER JOIN $tbl_session_rel_course session_rel_course
-                        ON course.id = session_rel_course.c_id
-                        AND session_rel_course.session_id = ".$sessionId."
-                        INNER JOIN $tbl_course_rel_access_url url_course
-                        ON (url_course.c_id = course.id)
+                    ON course.id = session_rel_course.c_id AND session_rel_course.session_id = $sessionId
+                    INNER JOIN $tbl_course_rel_access_url url_course
+                    ON (url_course.c_id = course.id)
                     WHERE access_url_id = $access_url_id
-                    ORDER BY ".(sizeof($courses) ? "(code IN(".implode(',', $courses).")) DESC," : "")." title";
+                    ORDER BY ".(count($courses) ? " (code IN(".implode(',', $courses).")) DESC," : '')." title";
         }
     }
 
@@ -161,8 +161,8 @@ if ($ajax_search) {
 			LEFT JOIN $tbl_session_rel_course session_rel_course
             ON
                 course.id = session_rel_course.c_id AND
-                session_rel_course.session_id = ".$sessionId."
-			ORDER BY ".(sizeof($courses) ? "(code IN(".implode(',', $courses).")) DESC," : "")." title";
+                session_rel_course.session_id = $sessionId
+			ORDER BY ".(count($courses) ? "(code IN(".implode(',', $courses).")) DESC," : '')." title";
 
     if (api_is_multiple_url_enabled()) {
         $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
@@ -173,11 +173,11 @@ if ($ajax_search) {
                     LEFT JOIN $tbl_session_rel_course session_rel_course
                     ON
                         course.id = session_rel_course.c_id AND
-                        session_rel_course.session_id = ".$sessionId."
+                        session_rel_course.session_id = $sessionId
                     INNER JOIN $tbl_course_rel_access_url url_course
                     ON (url_course.c_id = course.id)
                     WHERE access_url_id = $access_url_id
-                    ORDER BY ".(sizeof($courses) ? "(code IN(".implode(',', $courses).")) DESC," : "")." title";
+                    ORDER BY ".(count($courses) ? "(code IN(".implode(',', $courses).")) DESC," : '')." title";
         }
     }
     $result = Database::query($sql);
@@ -208,7 +208,8 @@ if (!api_is_platform_admin() && api_is_teacher()) {
 
 unset($Courses);
 ?>
-<form name="formulaire" method="post" action="<?php echo api_get_self(); ?>?page=<?php echo $page; ?>&id_session=<?php echo $sessionId; ?><?php if (!empty($_GET['add'])) {
+<form name="formulaire"
+      method="post" action="<?php echo api_get_self(); ?>?page=<?php echo $page; ?>&id_session=<?php echo $sessionId; if (!empty($_GET['add'])) {
     echo '&add=true';
 } ?>" style="margin:0px;" <?php if ($ajax_search) {
     echo ' onsubmit="valide();"';
@@ -251,7 +252,7 @@ unset($Courses);
                 <div class="code-course">
                     <?php echo get_lang('FirstLetterCourse'); ?> :
 
-                    <select name="firstLetterCourse" onchange = "xajax_search_courses(this.value,'multiple', <?php echo $sessionId; ?>)" class="selectpicker show-tick form-control">
+                    <select name="firstLetterCourse" onchange = "xajax_search_courses(this.value,'multiple', <?php echo $sessionId; ?>)" class="selectpicker form-control">
                         <option value="%">--</option>
                         <?php
                         echo Display :: get_alphabet_options();
@@ -289,6 +290,10 @@ unset($Courses);
                         <input type="checkbox" name="copy_evaluation">
                         <?php echo get_lang('ImportGradebookInCourse'); ?>
                     </label>
+                    <label>
+                        <input type="checkbox" name="import_teachers_as_course_coach">
+                        <?php echo get_lang('ImportCourseTeachersAsCourseCoach'); ?>
+                    </label>
                 </div>
             <?php
             echo '<div class="separate-action">';
@@ -304,7 +309,6 @@ unset($Courses);
         <div class="col-md-4">
             <label><?php echo get_lang('CourseListInSession'); ?> :</label>
             <select id='destination' name="SessionCoursesList[]" multiple="multiple" size="20" class="form-control">
-
                 <?php
                 foreach ($sessionCourses as $enreg) {
                     ?>
@@ -347,10 +351,10 @@ unset($Courses);
     }
 
     function mysort(a, b) {
-        if(a.text.toLowerCase() > b.text.toLowerCase()){
+        if (a.text.toLowerCase() > b.text.toLowerCase()){
             return 1;
         }
-        if(a.text.toLowerCase() < b.text.toLowerCase()){
+        if (a.text.toLowerCase() < b.text.toLowerCase()){
             return -1;
         }
         return 0;

+ 4 - 1
main/session/add_edit_users_to_session.php

@@ -15,7 +15,10 @@ $xajax->registerFunction('search_users');
 // setting the section (for the tabs)
 $this_section = SECTION_PLATFORM_ADMIN;
 
-$id_session = intval($_GET['id_session']);
+$id_session = isset($_GET['id_session']) ? (int) $_GET['id_session'] : 0;
+if (empty($id_session)) {
+    api_not_allowed(true);
+}
 $addProcess = isset($_GET['add']) ? Security::remove_XSS($_GET['add']) : null;
 
 SessionManager::protectSession($id_session);

+ 1 - 1
main/session/add_teachers_to_session.php

@@ -24,7 +24,7 @@ $tool_name = get_lang('EnrollTrainersFromExistingSessions');
 
 $form_sent = 0;
 $errorMsg = '';
-$id = intval($_GET['id']);
+$id = isset($_GET['id']) ? (int) $_GET['id'] : 0;
 
 SessionManager::protectSession($id);
 

+ 16 - 16
main/session/add_users_to_session.php

@@ -7,7 +7,6 @@
 // resetting the course id
 $cidReset = true;
 
-// including some necessary files
 require_once __DIR__.'/../inc/global.inc.php';
 $xajax = new xajax();
 $xajax->registerFunction('search_users');
@@ -15,7 +14,7 @@ $xajax->registerFunction('search_users');
 // setting the section (for the tabs)
 $this_section = SECTION_PLATFORM_ADMIN;
 
-$id_session = intval($_GET['id_session']);
+$id_session = isset($_GET['id_session']) ? (int) $_GET['id_session'] : 0;
 $addProcess = isset($_GET['add']) ? Security::remove_XSS($_GET['add']) : null;
 
 SessionManager::protectSession($id_session);
@@ -43,7 +42,6 @@ if (isset($_REQUEST['add_type']) && $_REQUEST['add_type'] != '') {
 $page = isset($_GET['page']) ? Security::remove_XSS($_GET['page']) : null;
 
 // Checking for extra field with filter on
-
 $extra_field_list = UserManager::get_extra_fields();
 
 $new_field_list = [];
@@ -108,7 +106,7 @@ function search_users($needle, $type)
         // Only for single & multiple
         if (in_array($type, ['single', 'multiple'])) {
             if (!empty($id_session)) {
-                $id_session = intval($id_session);
+                $id_session = (int) $id_session;
                 // check id_user from session_rel_user table
                 $sql = "
                     SELECT user_id FROM $tbl_session_rel_user
@@ -180,14 +178,14 @@ function search_users($needle, $type)
                             INNER JOIN $tbl_user_rel_access_url url_user
                                 ON (url_user.user_id = user.id)
                             WHERE
-                                access_url_id = '$access_url_id'
-                                AND (
-                                    username LIKE '$needle%'
-                                    OR lastname LIKE '$needle%'
-                                    OR firstname LIKE '$needle%'
-                                )
-                                AND user.status <> 6
-                                AND user.status <> ".DRH."
+                                access_url_id = '$access_url_id' AND
+                                (
+                                    username LIKE '$needle%' OR 
+                                    lastname LIKE '$needle%' OR 
+                                    firstname LIKE '$needle%'
+                                ) AND 
+                                user.status <> 6 AND 
+                                user.status <> ".DRH."
                             $order_clause LIMIT 11
                         ";
                         break;
@@ -238,8 +236,11 @@ function search_users($needle, $type)
                             $officialCode.$user['lastname'].' '.$user['firstname'].' ('.$user['username'].')';
                     }
 
-                    $return .= '<a href="javascript: void(0);" onclick="javascript: add_user_to_session(\''.$user['id']
-                        .'\',\''.$person_name.' '.'\')">'.$person_name.' </a><br />';
+                    $return .= Display::url(
+                        $person_name,
+                        'javascript: void(0);',
+                        ['onclick' => "add_user_to_session('".$user['id']."', '".addslashes($person_name)."');"]
+                    ).'<br>';
                 } else {
                     $return .= '...<br />';
                 }
@@ -247,7 +248,6 @@ function search_users($needle, $type)
 
             $xajax_response->addAssign('ajax_list_users_single', 'innerHTML', api_utf8_encode($return));
         } else {
-            global $nosessionUsersList;
             $return .= '<select id="origin_users" name="nosessionUsersList[]" multiple="multiple" size="15" style="width:360px;">';
             while ($user = Database:: fetch_array($rs)) {
                 $person_name =
@@ -748,7 +748,7 @@ $newLinks .= Display::url(
                         class="form-control">
                 </select>
                 <br />
-                <button style="display:none" id="remove_user" name="remove_user" class="btn btn-primary" type="button"
+                <button style="display:none" id="remove_user" name="remove_user" class="btn btn-danger" type="button"
                         onclick="remove_item(document.getElementById('destination_users'))">
                     <?php echo get_lang('Remove'); ?> <em class="fa fa-trash"></em>
                 </button>

+ 1 - 1
main/session/add_users_to_session_course.php

@@ -15,7 +15,7 @@ $xajax->registerFunction('search_users');
 // setting the section (for the tabs)
 $this_section = SECTION_PLATFORM_ADMIN;
 
-$id_session = (int) $_GET['id_session'];
+$id_session = isset($_GET['id_session']) ? (int) $_GET['id_session'] : 0;
 $courseId = isset($_GET['course_id']) ? (int) $_GET['course_id'] : 0;
 
 if (empty($id_session) || empty($courseId)) {

+ 40 - 31
main/session/index.php

@@ -13,11 +13,12 @@ use ChamiloSession as Session;
 $cidReset = true;
 require_once __DIR__.'/../inc/global.inc.php';
 
-if (empty($_GET['session_id'])) {
+$session_id = isset($_GET['session_id']) ? (int) $_GET['session_id'] : 0;
+
+if (empty($session_id)) {
     api_not_allowed(true);
 }
 
-$session_id = isset($_GET['session_id']) ? intval($_GET['session_id']) : null;
 $sessionField = new ExtraFieldValue('session');
 $valueAllowVisitors = $sessionField->get_values_by_handler_and_field_variable(
     $session_id,
@@ -32,7 +33,7 @@ if (!$allowVisitors) {
 
 $this_section = SECTION_COURSES;
 $htmlHeadXtra[] = api_get_jqgrid_js();
-$course_id = isset($_GET['course_id']) ? intval($_GET['course_id']) : null;
+$course_id = isset($_GET['course_id']) ? (int) $_GET['course_id'] : null;
 Session::write('id_session', $session_id);
 
 // Clear the exercise session just in case
@@ -43,12 +44,13 @@ Session::erase('duration_time');
 $userId = api_get_user_id();
 $session_info = SessionManager::fetch($session_id);
 $session_list = SessionManager::get_sessions_by_coach(api_get_user_id());
-$course_list = SessionManager::get_course_list_by_session_id($session_id);
-
+$courseList = SessionManager::get_course_list_by_session_id($session_id);
 $userIsGeneralCoach = SessionManager::user_is_general_coach($userId, $session_id);
 
 $user_course_list = [];
-foreach ($course_list as $course) {
+$exerciseListPerCourse = [];
+
+foreach ($courseList as $course) {
     $status = SessionManager::get_user_status_in_course_session(
         $userId,
         $course['real_id'],
@@ -57,6 +59,32 @@ foreach ($course_list as $course) {
     if ($status !== false || api_is_platform_admin() || $userIsGeneralCoach) {
         $user_course_list[] = $course['real_id'];
     }
+
+    $exerciseList = ExerciseLib::get_all_exercises_for_course_id(
+        $course,
+        $session_id,
+        $course['real_id'],
+        true
+    );
+
+    $exerciseListNew = [];
+    if (!empty($exerciseList)) {
+        // Exercises
+        foreach ($exerciseList as $exerciseInfo) {
+            $exerciseId = $exerciseInfo['id'];
+            $visibility = api_get_item_visibility(
+                $course,
+                TOOL_QUIZ,
+                $exerciseId,
+                $session_id
+            );
+            if ($visibility == 0) {
+                continue;
+            }
+            $exerciseListNew[] = $exerciseInfo;
+        }
+    }
+    $exerciseListPerCourse[$course['real_id']] = $exerciseListNew;
 }
 
 if (empty($user_course_list)) {
@@ -66,9 +94,8 @@ if (empty($user_course_list)) {
 $my_session_list = [];
 $final_array = [];
 $new_course_list = [];
-
-if (!empty($course_list)) {
-    foreach ($course_list as $course_data) {
+if (!empty($courseList)) {
+    foreach ($courseList as $course_data) {
         if (api_is_platform_admin()) {
             $course_data['title'] = Display::url(
                 $course_data['title'],
@@ -87,7 +114,7 @@ if (!empty($course_list)) {
 
         $list = new LearnpathList(
             api_get_user_id(),
-            $course_data['code'],
+            api_get_course_info($course_data['code']),
             $session_id,
             'lp.publicatedOn ASC',
             true,
@@ -107,17 +134,7 @@ if (!empty($course_list)) {
         }
 
         $course_info = api_get_course_info($course_data['code']);
-        $exercise_count = count(
-            ExerciseLib::get_all_exercises(
-                $course_info,
-                $session_id,
-                true,
-                null,
-                false,
-                1
-            )
-        );
-
+        $exerciseCount = count($exerciseListPerCourse[$course_info['real_id']]);
         $max_mutation_date = '';
         $last_date = Tracking::get_last_connection_date_on_the_course(
             api_get_user_id(),
@@ -158,7 +175,7 @@ if (!empty($course_list)) {
             'title' => $course_data['title'].$icons,
             //  'recent_lps' => $icons,
             //'max_mutation_date' => substr(api_get_local_time($max_mutation_date),0,10),
-            'exercise_count' => $exercise_count,
+            'exercise_count' => $exerciseCount,
             'lp_count' => $lp_count,
         ];
     }
@@ -223,7 +240,6 @@ if (empty($session_id)) {
 //Final data to be show
 $my_real_array = $new_exercises = [];
 $now = time();
-$courseList = SessionManager::get_course_list_by_session_id($session_id);
 
 if (!empty($courseList)) {
     foreach ($courseList as $courseInfo) {
@@ -237,18 +253,11 @@ if (!empty($courseList)) {
             $session_id
         );
 
-        $exerciseList = ExerciseLib::get_all_exercises_for_course_id(
-            $courseInfo,
-            $session_id,
-            $courseId,
-            true
-        );
+        $exerciseList = $exerciseListPerCourse[$courseId];
 
         if (!empty($exerciseList)) {
             // Exercises
             foreach ($exerciseList as $exerciseInfo) {
-                $exerciseId = $exerciseInfo['id'];
-
                 if ($exerciseInfo['start_time'] == '0000-00-00 00:00:00') {
                     $start_date = '-';
                 } else {

+ 85 - 50
main/session/resume_session.php

@@ -9,7 +9,7 @@ use Chamilo\CoreBundle\Entity\Session;
 use Chamilo\CoreBundle\Entity\SessionRelCourseRelUser;
 
 /**
- * @author Bart Mollet, Julio Montoya lot of fixes
+ * @author  Bart Mollet, Julio Montoya lot of fixes
  *
  * @package chamilo.admin
  */
@@ -27,6 +27,8 @@ if (empty($sessionId)) {
 
 SessionManager::protectSession($sessionId);
 
+$codePath = api_get_path(WEB_CODE_PATH);
+
 $tool_name = get_lang('SessionOverview');
 $interbreadcrumb[] = [
     'url' => 'session_list.php',
@@ -97,10 +99,17 @@ switch ($action) {
         }
 
         if (!empty($_GET['class'])) {
-            $result = Database::query("DELETE FROM $tbl_session_rel_class
-                             WHERE session_id='$sessionId' AND class_id=".intval($_GET['class']));
+            $class = (int) $_GET['class'];
+            $result = Database::query(
+                "DELETE FROM $tbl_session_rel_class
+                 WHERE session_id = $sessionId
+                  AND class_id = $class"
+            );
             $nbr_affected_rows = Database::affected_rows($result);
-            Database::query("UPDATE $tbl_session SET nbr_classes=nbr_classes-$nbr_affected_rows WHERE id='$sessionId'");
+            Database::query(
+                "UPDATE $tbl_session 
+                SET nbr_classes = nbr_classes - $nbr_affected_rows 
+                WHERE id = $sessionId");
         }
 
         if (!empty($_GET['user'])) {
@@ -109,6 +118,8 @@ switch ($action) {
                 $_GET['user']
             );
         }
+
+        Display::addFlash(Display::return_message(get_lang('Updated')));
         break;
 }
 
@@ -170,11 +181,13 @@ if ($session->getNbrCourses() === 0) {
         // Get coachs of the courses in session
         $namesOfCoaches = [];
         $coachSubscriptions = $session->getUserCourseSubscriptionsByStatus($course, Session::COACH)
-            ->forAll(function ($index, SessionRelCourseRelUser $subscription) use (&$namesOfCoaches) {
-                $namesOfCoaches[] = $subscription->getUser()->getCompleteNameWithUserName();
+            ->forAll(
+                function ($index, SessionRelCourseRelUser $subscription) use (&$namesOfCoaches) {
+                    $namesOfCoaches[] = $subscription->getUser()->getCompleteNameWithUserName();
 
-                return true;
-            });
+                    return true;
+                }
+            );
 
         $orderButtons = '';
         if (SessionManager::orderCourseIsEnabled()) {
@@ -204,11 +217,12 @@ if ($session->getNbrCourses() === 0) {
         // hide_course_breadcrumb the parameter has been added to hide the name
         // of the course, that appeared in the default $interbreadcrumb
         $courseItem .= '<tr>
-			<td class="title">'.
-            Display::url(
+			<td class="title">'
+            .Display::url(
                 $course->getTitle().' ('.$course->getVisualCode().')',
                 $courseUrl
-            ).'</td>';
+            )
+            .'</td>';
         $courseItem .= '<td>'.($namesOfCoaches ? implode('<br>', $namesOfCoaches) : get_lang('None')).'</td>';
         $courseItem .= '<td>'.$numberOfUsers.'</td>';
         $courseItem .= '<td>';
@@ -217,25 +231,51 @@ if ($session->getNbrCourses() === 0) {
         if ($allowSkills) {
             $courseItem .= Display::url(
                 Display::return_icon('skills.png', get_lang('Skills')),
-                api_get_path(WEB_CODE_PATH).'admin/skill_rel_course.php?session_id='.$sessionId.'&course_id='.$course->getId()
+                $codePath.'admin/skill_rel_course.php?session_id='.$sessionId.'&course_id='.$course->getId()
             );
         }
         $courseItem .= $orderButtons;
 
-        $courseItem .= '<a href="add_users_to_session_course.php?id_session='.$sessionId.'&course_id='.$course->getId().'">'.
-            Display::return_icon('new_user.png', get_lang('AddUsers'), ['style' => 'width:22px'], ICON_SIZE_MEDIUM).'</a>';
-        $courseItem .= '<a href="session_course_user_list.php?id_session='.$sessionId.'&course_code='.$course->getCode().'">'.
-                Display::return_icon('user.png', get_lang('Users'), '', ICON_SIZE_SMALL).'</a>';
-        $courseItem .= '<a href="'.api_get_path(WEB_CODE_PATH).'user/user_import.php?action=import&cidReq='.$course->getCode().'&id_session='.$sessionId.'">'.
-                Display::return_icon('import_csv.png', get_lang('ImportUsersToACourse'), null, ICON_SIZE_SMALL).'</a>
-                <a href="'.api_get_path(WEB_CODE_PATH).'user/user_export.php?file_type=csv&course_session='.$course->getCode().':'.$sessionId.'&addcsvheader=1">'.
-                Display::return_icon('export_csv.png', get_lang('ExportUsersOfACourse'), null, ICON_SIZE_SMALL).'</a>
-				<a href="../tracking/courseLog.php?id_session='.$sessionId.'&cidReq='.$course->getCode().$orig_param.'&hide_course_breadcrumb=1">'.
-                Display::return_icon('statistics.gif', get_lang('Tracking')).'</a>&nbsp;
-				<a href="session_course_edit.php?id_session='.$sessionId.'&page=resume_session.php&course_code='.$course->getCode().''.$orig_param.'">'.
-                Display::return_icon('teacher.png', get_lang('ModifyCoach'), '', ICON_SIZE_SMALL).'</a>
-				<a href="'.api_get_self().'?id_session='.$sessionId.'&action=delete&idChecked[]='.$course->getCode().'" onclick="javascript:if(!confirm(\''.get_lang('ConfirmYourChoice').'\')) return false;">'.
-            Display::return_icon('delete.png', get_lang('Delete')).'</a>';
+        $courseItem .= Display::url(
+            Display::return_icon('new_user.png', get_lang('AddUsers')),
+            $codePath."session/add_users_to_session_course.php?id_session=$sessionId&course_id=".$course->getId()
+        );
+        $courseItem .= Display::url(
+            Display::return_icon('user.png', get_lang('Users')),
+            $codePath."session/session_course_user_list.php?id_session=$sessionId&course_code=".$course->getCode()
+        );
+        $courseItem .= Display::url(
+            Display::return_icon('import_csv.png', get_lang('ImportUsersToACourse')),
+            $codePath."user/user_import.php?action=import&cidReq={$course->getCode()}&id_session=$sessionId"
+        );
+        $courseItem .= Display::url(
+            Display::return_icon('export_csv.png', get_lang('ExportUsersOfACourse')),
+            $codePath."user/user_export.php?file_type=csv&course_session={$course->getCode()}:$sessionId&addcsvheader=1"
+        );
+        $courseItem .= Display::url(
+            Display::return_icon('statistics.gif', get_lang('Tracking')),
+            $codePath."tracking/courseLog.php?id_session=$sessionId&cidReq={$course->getCode()}$orig_param&hide_course_breadcrumb=1"
+        );
+        $courseItem .= Display::url(
+            Display::return_icon('teacher.png', get_lang('ModifyCoach')),
+            $codePath."session/session_course_edit.php?id_session=$sessionId&page=resume_session.php&course_code={$course->getCode()}$orig_param"
+        );
+        $courseItem .= Display::url(
+            Display::return_icon('folder_document.png', get_lang('UploadFile')),
+            '#',
+            [
+                'class' => 'session-upload-file-btn',
+                'data-session' => $sessionId,
+                'data-course' => $course->getId(),
+            ]
+        );
+        $courseItem .= Display::url(
+            Display::return_icon('delete.png', get_lang('Delete')),
+            api_get_self()."?id_session=$sessionId&action=delete&idChecked[]={$course->getCode()}",
+            [
+                'onclick' => "javascript:if(!confirm('".get_lang('ConfirmYourChoice')."')) return false;",
+            ]
+        );
 
         $courseItem .= '</td></tr>';
         $count++;
@@ -245,16 +285,16 @@ if ($session->getNbrCourses() === 0) {
 $courseListToShow .= '</table><br />';
 
 $url = '&nbsp;'.Display::url(
-    Display::return_icon('user_subscribe_session.png', get_lang('Add'), [], ICON_SIZE_SMALL),
-    "add_users_to_session.php?page=resume_session.php&id_session=$sessionId"
+    Display::return_icon('user_subscribe_session.png', get_lang('Add')),
+    $codePath."session/add_users_to_session.php?page=resume_session.php&id_session=$sessionId"
 );
 $url .= Display::url(
-    Display::return_icon('import_csv.png', get_lang('ImportUsers'), [], ICON_SIZE_SMALL),
-    "session_user_import.php?id_session=$sessionId"
+    Display::return_icon('import_csv.png', get_lang('ImportUsers')),
+    $codePath."session/session_user_import.php?id_session=$sessionId"
 );
 $url .= Display::url(
-    Display::return_icon('export_csv.png', get_lang('ExportUsers'), [], ICON_SIZE_SMALL),
-    api_get_path(WEB_CODE_PATH)."user/user_export.php?file_type=csv&session=$sessionId&addcsvheader=1"
+    Display::return_icon('export_csv.png', get_lang('ExportUsers')),
+    $codePath."user/user_export.php?file_type=csv&session=$sessionId&addcsvheader=1"
 );
 
 $userListToShow = Display::page_subheader(get_lang('UserList').$url);
@@ -274,17 +314,19 @@ if (!empty($userList)) {
         $userId = $user['user_id'];
         $userInfo = api_get_user_info($userId);
 
-        $userLink = '<a href="'.api_get_path(WEB_CODE_PATH).'admin/user_information.php?user_id='.$userId.'">'.
+        $userLink = '<a href="'.$codePath.'admin/user_information.php?user_id='.$userId.'">'.
             api_htmlentities($userInfo['complete_name_with_username']).'</a>';
 
         $reportingLink = Display::url(
             Display::return_icon('statistics.gif', get_lang('Reporting')),
-            api_get_path(WEB_CODE_PATH).'mySpace/myStudents.php?student='.$user['user_id'].''.$orig_param.'&id_session='.$sessionId
+            $codePath.'mySpace/myStudents.php?student='.$user['user_id'].''.$orig_param.'&id_session='
+            .$sessionId
         );
 
         $courseUserLink = Display::url(
             Display::return_icon('course.png', get_lang('BlockCoursesForThisUser')),
-            api_get_path(WEB_CODE_PATH).'session/session_course_user.php?id_user='.$user['user_id'].'&id_session='.$sessionId
+            $codePath.'session/session_course_user.php?id_user='.$user['user_id'].'&id_session='
+            .$sessionId
         );
 
         $removeLink = Display::url(
@@ -296,26 +338,17 @@ if (!empty($userList)) {
         $addUserToUrlLink = '';
         if ($multiple_url_is_on) {
             if ($user['access_url_id'] != $url_id) {
-                $userLink .= ' '.Display::return_icon(
-                    'warning.png',
-                    get_lang('UserNotAddedInURL'),
-                    [],
-                    ICON_SIZE_SMALL
-                );
-                $add = Display::return_icon(
-                    'add.png',
-                    get_lang('AddUsersToURL'),
-                    [],
-                    ICON_SIZE_SMALL
-                );
-                $addUserToUrlLink = '<a href="resume_session.php?action=add_user_to_url&id_session='.$sessionId.'&user_id='.$user['user_id'].'">'.$add.'</a>';
+                $userLink .= ' '.Display::return_icon('warning.png', get_lang('UserNotAddedInURL'));
+                $add = Display::return_icon('add.png', get_lang('AddUsersToURL'));
+                $addUserToUrlLink = '<a href="resume_session.php?action=add_user_to_url&id_session='.$sessionId
+                    .'&user_id='.$user['user_id'].'">'.$add.'</a>';
             }
         }
 
         $editUrl = null;
         /*
         if (isset($sessionInfo['duration']) && !empty($sessionInfo['duration'])) {
-            $editUrl = api_get_path(WEB_CODE_PATH) . 'session/session_user_edit.php?session_id=' . $sessionId . '&user_id=' . $userId;
+            $editUrl = $codePath . 'session/session_user_edit.php?session_id=' . $sessionId . '&user_id=' . $userId;
             $editUrl = Display::url(
                 Display::return_icon('agenda.png', get_lang('SessionDurationEdit')),
                 $editUrl
@@ -329,7 +362,7 @@ if (!empty($userList)) {
                 $status = get_lang('Drh');
                 $link = Display::url(
                     Display::return_icon('edit.png', get_lang('Edit')),
-                    api_get_path(WEB_CODE_PATH).'admin/dashboard_add_sessions_to_user.php?user='.$userId
+                    $codePath.'admin/dashboard_add_sessions_to_user.php?user='.$userId
                 );
                 break;
             default:
@@ -373,6 +406,8 @@ if (!empty($sessionInfo['promotion_id'])) {
 $programmedAnnouncement = new ScheduledAnnouncement();
 $programmedAnnouncement = $programmedAnnouncement->allowed();
 
+$htmlHeadXtra[] = api_get_jquery_libraries_js(['jquery-ui', 'jquery-upload']);
+
 $tpl = new Template($tool_name);
 $tpl->assign('session_header', $sessionHeader);
 $tpl->assign('title', $sessionTitle);

+ 15 - 19
main/session/scheduled_announcement.php

@@ -34,26 +34,11 @@ $interbreadcrumb[] = [
     'name' => get_lang('SessionOverview'),
 ];
 
-if ($action == 'add') {
-    $interbreadcrumb[] = [
-        'url' => api_get_self().'?session_id='.$sessionId,
-        'name' => get_lang('ScheduledAnnouncements'),
-    ];
-    $tool_name = get_lang('Add');
-} elseif ($action == 'edit') {
-    $tool_name = get_lang('Edit');
-    $interbreadcrumb[] = [
-        'url' => api_get_self().'?session_id='.$sessionId,
-        'name' => get_lang('ScheduledAnnouncements'),
-    ];
-} else {
-    $tool_name = get_lang('ScheduledAnnouncements');
-}
+$tool_name = get_lang('ScheduledAnnouncements');
 
 switch ($action) {
     case 'run':
         $messagesSent = $object->sendPendingMessages();
-
         Display::addFlash(
             Display::return_message(
                 get_lang('MessageSent').': '.$messagesSent,
@@ -61,10 +46,15 @@ switch ($action) {
             )
         );
         $content = $object->getGrid($sessionId);
-
         break;
     case 'add':
-        $url = api_get_self().'?action='.Security::remove_XSS($_GET['action']).'&session_id='.$sessionId;
+        $interbreadcrumb[] = [
+            'url' => api_get_self().'?session_id='.$sessionId,
+            'name' => get_lang('ScheduledAnnouncements'),
+        ];
+        $tool_name = get_lang('Add');
+
+        $url = api_get_self().'?action=add&session_id='.$sessionId;
         $form = $object->returnForm($url, 'add', $sessionInfo);
 
         // The validation or display
@@ -125,8 +115,14 @@ switch ($action) {
         }
         break;
     case 'edit':
+        $tool_name = get_lang('Edit');
+        $interbreadcrumb[] = [
+            'url' => api_get_self().'?session_id='.$sessionId,
+            'name' => get_lang('ScheduledAnnouncements'),
+        ];
+
         // Action handling: Editing
-        $url = api_get_self().'?action='.Security::remove_XSS($_GET['action']).'&id='.$id.'&session_id='.$sessionId;
+        $url = api_get_self().'?action=edit&id='.$id.'&session_id='.$sessionId;
         $form = $object->returnSimpleForm($id, $url, 'edit', $sessionInfo);
         if ($form->validate()) {
             $values = $form->getSubmitValues();

+ 168 - 114
main/session/session_category_list.php

@@ -26,15 +26,17 @@ function selectAll(idCheck,numRows,action) {
 $tbl_session_category = Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY);
 $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
 
-$page = isset($_GET['page']) ? intval($_GET['page']) : null;
+$page = isset($_GET['page']) ? (int) $_GET['page'] : null;
 $action = isset($_REQUEST['action']) ? Security::remove_XSS($_REQUEST['action']) : null;
-$sort = isset($_GET['sort']) && in_array($_GET['sort'], ['name', 'nbr_session', 'date_start', 'date_end']) ? Security::remove_XSS($_GET['sort']) : 'name';
+$sort = isset($_GET['sort']) && in_array($_GET['sort'], ['name', 'nbr_session', 'date_start', 'date_end'])
+    ? Security::remove_XSS($_GET['sort'])
+    : 'name';
 $idChecked = isset($_REQUEST['idChecked']) ? Security::remove_XSS($_REQUEST['idChecked']) : null;
 $order = isset($_REQUEST['order']) ? Security::remove_XSS($_REQUEST['order']) : 'ASC';
-$keyword = isset($_GET['keyword']) ? Security::remove_XSS($_GET['keyword']) : null;
+$keyword = isset($_REQUEST['keyword']) ? Security::remove_XSS($_REQUEST['keyword']) : null;
 
-if ($action == 'delete_on_session' || $action == 'delete_off_session') {
-    $delete_session = ($action == 'delete_on_session') ? true : false;
+if ($action === 'delete_on_session' || $action === 'delete_off_session') {
+    $delete_session = $action == 'delete_on_session' ? true : false;
     SessionManager::delete_session_category($idChecked, $delete_session);
     Display::addFlash(Display::return_message(get_lang('SessionCategoryDelete')));
     header('Location: '.api_get_self().'?sort='.$sort);
@@ -43,10 +45,10 @@ if ($action == 'delete_on_session' || $action == 'delete_off_session') {
 
 $interbreadcrumb[] = ['url' => 'session_list.php', 'name' => get_lang('SessionList')];
 
-if (isset($_GET['search']) && $_GET['search'] == 'advanced') {
-    $interbreadcrumb[] = ["url" => 'session_category_list.php', "name" => get_lang('ListSessionCategory')];
+if (isset($_GET['search']) && $_GET['search'] === 'advanced') {
+    $interbreadcrumb[] = ['url' => 'session_category_list.php', 'name' => get_lang('ListSessionCategory')];
     $tool_name = get_lang('SearchASession');
-    Display :: display_header($tool_name);
+    Display::display_header($tool_name);
     $form = new FormValidator('advanced_search', 'get');
     $form->addElement('header', '', $tool_name);
     $active_group = [];
@@ -64,9 +66,9 @@ if (isset($_GET['search']) && $_GET['search'] == 'advanced') {
     //if user is crfp admin only list its sessions
     $where = null;
     if (!api_is_platform_admin()) {
-        $where .= (empty($keyword) ? "" : " WHERE name LIKE '%".Database::escape_string(trim($_REQUEST['keyword']))."%'");
+        $where .= empty($keyword) ? "" : " WHERE name LIKE '%".Database::escape_string(trim($keyword))."%'";
     } else {
-        $where .= (empty($keyword) ? "" : " WHERE name LIKE '%".Database::escape_string(trim($_REQUEST['keyword']))."%'");
+        $where .= empty($keyword) ? "" : " WHERE name LIKE '%".Database::escape_string(trim($keyword))."%'";
     }
     if (empty($where)) {
         $where = " WHERE access_url_id = ".api_get_current_access_url_id()." ";
@@ -102,65 +104,88 @@ if (isset($_GET['search']) && $_GET['search'] == 'advanced') {
     <div class="actions">
         <div class="row">
             <div class="col-md-6">
-            <?php
-                echo '<a href="'.api_get_path(WEB_CODE_PATH).'session/session_category_add.php">'.
-                        Display::return_icon('new_folder.png', get_lang('AddSessionCategory'), '', ICON_SIZE_MEDIUM).'</a>
-                      <a href="'.api_get_path(WEB_CODE_PATH).'session/session_list.php">'.
-                        Display::return_icon('session.png', get_lang('ListSession'), '', ICON_SIZE_MEDIUM).'</a>'; ?>
+                <?php
+                echo Display::url(
+                    Display::return_icon('new_folder.png', get_lang('AddSessionCategory'), [], ICON_SIZE_MEDIUM),
+                    api_get_path(WEB_CODE_PATH).'session/session_category_add.php'
+                );
+    echo Display::url(
+                    Display::return_icon('session.png', get_lang('ListSession'), [], ICON_SIZE_MEDIUM),
+                    api_get_path(WEB_CODE_PATH).'session/session_list.php'
+                ); ?>
             </div>
             <div class="col-md-6">
                 <div class="pull-right">
-                <form method="POST" action="session_category_list.php" class="form-inline">
-                    <div class="form-group">
-                    <input class="form-control" type="text" name="keyword" value="<?php echo $keyword; ?>"
-                    aria-label="<?php echo get_lang('Search'); ?>"/>
-                    <button class="btn btn-default" type="submit" name="name" value="<?php echo get_lang('Search'); ?>"><em class="fa fa-search"></em> <?php echo get_lang('Search'); ?></button>
-                    <!-- <a href="session_list.php?search=advanced"><?php echo get_lang('AdvancedSearch'); ?></a> -->
-                    </div>
-                </form>
+                    <form method="POST" action="session_category_list.php" class="form-inline">
+                        <div class="form-group">
+                            <input class="form-control" type="text" name="keyword" value="<?php echo $keyword; ?>"
+                                   aria-label="<?php echo get_lang('Search'); ?>"/>
+                            <button class="btn btn-default" type="submit" name="name"
+                                    value="<?php echo get_lang('Search'); ?>"><em
+                                        class="fa fa-search"></em> <?php echo get_lang('Search'); ?></button>
+                            <!-- <a href="session_list.php?search=advanced"><?php echo get_lang('AdvancedSearch'); ?></a> -->
+                        </div>
+                    </form>
                 </div>
             </div>
         </div>
-    <form method="post" action="<?php echo api_get_self(); ?>?action=delete&sort=<?php echo $sort; ?>" onsubmit="javascript:if(!confirm('<?php echo get_lang('ConfirmYourChoice'); ?>')) return false;">
     </div>
-    <div align="left">
+    <form method="post" action="<?php echo api_get_self(); ?>?action=delete&sort=<?php echo $sort; ?>"
+          onsubmit="if(!confirm('<?php echo get_lang('ConfirmYourChoice'); ?>')) return false;">
         <?php
         if (count($Sessions) == 0 && isset($_POST['keyword'])) {
-            echo get_lang('NoSearchResults');
-            echo '</div>';
+            echo Display::return_message(get_lang('NoSearchResults'), 'warning');
         } else {
             if ($num > $limit) {
-                if ($page) {
-                    ?>
-                    <a href="<?php echo api_get_self(); ?>?page=<?php echo $page - 1; ?>&sort=<?php echo $sort; ?>&order=<?php echo Security::remove_XSS($order); ?>&keyword=<?php echo $keyword; ?><?php echo @$cond_url; ?>"><?php echo get_lang('Previous'); ?></a>
+                ?>
+                <div>
                     <?php
-                } else {
-                    echo get_lang('Previous');
-                } ?>
-                |
-                <?php
-                if ($nbr_results > $limit) {
-                    ?>
-                    <a href="<?php echo api_get_self(); ?>?page=<?php echo $page + 1; ?>&sort=<?php echo $sort; ?>&order=<?php echo Security::remove_XSS($order); ?>&keyword=<?php echo $keyword; ?><?php echo @$cond_url; ?>"><?php echo get_lang('Next'); ?></a>
+                    if ($page) {
+                        ?>
+                        <a href="<?php echo api_get_self(); ?>?page=<?php echo $page
+                            - 1; ?>&sort=<?php echo $sort; ?>&order=<?php echo Security::remove_XSS(
+                            $order
+                        ); ?>&keyword=<?php echo $keyword; ?><?php echo @$cond_url; ?>"><?php echo get_lang(
+                                'Previous'
+                            ); ?></a>
+                        <?php
+                    } else {
+                        echo get_lang('Previous');
+                    } ?>
+                    |
                     <?php
-                } else {
-                    echo get_lang('Next');
-                }
+                    if ($nbr_results > $limit) {
+                        ?>
+                        <a href="<?php echo api_get_self(); ?>?page=<?php echo $page
+                            + 1; ?>&sort=<?php echo $sort; ?>&order=<?php echo Security::remove_XSS(
+                            $order
+                        ); ?>&keyword=<?php echo $keyword; ?><?php echo @$cond_url; ?>"><?php echo get_lang(
+                                'Next'
+                            ); ?></a>
+                        <?php
+                    } else {
+                        echo get_lang('Next');
+                    } ?>
+                </div>
+                <?php
             } ?>
-        </div>
 
-        <table class="data_table" width="100%">
-            <tr>
-                <th>&nbsp;</th>
-                <th><a href="<?php echo api_get_self(); ?>?sort=name&order=<?php echo ($sort == 'name') ? $order : 'ASC'; ?>"><?php echo get_lang('SessionCategoryName'); ?></a></th>
-                <th><a href="<?php echo api_get_self(); ?>?sort=nbr_session&order=<?php echo ($sort == 'nbr_session') ? $order : 'ASC'; ?>"><?php echo get_lang('NumberOfSession'); ?></a></th>
-                <th><a href="<?php echo api_get_self(); ?>?sort=date_start&order=<?php echo ($sort == 'date_start') ? $order : 'ASC'; ?>"><?php echo get_lang('StartDate'); ?></a></th>
-                <th><a href="<?php echo api_get_self(); ?>?sort=date_end&order=<?php echo ($sort == 'date_end') ? $order : 'ASC'; ?>"><?php echo get_lang('EndDate'); ?></a></th>
-                <th><?php echo get_lang('Actions'); ?></th>
-            </tr>
+            <table class="data_table" width="100%">
+                <tr>
+                    <th>&nbsp;</th>
+                    <th><a href="<?php echo api_get_self(); ?>?sort=name&order=<?php echo ($sort == 'name') ? $order
+                            : 'ASC'; ?>"><?php echo get_lang('SessionCategoryName'); ?></a></th>
+                    <th><a href="<?php echo api_get_self(); ?>?sort=nbr_session&order=<?php echo ($sort
+                            == 'nbr_session') ? $order : 'ASC'; ?>"><?php echo get_lang('NumberOfSession'); ?></a></th>
+                    <th><a href="<?php echo api_get_self(); ?>?sort=date_start&order=<?php echo ($sort == 'date_start')
+                            ? $order : 'ASC'; ?>"><?php echo get_lang('StartDate'); ?></a></th>
+                    <th><a href="<?php echo api_get_self(); ?>?sort=date_end&order=<?php echo ($sort == 'date_end')
+                            ? $order : 'ASC'; ?>"><?php echo get_lang('EndDate'); ?></a></th>
+                    <th><?php echo get_lang('Actions'); ?></th>
+                </tr>
 
-            <?php
-            $i = 0;
+                <?php
+                $i = 0;
             $x = 0;
             foreach ($Sessions as $key => $enreg) {
                 if ($key == $limit) {
@@ -176,74 +201,103 @@ if (isset($_GET['search']) && $_GET['search'] == 'advanced') {
 
                 $rs = Database::query($sql);
                 list($nb_courses) = Database::fetch_array($rs); ?>
-                <tr class="<?php echo $i ? 'row_odd' : 'row_even'; ?>">
-                    <td><input type="checkbox" id="idChecked_<?php echo $x; ?>" name="idChecked[]" value="<?php echo $enreg['id']; ?>"></td>
-                    <td><?php echo api_htmlentities($enreg['name'], ENT_QUOTES, $charset); ?></td>
-                    <td><?php echo "<a href=\"session_list.php?id_category=".$enreg['id']."\">".$nb_courses." Session(s) </a>"; ?></td>
-                    <td><?php echo api_format_date($enreg['date_start'], DATE_FORMAT_SHORT); ?></td>
-                    <td>
-                        <?php
-                        if (!empty($enreg['date_end']) && $enreg['date_end'] != '0000-00-00') {
-                            echo api_format_date($enreg['date_end'], DATE_FORMAT_SHORT);
-                        } else {
-                            echo '-';
-                        } ?>
-                    </td>
-                    <td>
-                        <a href="session_category_edit.php?&id=<?php echo $enreg['id']; ?>">
-                            <?php Display::display_icon('edit.png', get_lang('Edit'), [], ICON_SIZE_SMALL); ?>
-                        </a>
-                        <a href="<?php echo api_get_self(); ?>?sort=<?php echo $sort; ?>&action=delete_off_session&idChecked=<?php echo $enreg['id']; ?>" onclick="javascript:if(!confirm('<?php echo get_lang('ConfirmYourChoice'); ?>')) return false;">
-                            <?php Display::display_icon('delete.png', get_lang('Delete'), [], ICON_SIZE_SMALL); ?>
-                        </a>
-                    </td>
-                </tr>
-                <?php
-                $i = $i ? 0 : 1;
+                    <tr class="<?php echo $i ? 'row_odd' : 'row_even'; ?>">
+                        <td><input type="checkbox" id="idChecked_<?php echo $x; ?>" name="idChecked[]"
+                                   value="<?php echo $enreg['id']; ?>"></td>
+                        <td><?php echo api_htmlentities($enreg['name'], ENT_QUOTES, $charset); ?></td>
+                        <td><?php echo "<a href=\"session_list.php?id_category=".$enreg['id']."\">".$nb_courses
+                                ." Session(s) </a>"; ?></td>
+                        <td><?php echo api_format_date($enreg['date_start'], DATE_FORMAT_SHORT); ?></td>
+                        <td>
+                            <?php
+                            if (!empty($enreg['date_end']) && $enreg['date_end'] != '0000-00-00') {
+                                echo api_format_date($enreg['date_end'], DATE_FORMAT_SHORT);
+                            } else {
+                                echo '-';
+                            } ?>
+                        </td>
+                        <td>
+                            <a href="session_category_edit.php?&id=<?php echo $enreg['id']; ?>">
+                                <?php Display::display_icon('edit.png', get_lang('Edit'), [], ICON_SIZE_SMALL); ?>
+                            </a>
+                            <a href="<?php echo api_get_self(
+                            ); ?>?sort=<?php echo $sort; ?>&action=delete_off_session&idChecked=<?php echo $enreg['id']; ?>"
+                               onclick="if(!confirm('<?php echo get_lang(
+                                   'ConfirmYourChoice'
+                               ); ?>')) return false;">
+                                <?php Display::display_icon('delete.png', get_lang('Delete'), [], ICON_SIZE_SMALL); ?>
+                            </a>
+                        </td>
+                    </tr>
+                    <?php
+                    $i = $i ? 0 : 1;
                 $x++;
             }
             unset($Sessions); ?>
-        </table>
-        <br />
-        <div align="left">
-        <?php
-        if ($num > $limit) {
-            if ($page) {
-                ?>
-                    <a href="<?php echo api_get_self(); ?>?page=<?php echo $page - 1; ?>&sort=<?php echo $sort; ?>&order=<?php echo Security::remove_XSS($_REQUEST['order']); ?>&keyword=<?php echo $_REQUEST['keyword']; ?><?php echo @$cond_url; ?>">
-                        <?php echo get_lang('Previous'); ?></a>
+            </table>
+            <br/>
+            <div>
                 <?php
-            } else {
-                echo get_lang('Previous');
-            } ?>
-                |
-            <?php
-            if ($nbr_results > $limit) {
-                ?>
+                if ($num > $limit) {
+                    if ($page) {
+                        ?>
+                        <a href="<?php echo api_get_self(); ?>?page=<?php echo $page
+                            - 1; ?>&sort=<?php echo $sort; ?>&order=<?php echo Security::remove_XSS(
+                            $_REQUEST['order']
+                        ); ?>&keyword=<?php echo $_REQUEST['keyword']; ?><?php echo @$cond_url; ?>">
+                            <?php echo get_lang('Previous'); ?></a>
+                        <?php
+                    } else {
+                        echo get_lang('Previous');
+                    } ?>
+                    |
+                    <?php
+                    if ($nbr_results > $limit) {
+                        ?>
 
-                <a href="<?php echo api_get_self(); ?>?page=<?php echo $page + 1; ?>&sort=<?php echo $sort; ?>&order=<?php echo Security::remove_XSS($_REQUEST['order']); ?>&keyword=<?php echo $_REQUEST['keyword']; ?><?php echo @$cond_url; ?>">
-                    <?php echo get_lang('Next'); ?></a>
+                        <a href="<?php echo api_get_self(); ?>?page=<?php echo $page
+                            + 1; ?>&sort=<?php echo $sort; ?>&order=<?php echo Security::remove_XSS(
+                            $_REQUEST['order']
+                        ); ?>&keyword=<?php echo $_REQUEST['keyword']; ?><?php echo @$cond_url; ?>">
+                            <?php echo get_lang('Next'); ?></a>
 
-                <?php
-            } else {
-                echo get_lang('Next');
-            }
+                        <?php
+                    } else {
+                        echo get_lang('Next');
+                    }
+                } ?>
+            </div>
+            <div class="row">
+                <div class="col-sm-4">
+                    <div class="btn-group">
+                        <button type="button" class="btn btn-default" onclick="selectAll('idChecked',<?php echo $x; ?>,'true');">
+                            <?php echo get_lang('SelectAll'); ?>
+                        </button>
+                        <button type="button" class="btn btn-default" onclick="selectAll('idChecked',<?php echo $x; ?>,'false');">
+                            <?php echo get_lang('UnSelectAll'); ?>
+                        </button>
+                    </div>
+                </div>
+                <div class="col-sm-6">
+                    <select class="selectpicker form-control" name="action">
+                        <option value="delete_off_session" selected="selected">
+                            <?php echo get_lang('DeleteSelectedSessionCategory'); ?>
+                        </option>
+                        <option value="delete_on_session">
+                            <?php echo get_lang('DeleteSelectedFullSessionCategory'); ?>
+                        </option>
+                    </select>
+                </div>
+                <div class="col-sm-2">
+                    <button class="btn btn-success" type="submit" name="name" value="<?php echo get_lang('Ok'); ?>">
+                        <?php echo get_lang('Ok'); ?>
+                    </button>
+                </div>
+            </div>
+            <?php
         } ?>
-        </div>
-        <div class="btn-group">
-            <a class="btn btn-default" href="#" onclick="selectAll('idChecked',<?php echo $x; ?>,'true');return false;"><?php echo get_lang('SelectAll'); ?></a>
-            <a class="btn btn-default" href="#" onclick="selectAll('idChecked',<?php echo $x; ?>,'false');return false;"><?php echo get_lang('UnSelectAll'); ?></a>
-        </div>
-        <div class="list-category">
-            <select class="selectpicker show-tick form-control" name="action">
-                <option value="delete_off_session" selected="selected"><?php echo get_lang('DeleteSelectedSessionCategory'); ?></option>
-                <option value="delete_on_session"><?php echo get_lang('DeleteSelectedFullSessionCategory'); ?></option>
-            </select>
-        </div>
-        <button class="btn btn-success" type="submit" name="name" value="<?php echo get_lang('Ok'); ?>"><?php echo get_lang('Ok'); ?></button>
+        </table>
+    </form>
     <?php
-        } ?>
-    </table>
-<?php
 }
 Display::display_footer();

+ 1 - 1
main/session/session_course_edit.php

@@ -10,7 +10,7 @@ $cidReset = true;
 
 require_once __DIR__.'/../inc/global.inc.php';
 
-$id_session = intval($_GET['id_session']);
+$id_session = isset($_GET['id_session']) ? (int) $_GET['id_session'] : 0;
 SessionManager::protectSession($id_session);
 $course_code = $_GET['course_code'];
 $course_info = api_get_course_info($_REQUEST['course_code']);

+ 1 - 1
main/session/session_course_list.php

@@ -10,7 +10,7 @@ require_once __DIR__.'/../inc/global.inc.php';
 // setting the section (for the tabs)
 $this_section = SECTION_PLATFORM_ADMIN;
 
-$id_session = intval($_GET['id_session']);
+$id_session = isset($_GET['id_session']) ? (int) $_GET['id_session'] : 0;
 SessionManager::protectSession($id_session);
 
 // Database Table Definitions

+ 3 - 4
main/session/session_course_user.php

@@ -14,12 +14,11 @@ require_once __DIR__.'/../inc/global.inc.php';
 // setting the section (for the tabs)
 $this_section = SECTION_PLATFORM_ADMIN;
 $tool_name = get_lang('EditSessionCoursesByUser');
+$id_session = isset($_GET['id_session']) ? (int) $_GET['id_session'] : 0;
+SessionManager::protectSession($id_session);
 
-$id_session = intval($_GET['id_session']);
 $id_user = intval($_GET['id_user']);
 
-SessionManager::protectSession($id_session);
-
 $em = Database::getManager();
 /** @var Session $session */
 $session = $em->find('ChamiloCoreBundle:Session', $id_session);
@@ -103,7 +102,7 @@ $interbreadcrumb[] = [
 ];
 
 Display::display_header($tool_name);
-echo Display::page_header($session->getName().' - '.$user->getCompleteName());
+echo Display::page_header($session->getName().' - '.UserManager::formatUserFullName($user));
 ?>
 <div class="row">
     <div class="col-sm-8 col-sm-offset-2">

+ 1 - 1
main/session/session_course_user_list.php

@@ -15,7 +15,7 @@ $tbl_session_rel_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
 $tbl_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
 $tbl_session_rel_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
 
-$id_session = intval($_GET['id_session']);
+$id_session = isset($_GET['id_session']) ? (int) $_GET['id_session'] : 0;
 SessionManager::protectSession($id_session);
 
 if (empty($id_session)) {

+ 2 - 3
main/session/session_edit.php

@@ -21,7 +21,7 @@ $htmlHeadXtra[] = api_get_asset('cropper/dist/cropper.min.js');
 $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
 $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
 
-$id = intval($_GET['id']);
+$id = (int) $_GET['id'];
 
 SessionManager::protectSession($id);
 
@@ -51,7 +51,6 @@ if (!empty($sessionInfo['coach_access_end_date'])) {
     $sessionInfo['coach_access_end_date'] = api_get_local_time($sessionInfo['coach_access_end_date']);
 }
 
-$id_coach = $sessionInfo['id_coach'];
 $tool_name = get_lang('EditSession');
 
 $interbreadcrumb[] = ['url' => "session_list.php", "name" => get_lang('SessionList')];
@@ -239,7 +238,7 @@ function emptyDuration() {
     }
 }
 
-$(document).on('ready', function (){
+$(function() {
     $('#show-options').on('click', function (e) {
         e.preventDefault();
         var display = $('#options').css('display');

+ 1 - 0
main/session/session_export.php

@@ -14,6 +14,7 @@ $this_section = SECTION_PLATFORM_ADMIN;
 api_protect_admin_script(true);
 
 $session_id = isset($_GET['session_id']) ? intval($_GET['session_id']) : 0;
+
 $formSent = 0;
 $errorMsg = '';
 

+ 7 - 27
main/session/session_list.php

@@ -13,7 +13,7 @@ $this_section = SECTION_PLATFORM_ADMIN;
 
 SessionManager::protectSession(null, false);
 
-//Add the JS needed to use the jqgrid
+// Add the JS needed to use the jqgrid
 $htmlHeadXtra[] = api_get_jqgrid_js();
 
 $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : null;
@@ -133,13 +133,8 @@ $extra_params['height'] = 'auto';
 if (!isset($_GET['keyword'])) {
     $extra_params['postData'] = [
         'filters' => [
-            "groupOp" => "AND",
-            "rules" => $result['rules'],
-            /*array(
-                array( "field" => "display_start_date", "op" => "gt", "data" => ""),
-                array( "field" => "display_end_date", "op" => "gt", "data" => "")
-            ),*/
-            //'groups' => $groups
+            'groupOp' => 'AND',
+            'rules' => $result['rules'],
         ],
     ];
 }
@@ -164,23 +159,14 @@ $orderUrl = api_get_path(WEB_AJAX_PATH).'session.ajax.php?a=order';
     <script>
         function setSearchSelect(columnName) {
             $("#sessions").jqGrid('setColProp', columnName, {
-                /*searchoptions:{
-                 dataInit:function(el){
-                 $("option[value='1']",el).attr("selected", "selected");
-                 setTimeout(function(){
-                 $(el).trigger('change');
-                 }, 1000);
-                 }
-                 }*/
             });
         }
         var added_cols = [];
         var original_cols = [];
 
         function clean_cols(grid, added_cols) {
-            //Cleaning
+            // Cleaning
             for (key in added_cols) {
-                //console.log('hide: ' + key);
                 grid.hideCol(key);
             };
             grid.showCol('name');
@@ -192,7 +178,6 @@ $orderUrl = api_get_path(WEB_AJAX_PATH).'session.ajax.php?a=order';
         function show_cols(grid, added_cols) {
             grid.showCol('name').trigger('reloadGrid');
             for (key in added_cols) {
-                //console.log('show: ' + key);
                 grid.showCol(key);
             };
         }
@@ -268,17 +253,12 @@ $orderUrl = api_get_path(WEB_AJAX_PATH).'session.ajax.php?a=order';
                             filters = jQuery.parseJSON(postdata.filters);
                             clean_cols(grid, added_cols);
                             added_cols = [];
-                            $.each(filters, function(key, value){
-                                //console.log('key: ' + key );
+                            $.each(filters, function(key, value) {
                                 if (key == 'rules') {
                                     $.each(value, function(subkey, subvalue) {
                                         if (subvalue.data == undefined) {
                                         }
-
-                                        //if (added_cols[value.field] == undefined) {
                                         added_cols[subvalue.field] = subvalue.field;
-                                        //}
-                                        //grid.showCol(value.field);
                                     });
                                 }
                             });
@@ -308,10 +288,10 @@ $orderUrl = api_get_path(WEB_AJAX_PATH).'session.ajax.php?a=order';
                     });
                     orderList = JSON.stringify(orderList);
                     $.get("<?php echo $orderUrl; ?>", "order="+orderList, function (result) {
-                        console.log(result);
                     });
                 }
             };
+
             // Sortable rows
             grid.jqGrid('sortableRows', options);
             <?php
@@ -342,7 +322,7 @@ $orderUrl = api_get_path(WEB_AJAX_PATH).'session.ajax.php?a=order';
             gbox.before(searchDialog);
             gbox.css({clear:"left"});
 
-            //Select first elements by default
+            // Select first elements by default
             $('.input-elm').each(function(){
                 $(this).find('option:first').attr('selected', 'selected');
             });

+ 1 - 1
main/social/download.php

@@ -41,7 +41,7 @@ if (!empty($messageInfo['group_id'])) {
 }
 
 // Only process wall messages
-if (!in_array($messageInfo['msg_status'], [MESSAGE_STATUS_WALL, MESSAGE_STATUS_WALL_POST])) {
+if (!in_array($messageInfo['msg_status'], [MESSAGE_STATUS_WALL, MESSAGE_STATUS_WALL_POST, MESSAGE_STATUS_PROMOTED])) {
     api_not_allowed();
 }
 

+ 14 - 15
main/social/group_view.php

@@ -109,17 +109,16 @@ $role = 0;
 $usergroup = new UserGroup();
 
 if ($group_id != 0) {
-    $group_info = $usergroup->get($group_id);
-    $group_info['name'] = Security::remove_XSS($group_info['name']);
-    $group_info['description'] = Security::remove_XSS($group_info['description']);
-
-    $interbreadcrumb[] = ['url' => '#', 'name' => $group_info['name']];
+    $groupInfo = $usergroup->get($group_id);
+    $groupInfo['name'] = Security::remove_XSS($groupInfo['name']);
+    $groupInfo['description'] = Security::remove_XSS($groupInfo['description']);
+    $interbreadcrumb[] = ['url' => '#', 'name' => $groupInfo['name']];
 
     if (isset($_GET['action']) && $_GET['action'] == 'leave') {
         $user_leaved = intval($_GET['u']);
         // I can "leave me myself"
         if (api_get_user_id() == $user_leaved) {
-            if (UserGroup::canLeave($group_info)) {
+            if (UserGroup::canLeave($groupInfo)) {
                 $usergroup->delete_user_rel_group($user_leaved, $group_id);
                 Display::addFlash(
                     Display::return_message(get_lang('UserIsNotSubscribedToThisGroup'), 'confirmation', false)
@@ -133,7 +132,7 @@ if ($group_id != 0) {
         // we add a user only if is a open group
         $user_join = intval($_GET['u']);
         if (api_get_user_id() == $user_join && !empty($group_id)) {
-            if ($group_info['visibility'] == GROUP_PERMISSION_OPEN) {
+            if ($groupInfo['visibility'] == GROUP_PERMISSION_OPEN) {
                 $usergroup->add_user_to_group($user_join, $group_id);
                 Display::addFlash(
                     Display::return_message(get_lang('UserIsSubscribedToThisGroup'), 'confirmation', false)
@@ -155,9 +154,9 @@ $create_thread_link = '';
 $social_right_content = null;
 $socialForum = '';
 
-$group_info = $usergroup->get($group_id);
-$group_info['name'] = Security::remove_XSS($group_info['name']);
-$group_info['description'] = Security::remove_XSS($group_info['description']);
+$groupInfo = $usergroup->get($group_id);
+$groupInfo['name'] = Security::remove_XSS($groupInfo['name']);
+$groupInfo['description'] = Security::remove_XSS($groupInfo['description']);
 
 //Loading group information
 if (isset($_GET['status']) && $_GET['status'] == 'sent') {
@@ -167,13 +166,13 @@ if (isset($_GET['status']) && $_GET['status'] == 'sent') {
 $is_group_member = $usergroup->is_group_member($group_id);
 $role = $usergroup->get_user_group_role(api_get_user_id(), $group_id);
 
-if (!$is_group_member && $group_info['visibility'] == GROUP_PERMISSION_CLOSED) {
+if (!$is_group_member && $groupInfo['visibility'] == GROUP_PERMISSION_CLOSED) {
     if ($role == GROUP_USER_PERMISSION_PENDING_INVITATION_SENT_BY_USER) {
         $social_right_content .= Display::return_message(get_lang('YouAlreadySentAnInvitation'));
     }
 }
 
-if ($is_group_member || $group_info['visibility'] == GROUP_PERMISSION_OPEN) {
+if ($is_group_member || $groupInfo['visibility'] == GROUP_PERMISSION_OPEN) {
     if (!$is_group_member) {
         if (!in_array(
             $role,
@@ -244,7 +243,7 @@ if ($is_group_member || $group_info['visibility'] == GROUP_PERMISSION_OPEN) {
 
     // My friends
     $friend_html = SocialManager::listMyFriendsBlock(
-        $user_id,
+        api_get_user_id(),
         '',
         ''
     );
@@ -323,12 +322,12 @@ $tpl = new Template(null);
 
 // Block Social Avatar
 SocialManager::setSocialUserBlock($tpl, api_get_user_id(), 'groups', $group_id);
-//Block Social Menu
+
 $social_menu_block = SocialManager::show_social_menu('groups', $group_id);
 $tpl->setHelp('Groups');
 $tpl->assign('create_link', $create_thread_link);
 $tpl->assign('is_group_member', $is_group_member);
-$tpl->assign('group_info', $group_info);
+$tpl->assign('group_info', $groupInfo);
 $tpl->assign('social_friend_block', $friend_html);
 $tpl->assign('social_menu_block', $social_menu_block);
 $tpl->assign('social_forum', $socialForum);

+ 2 - 4
main/social/groups.php

@@ -21,10 +21,10 @@ $allowed_views = ['mygroups', 'newest', 'pop'];
 $content = null;
 
 if (isset($_GET['view']) && in_array($_GET['view'], $allowed_views)) {
-    if ($_GET['view'] == 'mygroups') {
+    if ($_GET['view'] === 'mygroups') {
         $interbreadcrumb[] = ['url' => 'groups.php', 'name' => get_lang('Groups')];
         $interbreadcrumb[] = ['url' => '#', 'name' => get_lang('MyGroups')];
-    } elseif ($_GET['view'] == 'newest') {
+    } elseif ($_GET['view'] === 'newest') {
         $interbreadcrumb[] = ['url' => 'groups.php', 'name' => get_lang('Groups')];
         $interbreadcrumb[] = ['url' => '#', 'name' => get_lang('Newest')];
     } else {
@@ -41,9 +41,7 @@ if (isset($_GET['view']) && in_array($_GET['view'], $allowed_views)) {
 // getting group information
 $relation_group_title = '';
 $my_group_role = 0;
-
 $usergroup = new UserGroup();
-
 $create_thread_link = '';
 
 $show_menu = 'browse_groups';

+ 9 - 6
main/social/home.php

@@ -84,14 +84,13 @@ if (!empty($threadList)) {
     $threadIdList = array_column($threadList, 'id');
 }
 
-// Social Post Wall
 $posts = SocialManager::getMyWallMessages($user_id, 0, 10, $threadIdList);
 $countPost = $posts['count'];
 $posts = $posts['posts'];
 SocialManager::getScrollJs($countPost, $htmlHeadXtra);
 
 // Block Menu
-$social_menu_block = SocialManager::show_social_menu('home');
+$menu = SocialManager::show_social_menu('home');
 
 $social_search_block = Display::panel(
     UserManager::get_search_form(''),
@@ -135,16 +134,20 @@ $formSearch->addText(
     ]
 );
 
+// Added a Jquery Function to return the Preview of OpenGraph URL Content
+$htmlHeadXtra[] = SocialManager::getScriptToGetOpenGraph();
+
 $tpl = new Template(get_lang('SocialNetwork'));
 SocialManager::setSocialUserBlock($tpl, $user_id, 'home');
-$tpl->assign('social_wall_block', $wallSocialAddPost);
-$tpl->assign('social_post_wall_block', $posts);
-$tpl->assign('social_menu_block', $social_menu_block);
+$tpl->assign('add_post_form', $wallSocialAddPost);
+$tpl->assign('posts', $posts);
+$tpl->assign('social_menu_block', $menu);
 $tpl->assign('social_auto_extend_link', $socialAutoExtendLink);
 $tpl->assign('search_friends_form', $formSearch->returnForm());
 $tpl->assign('social_friend_block', $friend_html);
 $tpl->assign('social_search_block', $social_search_block);
-$tpl->assign('social_skill_block', SocialManager::getSkillBlock($user_id));
+$tpl->assign('social_skill_block', SocialManager::getSkillBlock($user_id, 'vertical'));
 $tpl->assign('social_group_block', $social_group_block);
+$tpl->assign('session_list', $social_session_block);
 $social_layout = $tpl->get_template('social/home.tpl');
 $tpl->display($social_layout);

+ 0 - 1
main/social/map.php

@@ -95,7 +95,6 @@ foreach ($data as &$result) {
     $result['complete_name'] = $result['firstname'].' '.$result['lastname'];
     $result['lastname'] = '';
     $result['firstname'] = '';
-
     $parts = explode('::', $result['ville']);
     if (isset($parts[1]) && !empty($parts[1])) {
         $parts2 = explode(',', $parts[1]);

+ 20 - 4
main/social/my_skills_report.php

@@ -28,6 +28,12 @@ switch ($action) {
         $certificate = new Certificate(0, api_get_user_id(), false, false);
         $certificate->generatePdfFromCustomCertificate();
         break;
+    case 'generate':
+        $certificate = Certificate::generateUserSkills(api_get_user_id());
+        Display::addFlash(Display::return_message(get_lang('Updated')));
+        header('Location: '.api_get_self());
+        exit;
+        break;
 }
 
 $skillTable = Database::get_main_table(TABLE_MAIN_SKILL);
@@ -47,15 +53,26 @@ if ($isStudent) {
     $tpl->assign('skill_table', $result['table']);
     $tplPath = 'skill/student_report.tpl';
 } elseif ($isStudentBoss) {
-    $selectedStudent = isset($_REQUEST['student']) ? (int) $_REQUEST['student'] : 0;
     $tableRows = [];
     $followedStudents = UserManager::getUsersFollowedByStudentBoss($userId);
 
+    $frmStudents = new FormValidator('students', 'get');
+    $slcStudent = $frmStudents->addSelect(
+        'student',
+        get_lang('Student'),
+        ['0' => get_lang('Select')]
+    );
+    $frmStudents->addButtonSearch(get_lang('Search'));
+
     foreach ($followedStudents as &$student) {
         $student['completeName'] = api_get_person_name($student['firstname'], $student['lastname']);
+
+        $slcStudent->addOption($student['completeName'], $student['user_id']);
     }
 
-    if ($selectedStudent > 0) {
+    if ($frmStudents->validate()) {
+        $selectedStudent = (int) $frmStudents->exportValue('student');
+
         $sql = "SELECT s.name, sru.acquired_skill_at, c.title, c.directory
                 FROM $skillTable s
                 INNER JOIN $skillRelUserTable sru
@@ -109,8 +126,7 @@ if ($isStudent) {
     }
 
     $tplPath = 'skill/student_boss_report.tpl';
-    $tpl->assign('followed_students', $followedStudents);
-    $tpl->assign('selected_student', $selectedStudent);
+    $tpl->assign('form', $frmStudents->returnForm());
 } elseif ($isDRH) {
     $selectedCourse = isset($_REQUEST['course']) ? intval($_REQUEST['course']) : null;
     $selectedSkill = isset($_REQUEST['skill']) ? intval($_REQUEST['skill']) : 0;

+ 9 - 1
main/social/personal_data.php

@@ -10,6 +10,8 @@ $cidReset = true;
 
 require_once __DIR__.'/../inc/global.inc.php';
 
+api_set_more_memory_and_time_limits();
+
 api_block_anonymous_users();
 
 if (api_get_configuration_value('disable_gdpr')) {
@@ -268,7 +270,13 @@ foreach ($properties as $key => $value) {
                     $personalDataContent .= '<li>'.get_lang('NoData').'</li>';
                 } else {
                     foreach ($value as $subValue) {
-                        $personalDataContent .= '<li>'.$subValue->variable.': '.Security::remove_XSS($subValue->value).'</li>';
+                        if (is_array($subValue->value)) {
+                            // tags fields can be stored as arrays
+                            $val = json_encode(Security::remove_XSS($subValue->value));
+                        } else {
+                            $val = Security::remove_XSS($subValue->value);
+                        }
+                        $personalDataContent .= '<li>'.$subValue->variable.': '.$val.'</li>';
                     }
                 }
                 $personalDataContent .= '</ul>';

+ 8 - 44
main/social/profile.php

@@ -156,8 +156,8 @@ if (is_array($personal_course_list)) {
     $course_list_code = array_unique_dimensional($course_list_code);
 }
 
-//Social Block Menu
-$social_menu_block = SocialManager::show_social_menu(
+// Social Block Menu
+$menu = SocialManager::show_social_menu(
     'shared_profile',
     null,
     $user_id,
@@ -173,49 +173,13 @@ $sessionList = SessionManager::getSessionsFollowedByUser(
 
 // My friends
 $friend_html = SocialManager::listMyFriendsBlock($user_id, $link_shared);
-$wallSocialAddPost = SocialManager::getWallForm(api_get_self());
+$addPostForm = SocialManager::getWallForm(api_get_self());
 
 $posts = SocialManager::getWallMessagesByUser($friendId);
 $socialAutoExtendLink = SocialManager::getAutoExtendLink($user_id, $countPost);
 
 // Added a Jquery Function to return the Preview of OpenGraph URL Content
-$htmlHeadXtra[] = '<script>
-$(function() {
-    var getUrl = $("[name=\'social_wall_new_msg_main\']");
-    var matchUrl = /https?:\/\/w{0,3}\w*?\.(\w*?\.)?\w{2,3}\S*|www\.(\w*?\.)?\w*?\.\w{2,3}\S*|(\w*?\.)?\w*?\.\w{2,3}[\/\?]\S*/ ;
-
-    getUrl.on("paste", function(e) {
-        $.ajax({
-            contentType: "application/x-www-form-urlencoded",
-            beforeSend: function() {
-                $("[name=\'wall_post_button\']").prop( "disabled", true );
-                $(".panel-preview").hide();
-                $(".spinner").html("'.
-                    '<div class=\'text-center\'>'.
-                        '<em class=\'fa fa-spinner fa-pulse fa-1x\'></em>'.
-                        '<p>'.get_lang('Loading').' '.get_lang('Preview').'</p>'.
-                    '</div>'.
-                '");
-            },
-            type: "POST",
-            url: "'.api_get_path(WEB_AJAX_PATH).'social.ajax.php?a=read_url_with_open_graph",
-            data: "social_wall_new_msg_main=" + e.originalEvent.clipboardData.getData("text"),
-            success: function(response) {
-                $("[name=\'wall_post_button\']").prop( "disabled", false );
-                if (!response == false) {
-                    $(".spinner").html("");
-                    $(".panel-preview").show();
-                    $(".url_preview").html(response);
-                    $("[name=\'url_content\']").val(response);
-                    $(".url_preview img").addClass("img-responsive");
-                } else {
-                    $(".spinner").html("");
-                }
-            }
-        });
-    });
-});
-</script>';
+$htmlHeadXtra[] = SocialManager::getScriptToGetOpenGraph();
 
 $socialRightInformation = '';
 $social_right_content = '';
@@ -381,9 +345,9 @@ SocialManager::setSocialUserBlock(
 );
 
 $tpl->assign('social_friend_block', $friend_html);
-$tpl->assign('social_menu_block', $social_menu_block);
-$tpl->assign('social_wall_block', $wallSocialAddPost);
-$tpl->assign('social_post_wall_block', $posts);
+$tpl->assign('social_menu_block', $menu);
+$tpl->assign('add_post_form', $addPostForm);
+$tpl->assign('posts', $posts);
 $tpl->assign('social_course_block', $social_course_block);
 $tpl->assign('social_group_info_block', $social_group_info_block);
 $tpl->assign('social_rss_block', $social_rss_block);
@@ -394,7 +358,7 @@ $tpl->assign('social_right_information', $socialRightInformation);
 $tpl->assign('social_auto_extend_link', $socialAutoExtendLink);
 
 $formModalTpl = new Template();
-$formModalTpl->assign('invitation_form', MessageManager::generate_invitation_form('send_invitation'));
+$formModalTpl->assign('invitation_form', MessageManager::generate_invitation_form());
 $template = $formModalTpl->get_template('social/form_modals.tpl');
 $formModals = $formModalTpl->fetch($template);
 

+ 1 - 1
main/social/search.php

@@ -247,7 +247,7 @@ $tpl->assign('social_search', $block_search);
 $tpl->assign('search_form', $searchForm);
 
 $formModalTpl = new Template();
-$formModalTpl->assign('invitation_form', MessageManager::generate_invitation_form('send_invitation'));
+$formModalTpl->assign('invitation_form', MessageManager::generate_invitation_form());
 $template = $formModalTpl->get_template('social/form_modals.tpl');
 $formModals = $formModalTpl->fetch($template);
 

+ 14 - 2
main/survey/fillsurvey.php

@@ -99,8 +99,20 @@ if ($invitationcode == 'auto' && isset($_GET['scode'])) {
     if ($isAnonymous) {
         $autoInvitationcode = 'auto-ANONY_'.md5(time())."-$surveyCode";
     } else {
-        // New invitation code from userid
-        $autoInvitationcode = "auto-$userid-$surveyCode";
+        $invitations = SurveyManager::getUserInvitationsForSurveyInCourse(
+            $userid,
+            $surveyCode,
+            $courseInfo['real_id'],
+            $sessionId
+        );
+        $lastInvitation = current($invitations);
+
+        if (!$lastInvitation) {
+            // New invitation code from userid
+            $autoInvitationcode = "auto-$userid-$surveyCode";
+        } else {
+            $autoInvitationcode = $lastInvitation->getInvitationCode();
+        }
     }
 
     // The survey code must exist in this course, or the URL is invalid

+ 163 - 4
main/survey/survey.lib.php

@@ -430,11 +430,11 @@ class SurveyManager
             }
 
             $extraParams = [];
-            $extraParams['one_question_per_page'] = isset($values['one_question_per_page']) ? $values['one_question_per_page'] : null;
-            $extraParams['shuffle'] = isset($values['shuffle']) ? $values['shuffle'] : null;
+            $extraParams['one_question_per_page'] = isset($values['one_question_per_page']) ? $values['one_question_per_page'] : 0;
+            $extraParams['shuffle'] = isset($values['shuffle']) ? $values['shuffle'] : 0;
 
             if ($values['anonymous'] == 0) {
-                $extraParams['show_form_profile'] = isset($values['show_form_profile']) ? $values['show_form_profile'] : '';
+                $extraParams['show_form_profile'] = isset($values['show_form_profile']) ? $values['show_form_profile'] : 0;
                 if ($extraParams['show_form_profile'] == 1) {
                     $fields = explode(',', $values['input_name_list']);
                     $field_values = '';
@@ -1806,7 +1806,10 @@ class SurveyManager
                 $tblSurvey = Database::get_course_table(TABLE_SURVEY);
 
                 $sql = "SELECT i.user FROM $tblInvitation i
-                    INNER JOIN $tblSurvey s ON i.survey_code = s.code
+                    INNER JOIN $tblSurvey s 
+                    ON i.survey_code = s.code
+                        AND i.c_id = s.c_id
+                        AND i.session_id = s.session_id
                     WHERE i.answered IS TRUE AND s.iid = $survey_id";
             }
         }
@@ -2353,4 +2356,160 @@ class SurveyManager
             );
         }
     }
+
+    /**
+     * @param int    $userId
+     * @param string $surveyCode
+     * @param int    $courseId
+     * @param int    $sessionId
+     * @param int    $groupId
+     *
+     * @return array|CSurveyInvitation[]
+     */
+    public static function getUserInvitationsForSurveyInCourse(
+        $userId,
+        $surveyCode,
+        $courseId,
+        $sessionId = 0,
+        $groupId = 0
+    ) {
+        $invitationRepo = Database::getManager()->getRepository('ChamiloCourseBundle:CSurveyInvitation');
+        $invitations = $invitationRepo->findBy(
+            [
+                'user' => $userId,
+                'cId' => $courseId,
+                'sessionId' => $sessionId,
+                'groupId' => $groupId,
+                'surveyCode' => $surveyCode,
+            ],
+            ['invitationDate' => 'DESC']
+        );
+
+        return $invitations;
+    }
+
+    /**
+     * @param array $userInfo
+     * @param int   $answered (1 = answered 0 = not answered)
+     *
+     * @return string
+     */
+    public static function surveyReport($userInfo, $answered = 0)
+    {
+        $userId = isset($userInfo['user_id']) ? (int) $userInfo['user_id'] : 0;
+        $answered = (int) $answered;
+
+        if (empty($userId)) {
+            return '';
+        }
+
+        $em = Database::getManager();
+        $repo = $em->getRepository('ChamiloCourseBundle:CSurveyInvitation');
+        $repoSurvey = $em->getRepository('ChamiloCourseBundle:CSurvey');
+        $invitations = $repo->findBy(['user' => $userId, 'answered' => $answered]);
+        $mainUrl = api_get_path(WEB_CODE_PATH).'survey/survey.php?';
+        $content = '';
+
+        if (empty($answered)) {
+            $content .= Display::page_subheader(get_lang('Unanswered'));
+        } else {
+            $content .= Display::page_subheader(get_lang('Answered'));
+        }
+
+        if (!empty($invitations)) {
+            $table = new HTML_Table(['class' => 'table']);
+            $table->setHeaderContents(0, 0, get_lang('SurveyName'));
+            $table->setHeaderContents(0, 1, get_lang('Course'));
+
+            if (empty($answered)) {
+                $table->setHeaderContents(0, 2, get_lang('Survey').' - '.get_lang('EndDate'));
+            }
+
+            // Not answered
+            /** @var CSurveyInvitation $invitation */
+            $row = 1;
+            foreach ($invitations as $invitation) {
+                $courseId = $invitation->getCId();
+                $courseInfo = api_get_course_info_by_id($courseId);
+
+                $courseCode = $courseInfo['code'];
+                if (empty($courseInfo)) {
+                    continue;
+                }
+                $sessionId = $invitation->getSessionId();
+
+                if (!empty($answered)) {
+                    // check if user is subscribed to the course/session
+                    if (empty($sessionId)) {
+                        $subscribe = CourseManager::is_user_subscribed_in_course($userId, $courseCode);
+                    } else {
+                        $subscribe = CourseManager::is_user_subscribed_in_course($userId, $courseCode, true, $sessionId);
+                    }
+
+                    // User is not subscribe skip!
+                    if (empty($subscribe)) {
+                        continue;
+                    }
+                }
+
+                $surveyCode = $invitation->getSurveyCode();
+
+                $survey = $repoSurvey->findOneBy([
+                    'cId' => $courseId,
+                    'sessionId' => $sessionId,
+                    'code' => $surveyCode,
+                ]);
+
+                if (empty($survey)) {
+                    continue;
+                }
+
+                $url = $mainUrl.'survey_id='.$survey->getSurveyId().'&cidReq='.$courseCode.'&id_session='.$sessionId;
+                $title = $survey->getTitle();
+                $title = Display::url($title, $url);
+
+                if (!empty($sessionId)) {
+                    $sessionInfo = api_get_session_info($sessionId);
+                    $courseInfo['name'] .= ' ('.$sessionInfo['name'].')';
+                }
+
+                $surveyData = self::get_survey($survey->getSurveyId(), 0, $courseCode);
+                $table->setCellContents($row, 0, $title);
+                $table->setCellContents($row, 1, $courseInfo['name']);
+
+                if (empty($answered)) {
+                    $table->setHeaderContents(
+                        $row,
+                        2,
+                        api_get_local_time(
+                            $survey->getAvailTill(),
+                            null,
+                            null,
+                            true,
+                            false
+                        )
+                    );
+                }
+
+                if (!empty($answered) && $surveyData['anonymous'] == 0) {
+                    $answers = SurveyUtil::displayCompleteReport(
+                        $surveyData,
+                        $userId,
+                        false,
+                        false,
+                        false
+                    );
+                    $table->setCellContents(++$row, 0, $answers);
+                    $table->setCellContents(++$row, 1, '');
+                }
+
+                $row++;
+            }
+            $content .= $table->toHtml();
+        } else {
+            $content .= Display::return_message(get_lang('NoData'));
+        }
+
+        return $content;
+    }
 }

+ 331 - 198
main/survey/surveyUtil.class.php

@@ -250,13 +250,13 @@ class SurveyUtil
                 self::display_question_report($survey_data);
                 break;
             case 'userreport':
-                self::display_user_report($people_filled, $survey_data);
+                self::displayUserReport($survey_data, $people_filled);
                 break;
             case 'comparativereport':
                 self::display_comparative_report();
                 break;
             case 'completereport':
-                self::display_complete_report($survey_data);
+                echo self::displayCompleteReport($survey_data);
                 break;
             case 'deleteuserreport':
                 self::delete_user_report($_GET['survey_id'], $_GET['user']);
@@ -313,58 +313,18 @@ class SurveyUtil
     }
 
     /**
-     * This function displays the user report which is basically nothing more
-     * than a one-page display of all the questions
-     * of the survey that is filled with the answers of the person who filled the survey.
-     *
-     * @return string html code of the one-page survey with the answers of the selected user
-     *
-     * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
+     * @param array $survey_data
+     * @param array $people_filled
      *
-     * @version February 2007 - Updated March 2008
+     * @return string
      */
-    public static function display_user_report($people_filled, $survey_data)
+    public static function displayUserReportForm($survey_data, $people_filled)
     {
-        // Database table definitions
-        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
-        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
-        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
-        $surveyId = isset($_GET['survey_id']) ? (int) $_GET['survey_id'] : 0;
+        $surveyId = $survey_data['survey_id'];
 
-        // Actions bar
-        echo '<div class="actions">';
-        echo '<a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq().'">'.
-            Display::return_icon('back.png', get_lang('BackTo').' '.get_lang('ReportingOverview'), '', ICON_SIZE_MEDIUM)
-            .'</a>';
-        if (isset($_GET['user'])) {
-            if (api_is_allowed_to_edit()) {
-                // The delete link
-                echo '<a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action=deleteuserreport&survey_id='
-                    .$surveyId.'&'.api_get_cidreq().'&user='.Security::remove_XSS($_GET['user']).'" >'.
-                    Display::return_icon('delete.png', get_lang('Delete'), '', ICON_SIZE_MEDIUM).'</a>';
-            }
-
-            // Export the user report
-            echo '<a href="javascript: void(0);" onclick="document.form1a.submit();">'
-                .Display::return_icon('export_csv.png', get_lang('ExportAsCSV'), '', ICON_SIZE_MEDIUM).'</a> ';
-            echo '<a href="javascript: void(0);" onclick="document.form1b.submit();">'
-                .Display::return_icon('export_excel.png', get_lang('ExportAsXLS'), '', ICON_SIZE_MEDIUM).'</a> ';
-            echo '<form id="form1a" name="form1a" method="post" action="'.api_get_self().'?action='
-                .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'&user_id='
-                .Security::remove_XSS($_GET['user']).'">';
-            echo '<input type="hidden" name="export_report" value="export_report">';
-            echo '<input type="hidden" name="export_format" value="csv">';
-            echo '</form>';
-            echo '<form id="form1b" name="form1b" method="post" action="'.api_get_self().'?action='
-                .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'&user_id='
-                .Security::remove_XSS($_GET['user']).'">';
-            echo '<input type="hidden" name="export_report" value="export_report">';
-            echo '<input type="hidden" name="export_format" value="xls">';
-            echo '</form>';
-            echo '<form id="form2" name="form2" method="post" action="'.api_get_self().'?action='
-                .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'">';
+        if (empty($survey_data)) {
+            return '';
         }
-        echo '</div>';
 
         // Step 1: selection of the user
         echo "<script>
@@ -374,7 +334,6 @@ class SurveyUtil
         }
 		</script>";
         echo get_lang('SelectUserWhoFilledSurvey').'<br />';
-
         echo '<select name="user" onchange="jumpMenu(\'parent\',this,0)">';
         echo '<option value="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='
             .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'">'
@@ -401,15 +360,33 @@ class SurveyUtil
             echo '>'.$name.'</option>';
         }
         echo '</select>';
+    }
 
-        $course_id = api_get_course_int_id();
+    /**
+     * @param int   $userId
+     * @param array $survey_data
+     * @param bool  $addMessage
+     */
+    public static function displayUserReportAnswers($userId, $survey_data, $addMessage = true)
+    {
+        // Database table definitions
+        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
+        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
+        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
+        $course_id = (int) $survey_data['c_id'];
+        $surveyId = (int) $survey_data['survey_id'];
+        $userId = Database::escape_string($userId);
+
+        $content = '';
         // Step 2: displaying the survey and the answer of the selected users
-        if (isset($_GET['user'])) {
-            echo Display::return_message(
-                get_lang('AllQuestionsOnOnePage'),
-                'normal',
-                false
-            );
+        if (!empty($userId)) {
+            if ($addMessage) {
+                $content .= Display::return_message(
+                    get_lang('AllQuestionsOnOnePage'),
+                    'normal',
+                    false
+                );
+            }
 
             // Getting all the questions and options
             $sql = "SELECT
@@ -451,7 +428,7 @@ class SurveyUtil
 			        WHERE
                         c_id = $course_id AND
                         survey_id = '".$surveyId."' AND
-                        user = '".Database::escape_string($_GET['user'])."'";
+                        user = '".$userId."'";
             $result = Database::query($sql);
             while ($row = Database::fetch_array($result, 'ASSOC')) {
                 $answers[$row['question_id']][] = $row['option_id'];
@@ -459,7 +436,6 @@ class SurveyUtil
             }
 
             // Displaying all the questions
-
             foreach ($questions as &$question) {
                 // If the question type is a scoring then we have to format the answers differently
                 switch ($question['type']) {
@@ -495,10 +471,79 @@ class SurveyUtil
                     $form->addHtml($question['survey_question']);
                     $display->render($form, $question, $finalAnswer);
                     $form->addHtml('</div></div>');
-                    $form->display();
+                    $content .= $form->returnForm();
                 }
             }
         }
+
+        return $content;
+    }
+
+    /**
+     * This function displays the user report which is basically nothing more
+     * than a one-page display of all the questions
+     * of the survey that is filled with the answers of the person who filled the survey.
+     *
+     * @return string html code of the one-page survey with the answers of the selected user
+     *
+     * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
+     *
+     * @version February 2007 - Updated March 2008
+     */
+    public static function displayUserReport($survey_data, $people_filled, $addActionBar = true)
+    {
+        if (empty($survey_data)) {
+            return '';
+        }
+
+        $surveyId = $survey_data['survey_id'];
+        $reportingUrl = api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq();
+
+        // Actions bar
+        if ($addActionBar) {
+            echo '<div class="actions">';
+            echo '<a href="'.$reportingUrl.'">'.
+                Display::return_icon(
+                    'back.png',
+                    get_lang('BackTo').' '.get_lang('ReportingOverview'),
+                    '',
+                    ICON_SIZE_MEDIUM
+                )
+                .'</a>';
+            if (isset($_GET['user'])) {
+                if (api_is_allowed_to_edit()) {
+                    // The delete link
+                    echo '<a href="'.$reportingUrl.'&action=deleteuserreport&user='.Security::remove_XSS($_GET['user']).'" >'.
+                        Display::return_icon('delete.png', get_lang('Delete'), '', ICON_SIZE_MEDIUM).'</a>';
+                }
+
+                // Export the user report
+                echo '<a href="javascript: void(0);" onclick="document.form1a.submit();">'
+                    .Display::return_icon('export_csv.png', get_lang('ExportAsCSV'), '', ICON_SIZE_MEDIUM).'</a> ';
+                echo '<a href="javascript: void(0);" onclick="document.form1b.submit();">'
+                    .Display::return_icon('export_excel.png', get_lang('ExportAsXLS'), '', ICON_SIZE_MEDIUM).'</a> ';
+                echo '<form id="form1a" name="form1a" method="post" action="'.api_get_self().'?action='
+                    .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'&user_id='
+                    .Security::remove_XSS($_GET['user']).'">';
+                echo '<input type="hidden" name="export_report" value="export_report">';
+                echo '<input type="hidden" name="export_format" value="csv">';
+                echo '</form>';
+                echo '<form id="form1b" name="form1b" method="post" action="'.api_get_self().'?action='
+                    .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'&user_id='
+                    .Security::remove_XSS($_GET['user']).'">';
+                echo '<input type="hidden" name="export_report" value="export_report">';
+                echo '<input type="hidden" name="export_format" value="xls">';
+                echo '</form>';
+                echo '<form id="form2" name="form2" method="post" action="'.api_get_self().'?action='
+                    .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'">';
+            }
+            echo '</div>';
+        }
+
+        echo self::displayUserReportForm($survey_data, $people_filled);
+        if (isset($_GET['user'])) {
+            echo self::displayUserReportAnswers($_GET['user'], $survey_data);
+        }
     }
 
     /**
@@ -864,92 +909,119 @@ class SurveyUtil
     /**
      * This functions displays the complete reporting.
      *
-     * @return string HTML code
-     *
-     * @todo open questions are not in the complete report yet.
-     *
-     * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
+     * @param array $survey_data
+     * @param int   $userId
+     * @param bool  $addActionBar
+     * @param bool  $addFilters
+     * @param bool  $addExtraFields
      *
-     * @version February 2007
+     * @return string
      */
-    public static function display_complete_report($survey_data)
-    {
+    public static function displayCompleteReport(
+        $survey_data,
+        $userId = 0,
+        $addActionBar = true,
+        $addFilters = true,
+        $addExtraFields = true
+    ) {
         // Database table definitions
         $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
         $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
         $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
-        $course_id = api_get_course_int_id();
-        $surveyId = isset($_GET['survey_id']) ? (int) $_GET['survey_id'] : 0;
-        $action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : '';
 
-        // Actions bar
-        echo '<div class="actions">';
-        echo '<a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq().'">'
-            .Display::return_icon(
-                'back.png',
-                get_lang('BackTo').' '.get_lang('ReportingOverview'),
-                [],
-                ICON_SIZE_MEDIUM
-            )
-            .'</a>';
-        echo '<a class="survey_export_link" href="javascript: void(0);" onclick="document.form1a.submit();">'
-            .Display::return_icon('export_csv.png', get_lang('ExportAsCSV'), '', ICON_SIZE_MEDIUM).'</a>';
-        echo '<a class="survey_export_link" href="javascript: void(0);" onclick="document.form1b.submit();">'
-            .Display::return_icon('export_excel.png', get_lang('ExportAsXLS'), '', ICON_SIZE_MEDIUM).'</a>';
-        echo '</div>';
+        $surveyId = (int) $survey_data['survey_id'];
+        $course_id = (int) $survey_data['c_id'];
 
-        // The form
-        echo '<form id="form1a" name="form1a" method="post" action="'.api_get_self().'?action='.$action.'&survey_id='
-            .$surveyId.'&'.api_get_cidreq().'">';
-        echo '<input type="hidden" name="export_report" value="export_report">';
-        echo '<input type="hidden" name="export_format" value="csv">';
-        echo '</form>';
-        echo '<form id="form1b" name="form1b" method="post" action="'.api_get_self().'?action='.$action.'&survey_id='
-            .$surveyId.'&'.api_get_cidreq().'">';
-        echo '<input type="hidden" name="export_report" value="export_report">';
-        echo '<input type="hidden" name="export_format" value="xls">';
-        echo '</form>';
+        if (empty($surveyId) || empty($course_id)) {
+            return '';
+        }
 
-        echo '<form id="form2" name="form2" method="post" action="'.api_get_self().'?action='.$action.'&survey_id='
+        $action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : '';
+        $content = '';
+        if ($addActionBar) {
+            $content .= '<div class="actions">';
+            $content .= '<a 
+                href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq().'">'
+                .Display::return_icon(
+                    'back.png',
+                    get_lang('BackTo').' '.get_lang('ReportingOverview'),
+                    [],
+                    ICON_SIZE_MEDIUM
+                )
+                .'</a>';
+            $content .= '<a class="survey_export_link" href="javascript: void(0);" onclick="document.form1a.submit();">'
+                .Display::return_icon('export_csv.png', get_lang('ExportAsCSV'), '', ICON_SIZE_MEDIUM).'</a>';
+            $content .= '<a class="survey_export_link" href="javascript: void(0);" onclick="document.form1b.submit();">'
+                .Display::return_icon('export_excel.png', get_lang('ExportAsXLS'), '', ICON_SIZE_MEDIUM).'</a>';
+            $content .= '</div>';
+
+            // The form
+            $content .= '<form id="form1a" name="form1a" method="post" action="'.api_get_self(
+                ).'?action='.$action.'&survey_id='
+                .$surveyId.'&'.api_get_cidreq().'">';
+            $content .= '<input type="hidden" name="export_report" value="export_report">';
+            $content .= '<input type="hidden" name="export_format" value="csv">';
+            $content .= '</form>';
+            $content .= '<form id="form1b" name="form1b" method="post" action="'.api_get_self(
+                ).'?action='.$action.'&survey_id='
+                .$surveyId.'&'.api_get_cidreq().'">';
+            $content .= '<input type="hidden" name="export_report" value="export_report">';
+            $content .= '<input type="hidden" name="export_format" value="xls">';
+            $content .= '</form>';
+        }
+
+        $content .= '<form id="form2" name="form2" method="post" action="'.api_get_self().'?action='.$action.'&survey_id='
             .$surveyId.'&'.api_get_cidreq().'">';
 
         // The table
-        echo '<br /><table class="data_table" border="1">';
+        $content .= '<br /><table class="data_table" border="1">';
         // Getting the number of options per question
-        echo '	<tr>';
-        echo '		<th>';
-        if ((isset($_POST['submit_question_filter']) && $_POST['submit_question_filter']) ||
-            (isset($_POST['export_report']) && $_POST['export_report'])
-        ) {
-            echo '<button class="cancel" type="submit" name="reset_question_filter" value="'
-                .get_lang('ResetQuestionFilter').'">'.get_lang('ResetQuestionFilter').'</button>';
+        $content .= '	<tr>';
+        $content .= '		<th>';
+
+        if ($addFilters) {
+            if ((isset($_POST['submit_question_filter']) && $_POST['submit_question_filter']) ||
+                (isset($_POST['export_report']) && $_POST['export_report'])
+            ) {
+                $content .= '<button class="cancel" 
+                                type="submit" 
+                                name="reset_question_filter" value="'.get_lang('ResetQuestionFilter').'">'.
+                                get_lang('ResetQuestionFilter').'</button>';
+            }
+            $content .= '<button 
+                            class = "save" 
+                            type="submit" name="submit_question_filter" value="'.get_lang('SubmitQuestionFilter').'">'.
+                            get_lang('SubmitQuestionFilter').'</button>';
+            $content .= '</th>';
         }
-        echo '<button class="save" type="submit" name="submit_question_filter" value="'.get_lang('SubmitQuestionFilter')
-            .'">'.get_lang('SubmitQuestionFilter').'</button>';
-        echo '</th>';
 
         $display_extra_user_fields = false;
-        if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter'] ||
-            isset($_POST['export_report']) && $_POST['export_report']) ||
-            !empty($_POST['fields_filter'])
-        ) {
-            // Show user fields section with a big th colspan that spans over all fields
-            $extra_user_fields = UserManager::get_extra_fields(
-                0,
-                0,
-                5,
-                'ASC',
-                false,
-                true
-            );
-            $num = count($extra_user_fields);
-            if ($num > 0) {
-                echo '<th '.($num > 0 ? ' colspan="'.$num.'"' : '').'>';
-                echo '<label><input type="checkbox" name="fields_filter" value="1" checked="checked"/> ';
-                echo get_lang('UserFields');
-                echo '</label>';
-                echo '</th>';
-                $display_extra_user_fields = true;
+        if ($addExtraFields) {
+            if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter'] ||
+                    isset($_POST['export_report']) && $_POST['export_report']) ||
+                !empty($_POST['fields_filter'])
+            ) {
+                // Show user fields section with a big th colspan that spans over all fields
+                $extra_user_fields = UserManager::get_extra_fields(
+                    0,
+                    0,
+                    5,
+                    'ASC',
+                    false,
+                    true
+                );
+                $num = count($extra_user_fields);
+                if ($num > 0) {
+                    $content .= '<th '.($num > 0 ? ' colspan="'.$num.'"' : '').'>';
+                    $content .= '<label>';
+                    if ($addFilters) {
+                        $content .= '<input type="checkbox" name="fields_filter" value="1" checked="checked"/> ';
+                    }
+                    $content .= get_lang('UserFields');
+                    $content .= '</label>';
+                    $content .= '</th>';
+                    $display_extra_user_fields = true;
+                }
             }
         }
 
@@ -974,36 +1046,44 @@ class SurveyUtil
             // 1. there is no question filter and the export button has not been clicked
             // 2. there is a quesiton filter but the question is selected for display
             if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter']) ||
-                (is_array($_POST['questions_filter']) && in_array($row['question_id'], $_POST['questions_filter']))
+                (is_array($_POST['questions_filter']) &&
+                in_array($row['question_id'], $_POST['questions_filter']))
             ) {
                 // We do not show comment and pagebreak question types
                 if ($row['type'] != 'pagebreak') {
-                    echo ' <th';
+                    $content .= ' <th';
                     if ($row['number_of_options'] > 0 && $row['type'] != 'percentage') {
-                        echo ' colspan="'.$row['number_of_options'].'"';
+                        $content .= ' colspan="'.$row['number_of_options'].'"';
                     }
-                    echo '>';
-                    echo '<label><input type="checkbox" name="questions_filter[]" value="'.$row['question_id']
-                        .'" checked="checked"/> ';
-                    echo $row['survey_question'];
-                    echo '</label>';
-                    echo '</th>';
+                    $content .= '>';
+                    $content .= '<label>';
+                    if ($addFilters) {
+                        $content .= '<input 
+                                type="checkbox" 
+                                name="questions_filter[]" value="'.$row['question_id'].'" checked="checked"/>';
+                    }
+                    $content .= $row['survey_question'];
+                    $content .= '</label>';
+                    $content .= '</th>';
                 }
                 // No column at all if it's not a question
             }
             $questions[$row['question_id']] = $row;
         }
-        echo '	</tr>';
+        $content .= '	</tr>';
+
         // Getting all the questions and options
-        echo '	<tr>';
-        echo '		<th>&nbsp;</th>'; // the user column
+        $content .= '	<tr>';
+        $content .= '		<th>&nbsp;</th>'; // the user column
 
         if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter'] ||
             isset($_POST['export_report']) && $_POST['export_report']) || !empty($_POST['fields_filter'])
         ) {
-            //show the fields names for user fields
-            foreach ($extra_user_fields as &$field) {
-                echo '<th>'.$field[3].'</th>';
+            if ($addExtraFields) {
+                // show the fields names for user fields
+                foreach ($extra_user_fields as &$field) {
+                    $content .= '<th>'.$field[3].'</th>';
+                }
             }
         }
 
@@ -1040,26 +1120,32 @@ class SurveyUtil
             ) {
                 // we do not show comment and pagebreak question types
                 if ($row['type'] == 'open' || $row['type'] == 'comment') {
-                    echo '<th>&nbsp;-&nbsp;</th>';
+                    $content .= '<th>&nbsp;-&nbsp;</th>';
                     $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
                     $display_percentage_header = 1;
                 } elseif ($row['type'] == 'percentage' && $display_percentage_header) {
-                    echo '<th>&nbsp;%&nbsp;</th>';
+                    $content .= '<th>&nbsp;%&nbsp;</th>';
                     $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
                     $display_percentage_header = 0;
                 } elseif ($row['type'] == 'percentage') {
                     $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
                 } elseif ($row['type'] != 'pagebreak' && $row['type'] != 'percentage') {
-                    echo '<th>';
-                    echo $row['option_text'];
-                    echo '</th>';
+                    $content .= '<th>';
+                    $content .= $row['option_text'];
+                    $content .= '</th>';
                     $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
                     $display_percentage_header = 1;
                 }
             }
         }
 
-        echo '	</tr>';
+        $content .= '	</tr>';
+
+        $userCondition = '';
+        if (!empty($userId)) {
+            $userId = (int) $userId;
+            $userCondition = " AND user = $userId ";
+        }
 
         // Getting all the answers of the users
         $old_user = '';
@@ -1067,7 +1153,8 @@ class SurveyUtil
         $sql = "SELECT * FROM $table_survey_answer
                 WHERE
                     c_id = $course_id AND
-                    survey_id='".$surveyId."'
+                    survey_id = $surveyId 
+                    $userCondition
                 ORDER BY answer_id, user ASC";
         $result = Database::query($sql);
         $i = 1;
@@ -1078,7 +1165,7 @@ class SurveyUtil
                     $userParam = $i;
                     $i++;
                 }
-                self::display_complete_report_row(
+                $content .= self::display_complete_report_row(
                     $survey_data,
                     $possible_answers,
                     $answers_of_user,
@@ -1098,12 +1185,14 @@ class SurveyUtil
             }
             $old_user = $row['user'];
         }
+
         $userParam = $old_user;
         if ($survey_data['anonymous'] != 0) {
             $userParam = $i;
             $i++;
         }
-        self::display_complete_report_row(
+
+        $content .= self::display_complete_report_row(
             $survey_data,
             $possible_answers,
             $answers_of_user,
@@ -1111,23 +1200,25 @@ class SurveyUtil
             $questions,
             $display_extra_user_fields
         );
+
         // This is to display the last user
-        echo '</table>';
-        echo '</form>';
+        $content .= '</table>';
+        $content .= '</form>';
+
+        return $content;
     }
 
     /**
-     * This function displays a row (= a user and his/her answers) in the table of the complete report.
-     *
-     * @param array $survey_data
-     * @param array    Possible options
-     * @param array    User answers
-     * @param mixed    User ID or user details string
-     * @param bool  Whether to show extra user fields or not
+     * Return user answers in a row.
      *
-     * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
+     * @param      $survey_data
+     * @param      $possible_options
+     * @param      $answers_of_user
+     * @param      $user
+     * @param      $questions
+     * @param bool $display_extra_user_fields
      *
-     * @version February 2007 - Updated March 2008
+     * @return string
      */
     public static function display_complete_report_row(
         $survey_data,
@@ -1138,24 +1229,31 @@ class SurveyUtil
         $display_extra_user_fields = false
     ) {
         $user = Security::remove_XSS($user);
-        echo '<tr>';
+        $surveyId = (int) $survey_data['survey_id'];
+
+        if (empty($surveyId)) {
+            return '';
+        }
+
+        $content = '<tr>';
+        $url = api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq();
         if ($survey_data['anonymous'] == 0) {
             if (intval($user) !== 0) {
                 $userInfo = api_get_user_info($user);
+                $user_displayed = '-';
                 if (!empty($userInfo)) {
                     $user_displayed = $userInfo['complete_name_with_username'];
-                } else {
-                    $user_displayed = '-';
                 }
-                echo '<th>
-                    <a href="'.api_get_self().'?action=userreport&survey_id='.intval($_GET['survey_id']).'&user='.$user.'">'
+
+                $content .= '<th>
+                    <a href="'.$url.'&action=userreport&user='.$user.'">'
                     .$user_displayed.'</a>
                     </th>'; // the user column
             } else {
-                echo '<th>'.$user.'</th>'; // the user column
+                $content .= '<th>'.$user.'</th>'; // the user column
             }
         } else {
-            echo '<th>'.get_lang('Anonymous').' '.$user.'</th>';
+            $content .= '<th>'.get_lang('Anonymous').' '.$user.'</th>';
         }
 
         if ($display_extra_user_fields) {
@@ -1168,33 +1266,33 @@ class SurveyUtil
                 true
             );
             foreach ($user_fields_values as &$value) {
-                echo '<td align="center">'.$value.'</td>';
+                $content .= '<td align="center">'.$value.'</td>';
             }
         }
 
         if (is_array($possible_options)) {
             foreach ($possible_options as $question_id => &$possible_option) {
                 if ($questions[$question_id]['type'] == 'open' || $questions[$question_id]['type'] == 'comment') {
-                    echo '<td align="center">';
+                    $content .= '<td align="center">';
                     if (isset($answers_of_user[$question_id]) && isset($answers_of_user[$question_id]['0'])) {
-                        echo $answers_of_user[$question_id]['0']['option_id'];
+                        $content .= $answers_of_user[$question_id]['0']['option_id'];
                     }
-                    echo '</td>';
+                    $content .= '</td>';
                 } else {
                     foreach ($possible_option as $option_id => &$value) {
                         if ($questions[$question_id]['type'] == 'percentage') {
                             if (!empty($answers_of_user[$question_id][$option_id])) {
-                                echo "<td align='center'>";
-                                echo $answers_of_user[$question_id][$option_id]['value'];
-                                echo "</td>";
+                                $content .= "<td align='center'>";
+                                $content .= $answers_of_user[$question_id][$option_id]['value'];
+                                $content .= "</td>";
                             }
                         } else {
-                            echo '<td align="center">';
+                            $content .= '<td align="center">';
                             if (!empty($answers_of_user[$question_id][$option_id])) {
                                 if ($answers_of_user[$question_id][$option_id]['value'] != 0) {
-                                    echo $answers_of_user[$question_id][$option_id]['value'];
+                                    $content .= $answers_of_user[$question_id][$option_id]['value'];
                                 } else {
-                                    echo 'v';
+                                    $content .= 'v';
                                 }
                             }
                         }
@@ -1202,7 +1300,10 @@ class SurveyUtil
                 }
             }
         }
-        echo '</tr>';
+
+        $content .= '</tr>';
+
+        return $content;
     }
 
     /**
@@ -1512,6 +1613,7 @@ class SurveyUtil
     public static function export_complete_report_xls($survey_data, $filename, $user_id = 0)
     {
         $course_id = api_get_course_int_id();
+        $user_id = (int) $user_id;
         $surveyId = isset($_GET['survey_id']) ? (int) $_GET['survey_id'] : 0;
 
         if (empty($course_id) || empty($surveyId)) {
@@ -1672,7 +1774,7 @@ class SurveyUtil
         $sql = "SELECT * FROM $table_survey_answer
                 WHERE c_id = $course_id AND survey_id = $surveyId";
         if ($user_id != 0) {
-            $sql .= " AND user='".intval($user_id)."' ";
+            $sql .= " AND user='".$user_id."' ";
         }
         $sql .= ' ORDER BY user ASC';
 
@@ -2195,8 +2297,8 @@ class SurveyUtil
      * @param int  $reminder
      * @param bool $sendmail
      * @param int  $remindUnAnswered
-     *
-     * @return bool $isAdditionalEmail
+     * @param bool $isAdditionalEmail
+     * @param bool $hideLink
      *
      * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
      * @author Julio Montoya - Adding auto-generated link support
@@ -2210,7 +2312,8 @@ class SurveyUtil
         $reminder = 0,
         $sendmail = false,
         $remindUnAnswered = 0,
-        $isAdditionalEmail = false
+        $isAdditionalEmail = false,
+        $hideLink = false
     ) {
         if (!is_array($users_array)) {
             // Should not happen
@@ -2225,7 +2328,8 @@ class SurveyUtil
 
         // Remind unanswered is a special version of remind all reminder
         $exclude_users = [];
-        if ($remindUnAnswered == 1) { // Remind only unanswered users
+        if ($remindUnAnswered == 1) {
+            // Remind only unanswered users
             $reminder = 1;
             $exclude_users = SurveyManager::get_people_who_filled_survey($_GET['survey_id']);
         }
@@ -2315,7 +2419,8 @@ class SurveyUtil
                     $value,
                     $invitation_code,
                     $invitation_title,
-                    $invitation_text
+                    $invitation_text,
+                    $hideLink
                 );
                 $counter++;
             }
@@ -2337,6 +2442,15 @@ class SurveyUtil
             (!empty($params['user']) || !empty($params['group_id'])) &&
             !empty($params['survey_code'])
         ) {
+            if (!isset($params['survey_invitation_id'])) {
+                $params['survey_invitation_id'] = 0;
+            }
+            if (!isset($params['answered'])) {
+                $params['answered'] = 0;
+            }
+            if (!isset($params['group_id'])) {
+                $params['group_id'] = 0;
+            }
             $insertId = Database::insert($table, $params);
             if ($insertId) {
                 $sql = "UPDATE $table
@@ -2389,7 +2503,8 @@ class SurveyUtil
         $invitedUser,
         $invitation_code,
         $invitation_title,
-        $invitation_text
+        $invitation_text,
+        $hideLink = false
     ) {
         $_user = api_get_user_info();
         $_course = api_get_course_info();
@@ -2397,14 +2512,17 @@ class SurveyUtil
 
         // Replacing the **link** part with a valid link for the user
         $link = self::generateFillSurveyLink($invitation_code, $_course, $sessionId);
+        if ($hideLink) {
+            $full_invitation_text = str_replace('**link**', '', $invitation_text);
+        } else {
+            $text_link = '<a href="'.$link.'">'.get_lang('ClickHereToAnswerTheSurvey')."</a><br />\r\n<br />\r\n"
+                .get_lang('OrCopyPasteTheFollowingUrl')." <br /> \r\n <br /> \r\n ".$link;
 
-        $text_link = '<a href="'.$link.'">'.get_lang('ClickHereToAnswerTheSurvey')."</a><br />\r\n<br />\r\n"
-            .get_lang('OrCopyPasteTheFollowingUrl')." <br /> \r\n <br /> \r\n ".$link;
-
-        $replace_count = 0;
-        $full_invitation_text = api_str_ireplace('**link**', $text_link, $invitation_text, $replace_count);
-        if ($replace_count < 1) {
-            $full_invitation_text = $full_invitation_text."<br />\r\n<br />\r\n".$text_link;
+            $replace_count = 0;
+            $full_invitation_text = api_str_ireplace('**link**', $text_link, $invitation_text, $replace_count);
+            if ($replace_count < 1) {
+                $full_invitation_text = $full_invitation_text."<br />\r\n<br />\r\n".$text_link;
+            }
         }
 
         // Sending the mail
@@ -3385,7 +3503,13 @@ class SurveyUtil
         $now = api_get_utc_datetime(null, false, true);
         $filterDate = $allowSurveyAvailabilityDatetime ? $now->format('Y-m-d H:i') : $now->format('Y-m-d');
 
-        $sql = "SELECT *
+        $sql = "SELECT survey_invitation.answered,
+                    survey_invitation.invitation_code,
+                    survey_invitation.session_id,
+                    survey.title,
+                    survey.visible_results,
+                    survey.survey_id,
+                    survey.anonymous
                 FROM $table_survey survey
                 INNER JOIN
                 $table_survey_invitation survey_invitation
@@ -3406,7 +3530,13 @@ class SurveyUtil
 
         $efv = new ExtraFieldValue('survey');
 
+        $surveyIds = [];
+
         while ($row = Database::fetch_array($result, 'ASSOC')) {
+            if (in_array($row['survey_id'], $surveyIds)) {
+                continue;
+            }
+
             echo '<tr>';
             if ($row['answered'] == 0) {
                 echo '<td>';
@@ -3457,6 +3587,8 @@ class SurveyUtil
                 echo '<td class="text-center">'.($efvMandatory['value'] ? get_lang('Yes') : get_lang('No')).'</td>';
             }
             echo '</tr>';
+
+            $surveyIds[] = $row['survey_id'];
         }
         echo '</tbody>';
         echo '</table>';
@@ -3881,6 +4013,7 @@ class SurveyUtil
                 ON (survey_invitation.user = user.id AND survey_invitation.c_id = $courseId)
                 WHERE
                     survey_invitation.survey_code = '$surveyCode'
+                    AND survey_invitation.c_id = $courseId
                     $sessionCondition";
 
         $query = Database::query($sql);

+ 11 - 7
main/survey/survey_invite.php

@@ -157,14 +157,10 @@ if ($survey_data['anonymous'] != 1 || api_get_configuration_value('survey_anonym
 }
 // Allow resending to all selected users
 $form->addElement('checkbox', 'resend_to_all', '', get_lang('ReminderResendToAllUsers'));
+$form->addElement('checkbox', 'hide_link', '', get_lang('HideSurveyInvitationLink'));
 
 // Submit button
 $form->addButtonSave(get_lang('PublishSurvey'));
-// The rules (required fields)
-/*if ($survey_data['send_mail'] == 0) {
-    $form->addRule('mail_title', get_lang('ThisFieldIsRequired'), 'required');
-    $form->addRule('mail_text', get_lang('ThisFieldIsRequired'), 'required');
-}*/
 $portal_url = api_get_path(WEB_PATH);
 if (api_is_multiple_url_enabled()) {
     $access_url_id = api_get_current_access_url_id();
@@ -175,7 +171,12 @@ if (api_is_multiple_url_enabled()) {
 }
 
 // Show the URL that can be used by users to fill a survey without invitation
-$auto_survey_link = SurveyUtil::generateFillSurveyLink('auto', $_course, $survey_data['session_id'], $survey_data['survey_code']);
+$auto_survey_link = SurveyUtil::generateFillSurveyLink(
+    'auto',
+    $_course,
+    $survey_data['session_id'],
+    $survey_data['survey_code']
+);
 
 $form->addElement('label', null, get_lang('AutoInviteLink'));
 $form->addElement('label', null, $auto_survey_link);
@@ -187,6 +188,7 @@ if ($form->validate()) {
     $sendMail = isset($values['send_mail']) ? $values['send_mail'] : '';
     $remindUnAnswered = isset($values['remindUnAnswered']) ? $values['remindUnAnswered'] : '';
     $users = isset($values['users']) ? $values['users'] : [];
+    $hideLink = isset($values['hide_link']) && $values['hide_link'] ? true : false;
 
     if ($sendMail) {
         if (empty($values['mail_title']) || empty($values['mail_text'])) {
@@ -223,7 +225,9 @@ if ($form->validate()) {
         $values['mail_text'],
         $resendAll,
         $sendMail,
-        $remindUnAnswered
+        $remindUnAnswered,
+        false,
+        $hideLink
     );
 
     // Saving the invitations for the additional users

+ 1 - 1
main/template/default/admin/teacher_time_report.tpl

@@ -1,5 +1,5 @@
 <script>
-$(document).on('ready', function () {
+$(function () {
     $('#course').on('change', function () {
         $('#session').prop('selectedIndex', 0);
         $('#teacher').prop('selectedIndex', 0);

+ 2 - 2
main/template/default/auth/session_catalog.tpl

@@ -119,11 +119,11 @@
                             	{% endif %}
                             	<div class="block-info">
                                     <ul class="info list-inline">
-                                        <li>
+                                        <li class="course_label_number_courses">
                                             <i class="fa fa-book" aria-hidden="true"></i>
                                             {{ item.nbr_courses ~ ' ' ~ 'Courses'|get_lang }}
                                         </li>
-                                        <li>
+                                        <li class="course_label_number_users">
                                             <i class="fa fa-user" aria-hidden="true"></i>
                                             {{ item.nbr_users ~ ' ' ~ 'NbUsers'|get_lang }}
                                         </li>

+ 1 - 1
main/template/default/blog/blog.tpl

@@ -101,7 +101,7 @@
     </div>
 </div>
 <script>
-    $(document).on('ready', function () {
+    $(function () {
         $('.btn-read-more').on('click', function (e) {
             e.preventDefault();
 

+ 1 - 1
main/template/default/blog/post.tpl

@@ -156,7 +156,7 @@
 </div>
 
 <script>
-    $(document).on('ready', function () {
+    $(function () {
         $('.btn-reply-to').on('click', function (e) {
             e.preventDefault();
 

+ 1 - 1
main/template/default/chat/chat.tpl

@@ -65,7 +65,7 @@
     <source src="{{ _p.web_main }}chat/sound/notification.mp3" type="audio/mpeg"></source>
 </audio>
 <script>
-$(document).on('ready', function () {
+$(function () {
     var ChChat = {
         _ajaxUrl: '{{ _p.web_ajax }}course_chat.ajax.php?{{ _p.web_cid_query }}',
         _historySize: -1,

+ 1 - 1
main/template/default/chat/video.tpl

@@ -152,7 +152,7 @@
         }
     };
 
-    $(document).on('ready', function () {
+    $(function () {
         VideoChat.init();
     });
 })();

+ 2 - 0
main/template/default/javascript/editor/ckeditor/config_js.tpl

@@ -117,6 +117,8 @@ CKEDITOR.editorConfig = function (config) {
     ];
 
     config.language_list = ['{{ language_list }}'];
+
+    config.qMarkersRollsUrl = '{{ _p.web_ajax }}exercise.ajax.php?a=get_quiz_embeddable';
 };
 
 // Sets default target to "_blank" in link plugin

+ 9 - 3
main/template/default/layout/hot_course_item.tpl

@@ -16,9 +16,15 @@
                 <div class="description">
                     <div class="block-title">
                         <h5 class="title">
-                            <a alt="{{ item.title }}" title="{{ item.title }}" href="{{ _p.web }}course/{{ item.real_id  }}/about">
-                                {{ item.title_cut}}
-                            </a>
+                            {% if item.is_course_student or item.is_course_teacher %}
+                                <a alt="{{ item.title }}" title="{{ item.title }}" href="{{ _p.web }}courses/{{ item.code  }}/">
+                                    {{ item.title_cut}}
+                                </a>
+                            {% else %}
+                                <a alt="{{ item.title }}" title="{{ item.title }}" href="{{ _p.web }}course/{{ item.real_id  }}/about">
+                                    {{ item.title_cut}}
+                                </a>
+                            {% endif %}
                         </h5>
                     </div>
                     <div class="ranking">

+ 3 - 1
main/template/default/layout/main.js.tpl

@@ -268,6 +268,7 @@ $(function() {
             //renderers: ['html5', 'flash_video', 'native_flv'],
             features: ['{{ video_features }}'],
             success: function(mediaElement, originalNode, instance) {
+                {{ quiz_markers_rolls_js }}
             },
             vrPath: _p.web + 'web/assets/vrview/build/vrview.js'
         });
@@ -325,7 +326,7 @@ $(function() {
     $('video:not(.skip)').attr('preload', 'metadata');
 
     function socialLikes() {
-        {% if 'social_enable_likes_messages'|api_get_configuration_value %}
+        {% if 'social_enable_messages_feedback'|api_get_configuration_value %}
         $('body').on('click', '.social-like', function (e) {
             e.preventDefault();
 
@@ -570,6 +571,7 @@ if (typeof CKEDITOR !== 'undefined') {
         'youtube',
         'flash',
         'inserthtml',
+        'qmarkersrolls',
         'image2_chamilo'
     ];
 

+ 1 - 1
main/template/default/layout/menu.tpl

@@ -4,7 +4,7 @@
         $(document).ready(function () {
             $.get('{{ _p.web_main }}inc/ajax/message.ajax.php?a=get_count_message', function(data) {
                 var countNotifications = (data.ms_friends + data.ms_groups + data.ms_inbox);
-                if (countNotifications === 0 ) {
+                if (countNotifications === 0 || isNaN(countNotifications)) {
                     $("#count_message_li").addClass('hidden');
                 } else {
                     $("#count_message_li").removeClass('hidden');

+ 3 - 6
main/template/default/learnpath/list.tpl

@@ -22,7 +22,7 @@
                 {% if categories|length > 1 and lp_data.category.id %}
                     {% if is_allowed_to_edit %}
                         <h3 class="page-header">
-                            {{ lp_data.category.getName() }}
+                            {{ lp_data.category.getName() | trim }}
 
                             {% if lp_data.category.getId() > 0 %}
                                 {% if not _c.session_id %}
@@ -393,12 +393,11 @@
                                 </a>
                             </h4>
                         </div>
-
-                        <div id="collapse-{{ lp_data.category.getId() }}" class="panel-collapse collapse {{ (categories|length > 1 ? 'in':'') }}"
+                        {% set number = number + 1 %}
+                        <div id="collapse-{{ lp_data.category.getId() }}" class="panel-collapse collapse {{ (number == 1 ? 'in':'') }}"
                              role="tabpanel" aria-labelledby="heading-{{ lp_data.category.getId() }}">
                             <div class="panel-body">
                                 {% if lp_data.lp_list %}
-
                                     {% if is_allowed_to_edit %}
                                         <div class="table-responsive">
                                             <table class="table table-hover table-striped">
@@ -449,7 +448,6 @@
                                                                 </td>
                                                             {% endif %}
                                                         {% endif %}
-
                                                         <td>
                                                             {{ row.action_build }}
                                                             {{ row.action_edit }}
@@ -500,7 +498,6 @@
                             </div>
                         </div>
                     </div>
-
                 {% endif %}
                 <!-- end view block accordeon -->
             {% endif %}

+ 9 - 12
main/template/default/learnpath/view.tpl

@@ -10,12 +10,12 @@
                                 {{ lp_preview_image }}
                             </div>
                         {% else %}
-                            <div class="media">
-                                <div class="media-left">
+                            <div class="media-author">
+                                <div class="media-author-avatar">
                                     {{ lp_preview_image }}
                                 </div>
-                                <div class="media-body">
-                                    <div class="description-autor"> {{ lp_author }} </div>
+                                <div class="media-author-description">
+                                    {{ lp_author }}
                                 </div>
                             </div>
                         {% endif %}
@@ -130,18 +130,15 @@
                             </div>
                             <div class="row">
                                 <div class="col-xs-12 navegation-bar">
-                                    <div id="progress_bar">
-                                        {{ progress_bar }}
-                                    </div>
+                                   {{ lp_progress }}
                                 </div>
                             </div>
                         </div>
-                       <!--- end gamification -->
+                        <!--- end gamification -->
                     {% else %}
-                        <div id="progress_bar">
-                            {{ progress_bar }}
-                        </div>
+                       {{ lp_progress }}
                     {% endif %}
+
                     {{ teacher_toc_buttons }}
                 </div>
             </div>
@@ -224,7 +221,7 @@
         }
     };
 
-    $(document).on('ready', function () {
+    $(function() {
         if (/iPhone|iPod|iPad/.test(navigator.userAgent)) {
             // Fix an issue where you cannot scroll below first screen in
             // learning paths on Apple devices

+ 99 - 0
main/template/default/macro/macro.tpl

@@ -116,3 +116,102 @@
         {% endif %}
     </div>
 {% endmacro %}
+
+{% macro box_widget(name, content, icon) %}
+    <div class="card box-widget">
+        <div class="card-body">
+            <div class="stat-widget-five">
+                <i class="fa fa-{{ icon }}" aria-hidden="true"></i>
+                {{ content }}
+                <div class="box-name">
+                    {{ name }}
+                </div>
+            </div>
+        </div>
+    </div>
+{% endmacro %}
+
+{% macro card_widget(name, content, icon, extra) %}
+    <div class="card card-first-date">
+        <div class="card-body">
+            <div class="stat-widget-five">
+                <div class="stat-icon">
+                    <i class="fa fa-{{ icon }}" aria-hidden="true"></i>
+                    {% if extra %}
+                        <span class="active-icon">{{ extra }}</span>
+                    {% endif %}
+                </div>
+                <div class="stat-content">
+                    <div class="text-left">
+                        <div class="stat-text">
+                            {{ content }}
+                        </div>
+                        <div class="stat-heading">
+                            {{ name }}
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+{% endmacro %}
+
+{% macro reporting_user_details(user) %}
+    <div class="parameters">
+        <dl class="dl-horizontal">
+            {% if user.status %}
+                <dt>{{ 'Status'|get_lang }}</dt>
+                <dd>{{ user.status }}</dd>
+            {% endif %}
+
+            <dt>{{ 'OfficialCode'|get_lang }}</dt>
+            <dd>{{ user.code == '' ? 'NoOfficialCode'|get_lang : user.code }}</dd>
+            <dt>{{ 'OnLine'|get_lang }}</dt>
+            <dd>
+                {{ user.user_is_online }}
+                {{ user.online }}
+            </dd>
+            <dt>{{ 'Tel'|get_lang }}</dt>
+            <dd>{{ user.phone == '' ? 'NoTel'|get_lang : user.phone }}</dd>
+
+            {% if user.timezone %}
+                <dt>{{ 'Timezone'|get_lang }}</dt>
+                <dd>{{ user.timezone }}</dd>
+            {% endif %}
+        </dl>
+
+        {% if user.created %}
+            <div class="create">{{ user.created }}</div>
+        {% endif %}
+
+        {% if user.url_access or user.legal.url_send %}
+            <div class="access">
+                {{ user.url_access }}
+                {{ user.legal.url_send }}
+            </div>
+        {% endif %}
+    </div>
+{% endmacro %}
+
+{% macro reporting_user_box(user) %}
+    {% import _self as display %}
+
+    <div class="user">
+        <div class="avatar">
+            <img width="128px" src="{{ user.avatar }}" class="img-responsive">
+        </div>
+        <div class="name">
+            <h3>
+                {% if user.complete_name_link %}
+                    {{ user.complete_name_link }}
+                {% else %}
+                    {{ user.complete_name }}
+                {% endif %}
+            </h3>
+            <p class="email">{{ user.email }}</p>
+        </div>
+
+        {{ display.reporting_user_details(user) }}
+
+    </div>
+{% endmacro %}

+ 1 - 5
main/template/default/my_space/accessoverview.tpl

@@ -1,13 +1,9 @@
 <h2 class="page-header">{{ 'DisplayAccessOverview'|get_lang }}</h2>
-
 {{ form }}
-
 <h3 class="page-header">{{ 'Results'|get_lang }}</h3>
-
 {{ table }}
-
 <script>
-    $(document).on('ready', function () {
+    $(function(){
         var courseIdEl = $('#access_overview_course_id'),
             sessionIdEl = $('#access_overview_session_id');
 

+ 1 - 8
main/template/default/my_space/index.tpl

@@ -261,7 +261,7 @@
     </div>
 </div>
 
-<script type="text/javascript">
+<script>
     $(function() {
         $('#easypiechart-teal').easyPieChart({
             scaleColor: false,
@@ -269,27 +269,21 @@
             lineWidth:8,
             trackColor: '#f2f2f2'
         });
-    });
 
-    $(function() {
         $('#easypiechart-orange').easyPieChart({
             scaleColor: false,
             barColor: '#ffb53e',
             lineWidth:8,
             trackColor: '#f2f2f2'
         });
-    });
 
-    $(function() {
         $('#easypiechart-red').easyPieChart({
             scaleColor: false,
             barColor: '#f9243f',
             lineWidth:8,
             trackColor: '#f2f2f2'
         });
-    });
 
-    $(function() {
         $('#easypiechart-blue').easyPieChart({
             scaleColor: false,
             barColor: '#30a5ff',
@@ -297,5 +291,4 @@
             trackColor: '#f2f2f2'
         });
     });
-
 </script>

+ 19 - 3
main/template/default/my_space/pdf_export_student.tpl

@@ -2,22 +2,38 @@
     <img src="{{ _p.web_css_theme }}images/header-logo.png" width="200">
 </div>
 
+{% if title %}
 <h1 style="color:#000000; background-color:#fff;font-size: 22px; text-align: center; font-weight: bold; padding: 5px 10px;">
     {{ title }}
 </h1>
+{% endif %}
 
-<h1 style="color:#ffffff; background-color:#084B8A;font-size: 22px; text-align: center; font-weight: bold; padding: 5px 10px;">
-    {{ session_title }}
-</h1>
+{% if session_title %}
+    <h1 style="color:#ffffff; background-color:#084B8A;font-size: 22px; text-align: center; font-weight: bold; padding: 5px 10px;">
+        {{ session_title }}
+    </h1>
+{% endif %}
+
+{% if student %}
 <div style="font-weight: bold; padding-bottom: 20px;">
     {{ student }}
 </div>
+{% endif %}
+
+{% if table_progress %}
 <div style="background: #f1f6ff;">
     {{ table_progress }}
 </div>
+{% endif %}
+
+{% if subtitle %}
 <div style="padding-bottom: 20px; margin-top: 20px;">
     {{ subtitle }}
 </div>
+{% endif %}
+
+{% if table_course %}
 <div style="background: #f1f6ff;">
     {{ table_course }}
 </div>
+{% endif %}

+ 104 - 0
main/template/default/session/resume_session.tpl

@@ -119,4 +119,108 @@
 
 {{ requirements }}
 {{ dependencies }}
+
+    <script>
+        $(function () {
+            function loadFiles(courseId, sessionId) {
+                return $.get('{{ _p.web_ajax }}session.ajax.php', {
+                    course: courseId,
+                    session: sessionId,
+                    a: 'get_basic_course_documents_list'
+                });
+            }
+
+            function loadForm(courseId, sessionId) {
+                return $.get('{{ _p.web_ajax }}session.ajax.php', {
+                    course: courseId,
+                    session: sessionId,
+                    a: 'get_basic_course_documents_form'
+                });
+            }
+
+            var c = 0;
+
+            $('.session-upload-file-btn').on('click', function (e) {
+                e.preventDefault();
+
+                var $self = $(this),
+                    $trParent = $self.parents('tr'),
+                    $trContainer = $trParent.next(),
+                    courseId = $self.data('course') || 0,
+                    sessionId = $self.data('session') || 0;
+
+                $('.session-upload-file-tr').remove();
+
+                if (courseId == c) {
+                    c = 0;
+
+                    return;
+                }
+
+                c = courseId;
+
+                $trContainer = $('<tr>')
+                    .addClass('session-upload-file-tr')
+                    .html('<td colspan="4">{{ 'Loading'|get_lang }}</td>')
+                    .insertAfter($trParent);
+
+                $.when
+                    .apply($, [loadFiles(courseId, sessionId), loadForm(courseId, sessionId)])
+                    .then(function (response1, response2) {
+                        var filesCount = 0,
+                            filesUploadedCount = 0;
+
+                        $trContainer.find('td:first')
+                            .html('<div id="session-' + sessionId + '-docs">' + response1[0] + '</div>'
+                                + '<div id="session-' + sessionId + '-form">' + response2[0] + '</div>');
+
+                        $('#input_file_upload')
+                            .on('fileuploadadd', function (e, data) {
+                                filesCount += data.files.length;
+                            })
+                            .on('fileuploaddone', function (e, data) {
+                                filesUploadedCount += data.files.length;
+
+                                data.context.parent().remove();
+
+                                if (filesUploadedCount < filesCount) {
+                                    return;
+                                }
+
+                                $('#session-' + sessionId + '-docs').html('{{ 'Loading'|get_lang }}');
+
+                                loadFiles(courseId, sessionId)
+                                    .then(function (response) {
+                                        filesCount = 0;
+                                        filesUploadedCount = 0;
+
+                                        $('#session-' + sessionId + '-docs').html(response);
+                                    });
+                            });
+                    });
+            });
+
+            $('#session-list-course').on('click', '.delete_document', function (e) {
+                e.preventDefault();
+
+                if (!confirm('{{ 'ConfirmYourChoice'|get_lang }}')) {
+                    return;
+                }
+
+                var $self = $(this),
+                    courseId = $self.data('course') || 0,
+                    sessionId = $self.data('session') || 0;
+
+                $('#session-' + sessionId + '-docs').html('{{ 'Loading'|get_lang }}');
+
+                $.ajax(this.href)
+                    .then(function () {
+                        loadFiles(courseId, sessionId)
+                            .then(function (response) {
+                                $('#session-' + sessionId + '-docs').html(response);
+                            })
+                    });
+            });
+        });
+    </script>
 {% endblock %}

+ 1 - 1
main/template/default/skill/issued.tpl

@@ -51,7 +51,7 @@
         {% endif %}
     </div>
     <div class="col-md-7">
-        <h3>{{ 'RecipientDetails'|get_lang }}</h3>
+        <h5>{{ 'RecipientDetails'|get_lang }}</h5>
         <p class="lead">{{ issue_info.user_complete_name }}</p>
         <h4>{{ 'SkillAcquiredAt'|get_lang }}</h4>
         <ul class="fa-ul">

+ 8 - 7
main/template/default/skill/issued_all.tpl

@@ -52,21 +52,22 @@
             {% endif %}
         </div>
         <div class="col-md-7">
-            <h3>{{ 'RecipientDetails'|get_lang }}</h3>
+            <h5>{{ 'RecipientDetails'|get_lang }}</h5>
             <p class="lead">{{ badge.issue_info.user_complete_name }}</p>
-            <h4>{{ 'SkillAcquiredAt'|get_lang }}</h4>
+            <h4 class="bage-username">{{ 'SkillAcquiredAt'|get_lang }}</h4>
             <ul class="fa-ul">
-                <li>
+                <li class="badge-item">
                     {% if badge.issue_info.source_name %}
-                        <em class="fa-li fa fa-clock-o fa-fw"></em> {{ 'TimeXThroughCourseY'|get_lang|format(badge.issue_info.datetime, badge.issue_info.source_name) }}
+                        <em class="fa fa-clock-o fa-fw"></em> {{ 'TimeXThroughCourseY'|get_lang|format(badge.issue_info.datetime, badge.issue_info.source_name) }}
                     {% else %}
-                        <em class="fa-li fa fa-clock-o fa-fw"></em> {{ badge.issue_info.datetime }}
+                        <em class="fa fa-clock-o fa-fw"></em> {{ badge.issue_info.datetime }}
                     {% endif %}
                     {% if badge.issue_info.argumentation %}
                         {% if badge.issue_info.argumentation %}
-                            <b><p style="font-style: italic;">{{ 'UserXIndicated'|get_lang|format(badge.issue_info.argumentation_author_name) }} </p></b>
+                            <br>
+                            <p>{{ 'UserXIndicated'|get_lang|format(badge.issue_info.argumentation_author_name) }} </p>
                         {% endif %}
-                        <p>{{ badge.issue_info.argumentation }}</p>
+                        <p class="msg">{{ badge.issue_info.argumentation }}</p>
                     {% endif %}
                 </li>
             </ul>

+ 1 - 1
main/template/default/skill/list.tpl

@@ -41,7 +41,7 @@
                     {{ skill.img_small }}
                 </td>
                 <td width="200">{{ skill.name }}</td>
-                <td class="text-center">{{ skill.short_code }}</td>
+                <td>{{ skill.short_code }}</td>
                 <td width="500">{{ skill.description }}</td>
                 <td class="text-right">
                     <a href="{{ _p.web_main }}admin/skill_edit.php?id={{ skill.id }}" class="btn btn-default btn-sm" title="{{ "Edit" | get_lang }}">

+ 21 - 26
main/template/default/skill/student_boss_report.tpl

@@ -8,38 +8,33 @@
 
 <h1 class="page-header">{{ 'SkillsAcquired' | get_lang }}</h1>
 
-<form class="form-inline" method="post" action="{{ _p.web_self }}">
-    <label>{{ 'Students' | get_lang }}</label>
-    <select name="student" id="student">
-        <option value="0">{{ 'Select' | get_lang }}</option>
-        {% for student in followed_students %}
-            <option value="{{ student.user_id }}" {{ (student.user_id == selected_student) ? 'selected' : '' }}>
-                {{ student.completeName }}
-            </option>
-        {% endfor %}
-    </select>
-    <button type="submit" class="btn btn-primary">{{ 'Search' | get_lang }}</button>
-</form>
+{{ form }}
 
 {% if rows %}
-    <table class="table">
-        <thead>
+    <div class="table-responsive">
+        <table class="table table-hover">
+            <thead>
             <tr>
                 <th>{{ 'Student' | get_lang }}</th>
                 <th>{{ 'SkillsAcquired' | get_lang }}</th>
                 <th>{{ 'Date' | get_lang }}</th>
                 <th>{{ 'Course' | get_lang }}</th>
             </tr>
-        </thead>
-        <tbody>
-        {% for row in rows %}
-            <tr>
-                <td>{{ row.complete_name }}</td>
-                <td>{{ row.skill_name }}</td>
-                <td>{{ row.achieved_at }}</td>
-                <td><img src="{{ row.course_image }}" alt="{{ row.course_name }}"> {{ row.course_name }}</td>
-            </tr>
-        {% endfor %}
-        </tbody>
-    </table>
+            </thead>
+            <tbody>
+            {% for row in rows %}
+                <tr>
+                    <td>{{ row.complete_name }}</td>
+                    <td>{{ row.skill_name }}</td>
+                    <td>{{ row.achieved_at }}</td>
+                    <td>
+                        {% if not row.course_name is empty %}
+                            <img src="{{ row.course_image }}" alt="{{ row.course_name }}"> {{ row.course_name }}
+                        {% endif %}
+                    </td>
+                </tr>
+            {% endfor %}
+            </tbody>
+        </table>
+    </div>
 {% endif %}

+ 4 - 0
main/template/default/skill/student_report.tpl

@@ -3,6 +3,10 @@
         <a class="btn btn-default" href="{{ _p.web_main }}social/skills_wheel.php">
             {{ 'SkillsWheel' | get_lang }}
         </a>
+
+        <a class="btn btn-default" href="{{ _p.web_main }}social/my_skills_report.php?a=generate">
+            {{ 'RecalculateResults' | get_lang }}
+        </a>
     </div>
 {% endif %}
 

+ 2 - 7
main/template/default/social/home.tpl

@@ -16,10 +16,8 @@
             </div>
         </div>
         <div class="col-md-6">
-            {#{{ social_search_block }}#}
-
             <div id="wallMessages">
-                {{ social_wall_block }}
+                {{ add_post_form }}
                 <div class="spinner"></div>
                 <div class="panel panel-preview panel-default" hidden="true">
                     <div class="panel-heading">
@@ -29,19 +27,16 @@
                         <div class="url_preview"></div>
                     </div>
                 </div>
-                {{ social_post_wall_block }}
+                {{ posts }}
                 {{ social_auto_extend_link }}
             </div>
 
-            {#{{ social_skill_block }}#}
             {{ social_right_content }}
             <div id="message_ajax_reponse" class=""></div>
             <div id="display_response_id"></div>
         </div>
         <div class="col-md-3">
-
             {{ social_group_block }}
-
             <!-- Block chat list -->
             <div class="chat-friends">
                 <div class="panel-group" id="blocklistFriends" role="tablist" aria-multiselectable="true">

+ 2 - 2
main/template/default/social/profile.tpl

@@ -16,7 +16,7 @@
         </div>
     </div>
     <div id="wallMessages" class="col-md-6">
-        {{ social_wall_block }}
+        {{ add_post_form }}
         <div class="spinner"></div>
         <div class="panel panel-preview panel-default" hidden="true">
             <div class="panel-heading">
@@ -26,7 +26,7 @@
                 <div class="url_preview"></div>
             </div>
         </div>
-        {{ social_post_wall_block }}
+        {{ posts }}
         {{ social_auto_extend_link }}
     </div>
     <div class="col-md-3">

+ 2 - 1
main/template/default/social/skills_block.tpl

@@ -8,7 +8,8 @@ $(function() {
     <div class="panel panel-default">
         <div class="panel-heading" role="tab" id="headingOne">
             <h4 class="panel-title">
-                <a role="button" data-toggle="collapse" data-parent="#skill-block" href="#skillList" aria-expanded="true" aria-controls="skillList">
+                <a role="button" data-toggle="collapse"
+                   data-parent="#skill-block" href="#skillList" aria-expanded="true" aria-controls="skillList">
                     {{ "Skills" | get_lang }}
                 </a>
                 <div class="btn-group pull-right">

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません