Bläddra i källkod

Merge branch '1.11.x' of github.com:chamilo/chamilo-lms into 1.11.x

Julio Montoya 5 år sedan
förälder
incheckning
3973c397e2
37 ändrade filer med 715 tillägg och 174 borttagningar
  1. 4 15
      main/admin/career_diagram.php
  2. 17 7
      main/admin/user_update_import.php
  3. 106 2
      main/cron/import_csv.php
  4. 5 0
      main/document/document.php
  5. 0 1
      main/inc/lib/CoursesAndSessionsCatalog.class.php
  6. 1 1
      main/inc/lib/api.lib.php
  7. 102 13
      main/inc/lib/career.lib.php
  8. 25 0
      main/inc/lib/course.lib.php
  9. 8 0
      main/inc/lib/document.lib.php
  10. 5 2
      main/inc/lib/exercise_show_functions.lib.php
  11. 1 1
      main/inc/lib/sessionmanager.lib.php
  12. 67 0
      main/inc/lib/statistics.lib.php
  13. 5 0
      main/inc/lib/tracking.lib.php
  14. 42 1
      main/inc/lib/usermanager.lib.php
  15. 3 1
      main/inc/lib/userportal.lib.php
  16. 2 0
      main/install/configuration.dist.php
  17. 2 1
      main/mySpace/myStudents.php
  18. 0 2
      main/survey/ch_personality.php
  19. 1 1
      main/survey/ch_score.php
  20. 4 10
      main/survey/edit_meeting.php
  21. 1 1
      main/survey/generate_link.php
  22. 0 4
      main/survey/meeting.php
  23. 1 8
      main/survey/preview.php
  24. 1 1
      main/survey/reporting.php
  25. 8 13
      main/survey/surveyUtil.class.php
  26. 0 12
      main/survey/survey_invite.php
  27. 1 7
      main/survey/survey_list.php
  28. 83 0
      main/survey/survey_question.php
  29. 62 13
      main/template/default/career/diagram.tpl
  30. 0 1
      main/tracking/courseLog.php
  31. 7 15
      main/user/career_diagram.php
  32. 3 0
      plugin/customcertificate/lang/english.php
  33. 3 0
      plugin/customcertificate/lang/spanish.php
  34. 53 0
      plugin/customcertificate/src/CustomCertificatePlugin.php
  35. 51 0
      plugin/customcertificate/src/customcertificate.ajax.php
  36. 38 24
      plugin/customcertificate/src/index.php
  37. 3 17
      plugin/customcertificate/src/print_certificate.php

+ 4 - 15
main/admin/career_diagram.php

@@ -1,8 +1,6 @@
 <?php
 /* For licensing terms, see /license.txt */
 
-use Fhaculty\Graph\Graph;
-
 /**
  *  @package chamilo.admin
  */
@@ -57,8 +55,6 @@ $interbreadcrumb[] = [
 ];
 
 $action = isset($_GET['action']) ? $_GET['action'] : '';
-$check = Security::check_token('request');
-$token = Security::get_token();
 
 if ($action == 'add') {
     $interbreadcrumb[] = ['url' => 'careers.php', 'name' => get_lang('Careers')];
@@ -72,13 +68,6 @@ if ($action == 'add') {
 }
 
 $extraFieldValue = new ExtraFieldValue('career');
-$item = $extraFieldValue->get_values_by_handler_and_field_variable(
-    $careerId,
-    'career_diagram',
-    false,
-    false,
-    false
-);
 
 // Check urls
 $itemUrls = $extraFieldValue->get_values_by_handler_and_field_variable(
@@ -107,10 +96,10 @@ if (!empty($itemUrls) && !empty($itemUrls['value'])) {
 
 $tpl = new Template(get_lang('Diagram'));
 $html = Display::page_subheader2($careerInfo['name'].$urlToString);
-if (!empty($item) && isset($item['value']) && !empty($item['value'])) {
-    /** @var Graph $graph */
-    $graph = UnserializeApi::unserialize('career', $item['value']);
-    $html .= Career::renderDiagramByColumn($graph, $tpl);
+$diagram = Career::renderDiagramByColumn($careerInfo, $tpl);
+
+if (!empty($diagram)) {
+    $html .= $diagram;
 } else {
     Display::addFlash(
         Display::return_message(

+ 17 - 7
main/admin/user_update_import.php

@@ -144,7 +144,7 @@ function updateUsers($users)
         $inserted_in_course = [];
     }
     $usergroup = new UserGroup();
-    $send_mail = $_POST['sendMail'] ? true : false;
+    $send_mail = !empty($_POST['sendMail']) ? true : false;
     if (is_array($users)) {
         foreach ($users as $user) {
             $user = complete_missing_data($user);
@@ -158,8 +158,15 @@ function updateUsers($users)
             $firstName = isset($user['FirstName']) ? $user['FirstName'] : $userInfo['firstname'];
             $lastName = isset($user['LastName']) ? $user['LastName'] : $userInfo['lastname'];
             $userName = isset($user['NewUserName']) ? $user['NewUserName'] : $userInfo['username'];
-            $password = isset($user['Password']) ? $user['Password'] : $userInfo['password'];
-            $authSource = isset($user['AuthSource']) ? $user['AuthSource'] : $userInfo['auth_source'];
+            $changePassMethod = 0;
+            $password = isset($user['Password']) ? $user['Password'] : '';
+            if (!empty($password)) {
+                $changePassMethod = 2;
+            }
+            $authSource = isset($user['AuthSource']) ? $user['AuthSource'] : '';
+            if ($changePassMethod === 2 && !empty($authSource) && $authSource != $userInfo['auth_source']) {
+                $changePassMethod = 3;
+            }
             $email = isset($user['Email']) ? $user['Email'] : $userInfo['email'];
             $status = isset($user['Status']) ? $user['Status'] : $userInfo['status'];
             $officialCode = isset($user['OfficialCode']) ? $user['OfficialCode'] : $userInfo['official_code'];
@@ -191,12 +198,12 @@ function updateUsers($users)
                 $language,
                 '',
                 '',
-                ''
+                $changePassMethod
             );
-            if (!is_array($user['Courses']) && !empty($user['Courses'])) {
+            if (!empty($user['Courses']) && !is_array($user['Courses'])) {
                 $user['Courses'] = [$user['Courses']];
             }
-            if (is_array($user['Courses'])) {
+            if (!empty($user['Courses']) && is_array($user['Courses'])) {
                 foreach ($user['Courses'] as $course) {
                     if (CourseManager::course_exists($course)) {
                         CourseManager::subscribeUser($user_id, $course, $user['Status']);
@@ -347,6 +354,7 @@ if (isset($_POST['formSent']) && $_POST['formSent'] && $_FILES['import_file']['s
         $see_message_import = get_lang('FileImported');
     }
 
+    $warning_message = '';
     if (count($errors) != 0) {
         $warning_message = '<ul>';
         foreach ($errors as $index => $error_user) {
@@ -360,7 +368,9 @@ if (isset($_POST['formSent']) && $_POST['formSent'] && $_FILES['import_file']['s
     }
 
     // if the warning message is too long then we display the warning message trough a session
-    Display::addFlash(Display::return_message($warning_message, 'warning', false));
+    if (!empty($warning_message)) {
+        Display::addFlash(Display::return_message($warning_message, 'warning', false));
+    }
 
     if ($error_kind_file) {
         Display::addFlash(Display::return_message(get_lang('YouMustImportAFileAccordingToSelectedOption'), 'error', false));

+ 106 - 2
main/cron/import_csv.php

@@ -156,6 +156,10 @@ class ImportCsv
                         $method = 'importCareersDiagram';
                     }
 
+                    if ($method == 'importCareersresults') {
+                        $method = 'importCareersResults';
+                    }
+
                     if ($method == 'importOpensessions') {
                         $method = 'importOpenSessions';
                     }
@@ -209,6 +213,7 @@ class ImportCsv
                 'care',
                 'careers',
                 'careersdiagram',
+                'careersresults',
             ];
 
             foreach ($sections as $section) {
@@ -2643,6 +2648,105 @@ class ImportCsv
         }
     }
 
+    /**
+     * @param $file
+     * @param bool  $moveFile
+     * @param array $teacherBackup
+     * @param array $groupBackup
+     */
+    private function importCareersResults(
+        $file,
+        $moveFile = false,
+        &$teacherBackup = [],
+        &$groupBackup = []
+    ) {
+        $data = Import::csv_reader($file);
+
+        if (!empty($data)) {
+            $this->logger->addInfo(count($data).' records found.');
+
+            $extraFieldValue = new ExtraFieldValue('career');
+            $extraFieldName = $this->extraFieldIdNameList['career'];
+
+            foreach ($data as $row) {
+                if (empty($row)) {
+                    continue;
+                }
+                foreach ($row as $key => $value) {
+                    $key = (string) trim($key);
+                    // Remove utf8 bom
+                    $key = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $key);
+                    $row[$key] = $value;
+                }
+
+                $studentId = $row['StudentId'];
+                $studentId = UserManager::get_user_id_from_original_id(
+                    $studentId,
+                    $this->extraFieldIdNameList['user']
+                );
+
+                $studentInfo = api_get_user_info($studentId);
+                if (empty($studentInfo)) {
+                    $this->logger->addInfo("Student id not found: $studentId");
+                    continue;
+                }
+
+                $careerId = $row['CareerId'];
+                $item = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
+                    $extraFieldName,
+                    $careerId
+                );
+
+                $careerChamiloId = null;
+                if (empty($item)) {
+                    $this->logger->addInfo("Career not found: $careerId");
+                    continue;
+                } else {
+                    if (isset($item['item_id'])) {
+                        $careerChamiloId = $item['item_id'];
+                    } else {
+                        continue;
+                    }
+                }
+
+                if (UserManager::userHasCareer($studentId, $careerChamiloId) === false) {
+                    $this->logger->addInfo(
+                        "User $studentId (".$row['StudentId'].") has no career #$careerChamiloId (ext #$careerId)"
+                    );
+                    continue;
+                }
+
+                $userCareerData = UserManager::getUserCareer($studentId, $careerChamiloId);
+
+                $extraData = isset($userCareerData['extra_data']) && !empty($userCareerData['extra_data']) ? unserialize($userCareerData['extra_data']) : [];
+
+                $teacherInfo = api_get_user_info_from_username($row['TeacherUsername']);
+                $teacherName = $row['TeacherUsername'];
+                if ($teacherInfo) {
+                    $teacherName = $teacherInfo['complete_name'];
+                }
+
+                $extraData[$row['CourseId']][$row['ResultId']] = [
+                    'Description' => $row['Description'],
+                    'Period' => $row['Period'],
+                    'TeacherText' => $row['TeacherText'],
+                    'TeacherUsername' => $teacherName,
+                    'ScoreText' => $row['ScoreText'],
+                    'ScoreValue' => $row['ScoreValue'],
+                    'Info' => $row['Info'],
+                    'BgColor' => $row['BgColor'],
+                    'Color' => $row['Color'],
+                    'BorderColor' => $row['BorderColor'],
+                    'Icon' => $row['Icon'],
+                    'IconColor' => $row['IconColor'],
+                ];
+                $serializedValue = serialize($extraData);
+
+                UserManager::updateUserCareer($userCareerData['id'], $serializedValue);
+            }
+        }
+    }
+
     /**
      * @param $file
      * @param bool  $moveFile
@@ -2734,7 +2838,7 @@ class ImportCsv
                         $careerList[$careerId] = $graph;
                     }
 
-                    $currentCourseId = (int) $row['CourseId'];
+                    $currentCourseId = $row['CourseId'];
                     $name = $row['CourseName'];
                     $notes = $row['Notes'];
                     $groupValue = $row['Group'];
@@ -2778,7 +2882,7 @@ class ImportCsv
                         continue;
                     }
 
-                    $currentCourseId = (int) $row['CourseId'];
+                    $currentCourseId = $row['CourseId'];
                     if ($graph->hasVertex($currentCourseId)) {
                         $current = $graph->getVertex($currentCourseId);
                     } else {

+ 5 - 0
main/document/document.php

@@ -1843,6 +1843,11 @@ if (!empty($documentAndFolders)) {
             } else {
                 $document_name = basename($document_data['path']);
             }
+
+            if (api_get_configuration_value('save_titles_as_html')) {
+                $document_name = strip_tags($document_name);
+            }
+
             $row['name'] = $document_name;
             // Data for checkbox
             if (($isAllowedToEdit || $groupMemberWithUploadRights) && count($documentAndFolders) > 1) {

+ 0 - 1
main/inc/lib/CoursesAndSessionsCatalog.class.php

@@ -564,7 +564,6 @@ class CoursesAndSessionsCatalog
      * @param bool   $getCount
      *
      * @return array|\Doctrine\ORM\Query The session list
-     *
      */
     public static function browseSessions($date = null, $limit = [], $returnQueryBuilder = false, $getCount = false)
     {

+ 1 - 1
main/inc/lib/api.lib.php

@@ -280,7 +280,7 @@ define('LOG_USER_DELETE_ACCOUNT_REQUEST', 'user_delete_account_request');
 define('LOG_QUESTION_CREATED', 'question_created');
 define('LOG_QUESTION_UPDATED', 'question_updated');
 
-define('USERNAME_PURIFIER', '/[^0-9A-Za-z_\.]/');
+define('USERNAME_PURIFIER', '/[^0-9A-Za-z_\.-]/');
 
 //used when login_is_email setting is true
 define('USERNAME_PURIFIER_MAIL', '/[^0-9A-Za-z_\.@]/');

+ 102 - 13
main/inc/lib/career.lib.php

@@ -453,13 +453,34 @@ class Career extends Model
     }
 
     /**
-     * @param Graph    $graph
+     * @param array    $careerInfo
      * @param Template $tpl
+     * @param int      $loadUserIdData
      *
      * @return string
      */
-    public static function renderDiagramByColumn($graph, $tpl)
+    public static function renderDiagramByColumn($careerInfo, $tpl, $loadUserIdData = 0)
     {
+        $careerId = isset($careerInfo['id']) ? $careerInfo['id'] : 0;
+        if (empty($careerId)) {
+            return '';
+        }
+
+        $extraFieldValue = new ExtraFieldValue('career');
+        $item = $extraFieldValue->get_values_by_handler_and_field_variable(
+            $careerId,
+            'career_diagram',
+            false,
+            false,
+            false
+        );
+
+        $graph = null;
+        if (!empty($item) && isset($item['value']) && !empty($item['value'])) {
+            /** @var Graph $graph */
+            $graph = UnserializeApi::unserialize('career', $item['value']);
+        }
+
         if (!($graph instanceof Graph)) {
             return '';
         }
@@ -473,6 +494,14 @@ class Career extends Model
             }
         }
 
+        $userResult = [];
+        if (!empty($loadUserIdData)) {
+            $careerData = UserManager::getUserCareer($loadUserIdData, $careerId);
+            if (isset($careerData['extra_data']) && !empty($careerData['extra_data'])) {
+                $userResult = unserialize($careerData['extra_data']);
+            }
+        }
+
         $list = [];
         $subGroups = [];
         /** @var Vertex $vertex */
@@ -492,7 +521,6 @@ class Career extends Model
             $subGroupLabel = isset($subGroupData[1]) ? $subGroupData[1] : '';
 
             if (!empty($subGroupId) && !in_array($subGroupId, $subGroups)) {
-                //$subGroups[$subGroupId][] = $vertex->getId();
                 $subGroups[$subGroupId]['items'][] = $vertex->getId();
                 $subGroups[$subGroupId]['label'] = $subGroupLabel;
             }
@@ -507,7 +535,6 @@ class Career extends Model
             $list[$column]['column'] = $column;
         }
 
-        $groupDrawLine = [];
         $groupCourseList = [];
         $simpleConnectionList = [];
 
@@ -517,7 +544,6 @@ class Career extends Model
                 /** @var Vertex $vertex */
                 foreach ($subGroupList['items'] as $vertex) {
                     if ($vertex instanceof Vertex) {
-                        $rowId = $vertex->getId();
                         $groupCourseList[$vertex->getAttribute('Column')][] = $vertex->getId();
                         $connectionList = $vertex->getAttribute('Connections');
                         if (empty($connectionList)) {
@@ -537,12 +563,11 @@ class Career extends Model
                                     '',
                                     $explode[0]
                                 );
-                                $groupDrawLine[$groupValueId] = true;
                                 $simpleFirstConnection = 'g'.(int) $groupValueId;
                             } else {
                                 // Course block (row_123 id)
                                 if (!empty($explode[0])) {
-                                    $simpleFirstConnection = 'v'.(int) $explode[0];
+                                    $simpleFirstConnection = 'v'.$explode[0];
                                 }
                             }
                         } else {
@@ -566,7 +591,6 @@ class Career extends Model
                                     $value
                                 );
                                 $simpleSecondConnection = 'g'.(int) $groupValueId;
-                                $groupDrawLine[$groupValueId] = true;
                             } else {
                                 // Course block (row_123 id)
                                 if (!empty($explode[0]) && isset($explode[1])) {
@@ -607,11 +631,18 @@ class Career extends Model
 
         $graph->xGap = 70;
         $graph->yGap = 55;
+
         $graph->xDiff = 70;
         $graph->yDiff = 55;
 
+        if (!empty($userResult)) {
+            $graph->blockHeight = 180;
+            $graph->yGap = 60;
+            $graph->yDiff = 60;
+        }
+
         foreach ($groupsBetweenColumns as $group => $items) {
-            self::parseColumnList($groupCourseList, $items, '', $graph, $simpleConnectionList);
+            self::parseColumnList($groupCourseList, $items, $graph, $simpleConnectionList, $userResult);
         }
 
         $graphHtml .= '<style>
@@ -692,7 +723,6 @@ class Career extends Model
                 $width = $data['max_width'] + $subGroupDiffX * 2;
                 $height = $data['max_height'] + $subGroupDiffX * 2 + $spaceForSubGroupTitle;
 
-
                 $label = '<h4 style="background: white">'.$data['label'].'</h4>';
                 $vertexData = "var sg$subGroupId = graph.insertVertex(parent, null, '$label', $x, $y, $width, $height, '$style');";
                 $subGroupList[] = $vertexData;
@@ -721,7 +751,16 @@ class Career extends Model
         return $graphHtml;
     }
 
-    public static function parseColumnList($groupCourseList, $columnList, $width, &$graph, &$connections)
+    /**
+     * @param $groupCourseList
+     * @param $columnList
+     * @param $graph
+     * @param $connections
+     * @param $userResult
+     *
+     * @return string
+     */
+    public static function parseColumnList($groupCourseList, $columnList, &$graph, &$connections, $userResult)
     {
         $graphHtml = '';
         $oldGroup = null;
@@ -798,7 +837,8 @@ class Career extends Model
                     $addRow,
                     $graph,
                     $newGroup,
-                    $connections
+                    $connections,
+                    $userResult
                 );
             }
 
@@ -817,10 +857,11 @@ class Career extends Model
      * @param stdClass $graph
      * @param int      $group
      * @param array    $connections
+     * @param array    $userResult
      *
      * @return string
      */
-    public static function parseVertexList($groupCourseList, $vertexList, $addRow = 0, &$graph, $group, &$connections)
+    public static function parseVertexList($groupCourseList, $vertexList, $addRow = 0, &$graph, $group, &$connections, $userResult)
     {
         if (empty($vertexList)) {
             return '';
@@ -851,6 +892,54 @@ class Career extends Model
             $content = '<div class="pull-left">'.$vertex->getAttribute('Notes').'</div>';
             $content .= '<div class="pull-right">['.$id.']</div>';
 
+            if (!empty($userResult) && isset($userResult[$id])) {
+                $results = '';
+                $size = 2;
+                foreach ($userResult[$id] as $resultId => $iconData) {
+                    $icon = '';
+                    switch ($iconData['Icon']) {
+                        case 0:
+                            $icon = Display::returnFontAwesomeIcon('times-circle', $size);
+                            break;
+                        case 1:
+                            $icon = Display::returnFontAwesomeIcon('check-circle', $size);
+                            break;
+                        case 2:
+                            $icon = Display::returnFontAwesomeIcon('info-circle', $size);
+                            break;
+                    }
+
+                    if (substr($resultId, 0, 1) == 2) {
+                        $iconData['Description'] = 'Result Id = '.$resultId;
+                    }
+
+                    if (!empty($icon)) {
+                        $params = [
+                            'id' => 'course_'.$id.'_'.$resultId,
+                            'data-toggle' => 'popover',
+                            'title' => 'Popover title',
+                            'class' => 'popup',
+                            'data-description' => $iconData['Description'],
+                            'data-period' => $iconData['Period'],
+                            'data-teacher-text' => $iconData['TeacherText'],
+                            'data-teacher' => $iconData['TeacherUsername'],
+                            'data-score' => $iconData['ScoreText'],
+                            'data-score-value' => $iconData['ScoreValue'],
+                            'data-info' => $iconData['Info'],
+                            'data-background-color' => $iconData['BgColor'],
+                            'data-color' => $iconData['Color'],
+                            'data-border-color' => $iconData['BorderColor'],
+                            'style' => 'color:'.$iconData['IconColor'],
+                        ];
+                        $results .= Display::url($icon, 'javascript:void(0);', $params);
+                    }
+                }
+
+                if (!empty($results)) {
+                    $content .= '<div class="row"></div><div class="pull-right">'.$results.'</div>';
+                }
+            }
+
             $title = $vertex->getAttribute('graphviz.label');
             if (!empty($vertex->getAttribute('LinkedElement'))) {
                 $title = Display::url($title, $vertex->getAttribute('LinkedElement'));

+ 25 - 0
main/inc/lib/course.lib.php

@@ -4909,6 +4909,31 @@ class CourseManager
         return $hotCourses;
     }
 
+    public function totalSubscribedUsersInCourses($urlId)
+    {
+        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
+        $table_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
+        $courseUsers = Database::get_main_table(TABLE_MAIN_COURSE_USER);
+
+        $urlId = (int) $urlId;
+
+        $sql = "SELECT count(cu.user_id) count 
+                FROM $courseUsers cu 
+                INNER JOIN $table_course_rel_access_url u 
+                ON cu.c_id = u.c_id                
+                WHERE
+                    relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
+                    u.access_url_id = $urlId AND 
+                    visibility <> ".COURSE_VISIBILITY_CLOSED." AND
+                    visibility <> ".COURSE_VISIBILITY_HIDDEN." 
+                     ";
+
+        $res = Database::query($sql);
+        $row = Database::fetch_array($res);
+
+        return $row['count'];
+    }
+
     /**
      * Get courses count.
      *

+ 8 - 0
main/inc/lib/document.lib.php

@@ -5050,6 +5050,10 @@ class DocumentManager
             $title = basename($document_data['path']);
         }
 
+        if (api_get_configuration_value('save_titles_as_html')) {
+            $title = strip_tags($title);
+        }
+
         $filetype = $document_data['filetype'];
         $path = $document_data['path'];
         $url_path = urlencode($document_data['path']);
@@ -6600,6 +6604,10 @@ class DocumentManager
             $my_file_title = basename($path);
         }
 
+        if (api_get_configuration_value('save_titles_as_html')) {
+            $my_file_title = strip_tags($my_file_title);
+        }
+
         // Show the "image name" not the filename of the image.
         if ($lp_id) {
             // LP URL

+ 5 - 2
main/inc/lib/exercise_show_functions.lib.php

@@ -390,7 +390,6 @@ class ExerciseShowFunctions
         echo '<td width="5%">';
         echo Display::return_icon($icon, null, null, ICON_SIZE_TINY);
         echo '</td>';
-
         if ($exercise->showExpectedChoiceColumn()) {
             if ($hide_expected_answer === false) {
                 echo '<td width="5%">';
@@ -413,7 +412,11 @@ class ExerciseShowFunctions
                 $status = Display::label(get_lang('Correct'), 'success');
             }
             echo '<td width="20%">';
-            echo $status;
+            // Show only status for the selected student answer BT#16256
+            if ($studentChoice) {
+                echo $status;
+            }
+
             echo '</td>';
         }
 

+ 1 - 1
main/inc/lib/sessionmanager.lib.php

@@ -4630,7 +4630,7 @@ class SessionManager
     /**
      * Get the number of sessions.
      *
-     * @param  int $access_url_id ID of the URL we want to filter on (optional)
+     * @param int $access_url_id ID of the URL we want to filter on (optional)
      *
      * @return int Number of sessions
      */

+ 67 - 0
main/inc/lib/statistics.lib.php

@@ -164,6 +164,38 @@ class Statistics
         return $obj->number;
     }
 
+    /**
+     * @param string $startDate
+     * @param string $endDate
+     *
+     * @return array
+     */
+    public static function getCoursesWithActivity($startDate, $endDate)
+    {
+        $access_url_rel_course_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
+        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
+        $startDate = Database::escape_string($startDate);
+        $endDate = Database::escape_string($endDate);
+
+        $urlId = api_get_current_access_url_id();
+
+        if (api_is_multiple_url_enabled()) {
+            $sql = "SELECT DISTINCT(t.c_id) FROM $table t , $access_url_rel_course_table a
+                    WHERE
+                        t.c_id = a.c_id AND
+                        access_url_id='".$urlId."' AND
+                        access_date BETWEEN '$startDate' AND '$endDate'
+                    ";
+        } else {
+            $sql = "SELECT DISTINCT(t.c_id) FROM $table t
+                   access_date BETWEEN '$startDate' AND '$endDate' ";
+        }
+
+        $result = Database::query($sql);
+
+        return Database::store_result($result);
+    }
+
     /**
      * Count activities from track_e_default_table.
      *
@@ -626,6 +658,41 @@ class Statistics
         }
     }
 
+    public static function getLoginCount($startDate, $endDate)
+    {
+        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
+        $access_url_rel_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
+        $urlId = api_get_current_access_url_id();
+        $table_url = '';
+        $where_url = '';
+        if (api_is_multiple_url_enabled()) {
+            $table_url = ", $access_url_rel_user_table";
+            $where_url = " AND login_user_id=user_id AND access_url_id='".$urlId."'";
+        }
+        $startDate = Database::escape_string($startDate);
+        $endDate = Database::escape_string($endDate);
+
+        $sql = "
+                SELECT count(logins) count FROM (
+                    SELECT count(login_user_id) AS logins
+                    FROM $table $table_url 
+                    WHERE 
+                    login_date BETWEEN '$startDate' AND '$endDate'  
+                    $where_url 
+                    GROUP BY login_user_id
+                ) as t
+                ";
+
+        $res = Database::query($sql);
+        $totalLogin = 0;
+        $row = Database::fetch_array($res, 'ASSOC');
+        if ($row) {
+            $totalLogin = $row['count'];
+        }
+
+        return $totalLogin;
+    }
+
     /**
      * get the number of recent logins.
      *

+ 5 - 0
main/inc/lib/tracking.lib.php

@@ -1949,6 +1949,11 @@ class Tracking
         // protect data
         $student_id = (int) $student_id;
         $session_id = (int) $session_id;
+
+        if (empty($courseInfo) || empty($student_id)) {
+            return false;
+        }
+
         $courseId = $courseInfo['real_id'];
 
         $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);

+ 42 - 1
main/inc/lib/usermanager.lib.php

@@ -6572,7 +6572,7 @@ SQL;
         }
 
         if (self::userHasCareer($userId, $careerId) === false) {
-            $params = ['user_id' => $userId, 'career_id' => $careerId, 'created_at' => api_get_utc_datetime()];
+            $params = ['user_id' => $userId, 'career_id' => $careerId, 'created_at' => api_get_utc_datetime(), 'updated_at' => api_get_utc_datetime()];
             $table = Database::get_main_table(TABLE_MAIN_USER_CAREER);
             Database::insert($table, $params);
         }
@@ -6580,6 +6580,47 @@ SQL;
         return true;
     }
 
+    /**
+     * @param int   $userCareerId
+     * @param array $data
+     *
+     * @return bool
+     */
+    public static function updateUserCareer($userCareerId, $data)
+    {
+        if (!api_get_configuration_value('allow_career_users')) {
+            return false;
+        }
+
+        $params = ['extra_data' => $data, 'updated_at' => api_get_utc_datetime()];
+        $table = Database::get_main_table(TABLE_MAIN_USER_CAREER);
+        Database::update(
+            $table,
+            $params,
+            ['id = ?' => (int) $userCareerId]
+        );
+
+        return true;
+    }
+
+    /**
+     * @param int $userId
+     * @param int $careerId
+     *
+     * @return array
+     */
+    public static function getUserCareer($userId, $careerId)
+    {
+        $userId = (int) $userId;
+        $careerId = (int) $careerId;
+        $table = Database::get_main_table(TABLE_MAIN_USER_CAREER);
+
+        $sql = "SELECT * FROM $table WHERE user_id = $userId AND career_id = $careerId";
+        $result = Database::query($sql);
+
+        return Database::fetch_array($result, 'ASSOC');
+    }
+
     /**
      * @param int $userId
      * @param int $careerId

+ 3 - 1
main/inc/lib/userportal.lib.php

@@ -473,10 +473,12 @@ class IndexManager
 
         $resCats = Database::query($sqlGetSubCatList);
         $thereIsSubCat = false;
+
+        $htmlTitre = '';
+        $htmlListCat = '';
         if (Database::num_rows($resCats) > 0) {
             $htmlListCat = Display::page_header(get_lang('CatList'));
             $htmlListCat .= '<ul>';
-            $htmlTitre = '';
             while ($catLine = Database::fetch_array($resCats)) {
                 $category_has_open_courses = self::category_has_open_courses($catLine['code']);
                 if ($category_has_open_courses) {

+ 2 - 0
main/install/configuration.dist.php

@@ -1332,6 +1332,8 @@ requires extension "php-soap"  sudo apt-get install php-soap
 // $_configuration['ck_editor_enter_mode_value'] = 'CKEDITOR.ENTER_BR';
 
 // CREATE TABLE user_career (id INT AUTO_INCREMENT NOT NULL, user_id INT NOT NULL, career_id INT NOT NULL, created_at DATETIME NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
+// ALTER TABLE user_career ADD COLUMN extra_data LONGTEXT;
+// ALTER TABLE user_career ADD COLUMN updated_at DATETIME NOT NULL;
 // $_configuration['allow_career_users'] = false;
 
 // LP view menu location. Options: "left" or "right"

+ 2 - 1
main/mySpace/myStudents.php

@@ -16,6 +16,7 @@ if (!isset($_GET['course'])) {
 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;
@@ -545,7 +546,7 @@ $courses_in_session = [];
 
 // See #4676
 $drh_can_access_all_courses = false;
-if (api_is_drh() || api_is_platform_admin() || api_is_student_boss()) {
+if (api_is_drh() || api_is_platform_admin() || api_is_student_boss() || api_is_session_admin()) {
     $drh_can_access_all_courses = true;
 }
 

+ 0 - 2
main/survey/ch_personality.php

@@ -82,8 +82,6 @@ class ch_personality extends survey_question
                 $count++;
             }
         }
-        // The buttons for adding or removing
-        //$this->html .= parent :: add_remove_buttons($form_content);
     }
 
     /**

+ 1 - 1
main/survey/ch_score.php

@@ -8,7 +8,7 @@ class ch_score extends survey_question
 {
     /**
      * @param array $survey_data
-     * @param $form_content
+     * @param array $formData
      */
     public function createForm($survey_data, $formData)
     {

+ 4 - 10
main/survey/edit_meeting.php

@@ -61,13 +61,13 @@ $text = $form->addText(
 $allowSurveyAvailabilityDatetime = api_get_configuration_value('allow_survey_availability_datetime');
 
 if ($allowSurveyAvailabilityDatetime) {
-    $startDateElement = $form->addDateTimePicker('start_date', get_lang('StartDate'));
-    $endDateElement = $form->addDateTimePicker('end_date', get_lang('EndDate'));
+    $form->addDateTimePicker('start_date', get_lang('StartDate'));
+    $form->addDateTimePicker('end_date', get_lang('EndDate'));
     $form->addRule('start_date', get_lang('InvalidDate'), 'datetime');
     $form->addRule('end_date', get_lang('InvalidDate'), 'datetime');
 } else {
-    $startDateElement = $form->addElement('date_picker', 'start_date', get_lang('StartDate'));
-    $endDateElement = $form->addElement('date_picker', 'end_date', get_lang('EndDate'));
+    $form->addElement('date_picker', 'start_date', get_lang('StartDate'));
+    $form->addElement('date_picker', 'end_date', get_lang('EndDate'));
     $form->addRule('start_date', get_lang('InvalidDate'), 'date');
     $form->addRule('end_date', get_lang('InvalidDate'), 'date');
 }
@@ -203,14 +203,8 @@ if ($form->validate()) {
     $questionTable = Database::get_course_table(TABLE_SURVEY_QUESTION);
     $counter = 1;
     if (!empty($surveyData['iid'])) {
-        $questions = SurveyManager::get_questions($surveyData['iid']);
-        if (!empty($questions)) {
-            $questions = array_column($questions, 'question');
-        }
-
         foreach ($dates as $date) {
             $formattedDate = $date['start'].'@@'.$date['end'];
-
             if (!empty($date['id'])) {
                 $questionId = $date['id'];
                 $sql = "UPDATE $questionTable SET survey_question = '$formattedDate'

+ 1 - 1
main/survey/generate_link.php

@@ -7,7 +7,7 @@ if (!api_is_allowed_to_edit(false, true)) {
     api_not_allowed(true);
 }
 
-$survey_id = isset($_REQUEST['survey_id']) ? intval($_REQUEST['survey_id']) : null;
+$survey_id = isset($_REQUEST['survey_id']) ? (int) $_REQUEST['survey_id'] : null;
 
 if (empty($survey_id)) {
     api_not_allowed(true);

+ 0 - 4
main/survey/meeting.php

@@ -250,10 +250,6 @@ foreach ($students as $studentId) {
     }
     $column = 0;
     $table->setCellContents($row, $column, $name);
-    $class = 'class="row_odd"';
-    if ($row % 2) {
-        $class = 'class="row_even"';
-    }
     $row++;
 }
 if ($action === 'edit') {

+ 1 - 8
main/survey/preview.php

@@ -79,7 +79,6 @@ if (isset($_GET['show'])) {
     // Getting all the questions for this page and add them to a
     // multidimensional array where the first index is the page.
     // as long as there is no pagebreak fount we keep adding questions to the page
-    $questions_displayed = [];
     $paged_questions = [];
     $counter = 0;
     $sql = "SELECT * FROM $table_survey_question
@@ -153,11 +152,6 @@ if (isset($_GET['show'])) {
     }
 }
 
-$before = 0;
-if (isset($_GET['show']) && isset($paged_questions[$_GET['show'] - 1])) {
-    $before = count($paged_questions[$_GET['show'] - 1]);
-}
-
 $numberOfPages = SurveyManager::getCountPages($survey_data);
 
 // Displaying the form with the questions
@@ -189,8 +183,7 @@ if (is_array($questions) && count($questions) > 0) {
     }
     foreach ($questions as $key => &$question) {
         $ch_type = 'ch_'.$question['type'];
-        /** @var survey_question $display */
-        $display = new $ch_type();
+        $display = survey_question::createQuestion($question['type']);
         $form->addHtml('<div class="survey_question '.$ch_type.'">');
         $form->addHtml('<div style="float:left; font-weight: bold; margin-right: 5px;"> '.$counter.'. </div>');
         $form->addHtml('<div>'.Security::remove_XSS($question['survey_question']).'</div> ');

+ 1 - 1
main/survey/reporting.php

@@ -62,7 +62,7 @@ if (!empty($exportReport) && !empty($format)) {
     switch ($format) {
         case 'xls':
             $filename = 'survey_results_'.$survey_id.'.xlsx';
-            $data = SurveyUtil::export_complete_report_xls($survey_data, $filename, $userId);
+            SurveyUtil::export_complete_report_xls($survey_data, $filename, $userId);
             exit;
             break;
         case 'csv':

+ 8 - 13
main/survey/surveyUtil.class.php

@@ -460,19 +460,14 @@ class SurveyUtil
                         break;
                 }
 
-                $ch_type = 'ch_'.$question['type'];
-                if (class_exists($ch_type)) {
-                    /** @var survey_question $display */
-                    $display = new $ch_type();
-
-                    $url = api_get_self();
-                    $form = new FormValidator('question', 'post', $url);
-                    $form->addHtml('<div class="survey_question_wrapper"><div class="survey_question">');
-                    $form->addHtml($question['survey_question']);
-                    $display->render($form, $question, $finalAnswer);
-                    $form->addHtml('</div></div>');
-                    $content .= $form->returnForm();
-                }
+                $display = survey_question::createQuestion($question['type']);
+                $url = api_get_self();
+                $form = new FormValidator('question', 'post', $url);
+                $form->addHtml('<div class="survey_question_wrapper"><div class="survey_question">');
+                $form->addHtml($question['survey_question']);
+                $display->render($form, $question, $finalAnswer);
+                $form->addHtml('</div></div>');
+                $content .= $form->returnForm();
             }
         }
 

+ 0 - 12
main/survey/survey_invite.php

@@ -34,10 +34,6 @@ if (empty($survey_data)) {
 
 // Database table definitions
 $table_survey = Database::get_course_table(TABLE_SURVEY);
-$table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
-$table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
-$table_course = Database::get_main_table(TABLE_MAIN_COURSE);
-$table_user = Database::get_main_table(TABLE_MAIN_USER);
 
 $urlname = strip_tags(api_substr(api_html_entity_decode($survey_data['title'], ENT_QUOTES), 0, 40));
 if (api_strlen(strip_tags($survey_data['title'])) > 40) {
@@ -161,14 +157,6 @@ $form->addElement('checkbox', 'hide_link', '', get_lang('HideSurveyInvitationLin
 
 // Submit button
 $form->addButtonSave(get_lang('PublishSurvey'));
-$portal_url = api_get_path(WEB_PATH);
-if (api_is_multiple_url_enabled()) {
-    $access_url_id = api_get_current_access_url_id();
-    if ($access_url_id != -1) {
-        $url = api_get_access_url($access_url_id);
-        $portal_url = $url['url'];
-    }
-}
 
 // Show the URL that can be used by users to fill a survey without invitation
 $auto_survey_link = SurveyUtil::generateFillSurveyLink(

+ 1 - 7
main/survey/survey_list.php

@@ -67,12 +67,6 @@ if (!api_is_allowed_to_edit(false, true)) {
 
 $extend_rights_for_coachs = api_get_setting('extend_rights_for_coach_on_survey');
 
-// Database table definitions
-$table_survey = Database::get_course_table(TABLE_SURVEY);
-$table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
-$table_course = Database::get_main_table(TABLE_MAIN_COURSE);
-$table_user = Database::get_main_table(TABLE_MAIN_USER);
-
 // Language variables
 if (isset($_GET['search']) && $_GET['search'] == 'advanced') {
     $interbreadcrumb[] = [
@@ -165,7 +159,6 @@ switch ($action) {
         break;
 }
 
-// Header
 Display::display_header($tool_name, 'Survey');
 // Tool introduction
 Display::display_introduction_section('survey', 'left');
@@ -205,6 +198,7 @@ if (!api_is_session_general_coach() || $extend_rights_for_coachs == 'true') {
 echo '<a href="'.api_get_self().'?'.api_get_cidreq().'&amp;search=advanced">'.
     Display::return_icon('search.png', get_lang('Search'), '', ICON_SIZE_MEDIUM).'</a>';
 echo '</div>';
+
 // Load main content
 if (api_is_session_general_coach() && $extend_rights_for_coachs == 'false') {
     SurveyUtil::display_survey_list_for_coach();

+ 83 - 0
main/survey/survey_question.php

@@ -12,6 +12,89 @@ class survey_question
     /** @var FormValidator */
     private $form;
 
+    /**
+     * @param FormValidator $form
+     * @param array         $surveyData
+     */
+    public function addParentMenu(FormValidator $form, $surveyData)
+    {
+        $surveyId = $surveyData['survey_id'];
+        $questions = SurveyManager::get_questions($surveyId);
+
+        $options = [];
+        foreach ($questions as $question) {
+            $options[$question['question_id']] = strip_tags($question['question']);
+        }
+        $form->addSelect(
+            'parent_id',
+            get_lang('Parent'),
+            $options,
+            ['id' => 'parent_id', 'placeholder' => get_lang('SelectAnOption')]
+        );
+        $url = api_get_path(WEB_AJAX_PATH).'survey.ajax.php?'.api_get_cidreq();
+        $form->addHtml('
+            <script>
+                $(function() {                    
+                    $("#parent_id").on("change", function() {
+                        var questionId = $(this).val()
+                        var params = {
+                            "a": "load_question_options",
+                            "survey_id": "'.$surveyId.'",
+                            "question_id": questionId,
+                        };    
+                            
+                          $.ajax({
+                            type: "GET",
+                            url: "'.$url.'",
+                            data: params,
+                            async: false,
+                            success: function(data) {
+                                $("#parent_options").html(data);
+                            }
+                        });        
+                        console.log(); 
+                    });
+                });
+            </script>
+        ');
+        $form->addHtml('<div id="parent_options"></div>');
+        $form->addHidden('option_id', 0);
+    }
+
+    /**
+     * @param string $type
+     *
+     * @return survey_question
+     */
+    public static function createQuestion($type)
+    {
+        switch ($type) {
+            case 'comment':
+                return new ch_comment();
+            case 'dropdown':
+                return new ch_dropdown();
+            case 'multiplechoice':
+                return new ch_multiplechoice();
+            case 'multipleresponse':
+                return new ch_multipleresponse();
+            case 'open':
+                return new ch_open();
+            case 'pagebreak':
+                return new ch_pagebreak();
+            case 'percentage':
+                return new ch_percentage();
+            case 'personality':
+                return new ch_personality();
+            case 'score':
+                return new ch_score();
+            case 'yesno':
+                return new ch_yesno();
+            default:
+                api_not_allowed(true);
+                break;
+        }
+    }
+
     /**
      * Generic part of any survey question: the question field.
      *

+ 62 - 13
main/template/default/career/diagram.tpl

@@ -36,13 +36,10 @@
         function main(container)
         {
             // Checks if the browser is supported
-            if (!mxClient.isBrowserSupported())
-            {
+            if (!mxClient.isBrowserSupported()) {
                 // Displays an error message if the browser is not supported.
                 mxUtils.error('Browser is not supported!', 200, false);
-            }
-            else
-            {
+            } else {
                 // Disables the built-in context menu
                 mxEvent.disableContextMenu(container);
 
@@ -55,8 +52,7 @@
                 graph.setEnabled(false);
 
                 // Enables connect preview for the default edge style
-                graph.connectionHandler.createEdgeState = function(me)
-                {
+                graph.connectionHandler.createEdgeState = function(me) {
                     var edge = graph.createEdge(null, null, null, null, null);
 
                     return new mxCellState(this.graph.view, edge, this.graph.getCellStyle(edge));
@@ -78,7 +74,6 @@
                     //var v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30);
                     //var v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30);
                     //var e1 = graph.insertEdge(parent, null, '', v1, v2);
-
                     {% for vertex in group_list %}
                         {{ vertex }}
                     {% endfor %}
@@ -99,9 +94,9 @@
                     graph.getModel().endUpdate();
                 }
             }
-        };
+        }
 
-        $(document).ready(function () {
+        $(function () {
             main(document.getElementById('graphContainer'));
 
             var svg1 = document.getElementsByTagName("svg")[0];
@@ -109,12 +104,66 @@
             var widthValue = data.width + 100;
             var heightValue = data.height + 50;
 
-            var att = document.createAttributeNS(null, "viewBox");       // Create a "viewBox" attribute
-            att.value = '0 0 ' + widthValue + ' '+heightValue;                           // Set the value of the viewBox attribute
+            var att = document.createAttributeNS(null, "viewBox");
+            att.value = '0 0 ' + widthValue + ' '+heightValue;
             svg1.setAttributeNode(att);
 
+            //$('[data-toggle="popover"]').popover({container: 'body'});
+            //$('.popup').popover({trigger: 'hover'});
+
+            $(".popup").qtip({
+                content: {
+                    text: function(event, api) {
+                        var item = $(this);
+                        var itemId = $(this).attr("id");
+
+                        var desc = $(this).attr("data-description");
+                        var period = $(this).attr("data-period");
+                        var teacherText = $(this).attr("data-teacher-text");
+                        var teacher = $(this).attr("data-teacher");
+                        var score = $(this).attr("data-score");
+                        var value = $(this).attr("data-score-value");
+                        var info = $(this).attr("data-info");
+
+                        var textToShow = desc
+                            + '<br />'+ period + '<br />'
+                            + teacherText +': '+ teacher + '<br />'
+                            + score +': '+ value + '<br />'
+                            + '<br />'+ info + '<br />'
+                        ;
+
+                        return textToShow;
+                    }
+                },
+                events: {
+                    render: function(event, api) {
+                        var popup = $(api.elements.target);
+                        var bg = popup.attr("data-background-color");
+                        var color = popup.attr("data-color");
+                        var borderColor = popup.attr("data-border-color");
+
+                        console.log(bg);
+                        console.log(color);
+                        console.log(borderColor);
+                        // Grab the tooltip element from the API
+                        //var tooltip = api.elements.tooltip;
+
+                        $(this).css('background-color', bg);
+                        $(this).css('color', color);
+                        $(this).css('border-color', borderColor);
+                    }
+                },
+                position: {
+                    my: 'bottom left',  // Position my top left...
+                    at: 'top right', // at the bottom right of...
+                    adjust: {
+                        x: -55,
+                        y: -55
+                    }
+                }
+            });
+
         });
     </script>
-
     {{ content }}
 {% endblock %}

+ 0 - 1
main/tracking/courseLog.php

@@ -653,7 +653,6 @@ if ($export_csv) {
     array_unshift($csvContentInSession, $csv_headers);
 
     if ($sessionId) {
-        $sessionData = [];
         $sessionInfo = api_get_session_info($sessionId);
         $sessionDates = SessionManager::parseSessionDates($sessionInfo);
 

+ 7 - 15
main/user/career_diagram.php

@@ -1,8 +1,6 @@
 <?php
 /* For licensing terms, see /license.txt */
 
-use Fhaculty\Graph\Graph;
-
 /*
  *
  * Requires extra_field_values.value to be longtext to save diagram:
@@ -12,14 +10,13 @@ UPDATE extra_field_values SET updated_at = NULL WHERE CAST(updated_at AS CHAR(20
 ALTER TABLE extra_field_values modify column value longtext null;
 */
 
-$cidReset = true;
 require_once __DIR__.'/../inc/global.inc.php';
 
 if (api_get_configuration_value('allow_career_diagram') == false) {
     api_not_allowed(true);
 }
 
-$this_section = SECTION_PLATFORM_ADMIN;
+$this_section = SECTION_COURSES;
 
 $careerId = isset($_GET['career_id']) ? $_GET['career_id'] : 0;
 
@@ -41,6 +38,8 @@ if ($allow === false) {
 }
 
 $htmlHeadXtra[] = api_get_js('jsplumb2.js');
+$htmlHeadXtra[] = api_get_asset('qtip2/jquery.qtip.min.js');
+$htmlHeadXtra[] = api_get_css_asset('qtip2/jquery.qtip.min.css');
 
 // setting breadcrumbs
 $interbreadcrumb[] = [
@@ -54,13 +53,6 @@ $interbreadcrumb[] = [
 ];
 
 $extraFieldValue = new ExtraFieldValue('career');
-$item = $extraFieldValue->get_values_by_handler_and_field_variable(
-    $careerId,
-    'career_diagram',
-    false,
-    false,
-    false
-);
 
 // Check urls
 $itemUrls = $extraFieldValue->get_values_by_handler_and_field_variable(
@@ -89,10 +81,10 @@ if (!empty($itemUrls) && !empty($itemUrls['value'])) {
 
 $tpl = new Template(get_lang('Diagram'));
 $html = Display::page_subheader2($careerInfo['name'].$urlToString);
-if (!empty($item) && isset($item['value']) && !empty($item['value'])) {
-    /** @var Graph $graph */
-    $graph = UnserializeApi::unserialize('career', $item['value']);
-    $html .= Career::renderDiagramByColumn($graph, $tpl);
+$diagram = Career::renderDiagramByColumn($careerInfo, $tpl, $userId);
+
+if (!empty($diagram)) {
+    $html .= $diagram;
 } else {
     Display::addFlash(
         Display::return_message(

+ 3 - 0
plugin/customcertificate/lang/english.php

@@ -71,3 +71,6 @@ $strings['InfoFromDefaultCertificate'] = "The content of the certificate is base
 $strings['to'] = " to ";
 $strings['formatDownloadDate'] = " to %sth %s, %s";
 $strings['PrintCertificate'] = "Print certificate";
+$strings['QuestionDelete'] = "Do you want to delete the specific diploma and use the default certificate?";
+$strings['SuccessDelete'] = "Successfully deleted";
+$strings['ProblemDelete'] = "Problem deleting the certificate";

+ 3 - 0
plugin/customcertificate/lang/spanish.php

@@ -73,3 +73,6 @@ $strings['to'] = " a ";
 $strings['formatDownloadDate'] = " a %s de %s de %s";
 $strings['MessageUpdate'] = "El proceso de actualización ha terminado";
 $strings['PrintCertificate'] = "Imprimir certificado";
+$strings['QuestionDelete'] = "¿Desea eliminar el diploma específico y volver a usar el certificado por defecto?";
+$strings['SuccessDelete'] = "Borrado con éxito";
+$strings['ProblemDelete'] = "Hubo un problema al borrar el certificado";

+ 53 - 0
plugin/customcertificate/src/CustomCertificatePlugin.php

@@ -285,4 +285,57 @@ class CustomCertificatePlugin extends Plugin
             }
         }
     }
+
+    /**
+     * Get certificate info.
+     *
+     * @param int $courseId
+     * @param int $sessionId
+     * @param int $accessUrlId
+     *
+     * @return array
+     */
+    public static function getInfoCertificate($courseId, $sessionId, $accessUrlId)
+    {
+        $courseId = (int) $courseId;
+        $sessionId = (int) $sessionId;
+        $accessUrlId = !empty($accessUrlId) ? (int) $accessUrlId : 1;
+
+        $table = Database::get_main_table(self::TABLE_CUSTOMCERTIFICATE);
+        $sql = "SELECT * FROM $table
+                WHERE 
+                    c_id = $courseId AND 
+                    session_id = $sessionId AND
+                    access_url_id = $accessUrlId";
+        $result = Database::query($sql);
+        $resultArray = [];
+        if (Database::num_rows($result) > 0) {
+            $resultArray = Database::fetch_array($result);
+        }
+
+        return $resultArray;
+    }
+
+    /**
+     * Get default certificate info.
+     *
+     * @param int $accessUrlId
+     *
+     * @return array
+     */
+    public static function getInfoCertificateDefault($accessUrlId)
+    {
+        $accessUrlId = !empty($accessUrlId) ? (int) $accessUrlId : 1;
+
+        $table = Database::get_main_table(self::TABLE_CUSTOMCERTIFICATE);
+        $sql = "SELECT * FROM $table
+                WHERE certificate_default = 1 AND access_url_id = $accessUrlId";
+        $result = Database::query($sql);
+        $resultArray = [];
+        if (Database::num_rows($result) > 0) {
+            $resultArray = Database::fetch_array($result);
+        }
+
+        return $resultArray;
+    }
 }

+ 51 - 0
plugin/customcertificate/src/customcertificate.ajax.php

@@ -0,0 +1,51 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+/**
+ * Responses to AJAX calls.
+ *
+ * @package chamilo.plugin.customcertificate
+ */
+$cidReset = true;
+
+require_once __DIR__.'/../../../main/inc/global.inc.php';
+
+api_block_anonymous_users();
+
+$plugin = CustomCertificatePlugin::create();
+$enable = $plugin->get('enable_plugin_customcertificate') == 'true';
+
+if ($enable === false) {
+    api_not_allowed();
+}
+
+$action = isset($_GET['a']) ? $_GET['a'] : null;
+
+switch ($action) {
+    case 'delete_certificate':
+        $table = Database::get_main_table(CustomCertificatePlugin::TABLE_CUSTOMCERTIFICATE);
+        $courseId = isset($_POST['courseId']) ? (int) $_POST['courseId'] : 0;
+        $sessionId = isset($_POST['sessionId']) ? (int) $_POST['sessionId'] : 0;
+        $accessUrlId = isset($_POST['accessUrlId']) ? (int) $_POST['accessUrlId'] : 1;
+
+        if (!empty($courseId)) {
+            $sql = "DELETE FROM $table
+                    WHERE
+                        c_id = $courseId AND 
+                        session_id = $sessionId AND
+                        access_url_id = $accessUrlId";
+            Database::query($sql);
+            echo Display::return_message(
+                get_plugin_lang('SuccessDelete', 'CustomCertificatePlugin'),
+                'success'
+            );
+        } else {
+            echo Display::return_message(
+                get_plugin_lang('ProblemDelete', 'CustomCertificatePlugin'),
+                'error',
+                false
+            );
+        }
+
+        break;
+}

+ 38 - 24
plugin/customcertificate/src/index.php

@@ -1,6 +1,7 @@
 <?php
 /* For licensing terms, see /license.txt */
 
+$useDefault = false;
 $isDefault = isset($_GET['default']) ? (int) $_GET['default'] : null;
 
 if ($isDefault === 1) {
@@ -64,16 +65,34 @@ $htmlHeadXtra[] = api_get_asset('cropper/dist/cropper.min.js');
 $htmlHeadXtra[] = api_get_css(
     api_get_path(WEB_PLUGIN_PATH).'customcertificate/resources/css/form.css'
 );
+$htmlHeadXtra[] = '<script>
+    $(function () {
+        $("#delete_certificate").click(function (e) {
+            e.preventDefault();
+            e.stopPropagation();
+
+            if (confirm("'.$plugin->get_lang("QuestionDelete").'")) {
+                var courseId = '.$courseId.';
+                var sessionId = '.$sessionId.';
+                var accessUrlId = '.$accessUrlId.';
+                var plugin_path = "'.api_get_path(WEB_PLUGIN_PATH).'";
+                var ajax_path = plugin_path + "customcertificate/src/customcertificate.ajax.php?a=delete_certificate";
+                $.ajax({
+                    data: {courseId: courseId, sessionId: sessionId, accessUrlId: accessUrlId},
+                    url: ajax_path,
+                    type: "POST",
+                    success: function (response) {
+                        window.location.reload();
+                    }
+                }); 
+            }
+        });
+
+    });
+</script>';
 
 // Get info certificate
-$infoCertificate = Database::select(
-    '*',
-    $table,
-    ['where' => [
-        'access_url_id = ? AND c_id = ? AND session_id = ?' => [$accessUrlId, $courseId, $sessionId], ],
-    ],
-    'first'
-);
+$infoCertificate = CustomCertificatePlugin::getInfoCertificate($courseId, $sessionId, $accessUrlId);
 
 $form = new FormValidator(
     'formEdit',
@@ -172,12 +191,7 @@ if ($form->validate()) {
 
         // Certificate Default
         if (intval($formValues['use_default'] == 1)) {
-            $infoCertificateDefault = Database::select(
-                '*',
-                $table,
-                ['where' => ['access_url_id = ? AND certificate_default = ? ' => [$accessUrlId, 1]]],
-                'first'
-            );
+            $infoCertificateDefault = CustomCertificatePlugin::getInfoCertificateDefault($accessUrlId);
             if (!empty($infoCertificateDefault)) {
                 foreach ($fieldList as $field) {
                     if (!empty($infoCertificateDefault[$field]) && !$checkLogo[$field]) {
@@ -199,14 +213,9 @@ if ($form->validate()) {
 }
 
 if (empty($infoCertificate)) {
-    $infoCertificate = Database::select(
-        '*',
-        $table,
-        ['where' => ['access_url_id = ? AND certificate_default = ? ' => [$accessUrlId, 1]]],
-        'first'
-    );
+    $infoCertificate = CustomCertificatePlugin::getInfoCertificateDefault($accessUrlId);
 
-    if (!is_array($infoCertificate)) {
+    if (empty($infoCertificate)) {
         $infoCertificate = [
             'type_date_expediction' => '',
             'year' => '',
@@ -215,9 +224,7 @@ if (empty($infoCertificate)) {
             'date_change' => '',
         ];
     }
-    if (!empty($infoCertificate)) {
-        $useDefault = true;
-    }
+    $useDefault = true;
 }
 
 // Display the header
@@ -226,6 +233,13 @@ $actionsLeft = Display::url(
     Display::return_icon('certificate.png', get_lang('Certificate'), '', ICON_SIZE_MEDIUM),
     'print_certificate.php'.$urlParams
 );
+if (!empty($courseId) && !$useDefault) {
+    $actionsLeft .= Display::url(
+        Display::return_icon('delete.png', $plugin->get_lang('DeleteCertificate'), '', ICON_SIZE_MEDIUM),
+        'delete_certificate.php'.$urlParams,
+        ['id' => 'delete_certificate']
+    );
+}
 
 echo Display::toolbarAction(
     'toolbar-document',

+ 3 - 17
plugin/customcertificate/src/print_certificate.php

@@ -46,7 +46,7 @@ if (empty($courseCode)) {
 }
 
 if (empty($sessionId)) {
-    $sessionId = isset($_REQUEST['session_id']) ? (int) $_REQUEST['session_id'] : '';
+    $sessionId = isset($_REQUEST['session_id']) ? (int) $_REQUEST['session_id'] : 0;
 }
 
 $accessUrlId = api_get_current_access_url_id();
@@ -83,28 +83,14 @@ $useDefault = false;
 $path = api_get_path(SYS_UPLOAD_PATH).'certificates/';
 
 // Get info certificate
-$infoCertificate = Database::select(
-    '*',
-    $table,
-    ['where' => ['access_url_id = ? AND c_id = ? AND session_id = ?' => [$accessUrlId, $courseId, $sessionId]]],
-    'first'
-);
+$infoCertificate = CustomCertificatePlugin::getInfoCertificate($courseId, $sessionId, $accessUrlId);
 
 if (!is_array($infoCertificate)) {
     $infoCertificate = [];
 }
 
 if (empty($infoCertificate)) {
-    $infoCertificate = Database::select(
-        '*',
-        Database::get_main_table(CustomCertificatePlugin::TABLE_CUSTOMCERTIFICATE),
-        ['where' => ['access_url_id = ? AND certificate_default = ? ' => [$accessUrlId, 1]]],
-        'first'
-    );
-
-    if (!is_array($infoCertificate)) {
-        $infoCertificate = [];
-    }
+    $infoCertificate = CustomCertificatePlugin::getInfoCertificateDefault($accessUrlId);
 
     if (empty($infoCertificate)) {
         Display::display_header($plugin->get_lang('PrintCertificate'));