فهرست منبع

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

Conflicts:
	main/lang/english/trad4all.inc.php
	main/lang/spanish/trad4all.inc.php
Angel Fernando Quiroz Campos 10 سال پیش
والد
کامیت
c2edc89c48

+ 1 - 0
index.php

@@ -165,6 +165,7 @@ $controller->tpl->assign('navigation_course_links', $controller->return_navigati
 $controller->tpl->assign('notice_block', $controller->return_notice());
 $controller->tpl->assign('main_navigation_block', $controller->return_navigation_links());
 $controller->tpl->assign('help_block', $controller->return_help());
+$controller->tpl->assign('certificates_search_block', $controller->returnCertificatesSearchBlock());
 
 if (api_is_platform_admin() || api_is_drh()) {
     $controller->tpl->assign('skills_block', $controller->return_skills_links());

+ 1 - 1
main/admin/group_add.php

@@ -67,7 +67,7 @@ $form->addElement('file', 'picture', get_lang('AddPicture'));
 $allowed_picture_types = array('jpg', 'jpeg', 'png', 'gif');
 $form->addRule(
     'picture',
-    get_lang('OnlyImagesAllowed').' ('.implode(',', $allowed_picture_types).')',
+    get_lang('OnlyImagesAllowed').' ('.implode(', ', $allowed_picture_types).')',
     'filetype',
     $allowed_picture_types
 );

+ 112 - 5
main/cron/create_course_sessions.php

@@ -2,7 +2,7 @@
 /* For licensing terms, see /license.txt */
 /**
  * Create course sessions procedure. It creates sessions for courses that haven't it yet.
- * If today is greater than OFFSET, it will create them also for the next month.
+ * If today is greater than OFFSET, it will create them also for the next quarter
  * @package chamilo.cron
  * @author Imanol Losada <imanol.losada@beeznest.com>
  */
@@ -32,6 +32,106 @@ function getMonthFirstAndLastDates($initialDate = null)
     return array('startDate' => $startDate, 'endDate' => $endDate);
 }
 
+/**
+ * Same as month, but for quarters
+ * @param   array   $initialDate First day of the quarter
+ * @return  array   First and last days of the quarter
+ */
+function getQuarterFirstAndLastDates($initialDate = null)
+{
+    $startDate = $initialDate ? $initialDate : date("Y-m-01");
+    $month = getQuarterFirstMonth(getQuarter(date('m', $startDate)));
+    $startDate = substr($startDate, 0, 5) . $month . '-01';
+    $nextQuarterStartDate = date('Y-m-d', api_strtotime($startDate.' + 3 month'));
+    $endDate = date('Y-m-d', api_strtotime($nextQuarterStartDate.' - 1 minute'));
+    return array('startDate' => $startDate, 'endDate' => $endDate);
+}
+
+/**
+ * Returns a quarter from a month
+ * @param   string  The month (digit), with or without leading 0
+ * @return  int The yearly quarter (1, 2, 3 or 4) in which this month lies
+ */
+function getQuarter($month)
+{
+    $quarter = 1;
+    // Remove the leading 0 if any
+    if (substr($month, 0, 1) == '0') {
+        $month = substr($month, 1);
+    }
+    // reduce to 4 quarters: 1..3=1; 4..6=2
+    switch ($month) {
+        case 1:
+            //no break
+        case 2:
+            //no break
+        case 3:
+            $quarter = 1;
+            break;
+        case 4:
+            //no break
+        case 5:
+            //no break
+        case 6:
+            $quarter = 2;
+            break;
+        case 7:
+            //no break
+        case 8:
+            //no break
+        case 9:
+            $quarter = 3;
+            break;
+        case 10:
+            //no break
+        case 11:
+            //no break
+        case 12:
+            $quarter = 4;
+            break;
+    }
+    return $quarter;
+}
+
+/**
+ * Returns the first month of the quarter
+ * @param   int Quarter
+ * @return  string Number of the month, with leading 0
+ */
+function getQuarterFirstMonth($quarter)
+{
+    switch ($quarter) {
+        case 1:
+            return '01';
+        case 2:
+            return '04';
+        case 3:
+            return '07';
+        case 4:
+            return '10';
+    }
+    return false;
+}
+
+/**
+ * Get the quarter in Roman letters
+ * @param   int Quarter
+ * @return  string  Roman letters
+ */
+function getQuarterRoman($quarter)
+{
+    switch ($quarter) {
+        case 1:
+            return 'I';
+        case 2:
+            return 'II';
+        case 3:
+            return 'III';
+        case 4:
+            return 'IV';
+    }
+}
+
 /**
  * Creates one session per course with $administratorId as the creator and
  * adds it to the session starting on $startDate and finishing on $endDate
@@ -50,7 +150,13 @@ function createCourseSessions($courses, $administratorId, $startDate, $endDate)
     echo "\n=====================================================================================\n\n";
     // Loop through courses creating one session per each and adding them
     foreach ($courses as $course) {
-        $sessionName = $course['title']." (".date("m/Y", api_strtotime($startDate)).")";
+        //$period = date("m/Y", api_strtotime($startDate));
+        $month = date("m", api_strtotime($startDate));
+        $year = date("Y", api_strtotime($startDate));
+        $quarter = getQuarter($month);
+        $quarter = getQuarterRoman($quarter);
+        $period = $year . '-' . $quarter;
+        $sessionName = '[' . $period . '] ' . $course['title'];
         $sessionId = SessionManager::create_session(
             $sessionName,
             $startDate,
@@ -82,14 +188,15 @@ if (!$lastingAdministrators) {
 $administratorId = intval($administrators[$lastingAdministrators - 1]['user_id']);
 
 // Creates course sessions for the current month
-$dates = getMonthFirstAndLastDates(date('Y-m-').'01');
+$dates = getQuarterFirstAndLastDates(date('Y-m-').'01');
 // Get courses that don't have any session
 $courses = CourseManager::getCoursesWithoutSession($dates['startDate'], $dates['endDate']);
 createCourseSessions($courses, $administratorId, $dates['startDate'], $dates['endDate']);
 
 // Creates course sessions for the following month
-if (date("Y-m-d") >= date("Y-m-".OFFSET)) {
-    $dates = getMonthFirstAndLastDates(date("Y-m-d", api_strtotime(date("Y-m-01")." + 1 month")));
+$offsetDay = intval(substr($dates['endDate'], 8, 2)) - OFFSET;
+if (date("Y-m-d") >= date(substr($dates['endDate'], 0, 8) . $offsetDay)) {
+    $dates = getQuarterFirstAndLastDates(date("Y-m-d", api_strtotime(date("Y-m-01")." + 3 month")));
     // Get courses that don't have any session the next month
     $courses = CourseManager::getCoursesWithoutSession($dates['startDate'], $dates['endDate']);
     createCourseSessions($courses, $administratorId, $dates['startDate'], $dates['endDate']);

+ 1 - 1
main/exercice/exercise.class.php

@@ -2837,7 +2837,7 @@ class Exercise
                                     }
                                 } else {
                                     if ($answerType == DRAGGABLE) {
-                                        $user_answer = Display::label(get_lang('NotCorrect'), 'danger');
+                                        $user_answer = Display::label(get_lang('Incorrect'), 'danger');
                                     } else {
                                         $user_answer = Display::span(
                                             $real_list[$s_user_answer],

+ 2 - 2
main/gradebook/certificate_report.php

@@ -34,7 +34,7 @@ if (api_is_student_boss()) {
     $userList = GroupPortalManager::getGroupUsersByUser($userId);
     $sessionsList = SessionManager::getSessionsFollowedForGroupAdmin($userId);
 } else {
-    $sessionsList = SessionManager::getSessionsCoachedByUser($userId);
+    $sessionsList = SessionManager::getSessionsCoachedByUser($userId, false, api_is_platform_admin());
 }
 
 foreach ($sessionsList as $session) {
@@ -60,7 +60,7 @@ if ($selectedSession > 0) {
     if (api_is_student_boss()) {
         $coursesList = CourseManager::getCoursesFollowedByGroupAdmin($userId);
     } else {
-        $coursesList = CourseManager::get_courses_list_by_user_id($userId);
+        $coursesList = CourseManager::get_courses_list_by_user_id($userId, false, true);
 
         if (is_array($coursesList)) {
             foreach ($coursesList as &$course) {

+ 114 - 0
main/gradebook/lib/GradebookUtils.php

@@ -1173,4 +1173,118 @@ class GradebookUtils
                WHERE id = '.$id;
         Database::query($sql);
     }
+
+    /**
+     * 
+     * Get the achieved certificates for a user in courses
+     * @param int $userId The user id
+     * @param type $includeNonPublicCertificates Whether include the non-plublic certificates
+     * @return array
+     */
+    public static function getUserCertificatesInCourses($userId, $includeNonPublicCertificates = true)
+    {
+        $userId = intval($userId);
+        $courseList = [];
+
+        $courses = CourseManager::get_courses_list_by_user_id($userId);
+
+        foreach ($courses as $course) {
+            if (!$includeNonPublicCertificates) {
+                $allowPublicCertificates = api_get_course_setting('allow_public_certificates', $course['code']);
+
+                if (empty($allowPublicCertificates)) {
+                    continue;
+                }
+            }
+
+            $courseGradebookCategory = Category::load(null, null, $course['code']);
+
+            if (empty($courseGradebookCategory)) {
+                continue;
+            }
+
+            $courseGradebookId = $courseGradebookCategory[0]->get_id();
+
+            $certificateInfo = GradebookUtils::get_certificate_by_user_id($courseGradebookId, $userId);
+
+            if (empty($certificateInfo)) {
+                continue;
+            }
+
+            $courseInfo = api_get_course_info($course['code']);
+
+            $courseList[] = [
+                'course' => $courseInfo['title'],
+                'score' => $certificateInfo['score_certificate'],
+                'date' => api_format_date($certificateInfo['created_at'], DATE_FORMAT_SHORT),
+                'link' => api_get_path(WEB_PATH) . "certificates/index.php?id={$certificateInfo['id']}"
+            ];
+        }
+
+        return $courseList;
+    }
+
+    /**
+     * Get the achieved certificates for a user in course sessions
+     * @param int $userId The user id
+     * @param type $includeNonPublicCertificates Whether include the non-plublic certificates
+     * @return array
+     */
+    public static function getUserCertificatesInSessions($userId, $includeNonPublicCertificates = true)
+    {
+        $userId = intval($userId);
+        $sessionList = [];
+
+        $sessions = SessionManager::get_sessions_by_user($userId);
+
+        foreach ($sessions as $session) {
+            if (empty($session['courses'])) {
+                continue;
+            }
+
+            $sessionCourses = SessionManager::get_course_list_by_session_id($session['session_id']);
+
+            foreach ($sessionCourses as $course) {
+                if (!$includeNonPublicCertificates) {
+                    $allowPublicCertificates = api_get_course_setting('allow_public_certificates', $course['code']);
+
+                    if (empty($allowPublicCertificates)) {
+                        continue;
+                    }
+                }
+
+                $courseGradebookCategory = Category::load(
+                    null,
+                    null,
+                    $course['code'],
+                    null,
+                    null,
+                    $session['session_id']
+                );
+
+                if (empty($courseGradebookCategory)) {
+                    continue;
+                }
+
+                $courseGradebookId = $courseGradebookCategory[0]->get_id();
+
+                $certificateInfo = GradebookUtils::get_certificate_by_user_id($courseGradebookId, $userId);
+
+                if (empty($certificateInfo)) {
+                    continue;
+                }
+
+                $sessionList[] = [
+                    'session' => $session['session_name'],
+                    'course' => $course['title'],
+                    'score' => $certificateInfo['score_certificate'],
+                    'date' => api_format_date($certificateInfo['created_at'], DATE_FORMAT_SHORT),
+                    'link' => api_get_path(WEB_PATH) . "certificates/index.php?id={$certificateInfo['id']}"
+                ];
+            }
+        }
+
+        return $sessionList;
+    }
+
 }

+ 48 - 0
main/gradebook/my_certificates.php

@@ -0,0 +1,48 @@
+<?php
+
+/* For licensing terms, see /license.txt */
+/**
+ * List of achieved certificates by the current user
+ * @author Angel Fernando Quiroz Campos <angel.quiroz@beeznest.com>
+ * @package chamilo.gradebook
+ */
+$cidReset = true;
+
+require_once '../inc/global.inc.php';
+
+if (api_is_anonymous()) {
+    api_not_allowed(true);
+}
+
+$userId = api_get_user_id();
+
+$courseList = GradebookUtils::getUserCertificatesInCourses($userId);
+$sessionList = GradebookUtils::getUserCertificatesInSessions($userId);
+
+$template = new Template(get_lang('MyCertificates'));
+
+$template->assign('course_list', $courseList);
+$template->assign('session_list', $sessionList);
+$content = $template->fetch('default/gradebook/my_certificates.tpl');
+
+if (empty($courseList) || empty($sessionList)) {
+    $template->assign(
+        'message',
+        Display::return_message(get_lang('YouNotYetAchievedCertificates'), 'warning')
+    );
+}
+
+if (api_get_setting('allow_public_certificates') == 'true') {
+    $template->assign(
+        'actions',
+        Display::toolbarButton(
+            get_lang('SearchCertificates'),
+            api_get_path(WEB_CODE_PATH) . "gradebook/search.php",
+            'search',
+            'info'
+        )
+    );
+}
+
+$template->assign('content', $content);
+$template->display_one_col_template();

+ 85 - 0
main/gradebook/search.php

@@ -0,0 +1,85 @@
+<?php
+
+/* For licensing terms, see /license.txt */
+/**
+ * Search user certificates if them are publics
+ * @author Angel Fernando Quiroz Campos <angel.quiroz@beeznest.com>
+ * @package chamilo.gradebook
+ */
+use \ChamiloSession as Session;
+
+$cidReset = true;
+
+require_once '../inc/global.inc.php';
+
+if (api_get_setting('allow_public_certificates') != 'true') {
+    api_not_allowed(
+        true,
+        Display::return_message(get_lang('CertificatesNotPublic'), 'warning')
+    );
+}
+
+$userId = isset($_GET['id']) ? intval($_GET['id']) : 0;
+
+$userList = $userInfo = $courseList = $sessionList = [];
+
+$searchForm = new FormValidator('search_form', 'post', null, null);
+$searchForm->addText('firstname', get_lang('Firstname'));
+$searchForm->addText('lastname', get_lang('Lastname'));
+$searchForm->addButtonSearch();
+
+if ($searchForm->validate()) {
+    $firstname = $searchForm->getSubmitValue('firstname');
+    $lastname = $searchForm->getSubmitValue('lastname');
+
+    $userList = UserManager::getUserByName($firstname, $lastname);
+
+    if (empty($userList)) {
+        Session::write('message', Display::return_message(get_lang('NoResults'), 'warning'));
+
+        Header::location(api_get_self());
+    }
+} elseif ($userId > 0) {
+    $userInfo = api_get_user_info($userId);
+
+    if (empty($userInfo)) {
+        Session::write('message', Display::return_message(get_lang('NoUser'), 'warning'));
+
+        Header::location(api_get_self());
+    }
+
+    $courseList = GradebookUtils::getUserCertificatesInCourses($userId, false);
+    $sessionList = GradebookUtils::getUserCertificatesInSessions($userId, false);
+
+    if (empty($courseList) && empty($sessionList)) {
+        Session::write(
+            'message',
+            Display::return_message(
+                sprintf(get_lang('TheUserXNotYetAchievedCertificates'), $userInfo['complete_name']),
+                'warning'
+            )
+        );
+
+        Header::location(api_get_self());
+    }
+}
+
+$template = new Template(get_lang('SearchCertificates'));
+
+$template->assign('search_form', $searchForm->returnForm());
+$template->assign('user_list', $userList);
+$template->assign('user_info', $userInfo);
+$template->assign('course_list', $courseList);
+$template->assign('session_list', $sessionList);
+
+if (Session::has('message')) {
+    $template->assign('message', Session::read('message'));
+    Session::erase('message');
+}
+
+$content = $template->fetch('default/gradebook/search.tpl');
+
+$template->assign('header', get_lang('SearchCertificates'));
+$template->assign('content', $content);
+
+$template->display_one_col_template();

+ 29 - 21
main/inc/lib/course.lib.php

@@ -2571,10 +2571,11 @@ class CourseManager
      * Get list of courses for a given user
      * @param int $user_id
      * @param boolean $include_sessions Whether to include courses from session or not
-     * @return array    List of codes and db names
+     * @param boolean $adminGetsAllCourses If the user is platform admin, whether he gets all the courses or just his. Note: This does *not* include all sessions
+     * @return array    List of codes and db name
      * @author isaac flores paz
      */
-    public static function get_courses_list_by_user_id($user_id, $include_sessions = false)
+    public static function get_courses_list_by_user_id($user_id, $include_sessions = false, $adminGetsAllCourses = false)
     {
         $user_id = intval($user_id);
         $course_list = array();
@@ -2584,15 +2585,22 @@ class CourseManager
         $tbl_user_course_category = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
         $special_course_list = self::get_special_course_list();
 
-        $with_special_courses = $without_special_courses = '';
-        if (!empty($special_course_list)) {
-            $sc_string = '"' . implode('","', $special_course_list) . '"';
-            $with_special_courses = ' course.code IN (' . $sc_string . ')';
-            $without_special_courses = ' AND course.code NOT IN (' . $sc_string . ')';
-        }
-
-        if (!empty($with_special_courses)) {
+        if ($adminGetsAllCourses && UserManager::is_admin($user_id)) {
+            // get the whole courses list
             $sql = "SELECT DISTINCT(course.code), course.id as real_id
+                FROM $tbl_course course";
+
+        } else {
+
+            $with_special_courses = $without_special_courses = '';
+            if (!empty($special_course_list)) {
+                $sc_string = '"' . implode('","', $special_course_list) . '"';
+                $with_special_courses = ' course.code IN (' . $sc_string . ')';
+                $without_special_courses = ' AND course.code NOT IN (' . $sc_string . ')';
+            }
+
+            if (!empty($with_special_courses)) {
+                $sql = "SELECT DISTINCT(course.code), course.id as real_id
                     FROM    " . $tbl_course_user . " course_rel_user
                     LEFT JOIN " . $tbl_course . " course
                     ON course.id = course_rel_user.c_id
@@ -2601,23 +2609,23 @@ class CourseManager
                     WHERE  $with_special_courses
                     GROUP BY course.code
                     ORDER BY user_course_category.sort,course.title,course_rel_user.sort ASC";
-            $rs_special_course = Database::query($sql);
-            if (Database::num_rows($rs_special_course) > 0) {
-                while ($result_row = Database::fetch_array($rs_special_course)) {
-                    $result_row['special_course'] = 1;
-                    $course_list[] = $result_row;
-                    $codes[] = $result_row['real_id'];
+                $rs_special_course = Database::query($sql);
+                if (Database::num_rows($rs_special_course) > 0) {
+                    while ($result_row = Database::fetch_array($rs_special_course)) {
+                        $result_row['special_course'] = 1;
+                        $course_list[] = $result_row;
+                        $codes[] = $result_row['real_id'];
+                    }
                 }
             }
-        }
 
-        // get course list not auto-register. Use Distinct to avoid multiple
-        // entries when a course is assigned to a HRD (DRH) as watcher
-        $sql = "SELECT DISTINCT(course.code), course.id as real_id
+            // get course list not auto-register. Use Distinct to avoid multiple
+            // entries when a course is assigned to a HRD (DRH) as watcher
+            $sql = "SELECT DISTINCT(course.code), course.id as real_id
                 FROM $tbl_course course
                 INNER JOIN $tbl_course_user cru ON course.id = cru.c_id
                 WHERE cru.user_id='$user_id' $without_special_courses";
-
+        }
         $result = Database::query($sql);
 
         if (Database::num_rows($result)) {

+ 438 - 434
main/inc/lib/course_description.lib.php

@@ -14,55 +14,55 @@
  */
 class CourseDescription
 {
-	private $id;
+    private $id;
     private $course_id;
-	private $title;
-	private $content;
+    private $title;
+    private $content;
     private $session_id;
     private $description_type;
     private $progress;
 
-   	/**
-	 * Constructor
-	 */
-	public function __construct()
+    /**
+     * Constructor
+     */
+    public function __construct()
     {
 
     }
 
-	/**
-	 * Returns an array of objects of type CourseDescription corresponding to
+    /**
+     * Returns an array of objects of type CourseDescription corresponding to
      * a specific course, without session ids (session id = 0)
-	 *
-	 * @param int Course id
-	 * @return array Array of CourseDescriptions
-	 */
-	public static function get_descriptions($course_id)
+     *
+     * @param int Course id
+     * @return array Array of CourseDescriptions
+     */
+    public static function get_descriptions($course_id)
     {
-		// Get course code
-		$course_info = api_get_course_info_by_id($course_id);
+        // Get course code
+        $course_info = api_get_course_info_by_id($course_id);
         if (!empty($course_info)) {
             $course_id = $course_info['real_id'];
         } else {
             return array();
         }
-		$t_course_desc = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
-		$sql = "SELECT * FROM $t_course_desc
-		        WHERE c_id = $course_id AND session_id = '0'";
-		$sql_result = Database::query($sql);
-		$results = array();
-		while($row = Database::fetch_array($sql_result)) {
-			$desc_tmp = new CourseDescription();
-			$desc_tmp->set_id($row['id']);
-			$desc_tmp->set_title($row['title']);
-			$desc_tmp->set_content($row['content']);
-			$desc_tmp->set_session_id($row['session_id']);
-			$desc_tmp->set_description_type($row['description_type']);
-			$desc_tmp->set_progress($row['progress']);
-			$results[] = $desc_tmp;
-		}
-		return $results;
-	}
+        $t_course_desc = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
+        $sql = "SELECT * FROM $t_course_desc
+              WHERE c_id = $course_id AND session_id = '0'";
+        $sql_result = Database::query($sql);
+        $results = array();
+        while ($row = Database::fetch_array($sql_result)) {
+            $desc_tmp = new CourseDescription();
+            $desc_tmp->set_id($row['id']);
+            $desc_tmp->set_title($row['title']);
+            $desc_tmp->set_content($row['content']);
+            $desc_tmp->set_session_id($row['session_id']);
+            $desc_tmp->set_description_type($row['description_type']);
+            $desc_tmp->set_progress($row['progress']);
+            $results[] = $desc_tmp;
+        }
+        return $results;
+    }
 
 
     /**
@@ -70,87 +70,90 @@ class CourseDescription
      * first you must set session_id property with the object CourseDescription
      * @return array
      */
-	public function get_description_data()
+    public function get_description_data()
     {
-		$tbl_course_description = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
-		$condition_session = api_get_session_condition($this->session_id, true, true);
+        $tbl_course_description = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
+        $condition_session = api_get_session_condition($this->session_id, true, true);
         $course_id = api_get_course_int_id();
-		$sql = "SELECT * FROM $tbl_course_description
+        $sql = "SELECT * FROM $tbl_course_description
 		        WHERE c_id = $course_id $condition_session
 		        ORDER BY id ";
-		$rs = Database::query($sql);
-		$data = array();
-		while ($description = Database::fetch_array($rs)) {
-			$data['descriptions'][$description['id']] = Security::remove_XSS($description, STUDENT);
-			//reload titles to ensure we have the last version (after edition)
-			//$data['default_description_titles'][$description['id']] = Security::remove_XSS($description['title'], STUDENT);
-		}
-		return $data;
-	}
-
-	/**
+        $rs = Database::query($sql);
+        $data = array();
+        while ($description = Database::fetch_array($rs)) {
+            $data['descriptions'][$description['id']] = Security::remove_XSS($description, STUDENT);
+            //reload titles to ensure we have the last version (after edition)
+            //$data['default_description_titles'][$description['id']] = Security::remove_XSS($description['title'], STUDENT);
+        }
+        return $data;
+    }
+
+    /**
      * Get all data of course description by session id,
      * first you must set session_id property with the object CourseDescription
      * @deprecated
      * @return array
      */
-	public function get_description_history($description_type)
+    public function get_description_history($description_type)
     {
-		$tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
-		$tbl_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
+        $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
+        $tbl_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
 
-		$description_id = $this->get_id_by_description_type($description_type);
-		$item_property_id = api_get_item_property_id($course_id, TOOL_COURSE_DESCRIPTION, $description_id);
+        $description_id = $this->get_id_by_description_type($description_type);
+        $item_property_id = api_get_item_property_id(api_get_course_id(), TOOL_COURSE_DESCRIPTION, $description_id);
 
-		$course_id = api_get_course_int_id();
+        $course_id = api_get_course_int_id();
 
-		$sql = "SELECT tip.id, tip.course_id, tip.item_property_id, tip.title, tip.content, tip.progress, tip.lastedit_date, tip.session_id
+        $sql = "SELECT tip.id, tip.course_id, tip.item_property_id, tip.title, tip.content, tip.progress, tip.lastedit_date, tip.session_id
 				FROM $tbl_stats_item_property tip INNER JOIN $tbl_item_property ip
-				ON ip.tool = '".TOOL_COURSE_DESCRIPTION."' AND ip.id = tip.item_property_id
-				WHERE ip.c_id = $course_id AND tip.course_id = '$course_id' AND tip.session_id = '".intval($this->session_id)."'
+				ON ip.tool = '" . TOOL_COURSE_DESCRIPTION . "' AND ip.id = tip.item_property_id
+				WHERE ip.c_id = $course_id AND tip.course_id = '$course_id' AND tip.session_id = '" . intval($this->session_id) . "'
 				ORDER BY tip.lastedit_date DESC";
 
-		$rs = Database::query($sql);
-		$data = array();
-		while ($description = Database::fetch_array($rs)) {
-			$data['descriptions'][] = $description;
-		}
-		return $data;
-	}
+        $rs = Database::query($sql);
+        $data = array();
+        while ($description = Database::fetch_array($rs)) {
+            $data['descriptions'][] = $description;
+        }
+        return $data;
+    }
 
-	/**
+    /**
      * Get all data by description and session id,
      * first you must set session_id property with the object CourseDescription
-     * @param 	int		description type
+     * @param    int        description type
      * @param   string  course code (optional)
-     * @param	int		session id (optional)
+     * @param    int        session id (optional)
      * @return array
      */
-	public function get_data_by_description_type($description_type, $course_code = '', $session_id = null)
-    {
-		$tbl_course_description = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
-		$course_id = api_get_course_int_id();
-
-		if (!isset($session_id)) {
-			$session_id = $this->session_id;
-		}
-		$condition_session = api_get_session_condition($session_id);
-		if (!empty($course_code)) {
-			$course_info = api_get_course_info($course_code);
+    public function get_data_by_description_type(
+        $description_type,
+        $course_code = '',
+        $session_id = null
+    ) {
+        $tbl_course_description = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
+        $course_id = api_get_course_int_id();
+
+        if (!isset($session_id)) {
+            $session_id = $this->session_id;
+        }
+        $condition_session = api_get_session_condition($session_id);
+        if (!empty($course_code)) {
+            $course_info = api_get_course_info($course_code);
             $course_id = $course_info['real_id'];
-		}
+        }
         $description_type = intval($description_type);
-		$sql = "SELECT * FROM $tbl_course_description
+        $sql = "SELECT * FROM $tbl_course_description
 		        WHERE c_id = $course_id AND description_type='$description_type' $condition_session ";
-		$rs = Database::query($sql);
-		$data = array();
-		if ($description = Database::fetch_array($rs)) {
-			$data['description_title']	 = $description['title'];
-			$data['description_content'] = $description['content'];
-			$data['progress'] 			 = $description['progress'];
-		}
-		return $data;
-	}
+        $rs = Database::query($sql);
+        $data = array();
+        if ($description = Database::fetch_array($rs)) {
+            $data['description_title'] = $description['title'];
+            $data['description_content'] = $description['content'];
+            $data['progress'] = $description['progress'];
+        }
+        return $data;
+    }
 
     /**
      * @param int $id
@@ -160,149 +163,147 @@ class CourseDescription
      */
     public function get_data_by_id($id, $course_code = '', $session_id = null)
     {
-		$tbl_course_description = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
-		$course_id = api_get_course_int_id();
-
-		if (!isset($session_id)) {
-			$session_id = $this->session_id;
-		}
-		$condition_session = api_get_session_condition($session_id);
-		if (!empty($course_code)) {
-			$course_info = api_get_course_info($course_code);
+        $tbl_course_description = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
+        $course_id = api_get_course_int_id();
+
+        if (!isset($session_id)) {
+            $session_id = $this->session_id;
+        }
+        $condition_session = api_get_session_condition($session_id);
+        if (!empty($course_code)) {
+            $course_info = api_get_course_info($course_code);
             $course_id = $course_info['real_id'];
-		}
+        }
         $id = intval($id);
-		$sql = "SELECT * FROM $tbl_course_description
+        $sql = "SELECT * FROM $tbl_course_description
 		        WHERE c_id = $course_id AND id='$id' $condition_session ";
-		$rs = Database::query($sql);
-		$data = array();
-		if ($description = Database::fetch_array($rs)) {
-            $data['description_type']	 = $description['description_type'];
-			$data['description_title']	 = $description['title'];
-			$data['description_content'] = $description['content'];
-			$data['progress'] 			 = $description['progress'];
-		}
+        $rs = Database::query($sql);
+        $data = array();
+        if ($description = Database::fetch_array($rs)) {
+            $data['description_type'] = $description['description_type'];
+            $data['description_title'] = $description['title'];
+            $data['description_content'] = $description['content'];
+            $data['progress'] = $description['progress'];
+        }
 
-		return $data;
-	}
+        return $data;
+    }
 
 
-	/**
+    /**
      * Get maximum description type by session id,
      * first you must set session_id properties with the object CourseDescription
      * @return  int  maximum description time adding one
      */
-	public function get_max_description_type()
+    public function get_max_description_type()
     {
-		$tbl_course_description = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
+        $tbl_course_description = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
         $course_id = api_get_course_int_id();
 
-		$sql = "SELECT MAX(description_type) as MAX FROM $tbl_course_description
-		        WHERE c_id = $course_id AND session_id='".$this->session_id."'";
-		$rs  = Database::query($sql);
-		$max = Database::fetch_array($rs);
-		$description_type = $max['MAX']+1;
-		if ($description_type < ADD_BLOCK) {
-			$description_type = ADD_BLOCK;
-		}
-		return $description_type;
-	}
-
-	/**
+        $sql = "SELECT MAX(description_type) as MAX FROM $tbl_course_description
+		        WHERE c_id = $course_id AND session_id='" . $this->session_id . "'";
+        $rs = Database::query($sql);
+        $max = Database::fetch_array($rs);
+        $description_type = $max['MAX'] + 1;
+        if ($description_type < ADD_BLOCK) {
+            $description_type = ADD_BLOCK;
+        }
+        return $description_type;
+    }
+
+    /**
      * Insert a description to the course_description table,
      * first you must set description_type, title, content, progress and
      * session_id properties with the object CourseDescription
      * @return  int  affected rows
      */
-	public function insert()
+    public function insert()
     {
         if (empty($this->course_id)) {
-		    $course_id = api_get_course_int_id();
+            $course_id = api_get_course_int_id();
         } else {
             $course_id = $this->course_id;
         }
-		$tbl_course_description = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
-		$sql = "INSERT IGNORE INTO $tbl_course_description SET
+        $tbl_course_description = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
+        $sql = "INSERT IGNORE INTO $tbl_course_description SET
 				c_id 				=  $course_id,
-				description_type	= '".intval($this->description_type)."',
-				title 				= '".Database::escape_string($this->title)."',
-				content 			= '".Database::escape_string($this->content)."',
-				progress 			= '".intval($this->progress)."',
-				session_id = '".intval($this->session_id)."' ";
-		$result = Database::query($sql);
-		$last_id = Database::insert_id();
-		$affected_rows = Database::affected_rows($result);
-		if ($last_id > 0) {
+				description_type	= '" . intval($this->description_type) . "',
+				title 				= '" . Database::escape_string($this->title) . "',
+				content 			= '" . Database::escape_string($this->content) . "',
+				progress 			= '" . intval($this->progress) . "',
+				session_id = '" . intval($this->session_id) . "' ";
+        $result = Database::query($sql);
+        $last_id = Database::insert_id();
+        $affected_rows = Database::affected_rows($result);
+        if ($last_id > 0) {
             $sql = "UPDATE $tbl_course_description SET id = iid WHERE iid = $last_id";
             Database::query($sql);
 
-			//insert into item_property
-			api_item_property_update(
-				api_get_course_info(),
-				TOOL_COURSE_DESCRIPTION,
-				$last_id,
-				'CourseDescriptionAdded',
-				api_get_user_id()
-			);
-		}
+            //insert into item_property
+            api_item_property_update(
+                api_get_course_info(),
+                TOOL_COURSE_DESCRIPTION,
+                $last_id,
+                'CourseDescriptionAdded',
+                api_get_user_id()
+            );
+        }
 
-		return $affected_rows;
-	}
+        return $affected_rows;
+    }
 
-	/**
+    /**
      * Insert a row like history inside track_e_item_property table
      * first you must set description_type, title, content, progress and
      * session_id properties with the object CourseDescription
-     * @param 	int 	description type
-     * @return  int		affected rows
+     * @param    int    description type
+     * @return  int        affected rows
      */
-	public function insert_stats($description_type)
+    public function insert_stats($description_type)
     {
-		$tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
-		$description_id = $this->get_id_by_description_type($description_type);
-		$course_id = api_get_real_course_id();
-		$course_code = api_get_course_id();
-		$item_property_id = api_get_item_property_id($course_code, TOOL_COURSE_DESCRIPTION, $description_id);
-		$sql = "INSERT IGNORE INTO $tbl_stats_item_property SET
-				c_id				= ".api_get_course_int_id().",
+        $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
+        $description_id = $this->get_id_by_description_type($description_type);
+        $course_id = api_get_real_course_id();
+        $course_code = api_get_course_id();
+        $item_property_id = api_get_item_property_id($course_code,
+            TOOL_COURSE_DESCRIPTION, $description_id);
+        $sql = "INSERT IGNORE INTO $tbl_stats_item_property SET
+				c_id				= " . api_get_course_int_id() . ",
 				course_id 			= '$course_id',
 			 	item_property_id 	= '$item_property_id',
-			 	title 				= '".Database::escape_string($this->title)."',
-			 	content 			= '".Database::escape_string($this->content)."',
-			 	progress 			= '".intval($this->progress)."',
-			 	lastedit_date 		= '".date('Y-m-d H:i:s')."',
-			 	lastedit_user_id 	= '".api_get_user_id()."',
-			 	session_id			= '".intval($this->session_id)."'";
-		$result = Database::query($sql);
-		$affected_rows = Database::affected_rows($result);
-
-        $sql = "UPDATE $tbl_course_description SET id = iid WHERE iid = $last_id";
-        Database::query($sql);
-
-		return $affected_rows;
-	}
-
-	/**
+			 	title 				= '" . Database::escape_string($this->title) . "',
+			 	content 			= '" . Database::escape_string($this->content) . "',
+			 	progress 			= '" . intval($this->progress) . "',
+			 	lastedit_date 		= '" . date('Y-m-d H:i:s') . "',
+			 	lastedit_user_id 	= '" . api_get_user_id() . "',
+			 	session_id			= '" . intval($this->session_id) . "'";
+        $result = Database::query($sql);
+        $affected_rows = Database::affected_rows($result);
+
+        return $affected_rows;
+    }
+
+    /**
      * Update a description, first you must set description_type, title, content, progress
      * and session_id properties with the object CourseDescription
-     * @return int	affected rows
+     * @return int    affected rows
      */
-	public function update()
+    public function update()
     {
-		$tbl_course_description = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
-		$sql = "UPDATE $tbl_course_description SET
-                    title       = '".Database::escape_string($this->title)."',
-                    content     = '".Database::escape_string($this->content)."',
-                    progress    = '".$this->progress."'
+        $tbl_course_description = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
+        $sql = "UPDATE $tbl_course_description SET
+                    title       = '" . Database::escape_string($this->title) . "',
+                    content     = '" . Database::escape_string($this->content) . "',
+                    progress    = '" . $this->progress . "'
                 WHERE
-                    id = '".intval($this->id)."' AND
-                    session_id = '".$this->session_id."' AND
-                    c_id = ".api_get_course_int_id();
-		$result = Database::query($sql);
-		$affected_rows = Database::affected_rows($result);
-
-		if ($this->id > 0) {
-			//insert into item_property
+                    id = '" . intval($this->id) . "' AND
+                    session_id = '" . $this->session_id . "' AND
+                    c_id = " . api_get_course_int_id();
+        $result = Database::query($sql);
+        $affected_rows = Database::affected_rows($result);
+
+        if ($this->id > 0) {
+            //insert into item_property
             api_item_property_update(
                 api_get_course_info(),
                 TOOL_COURSE_DESCRIPTION,
@@ -310,28 +311,28 @@ class CourseDescription
                 'CourseDescriptionUpdated',
                 api_get_user_id()
             );
-		}
-		return $affected_rows;
-	}
+        }
+        return $affected_rows;
+    }
 
-	/**
+    /**
      * Delete a description, first you must set description_type and session_id
      * properties with the object CourseDescription
-     * @return int	affected rows
+     * @return int    affected rows
      */
-	public function delete()
+    public function delete()
     {
-		$tbl_course_description = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
-		$course_id = api_get_course_int_id();
-		$sql = "DELETE FROM $tbl_course_description
+        $tbl_course_description = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
+        $course_id = api_get_course_int_id();
+        $sql = "DELETE FROM $tbl_course_description
 			 	WHERE
 			 	    c_id = $course_id AND
-			 	    id = '".intval($this->id)."' AND
-			 	    session_id = '".intval($this->session_id)."'";
-		$result = Database::query($sql);
-		$affected_rows = Database::affected_rows($result);
-		if ($this->id > 0) {
-			//insert into item_property
+			 	    id = '" . intval($this->id) . "' AND
+			 	    session_id = '" . intval($this->session_id) . "'";
+        $result = Database::query($sql);
+        $affected_rows = Database::affected_rows($result);
+        if ($this->id > 0) {
+            //insert into item_property
             api_item_property_update(
                 api_get_course_info(),
                 TOOL_COURSE_DESCRIPTION,
@@ -339,164 +340,167 @@ class CourseDescription
                 'CourseDescriptionDeleted',
                 api_get_user_id()
             );
-		}
+        }
 
-		return $affected_rows;
-	}
+        return $affected_rows;
+    }
 
-	/**
-	 * Get description id by description type
-	 * @param int description type
-	 * @return int description id
-	 */
-	public function get_id_by_description_type($description_type)
+    /**
+     * Get description id by description type
+     * @param int description type
+     * @return int description id
+     */
+    public function get_id_by_description_type($description_type)
     {
-		$tbl_course_description = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
+        $tbl_course_description = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
         $course_id = api_get_course_int_id();
 
-		$sql = "SELECT id FROM $tbl_course_description
-		        WHERE c_id = $course_id AND description_type = '".intval($description_type)."'";
-		$rs  = Database::query($sql);
-		$row = Database::fetch_array($rs);
-		$description_id = $row['id'];
-		return $description_id;
-	}
-
-	/**
-	 * get thematic progress in porcent for a course,
-	 * first you must set session_id property with the object CourseDescription
-	 * @param bool		true for showing a icon about the progress, false otherwise (optional)
-	 * @param int		Description type (optional)
-	 * @return string   img html
-	 */
-	 public function get_progress_porcent($with_icon = false, $description_type = THEMATIC_ADVANCE)
-     {
-	 	$tbl_course_description = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
-	 	$session_id = intval($session_id);
+        $sql = "SELECT id FROM $tbl_course_description
+		        WHERE c_id = $course_id AND description_type = '" . intval($description_type) . "'";
+        $rs = Database::query($sql);
+        $row = Database::fetch_array($rs);
+        $description_id = $row['id'];
+        return $description_id;
+    }
+
+    /**
+     * get thematic progress in porcent for a course,
+     * first you must set session_id property with the object CourseDescription
+     * @param bool        true for showing a icon about the progress, false otherwise (optional)
+     * @param int        Description type (optional)
+     * @return string   img html
+     */
+    public function get_progress_porcent(
+        $with_icon = false,
+        $description_type = THEMATIC_ADVANCE
+    ) {
+        $tbl_course_description = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
+        $session_id = api_get_session_id();
         $course_id = api_get_course_int_id();
 
-		$sql = "SELECT progress FROM $tbl_course_description
+        $sql = "SELECT progress FROM $tbl_course_description
 		        WHERE
 		            c_id = $course_id AND
-		            description_type = '".intval($description_type)."' AND
-		            session_id = '".intval($this->session_id)."' ";
-		$rs  = Database::query($sql);
-		$progress = '';
-		$img = '';
-		$title = '0%';
-		$image = 'level_0.png';
-		if (Database::num_rows($rs) > 0) {
-			$row = Database::fetch_array($rs);
-			$progress = $row['progress'].'%';
-			$image = 'level_'.$row['progress'].'.png';
-		}
-		if ($with_icon) {
-			$img = Display::return_icon($image,get_lang('ThematicAdvance'),array('style'=>'vertical-align:middle'));
-		}
-		$progress = $img.$progress;
-		return $progress;
-	 }
-
-	/**
-	 * Get description titles by default
-	 * @return array
-	 */
-	public function get_default_description_title()
+		            description_type = '" . intval($description_type) . "' AND
+		            session_id = '" . intval($this->session_id) . "' ";
+        $rs = Database::query($sql);
+        $progress = '';
+        $img = '';
+        $title = '0%';
+        $image = 'level_0.png';
+        if (Database::num_rows($rs) > 0) {
+            $row = Database::fetch_array($rs);
+            $progress = $row['progress'] . '%';
+            $image = 'level_' . $row['progress'] . '.png';
+        }
+        if ($with_icon) {
+            $img = Display::return_icon($image, get_lang('ThematicAdvance'),
+                array('style' => 'vertical-align:middle'));
+        }
+        $progress = $img . $progress;
+        return $progress;
+    }
+
+    /**
+     * Get description titles by default
+     * @return array
+     */
+    public function get_default_description_title()
     {
-		$default_description_titles = array();
-		$default_description_titles[1]= get_lang('GeneralDescription');
-		$default_description_titles[2]= get_lang('Objectives');
-		$default_description_titles[3]= get_lang('Topics');
-		$default_description_titles[4]= get_lang('Methodology');
-		$default_description_titles[5]= get_lang('CourseMaterial');
-		$default_description_titles[6]= get_lang('HumanAndTechnicalResources');
-		$default_description_titles[7]= get_lang('Assessment');
-
-		$default_description_titles[8]= get_lang('Other');
-		return $default_description_titles;
-	}
-
-	/**
-	 * Get description titles editable by default
-	 * @return array
-	 */
-	public function get_default_description_title_editable()
+        $default_description_titles = array();
+        $default_description_titles[1] = get_lang('GeneralDescription');
+        $default_description_titles[2] = get_lang('Objectives');
+        $default_description_titles[3] = get_lang('Topics');
+        $default_description_titles[4] = get_lang('Methodology');
+        $default_description_titles[5] = get_lang('CourseMaterial');
+        $default_description_titles[6] = get_lang('HumanAndTechnicalResources');
+        $default_description_titles[7] = get_lang('Assessment');
+
+        $default_description_titles[8] = get_lang('Other');
+        return $default_description_titles;
+    }
+
+    /**
+     * Get description titles editable by default
+     * @return array
+     */
+    public function get_default_description_title_editable()
     {
-		$default_description_title_editable = array();
-		$default_description_title_editable[1] = true;
-		$default_description_title_editable[2] = true;
-		$default_description_title_editable[3] = true;
-		$default_description_title_editable[4] = true;
-		$default_description_title_editable[5] = true;
-		$default_description_title_editable[6] = true;
-		$default_description_title_editable[7] = true;
-		//$default_description_title_editable[8] = true;
-		return $default_description_title_editable;
-	}
-
-	/**
-	 * Get description icons by default
-	 * @return array
-	 */
-	public function get_default_description_icon()
+        $default_description_title_editable = array();
+        $default_description_title_editable[1] = true;
+        $default_description_title_editable[2] = true;
+        $default_description_title_editable[3] = true;
+        $default_description_title_editable[4] = true;
+        $default_description_title_editable[5] = true;
+        $default_description_title_editable[6] = true;
+        $default_description_title_editable[7] = true;
+        //$default_description_title_editable[8] = true;
+        return $default_description_title_editable;
+    }
+
+    /**
+     * Get description icons by default
+     * @return array
+     */
+    public function get_default_description_icon()
     {
-		$default_description_icon = array();
-		$default_description_icon[1]= 'info.png';
-		$default_description_icon[2]= 'objective.png';
-		$default_description_icon[3]= 'topics.png';
-		$default_description_icon[4]= 'strategy.png';
-		$default_description_icon[5]= 'laptop.png';
-		$default_description_icon[6]= 'teacher.png';
-		$default_description_icon[7]= 'assessment.png';
-		//$default_description_icon[8]= 'porcent.png';
-		$default_description_icon[8]= 'wizard.png';
-		return $default_description_icon;
-	}
-
-	/**
-	 * Get questions by default for help
-	 * @return array
-	 */
-	public function get_default_question()
+        $default_description_icon = array();
+        $default_description_icon[1] = 'info.png';
+        $default_description_icon[2] = 'objective.png';
+        $default_description_icon[3] = 'topics.png';
+        $default_description_icon[4] = 'strategy.png';
+        $default_description_icon[5] = 'laptop.png';
+        $default_description_icon[6] = 'teacher.png';
+        $default_description_icon[7] = 'assessment.png';
+        //$default_description_icon[8]= 'porcent.png';
+        $default_description_icon[8] = 'wizard.png';
+        return $default_description_icon;
+    }
+
+    /**
+     * Get questions by default for help
+     * @return array
+     */
+    public function get_default_question()
     {
-		$question = array();
-		$question[1]= get_lang('GeneralDescriptionQuestions');
-		$question[2]= get_lang('ObjectivesQuestions');
-		$question[3]= get_lang('TopicsQuestions');
-		$question[4]= get_lang('MethodologyQuestions');
-		$question[5]= get_lang('CourseMaterialQuestions');
-		$question[6]= get_lang('HumanAndTechnicalResourcesQuestions');
-		$question[7]= get_lang('AssessmentQuestions');
-		//$question[8]= get_lang('ThematicAdvanceQuestions');
-		return $question;
-	}
-
-	/**
-	 * Get informations by default for help
-	 * @return array
-	 */
-	public function get_default_information()
+        $question = array();
+        $question[1] = get_lang('GeneralDescriptionQuestions');
+        $question[2] = get_lang('ObjectivesQuestions');
+        $question[3] = get_lang('TopicsQuestions');
+        $question[4] = get_lang('MethodologyQuestions');
+        $question[5] = get_lang('CourseMaterialQuestions');
+        $question[6] = get_lang('HumanAndTechnicalResourcesQuestions');
+        $question[7] = get_lang('AssessmentQuestions');
+        //$question[8]= get_lang('ThematicAdvanceQuestions');
+        return $question;
+    }
+
+    /**
+     * Get informations by default for help
+     * @return array
+     */
+    public function get_default_information()
     {
-		$information = array();
-		$information[1]= get_lang('GeneralDescriptionInformation');
-		$information[2]= get_lang('ObjectivesInformation');
-		$information[3]= get_lang('TopicsInformation');
-		$information[4]= get_lang('MethodologyInformation');
-		$information[5]= get_lang('CourseMaterialInformation');
-		$information[6]= get_lang('HumanAndTechnicalResourcesInformation');
-		$information[7]= get_lang('AssessmentInformation');
-		//$information[8]= get_lang('ThematicAdvanceInformation');
-		return $information;
-	}
-
-	/**
-	 * Set description id
-	 * @return void
-	 */
-	public function set_id($id)
+        $information = array();
+        $information[1] = get_lang('GeneralDescriptionInformation');
+        $information[2] = get_lang('ObjectivesInformation');
+        $information[3] = get_lang('TopicsInformation');
+        $information[4] = get_lang('MethodologyInformation');
+        $information[5] = get_lang('CourseMaterialInformation');
+        $information[6] = get_lang('HumanAndTechnicalResourcesInformation');
+        $information[7] = get_lang('AssessmentInformation');
+        //$information[8]= get_lang('ThematicAdvanceInformation');
+        return $information;
+    }
+
+    /**
+     * Set description id
+     * @return void
+     */
+    public function set_id($id)
     {
-		$this->id = $id;
-	}
+        $this->id = $id;
+    }
 
     /**
      * Set description's course id
@@ -508,102 +512,102 @@ class CourseDescription
         $this->course_id = intval($id);
     }
 
-   	/**
-	 * Set description title
-	 * @return void
-	 */
-	public function set_title($title)
+    /**
+     * Set description title
+     * @return void
+     */
+    public function set_title($title)
     {
-		$this->title = $title;
-	}
+        $this->title = $title;
+    }
 
     /**
-	 * Set description content
-	 * @return void
-	 */
-	public function set_content($content)
+     * Set description content
+     * @return void
+     */
+    public function set_content($content)
     {
-		$this->content = $content;
-	}
-
-	/**
-	 * Set description session id
-	 * @return void
-	 */
-	public function set_session_id($session_id)
+        $this->content = $content;
+    }
+
+    /**
+     * Set description session id
+     * @return void
+     */
+    public function set_session_id($session_id)
     {
-		$this->session_id = $session_id;
-	}
-
-   	/**
-	 * Set description type
-	 * @return void
-	 */
-	public function set_description_type($description_type)
+        $this->session_id = $session_id;
+    }
+
+    /**
+     * Set description type
+     * @return void
+     */
+    public function set_description_type($description_type)
     {
-		$this->description_type = $description_type;
-	}
-
-	/**
-	 * Set progress of a description
-	 * @return void
-	 */
-	public function set_progress($progress)
+        $this->description_type = $description_type;
+    }
+
+    /**
+     * Set progress of a description
+     * @return void
+     */
+    public function set_progress($progress)
     {
-		$this->progress = $progress;
-	}
-
-	/**
-	 * get description id
-	 * @return int
-	 */
-	public function get_id()
+        $this->progress = $progress;
+    }
+
+    /**
+     * get description id
+     * @return int
+     */
+    public function get_id()
     {
-		return $this->id;
-	}
-
-   	/**
-	 * get description title
-	 * @return string
-	 */
-	public function get_title()
+        return $this->id;
+    }
+
+    /**
+     * get description title
+     * @return string
+     */
+    public function get_title()
     {
-		return $this->title;
-	}
-
-   	/**
-	 * get description content
-	 * @return string
-	 */
-	public function get_content()
+        return $this->title;
+    }
+
+    /**
+     * get description content
+     * @return string
+     */
+    public function get_content()
     {
-		return $this->content;
-	}
-
-	/**
-	 * get session id
-	 * @return int
-	 */
-	public function get_session_id()
+        return $this->content;
+    }
+
+    /**
+     * get session id
+     * @return int
+     */
+    public function get_session_id()
     {
-		return $this->session_id;
-	}
-
-   	/**
-	 * get description type
-	 * @return int
-	 */
-	public function get_description_type()
+        return $this->session_id;
+    }
+
+    /**
+     * get description type
+     * @return int
+     */
+    public function get_description_type()
     {
-		return $this->description_type;
-	}
-
-	/**
-	 * get progress of a description
-	 * @return int
-	 */
-	public function get_progress()
+        return $this->description_type;
+    }
+
+    /**
+     * get progress of a description
+     * @return int
+     */
+    public function get_progress()
     {
-		return $this->progress;
-	}
+        return $this->progress;
+    }
 }

+ 21 - 17
main/inc/lib/formvalidator/Rule/Filetype.php

@@ -6,21 +6,25 @@
  */
 class HTML_QuickForm_Rule_Filetype extends HTML_QuickForm_Rule
 {
-	/**
-	 * Function to check if a filetype is allowed
-	 * @see HTML_QuickForm_Rule
-	 * @param array $file Uploaded file
-	 * @param array $extensions Allowed extensions
-	 * @return boolean True if filetype is allowed
-	 */
-	function validate($file,$extensions = array())
-	{
-		$parts = explode('.',$file['name']);
-		if( count($parts) < 2 )
-		{
-			return false;
-		}
-		$ext = $parts[count($parts)-1];
-		return api_in_array_nocase($ext, $extensions);
-	}
+    /**
+     * Function to check if a filetype is allowed
+     * @see HTML_QuickForm_Rule
+     *
+     * @param array $file Uploaded file
+     * @param array $extensions Allowed extensions
+     *
+     * @return boolean True if filetype is allowed
+     */
+    function validate($file, $extensions = array())
+    {
+        $parts = explode('.', $file['name']);
+        if (count($parts) < 2) {
+            return false;
+        }
+
+        $ext = $parts[count($parts) - 1];
+        $extensions = array_map('strtolower', $extensions);
+
+        return in_array(api_strtolower($ext), $extensions);
+    }
 }

+ 4 - 522
main/inc/lib/internationalization.lib.php

@@ -93,7 +93,7 @@ function api_set_internationalization_default_encoding($encoding) {
     $result = _api_mb_internal_encoding();
     _api_mb_internal_encoding($encoding);
     _api_mb_regex_encoding($encoding);
-    _api_iconv_set_encoding('iconv_internal_encoding', $encoding);
+    //_api_iconv_set_encoding('iconv_internal_encoding', $encoding);
 
     return $result;
 }
@@ -1399,18 +1399,6 @@ function api_ord($character, $encoding) {
     return _api_utf8_ord(api_utf8_encode($character, $encoding));
 }
 
-/**
- * Takes a Unicode codepoint and returns its correspondent character, encoded in given encoding.
- * @param int $codepoint				The Unicode codepoint.
- * @param string $encoding (optional)	The encoding of the returned character. If it is omitted, the platform character set will be used by default.
- * @return string						Returns the corresponding character, encoded as it has been requested.
- * This is a multibyte aware version of the function chr().
- * @link http://php.net/manual/en/function.chr.php
- */
-function api_chr($codepoint, $encoding) {
-    return api_utf8_decode(_api_utf8_chr($codepoint), $encoding);
-}
-
 /**
  * This function returns a string or an array with all occurrences of search in subject (ignoring case) replaced with the given replace value.
  * @param mixed $search					String or array of strings to be found.
@@ -2102,46 +2090,6 @@ function api_ereg($pattern, $string, & $regs = null) {
     return ereg($pattern, $string, $regs);
 }
 
-/**
- * Note: Try to avoid using this function. Use api_preg_replace() with Perl-compatible regular expression syntax.
- *
- * Scans string for matches to pattern, then replaces the matched text with replacement, with extended multibyte support.
- * By default this function uses the platform character set.
- * @param string $pattern				The regular expression pattern.
- * @param string $replacement			The replacement text.
- * @param string $string				The searched string.
- * @param string $option (optional)		Matching condition.
- * If i is specified for the matching condition parameter, the case will be ignored.
- * If x is specified, white space will be ignored.
- * If m is specified, match will be executed in multiline mode and line break will be included in '.'.
- * If p is specified, match will be executed in POSIX mode, line break will be considered as normal character.
- * If e is specified, replacement string will be evaluated as PHP expression.
- * @return mixed						The modified string is returned. If no matches are found within the string, then it will be returned unchanged. FALSE will be returned on error.
- * This function is aimed at replacing the functions ereg_replace() and mb_ereg_replace() for human-language strings.
- * @link http://php.net/manual/en/function.ereg-replace
- * @link http://php.net/manual/en/function.mb-ereg-replace
- */
-function api_ereg_replace($pattern, $replacement, $string, $option = null) {
-    $encoding = _api_mb_regex_encoding();
-    if (_api_mb_supports($encoding)) {
-        if (is_null($option)) {
-            return @mb_ereg_replace($pattern, $replacement, $string);
-        }
-        return @mb_ereg_replace($pattern, $replacement, $string, $option);
-    }
-    if (MBSTRING_INSTALLED && api_is_encoding_supported($encoding)) {
-        _api_mb_regex_encoding('UTF-8');
-        if (is_null($option)) {
-            $result = api_utf8_decode(@mb_ereg_replace(api_utf8_encode($pattern, $encoding), api_utf8_encode($replacement, $encoding), api_utf8_encode($string, $encoding)), $encoding);
-        } else {
-            $result = api_utf8_decode(@mb_ereg_replace(api_utf8_encode($pattern, $encoding), api_utf8_encode($replacement, $encoding), api_utf8_encode($string, $encoding), $option), $encoding);
-        }
-        _api_mb_regex_encoding($encoding);
-        return $result;
-    }
-    return ereg_replace($pattern, $replacement, $string);
-}
-
 /**
  * Note: Try to avoid using this function. Use api_preg_match() with Perl-compatible regular expression syntax.
  *
@@ -2183,46 +2131,6 @@ function api_eregi($pattern, $string, & $regs = null) {
     return eregi($pattern, $string, $regs);
 }
 
-/**
- * Note: Try to avoid using this function. Use api_preg_replace() with Perl-compatible regular expression syntax.
- *
- * Scans string for matches to pattern, then replaces the matched text with replacement, ignoring case, with extended multibyte support.
- * By default this function uses the platform character set.
- * @param string $pattern				The regular expression pattern.
- * @param string $replacement			The replacement text.
- * @param string $string				The searched string.
- * @param string $option (optional)		Matching condition.
- * If i is specified for the matching condition parameter, the case will be ignored.
- * If x is specified, white space will be ignored.
- * If m is specified, match will be executed in multiline mode and line break will be included in '.'.
- * If p is specified, match will be executed in POSIX mode, line break will be considered as normal character.
- * If e is specified, replacement string will be evaluated as PHP expression.
- * @return mixed						The modified string is returned. If no matches are found within the string, then it will be returned unchanged. FALSE will be returned on error.
- * This function is aimed at replacing the functions eregi_replace() and mb_eregi_replace() for human-language strings.
- * @link http://php.net/manual/en/function.eregi-replace
- * @link http://php.net/manual/en/function.mb-eregi-replace
- */
-function api_eregi_replace($pattern, $replacement, $string, $option = null) {
-    $encoding = _api_mb_regex_encoding();
-    if (_api_mb_supports($encoding)) {
-        if (is_null($option)) {
-            return @mb_eregi_replace($pattern, $replacement, $string);
-        }
-        return @mb_eregi_replace($pattern, $replacement, $string, $option);
-    }
-    if (MBSTRING_INSTALLED && api_is_encoding_supported($encoding)) {
-        _api_mb_regex_encoding('UTF-8');
-        if (is_null($option)) {
-            $result = api_utf8_decode(@mb_eregi_replace(api_utf8_encode($pattern, $encoding), api_utf8_encode($replacement, $encoding), api_utf8_encode($string, $encoding)), $encoding);
-        } else {
-            $result = api_utf8_decode(@mb_eregi_replace(api_utf8_encode($pattern, $encoding), api_utf8_encode($replacement, $encoding), api_utf8_encode($string, $encoding), $option), $encoding);
-        }
-        _api_mb_regex_encoding($encoding);
-        return $result;
-    }
-    return eregi_replace($pattern, $replacement, $string);
-}
-
 /**
  * String comparison
  */
@@ -2264,20 +2172,6 @@ function api_strcmp($string1, $string2, $language = null, $encoding = null)
     return strcmp($string1, $string2);
 }
 
-/**
- * Performs string comparison in so called "natural order", case insensitive, language sensitive, with extended multibyte support.
- * @param string $string1				The first string.
- * @param string $string2				The second string.
- * @param string $language (optional)	The language in which comparison is to be made. If language is omitted, interface language is assumed then.
- * @param string $encoding (optional)	The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
- * @return int							Returns < 0 if $string1 is less than $string2; > 0 if $string1 is greater than $string2; and 0 if the strings are equal.
- * This function is aimed at replacing the function strnatcasecmp() for human-language strings.
- * @link http://php.net/manual/en/function.strnatcasecmp
- */
-function api_strnatcasecmp($string1, $string2, $language = null, $encoding = null) {
-    return api_strnatcmp(api_strtolower($string1, $encoding), api_strtolower($string2, $encoding), $language, $encoding);
-}
-
 /**
  * Performs string comparison in so called "natural order", case sensitive, language sensitive, with extended multibyte support.
  * @param string $string1				The first string.
@@ -2304,77 +2198,6 @@ function api_strnatcmp($string1, $string2, $language = null, $encoding = null) {
  * Sorting arrays
  */
 
-/**
- * Sorts an array with maintaining index association, elements will be arranged from the lowest to the highest.
- * @param array $array					The input array.
- * @param int $sort_flag (optional)		Shows how elements of the array to be compared.
- * @param string $language (optional)	The language in which comparison is to be made. If language is omitted, interface language is assumed then.
- * @param string $encoding (optional)	The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
- * @return bool							Returns TRUE on success, FALSE on error.
- * Note: $sort_flag may have the following values:
- * SORT_REGULAR - internal PHP-rules for comparison will be applied, without preliminary changing types;
- * SORT_NUMERIC - items will be compared as numbers;
- * SORT_STRING - items will be compared as strings. If intl extension is enabled, then comparison will be language-sensitive using internally a created ICU locale;
- * SORT_LOCALE_STRING - items will be compared as strings depending on the current POSIX locale. If intl extension is enabled, then comparison will be language-sensitive using internally a created ICU locale.
- * This function is aimed at replacing the function asort() for sorting human-language strings.
- * @link http://php.net/manual/en/function.asort.php
- * @link http://php.net/manual/en/collator.asort.php
- */
-function api_asort(&$array, $sort_flag = SORT_REGULAR, $language = null, $encoding = null) {
-    if (INTL_INSTALLED) {
-        if (empty($encoding)) {
-            $encoding = _api_mb_internal_encoding();
-        }
-        $collator = _api_get_collator($language);
-        if (is_object($collator)) {
-            if (api_is_utf8($encoding)) {
-                $sort_flag = ($sort_flag == SORT_LOCALE_STRING) ? SORT_STRING : $sort_flag;
-                return collator_asort($collator, $array, _api_get_collator_sort_flag($sort_flag));
-            }
-            elseif ($sort_flag == SORT_STRING || $sort_flag == SORT_LOCALE_STRING) {
-                global $_api_collator, $_api_encoding;
-                $_api_collator = $collator;
-                $_api_encoding = $encoding;
-                return uasort($array, '_api_cmp');
-            }
-        }
-    }
-    return asort($array, $sort_flag);
-}
-
-/**
- * Sorts an array with maintaining index association, elements will be arranged from the highest to the lowest (in reverse order).
- * @param array $array					The input array.
- * @param int $sort_flag (optional)		Shows how elements of the array to be compared.
- * @param string $language (optional)	The language in which comparison is to be made. If language is omitted, interface language is assumed then.
- * @param string $encoding (optional)	The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
- * @return bool							Returns TRUE on success, FALSE on error.
- * Note: $sort_flag may have the following values:
- * SORT_REGULAR - internal PHP-rules for comparison will be applied, without preliminary changing types;
- * SORT_NUMERIC - items will be compared as numbers;
- * SORT_STRING - items will be compared as strings. If intl extension is enabled, then comparison will be language-sensitive using internally a created ICU locale;
- * SORT_LOCALE_STRING - items will be compared as strings depending on the current POSIX locale. If intl extension is enabled, then comparison will be language-sensitive using internally a created ICU locale.
- * This function is aimed at replacing the function arsort() for sorting human-language strings.
- * @link http://php.net/manual/en/function.arsort.php
- */
-function api_arsort(&$array, $sort_flag = SORT_REGULAR, $language = null, $encoding = null) {
-    if (INTL_INSTALLED) {
-        if (empty($encoding)) {
-            $encoding = _api_mb_internal_encoding();
-        }
-        $collator = _api_get_collator($language);
-        if (is_object($collator)) {
-            if ($sort_flag == SORT_STRING || $sort_flag == SORT_LOCALE_STRING) {
-                global $_api_collator, $_api_encoding;
-                $_api_collator = $collator;
-                $_api_encoding = $encoding;
-                return uasort($array, '_api_rcmp');
-            }
-        }
-    }
-    return arsort($array, $sort_flag);
-}
-
 /**
  * Sorts an array using natural order algorithm.
  * @param array $array					The input array.
@@ -2423,297 +2246,6 @@ function api_natrsort(&$array, $language = null, $encoding = null) {
     return uasort($array, '_api_strnatrcmp');
 }
 
-/**
- * Sorts an array using natural order algorithm, case-insensitive.
- * @param array $array					The input array.
- * @param string $language (optional)	The language in which comparison is to be made. If language is omitted, interface language is assumed then.
- * @param string $encoding (optional)	The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
- * @return bool							Returns TRUE on success, FALSE on error.
- * This function is aimed at replacing the function natcasesort() for sorting human-language strings.
- * @link http://php.net/manual/en/function.natcasesort.php
- */
-function api_natcasesort(&$array, $language = null, $encoding = null) {
-    if (INTL_INSTALLED) {
-        if (empty($encoding)) {
-            $encoding = _api_mb_internal_encoding();
-        }
-        $collator = _api_get_alpha_numerical_collator($language);
-        if (is_object($collator)) {
-            global $_api_collator, $_api_encoding;
-            $_api_collator = $collator;
-            $_api_encoding = $encoding;
-            return uasort($array, '_api_casecmp');
-        }
-    }
-    return natcasesort($array);
-}
-
-/**
- * Sorts an array using natural order algorithm, case-insensitive, reverse order.
- * @param array $array					The input array.
- * @param string $language (optional)	The language in which comparison is to be made. If language is omitted, interface language is assumed then.
- * @param string $encoding (optional)	The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
- * @return bool							Returns TRUE on success, FALSE on error.
- */
-function api_natcasersort(&$array, $language = null, $encoding = null) {
-    if (INTL_INSTALLED) {
-        if (empty($encoding)) {
-            $encoding = _api_mb_internal_encoding();
-        }
-        $collator = _api_get_alpha_numerical_collator($language);
-        if (is_object($collator)) {
-            global $_api_collator, $_api_encoding;
-            $_api_collator = $collator;
-            $_api_encoding = $encoding;
-            return uasort($array, '_api_casercmp');
-        }
-    }
-    return uasort($array, '_api_strnatcasercmp');
-}
-
-/**
- * Sorts an array by keys, elements will be arranged from the lowest key to the highest key.
- * @param array $array					The input array.
- * @param int $sort_flag (optional)		Shows how keys of the array to be compared.
- * @param string $language (optional)	The language in which comparison is to be made. If language is omitted, interface language is assumed then.
- * @param string $encoding (optional)	The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
- * @return bool							Returns TRUE on success, FALSE on error.
- * Note: $sort_flag may have the following values:
- * SORT_REGULAR - internal PHP-rules for comparison will be applied, without preliminary changing types;
- * SORT_NUMERIC - keys will be compared as numbers;
- * SORT_STRING - keys will be compared as strings. If intl extension is enabled, then comparison will be language-sensitive using internally a created ICU locale;
- * SORT_LOCALE_STRING - keys will be compared as strings depending on the current POSIX locale. If intl extension is enabled, then comparison will be language-sensitive using internally a created ICU locale.
- * This function is aimed at replacing the function ksort() for sorting human-language key strings.
- * @link http://php.net/manual/en/function.ksort.php
- */
-function api_ksort(&$array, $sort_flag = SORT_REGULAR, $language = null, $encoding = null) {
-    if (INTL_INSTALLED) {
-        if (empty($encoding)) {
-            $encoding = _api_mb_internal_encoding();
-        }
-        $collator = _api_get_collator($language);
-        if (is_object($collator)) {
-            if ($sort_flag == SORT_STRING || $sort_flag == SORT_LOCALE_STRING) {
-                global $_api_collator, $_api_encoding;
-                $_api_collator = $collator;
-                $_api_encoding = $encoding;
-                return uksort($array, '_api_cmp');
-            }
-        }
-    }
-    return ksort($array, $sort_flag);
-}
-
-/**
- * Sorts an array by keys, elements will be arranged from the highest key to the lowest key (in reverse order).
- * @param array $array					The input array.
- * @param int $sort_flag (optional)		Shows how keys of the array to be compared.
- * @param string $language (optional)	The language in which comparison is to be made. If language is omitted, interface language is assumed then.
- * @param string $encoding (optional)	The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
- * @return bool							Returns TRUE on success, FALSE on error.
- * Note: $sort_flag may have the following values:
- * SORT_REGULAR - internal PHP-rules for comparison will be applied, without preliminary changing types;
- * SORT_NUMERIC - keys will be compared as numbers;
- * SORT_STRING - keys will be compared as strings. If intl extension is enabled, then comparison will be language-sensitive using internally a created ICU locale;
- * SORT_LOCALE_STRING - keys will be compared as strings depending on the current POSIX locale. If intl extension is enabled, then comparison will be language-sensitive using internally a created ICU locale.
- * This function is aimed at replacing the function krsort() for sorting human-language key strings.
- * @link http://php.net/manual/en/function.krsort.php
- */
-function api_krsort(&$array, $sort_flag = SORT_REGULAR, $language = null, $encoding = null) {
-    if (INTL_INSTALLED) {
-        if (empty($encoding)) {
-            $encoding = _api_mb_internal_encoding();
-        }
-        $collator = _api_get_collator($language);
-        if (is_object($collator)) {
-            if ($sort_flag == SORT_STRING || $sort_flag == SORT_LOCALE_STRING) {
-                global $_api_collator, $_api_encoding;
-                $_api_collator = $collator;
-                $_api_encoding = $encoding;
-                return uksort($array, '_api_rcmp');
-            }
-        }
-    }
-    return krsort($array, $sort_flag);
-}
-
-/**
- * Sorts an array by keys using natural order algorithm.
- * @param array $array					The input array.
- * @param string $language (optional)	The language in which comparison is to be made. If language is omitted, interface language is assumed then.
- * @param string $encoding (optional)	The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
- * @return bool							Returns TRUE on success, FALSE on error.
- */
-function api_knatsort(&$array, $language = null, $encoding = null) {
-    if (INTL_INSTALLED) {
-        if (empty($encoding)) {
-            $encoding = _api_mb_internal_encoding();
-        }
-        $collator = _api_get_alpha_numerical_collator($language);
-        if (is_object($collator)) {
-            global $_api_collator, $_api_encoding;
-            $_api_collator = $collator;
-            $_api_encoding = $encoding;
-            return uksort($array, '_api_cmp');
-        }
-    }
-    return uksort($array, 'strnatcmp');
-}
-
-/**
- * Sorts an array by keys using natural order algorithm in reverse order.
- * @param array $array					The input array.
- * @param string $language (optional)	The language in which comparison is to be made. If language is omitted, interface language is assumed then.
- * @param string $encoding (optional)	The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
- * @return bool							Returns TRUE on success, FALSE on error.
- */
-function api_knatrsort(&$array, $language = null, $encoding = null) {
-    if (INTL_INSTALLED) {
-        if (empty($encoding)) {
-            $encoding = _api_mb_internal_encoding();
-        }
-        $collator = _api_get_alpha_numerical_collator($language);
-        if (is_object($collator)) {
-            global $_api_collator, $_api_encoding;
-            $_api_collator = $collator;
-            $_api_encoding = $encoding;
-            return uksort($array, '_api_rcmp');
-        }
-    }
-    return uksort($array, '_api_strnatrcmp');
-}
-
-/**
- * Sorts an array by keys using natural order algorithm, case insensitive.
- * @param array $array					The input array.
- * @param string $language (optional)	The language in which comparison is to be made. If language is omitted, interface language is assumed then.
- * @param string $encoding (optional)	The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
- * @return bool							Returns TRUE on success, FALSE on error.
- */
-function api_knatcasesort(&$array, $language = null, $encoding = null) {
-    if (INTL_INSTALLED) {
-        if (empty($encoding)) {
-            $encoding = _api_mb_internal_encoding();
-        }
-        $collator = _api_get_alpha_numerical_collator($language);
-        if (is_object($collator)) {
-            global $_api_collator, $_api_encoding;
-            $_api_collator = $collator;
-            $_api_encoding = $encoding;
-            return uksort($array, '_api_casecmp');
-        }
-    }
-    return uksort($array, 'strnatcasecmp');
-}
-
-/**
- * Sorts an array, elements will be arranged from the lowest to the highest.
- * @param array $array					The input array.
- * @param int $sort_flag (optional)		Shows how elements of the array to be compared.
- * @param string $language (optional)	The language in which comparison is to be made. If language is omitted, interface language is assumed then.
- * @param string $encoding (optional)	The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
- * @return bool							Returns TRUE on success, FALSE on error.
- * Note: $sort_flag may have the following values:
- * SORT_REGULAR - internal PHP-rules for comparison will be applied, without preliminary changing types;
- * SORT_NUMERIC - items will be compared as numbers;
- * SORT_STRING - items will be compared as strings. If intl extension is enabled, then comparison will be language-sensitive using internally a created ICU locale;
- * SORT_LOCALE_STRING - items will be compared as strings depending on the current POSIX locale. If intl extension is enabled, then comparison will be language-sensitive using internally a created ICU locale.
- * This function is aimed at replacing the function sort() for sorting human-language strings.
- * @link http://php.net/manual/en/function.sort.php
- * @link http://php.net/manual/en/collator.sort.php
- */
-function api_sort(&$array, $sort_flag = SORT_REGULAR, $language = null, $encoding = null) {
-    if (INTL_INSTALLED) {
-        if (empty($encoding)) {
-            $encoding = _api_mb_internal_encoding();
-        }
-        $collator = _api_get_collator($language);
-        if (is_object($collator)) {
-            if (api_is_utf8($encoding)) {
-                $sort_flag = ($sort_flag == SORT_LOCALE_STRING) ? SORT_STRING : $sort_flag;
-                return collator_sort($collator, $array, _api_get_collator_sort_flag($sort_flag));
-            } elseif ($sort_flag == SORT_STRING || $sort_flag == SORT_LOCALE_STRING) {
-                global $_api_collator, $_api_encoding;
-                $_api_collator = $collator;
-                $_api_encoding = $encoding;
-                return usort($array, '_api_cmp');
-            }
-        }
-    }
-    return sort($array, $sort_flag);
-}
-
-/**
- * Sorts an array, elements will be arranged from the highest to the lowest (in reverse order).
- * @param array $array					The input array.
- * @param int $sort_flag (optional)		Shows how elements of the array to be compared.
- * @param string $language (optional)	The language in which comparison is to be made. If language is omitted, interface language is assumed then.
- * @param string $encoding (optional)	The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
- * @return bool							Returns TRUE on success, FALSE on error.
- * Note: $sort_flag may have the following values:
- * SORT_REGULAR - internal PHP-rules for comparison will be applied, without preliminary changing types;
- * SORT_NUMERIC - items will be compared as numbers;
- * SORT_STRING - items will be compared as strings. If intl extension is enabled, then comparison will be language-sensitive using internally a created ICU locale;
- * SORT_LOCALE_STRING - items will be compared as strings depending on the current POSIX locale. If intl extension is enabled, then comparison will be language-sensitive using internally a created ICU locale.
- * This function is aimed at replacing the function rsort() for sorting human-language strings.
- * @link http://php.net/manual/en/function.rsort.php
- */
-function api_rsort(&$array, $sort_flag = SORT_REGULAR, $language = null, $encoding = null) {
-    if (INTL_INSTALLED) {
-        if (empty($encoding)) {
-            $encoding = _api_mb_internal_encoding();
-        }
-        $collator = _api_get_collator($language);
-        if (is_object($collator)) {
-            if ($sort_flag == SORT_STRING || $sort_flag == SORT_LOCALE_STRING) {
-                global $_api_collator, $_api_encoding;
-                $_api_collator = $collator;
-                $_api_encoding = $encoding;
-                return usort($array, '_api_rcmp');
-            }
-        }
-    }
-    return rsort($array, $sort_flag);
-}
-
-/**
- * Common sting operations with arrays
- */
-
-/**
- * Checks if a value exists in an array, a case insensitive version of in_array() function with extended multibyte support.
- * @param mixed $needle					The searched value. If needle is a string, the comparison is done in a case-insensitive manner.
- * @param array $haystack				The array.
- * @param bool $strict (optional)		If is set to TRUE then the function will also check the types of the $needle in the $haystack. The default value if FALSE.
- * @param string $encoding (optional)	The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
- * @return bool							Returns TRUE if $needle is found in the array, FALSE otherwise.
- * @link http://php.net/manual/en/function.in-array.php
- */
-function api_in_array_nocase($needle, $haystack, $strict = false, $encoding = null) {
-    if (is_array($needle)) {
-        foreach ($needle as $item) {
-            if (api_in_array_nocase($item, $haystack, $strict, $encoding)) return true;
-        }
-        return false;
-    }
-    if (!is_string($needle)) {
-        return in_array($needle, $haystack, $strict);
-    }
-    $needle = api_strtolower($needle, $encoding);
-    if (!is_array($haystack)) {
-        return false;
-    }
-    foreach ($haystack as $item) {
-        if ($strict && !is_string($item)) {
-            continue;
-        }
-        if (api_strtolower($item, $encoding) == $needle) {
-            return true;
-        }
-    }
-    return false;
-}
-
 /**
  * Encoding management functions
  */
@@ -2835,41 +2367,6 @@ function api_get_system_encoding() {
     return $system_encoding;
 }
 
-/**
- * This function returns the encoding, currently used by the file system.
- * @return string	The file system's encoding, it depends on the locale that OS currently uses.
- * @link http://php.net/manual/en/function.setlocale.php
- * Note: For Linux systems, to see all installed locales type in a terminal  locale -a
- */
-function api_get_file_system_encoding() {
-    static $file_system_encoding;
-    if (!isset($file_system_encoding)) {
-        $locale = setlocale(LC_CTYPE, '0');
-        $seek_pos = strpos($locale, '.');
-        if ($seek_pos !== false) {
-            $file_system_encoding = substr($locale, $seek_pos + 1);
-            if (IS_WINDOWS_OS) {
-                $file_system_encoding = 'CP'.$file_system_encoding;
-            }
-        }
-        // Dealing with some aliases.
-        $file_system_encoding = str_ireplace('utf8', 'UTF-8', $file_system_encoding);
-        $file_system_encoding = preg_replace('/^CP65001$/', 'UTF-8', $file_system_encoding);
-        $file_system_encoding = preg_replace('/^CP(125[0-9])$/', 'WINDOWS-\1', $file_system_encoding);
-        $file_system_encoding = str_replace('WINDOWS-1252', 'ISO-8859-15', $file_system_encoding);
-        if (empty($file_system_encoding)) {
-            if (IS_WINDOWS_OS) {
-                // Not expected for Windows, this assignment is here just in case.
-                $file_system_encoding = api_get_system_encoding();
-            } else {
-                // For Ububntu and other UTF-8 enabled Linux systems this fits with the default settings.
-                $file_system_encoding = 'UTF-8';
-            }
-        }
-    }
-    return $file_system_encoding;
-}
-
 /**
  * Checks whether a specified encoding is supported by this API.
  * @param string $encoding	The specified encoding.
@@ -2972,7 +2469,6 @@ function api_detect_encoding($string, $language = null) {
  */
 function api_is_valid_utf8(&$string)
 {
-
     return Utf8::isUtf8($string);
 }
 
@@ -2994,27 +2490,12 @@ function api_is_valid_ascii(&$string)
  *
  * @return bool
  */
-function api_is_valid_date($date, $format = 'Y-m-d H:i:s') {
+function api_is_valid_date($date, $format = 'Y-m-d H:i:s')
+{
     $d = DateTime::createFromFormat($format, $date);
     return $d && $d->format($format) == $date;
 }
 
-/**
- * Return the encoding country code for jquery datepicker
- * used for exemple in main/exercice/exercise_report.php
- */
-function get_datepicker_langage_code() {
-    $languaje   = 'en-GB';
-    $platform_isocode = strtolower(api_get_language_isocode());
-
-    // languages supported by jqgrid see files in main/inc/lib/javascript/jqgrid/js/i18n
-    $datapicker_langs = array('af', 'ar', 'ar-DZ', 'az', 'bg', 'bs', 'ca', 'cs', 'cy-GB', 'da', 'de', 'el', 'en-AU', 'en-GB', 'en-NZ', 'eo', 'es', 'et', 'eu', 'fa', 'fi', 'fo', 'fr', 'fr-CH', 'gl', 'he', 'hi', 'hr', 'hu', 'hy', 'id', 'is', 'it', 'ja', 'ka', 'kk', 'km', 'ko', 'lb', 'lt', 'lv', 'mk', 'ml', 'ms', 'nl', 'nl-BE', 'no', 'pl', 'pt', 'pt-BR', 'rm', 'ro', 'ru', 'sk', 'sl', 'sq', 'sr', 'sr-SR', 'sv', 'ta', 'th', 'tj', 'tr', 'uk', 'vi', 'zh-CN', 'zh-HK', 'zh-TW');
-    if (in_array($platform_isocode, $datapicker_langs)) {
-        $languaje = $platform_isocode;
-    }
-    return $languaje;
-}
-
 /**
  * Returns the variable translated
  * @param string $variable the string to translate
@@ -3025,6 +2506,7 @@ function get_plugin_lang($variable, $pluginName) {
     $plugin = $pluginName::create();
     return $plugin->get_lang($variable);
 }
+
 /**
  * Functions for internal use behind this API
  */

+ 2 - 130
main/inc/lib/internationalization_internal.lib.php

@@ -255,43 +255,6 @@ function _api_get_character_map_name($encoding) {
     return isset($character_map_selector[$encoding]) ? $character_map_selector[$encoding] : '';
 }
 
-/**
- * This function parses a given conversion table (a text file) and creates in the memory
- * two tables for conversion - character set from/to Unicode codepoints.
- * @param string $name		The name of the thext file that contains the conversion table, for example 'CP1252' (file CP1252.TXT will be parsed).
- * @return array			Returns an array that contains forward and reverse tables (from/to Unicode).
- */
-function &_api_parse_character_map($name) {
-    $result = array();
-    $file = dirname(__FILE__).'/internationalization_database/conversion/' . $name . '.TXT';
-    if (file_exists($file)) {
-        $text = @file_get_contents($file);
-        if ($text !== false) {
-            $text = explode(chr(10), $text);
-            foreach ($text as $line) {
-                if (empty($line)) {
-                    continue;
-                }
-                if (!empty($line) && trim($line) && $line[0] != '#') {
-                    $matches = array();
-                    preg_match('/[[:space:]]*0x([[:alnum:]]*)[[:space:]]+0x([[:alnum:]]*)[[:space:]]+/', $line, $matches);
-                    $ord = hexdec(trim($matches[1]));
-                    if ($ord > 127) {
-                        $codepoint =  hexdec(trim($matches[2]));
-                        $result['local'][$ord] = $codepoint;
-                        $result['unicode'][$codepoint] = $ord;
-                    }
-                }
-            }
-        } else {
-            return false ;
-        }
-    } else {
-        return false;
-    }
-    return $result;
-}
-
 /**
  * Takes an UTF-8 string and returns an array of integer values representing the Unicode characters.
  * Astral planes are supported ie. the ints in the output can be > 0xFFFF. Occurrances of the BOM are ignored.
@@ -801,7 +764,8 @@ function & _api_non_utf8_encodings() {
  * Note: This function is used in the global initialization script for setting the internal encoding to the platform's character set.
  * @link http://php.net/manual/en/function.mb-internal-encoding
  */
-function _api_mb_internal_encoding($encoding = null) {
+function _api_mb_internal_encoding($encoding = null)
+{
     static $mb_internal_encoding = null;
     if (empty($encoding)) {
         if (is_null($mb_internal_encoding)) {
@@ -846,98 +810,6 @@ function _api_mb_regex_encoding($encoding = null) {
     return false;
 }
 
-/**
- * Retrieves specified internal encoding configuration variable within the PHP iconv extension.
- * @param string $type	The parameter $type could be: 'iconv_internal_encoding', 'iconv_input_encoding', or 'iconv_output_encoding'.
- * @return mixed		The function returns the requested encoding or FALSE on error.
- * @link http://php.net/manual/en/function.iconv-get-encoding
- */
-function _api_iconv_get_encoding($type) {
-    return _api_iconv_set_encoding($type);
-}
-
-/**
- * Sets specified internal encoding configuration variables within the PHP iconv extension.
- * @param string $type					The parameter $type could be: 'iconv_internal_encoding', 'iconv_input_encoding', or 'iconv_output_encoding'.
- * @param string $encoding (optional)	The desired encoding to be set.
- * @return bool							Returns TRUE on success, FALSE on error.
- * Note: This function is used in the global initialization script for setting these three internal encodings to the platform's character set.
- * @link http://php.net/manual/en/function.iconv-set-encoding
- */
-function _api_iconv_set_encoding($type, $encoding = null) {
-    static $iconv_internal_encoding = null;
-    static $iconv_input_encoding = null;
-    static $iconv_output_encoding = null;
-    if (!ICONV_INSTALLED) {
-        return false;
-    }
-    switch ($type) {
-        case 'iconv_internal_encoding':
-            if (empty($encoding)) {
-                if (is_null($iconv_internal_encoding)) {
-                    $iconv_internal_encoding = @iconv_get_encoding($type);
-                }
-                return $iconv_internal_encoding;
-            }
-            if (_api_iconv_supports($encoding)) {
-                if(@iconv_set_encoding($type, $encoding)) {
-                    $iconv_internal_encoding = $encoding;
-                    return true;
-                }
-                return false;
-            }
-            return false;
-        case 'iconv_input_encoding':
-            if (empty($encoding)) {
-                if (is_null($iconv_input_encoding)) {
-                    $iconv_input_encoding = @iconv_get_encoding($type);
-                }
-                return $iconv_input_encoding;
-            }
-            if (_api_iconv_supports($encoding)) {
-                if(@iconv_set_encoding($type, $encoding)) {
-                    $iconv_input_encoding = $encoding;
-                    return true;
-                }
-                return false;
-            }
-            return false;
-        case 'iconv_output_encoding':
-            if (empty($encoding)) {
-                if (is_null($iconv_output_encoding)) {
-                    $iconv_output_encoding = @iconv_get_encoding($type);
-                }
-                return $iconv_output_encoding;
-            }
-            if (_api_iconv_supports($encoding)) {
-                if(@iconv_set_encoding($type, $encoding)) {
-                    $iconv_output_encoding = $encoding;
-                    return true;
-                }
-                return false;
-            }
-            return false;
-    }
-    return false;
-}
-
-/**
- * Checks whether a given encoding is known to define single-byte characters only.
- * The result might be not accurate for unknown by this library encodings. This is not fatal,
- * then the library picks up conversions plus Unicode related internal algorithms.
- * @param string $encoding		A given encoding identificator.
- * @return bool					TRUE if the encoding is known as single-byte (for ISO-8859-15, WINDOWS-1251, etc.), FALSE otherwise.
- */
-function _api_is_single_byte_encoding($encoding) {
-    static $checked = array();
-    if (!isset($checked[$encoding])) {
-        $character_map = _api_get_character_map_name(api_refine_encoding_id($encoding));
-        $checked[$encoding] = (!empty($character_map)
-            && !in_array($character_map, array('UTF-8', 'HTML-ENTITIES')));
-    }
-    return $checked[$encoding];
-}
-
 /**
  * Checks whether the specified encoding is supported by the PHP mbstring extension.
  * @param string $encoding	The specified encoding.

+ 17 - 6
main/inc/lib/sessionmanager.lib.php

@@ -3341,26 +3341,36 @@ class SessionManager
     /**
      * The general coach (field: session.id_coach)
      * @param int $user_id user id
+     * @param boolean   $asPlatformAdmin The user is platform admin, return everything
      * @return array
      */
-    public static function get_sessions_by_general_coach($user_id)
+    public static function get_sessions_by_general_coach($user_id, $asPlatformAdmin = false)
     {
         $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
         $user_id = intval($user_id);
 
         // Session where we are general coach
         $sql = "SELECT DISTINCT *
-                FROM $session_table
-                WHERE id_coach = $user_id";
+                FROM $session_table";
+
+        if (!$asPlatformAdmin) {
+            $sql .= " WHERE id_coach = $user_id";
+        }
 
         if (api_is_multiple_url_enabled()) {
             $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
             $access_url_id = api_get_current_access_url_id();
+
+            $sqlCoach = '';
+            if (!$asPlatformAdmin) {
+                $sqlCoach = " id_coach = $user_id AND ";
+            }
+
             if ($access_url_id != -1) {
                 $sql = 'SELECT DISTINCT session.*
                     FROM ' . $session_table . ' session INNER JOIN ' . $tbl_session_rel_access_url . ' session_rel_url
                     ON (session.id = session_rel_url.session_id)
-                    WHERE id_coach = ' . $user_id . ' AND access_url_id = ' . $access_url_id;
+                    WHERE '.$sqlCoach.' access_url_id = ' . $access_url_id;
             }
         }
         $sql .= ' ORDER by name';
@@ -5446,12 +5456,13 @@ class SessionManager
      * Get the session coached by a user (general coach and course-session coach)
      * @param int $coachId The coach id
      * @param boolean $checkSessionRelUserVisibility Check the session visibility
+     * @param boolean $asPlatformAdmin The user is a platform admin and we want all sessions
      * @return array The session list
      */
-    public static function getSessionsCoachedByUser($coachId, $checkSessionRelUserVisibility = false)
+    public static function getSessionsCoachedByUser($coachId, $checkSessionRelUserVisibility = false, $asPlatformAdmin = false)
     {
         // Get all sessions where $coachId is the general coach
-        $sessions = self::get_sessions_by_general_coach($coachId);
+        $sessions = self::get_sessions_by_general_coach($coachId, $asPlatformAdmin);
         // Get all sessions where $coachId is the course - session coach
         $courseSessionList = self::getCoursesListByCourseCoach($coachId);
         $sessionsByCoach = array();

+ 32 - 0
main/inc/lib/usermanager.lib.php

@@ -5356,4 +5356,36 @@ EOF;
 
         return Display::url(Display::img($userProfile['file']), $userInfo['profile_url']);
     }
+
+    /**
+     * Get users whose name matches $firstname and $lastname
+     * @param string $firstname Firstname to search
+     * @param string $lastname Lastname to search
+     * @return array The user list
+     */
+    public static function getUserByName($firstname, $lastname)
+    {
+        $firstname = Database::escape_string($firstname);
+        $lastname = Database::escape_string($lastname);
+
+        $userTable = Database::get_main_table(TABLE_MAIN_USER);
+
+        $sql = <<<SQL
+            SELECT id, username, lastname, firstname
+            FROM $userTable
+            WHERE firstname LIKE '$firstname%' AND
+                lastname LIKE '$lastname%'
+SQL;
+
+        $result = Database::query($sql);
+
+        $users = [];
+
+        while ($resultData = Database::fetch_object($result)) {
+            $users[] = $resultData;
+        }
+
+        return $users;
+    }
+
 }

+ 37 - 0
main/inc/lib/userportal.lib.php

@@ -1425,4 +1425,41 @@ class IndexManager
     {
         return CourseManager::return_hot_courses();
     }
+
+    /**
+     * Generate the block for show a panel with links to My Certificates and Certificates Search pages
+     * @return string The HTML code for the panel
+     */
+    public function returnCertificatesSearchBlock()
+    {
+        $certificatesItem = Display::tag(
+            'li',
+            Display::url(
+                get_lang('MyCertificates'),
+                api_get_path(WEB_CODE_PATH) . "gradebook/my_certificates.php"
+            )
+        );
+
+        $searchItem = null;
+
+        if (api_get_setting('allow_public_certificates') == 'true') {
+            $searchItem = Display::tag(
+                'li',
+                Display::url(
+                    get_lang('Search'),
+                    api_get_path(WEB_CODE_PATH) . "gradebook/search.php"
+                )
+            );
+        }
+
+        return Display::panel(
+            Display::tag(
+                'ul',
+                implode(' ', [$certificatesItem, $searchItem]),
+                ['class' => 'nav nav-pills nav-stacked']
+            ),
+            get_lang('Certificates')
+        );
+    }
+
 }

+ 55 - 55
main/lang/english/trad4all.inc.php

@@ -325,18 +325,18 @@ $DeleteUsersNotInList = "Unsubscribe students which are not in the imported list
 $IfSessionExistsUpdate = "If a session exists, update it";
 $CreatedByXYOnZ = "Create by <a href=\"%s\">%s</a> on %s";
 $LoginWithExternalAccount = "Login without an institutional account";
-$ImportAikenQuizExplanationExample = "This is the text for question 1
-A. Answer 1
-B. Answer 2
-C. Answer 3
-ANSWER: B
-
-This is the text for question 2
-A. Answer 1
-B. Answer 2
-C. Answer 3
-D. Answer 4
-ANSWER: D
+$ImportAikenQuizExplanationExample = "This is the text for question 1
+A. Answer 1
+B. Answer 2
+C. Answer 3
+ANSWER: B
+
+This is the text for question 2
+A. Answer 1
+B. Answer 2
+C. Answer 3
+D. Answer 4
+ANSWER: D
 ANSWER_EXPLANATION: this is an optional feedback comment that will appear next to the correct answer.";
 $ImportAikenQuizExplanation = "The Aiken format comes in a simple text (.txt) file, with several question blocks, each separated by a blank line. The first line is the question, the answer lines are prefixed by a letter and a dot, and the correct answer comes next with the ANSWER: prefix. See example below.";
 $ExerciseAikenErrorNoAnswerOptionGiven = "The imported file has at least one question without any answer (or the answers do not include the required prefix letter). Please make sure each question has at least one answer and that it is prefixed by a letter and a dot or a parenthesis, like this: A. answer one";
@@ -425,18 +425,18 @@ $VersionUpToDate = "Your version is up-to-date";
 $LatestVersionIs = "The latest version is";
 $YourVersionNotUpToDate = "Your version is not up-to-date";
 $Hotpotatoes = "Hotpotatoes";
-$ZeroMeansNoQuestionWillBeSelectedMinusOneMeansThatAllQuestionsWillBeSelected = "-1 = All questions will be selected.
+$ZeroMeansNoQuestionWillBeSelectedMinusOneMeansThatAllQuestionsWillBeSelected = "-1 = All questions will be selected.
  0 = No questions will be selected.";
-$EmailNotificationTemplateDescription = "You can customize the email sent to users when they finished the exercise. You can use tags like these:
-
-1. {{ student.username }}
-2. {{ student.firstname }}
-3. {{ student.lastname }}
-4. {{ student.official_code }}
-5. {{ exercise.title }}
-6. {{ exercise.start_time }}
-7. {{ exercise.end_time }}
-8. {{ course.title }}
+$EmailNotificationTemplateDescription = "You can customize the email sent to users when they finished the exercise. You can use tags like these:
+
+1. {{ student.username }}
+2. {{ student.firstname }}
+3. {{ student.lastname }}
+4. {{ student.official_code }}
+5. {{ exercise.title }}
+6. {{ exercise.start_time }}
+7. {{ exercise.end_time }}
+8. {{ course.title }}
 9. {{ course.code }}";
 $EmailNotificationTemplate = "Email notification template";
 $ExerciseEndButtonDisconnect = "Logout";
@@ -844,10 +844,10 @@ $AllowVisitors = "Allow visitors";
 $EnableIframeInclusionComment = "Allowing arbitrary iframes in the HTML Editor will enhance the edition capabilities of the users, but it can represent a security risk. Please make sure you can rely on your users (i.e. you know who they are) before enabling this feature.";
 $AddedToLPCannotBeAccessed = "This exercise has been included in a learning path, so it cannot be accessed by students directly from here. If you want to put the same exercise available through the exercises tool, please make a copy of the current exercise using the copy icon.";
 $EnableIframeInclusionTitle = "Allow iframes in HTML Editor";
-$MailTemplateRegistrationMessage = "Dear ((firstname)) ((lastname)),\n\nYou are registered on
-((sitename)) with the following settings:\n\nUsername :
-((username))\nPass : ((password))\n\nThe address of ((sitename)) is :
-((url))\n\nIn case of trouble, contact us.\n\nYours sincerely
+$MailTemplateRegistrationMessage = "Dear ((firstname)) ((lastname)),\n\nYou are registered on
+((sitename)) with the following settings:\n\nUsername :
+((username))\nPass : ((password))\n\nThe address of ((sitename)) is :
+((url))\n\nIn case of trouble, contact us.\n\nYours sincerely
 \n((admin_name)) ((admin_surname)).";
 $Explanation = "Once you click on \"Create a course\", a course is created with a section for Tests, Project based learning, Assessments, Courses, Dropbox, Agenda and much more. Logging in as teacher provides you with editing privileges for this course.";
 $CodeTaken = "This training code is already in use.  <br>Use the <b>Back</b> button on your browser and try again";
@@ -2640,16 +2640,16 @@ $NoPosts = "No posts";
 $WithoutAchievedSkills = "Without achieved skills";
 $TypeMessage = "Please type your message!";
 $ConfirmReset = "Do you really want to delete all messages?";
-$MailCronCourseExpirationReminderBody = "Dear %s,
-
-It has come to our attention that you have not completed the course %s although its expiration date had been set on %s, remaining %s days to finish it.
-
-We remind you that you have only the possibility to follow this course once a year, that is why we invite you insistently to complete your course on time.
-
-You can return to the course connecting to the platform through this address: %s
-
-Best Regards,
-
+$MailCronCourseExpirationReminderBody = "Dear %s,
+
+It has come to our attention that you have not completed the course %s although its expiration date had been set on %s, remaining %s days to finish it.
+
+We remind you that you have only the possibility to follow this course once a year, that is why we invite you insistently to complete your course on time.
+
+You can return to the course connecting to the platform through this address: %s
+
+Best Regards,
+
 %s Team";
 $MailCronCourseExpirationReminderSubject = "Urgent: %s course expiration reminder";
 $ExerciseAndLearningPath = "Exercise and learning path";
@@ -5778,8 +5778,8 @@ $CheckThatYouHaveEnoughQuestionsInYourCategories = "Make sure you have enough qu
 $PortalCoursesLimitReached = "Sorry, this installation has a courses limit, which has now been reached. To increase the number of courses allowed on this Chamilo installation, please contact your hosting provider or, if available, upgrade to a superior hosting plan.";
 $PortalTeachersLimitReached = "Sorry, this installation has a teachers limit, which has now been reached. To increase the number of teachers allowed on this Chamilo installation, please contact your hosting provider or, if available, upgrade to a superior hosting plan.";
 $PortalUsersLimitReached = "Sorry, this installation has a users limit, which has now been reached. To increase the number of users allowed on this Chamilo installation, please contact your hosting provider or, if available, upgrade to a superior hosting plan.";
-$GenerateSurveyAccessLinkExplanation = "By copying the link below and pasting it in an e-mail or on a website, you will allow any anonymous person to enter and answer this survey.
-You can test this feature by clicking the link above and answering the survey.
+$GenerateSurveyAccessLinkExplanation = "By copying the link below and pasting it in an e-mail or on a website, you will allow any anonymous person to enter and answer this survey.
+You can test this feature by clicking the link above and answering the survey.
 This is particularly useful if you want to allow anyone on a forum to answer you survey and you don't know their e-mail addresses.";
 $LinkOpenSelf = "Open self";
 $LinkOpenBlank = "Open blank";
@@ -5832,8 +5832,8 @@ $Item = "Item";
 $ConfigureDashboardPlugin = "Configure Dashboard Plugin";
 $EditBlocks = "Edit blocks";
 $Never = "Never";
-$YourAccountIsActiveYouCanLoginAndCheckYourCourses = "Dear user, 
-
+$YourAccountIsActiveYouCanLoginAndCheckYourCourses = "Dear user, 
+
 Your account has now been activated on the platform. Please login and enjoy your courses.";
 $SessionFields = "Session fields";
 $CopyLabelSuffix = "Copy";
@@ -5895,7 +5895,7 @@ $CourseSettingsRegisterDirectLink = "If your course is public or open, you can u
 $DirectLink = "Direct link";
 $here = "here";
 $GoAheadAndBrowseOurCourseCatalogXOnceRegisteredYouWillSeeTheCourseHereX = "<p>Go ahead and browse our course catalog %s to register to any course you like. Once registered, you will see the course appear right %s, instead of this message.</p>";
-$HelloXAsYouCanSeeYourCourseListIsEmpty = "<p>Hello <strong>%s</strong> and welcome,</p>
+$HelloXAsYouCanSeeYourCourseListIsEmpty = "<p>Hello <strong>%s</strong> and welcome,</p>
 <p>As you can see, your courses list is still empty. That's because you are not registered to any course yet! </p>";
 $UnsubscribeUsersAlreadyAddedInCourse = "Unsubscribe users already added";
 $ImportUsers = "Import users";
@@ -6159,7 +6159,7 @@ $AverageScore = "Average score";
 $LastConnexionDate = "Last connexion date";
 $ToolVideoconference = "Videoconference";
 $BigBlueButtonEnableTitle = "BigBlueButton videoconference tool";
-$BigBlueButtonEnableComment = "Choose whether you want to enable the BigBlueButton videoconference tool. Once enabled, it will show as an additional course tool in all courses' homepage, and teachers will be able to launch a conference at any time. Learners will not be able to launch a conference, only join one. If you don't have a BigBlueButton server, please <a href=\"http://bigbluebutton.org/\" target=\"_blank\">set one up</a> or ask the <a href=\"http://www.chamilo.org/en/providers\" target=\"_blank\">Chamilo official providers</a> for a quote.
+$BigBlueButtonEnableComment = "Choose whether you want to enable the BigBlueButton videoconference tool. Once enabled, it will show as an additional course tool in all courses' homepage, and teachers will be able to launch a conference at any time. Learners will not be able to launch a conference, only join one. If you don't have a BigBlueButton server, please <a href=\"http://bigbluebutton.org/\" target=\"_blank\">set one up</a> or ask the <a href=\"http://www.chamilo.org/en/providers\" target=\"_blank\">Chamilo official providers</a> for a quote.
 BigBlueButton is a free (as in freedom *and* beer), but its installation requires a set of technical skills that might not be immediately available to all. You can install it on your own or seek professional help to assist you or do it for you. This help, however, will generate a certain cost. In the pure logic of the free software, we offer you the tools to make your work easier and recommend professionals (the Chamilo Official Providers) that will be able to help you if this were too difficult.";
 $BigBlueButtonHostTitle = "BigBlueButton server host";
 $BigBlueButtonHostComment = "This is the name of the server where your BigBlueButton server is running. Might be <i>localhost</i>, an IP address (e.g. 192.168.13.54) or a domain name (e.g. my.video.com).";
@@ -6170,14 +6170,14 @@ $OnlyAccessFromYourGroup = "Only accessible from your group";
 $CreateAssignmentPage = "This will create a special wiki page in which the teacher can describe the task and which will be automatically linked to the wiki pages where learners perform the task. Both the teacher's and the learners' pages are created automatically. In these tasks, learners can only edit and view theirs pages, but this can be changed easily if you need to.";
 $UserFolders = "Folders of users";
 $UserFolder = "User folder";
-$HelpUsersFolder = "INFORMATION VISIBLE TO THE TEACHER ONLY:\nThe users folder contains a folder for each user who has accessed it through the documents tool, or when any file has been sent in the course through the online editor. If neither circumstances has occurred, then no user folder will have been created. In the case of groups, files that are sent through the editor will be added in the folder of each group, which is only accessible by students from this group.
-<br /><br />
-The users folder and each of the included folders will be hidden by default in for all students, but each student can see the contents of his/her directory through the online editor. However, if a student knows the address of a file or folder of another student, he may be able to access it.
-<br /><br />
-If the folder of a student is visible, other students can see what it contains. In this case, the student that owns the folder can also (from the documents tool and only in his/her folder): create and edit web documents, convert a document into a template for personal use, create and edit drawings in SVG and PNG formats, record audio files in WAV format, make audio files in MP3 from a text, make snapshops from a webcam, send documents, create folders, move folders and files, delete folders and files, and download backup of his/her folder.
-<br /><br />
-Moreover, the documents tool is synchronized with the file manager of the online editor, so changes in the documents triggered in any one of these will affect both.
-<br /><br />
+$HelpUsersFolder = "INFORMATION VISIBLE TO THE TEACHER ONLY:\nThe users folder contains a folder for each user who has accessed it through the documents tool, or when any file has been sent in the course through the online editor. If neither circumstances has occurred, then no user folder will have been created. In the case of groups, files that are sent through the editor will be added in the folder of each group, which is only accessible by students from this group.
+<br /><br />
+The users folder and each of the included folders will be hidden by default in for all students, but each student can see the contents of his/her directory through the online editor. However, if a student knows the address of a file or folder of another student, he may be able to access it.
+<br /><br />
+If the folder of a student is visible, other students can see what it contains. In this case, the student that owns the folder can also (from the documents tool and only in his/her folder): create and edit web documents, convert a document into a template for personal use, create and edit drawings in SVG and PNG formats, record audio files in WAV format, make audio files in MP3 from a text, make snapshops from a webcam, send documents, create folders, move folders and files, delete folders and files, and download backup of his/her folder.
+<br /><br />
+Moreover, the documents tool is synchronized with the file manager of the online editor, so changes in the documents triggered in any one of these will affect both.
+<br /><br />
 As such, the user folder is not only a place to deposit files, it becomes a complete manager of the documents students use during the course. Also, remember that any user can copy a file that is visible from any folder in the documents tool (whether or not he is the owner) to his/her portfolios or personal documents area of social network, which will be available to him/her for use in other courses.";
 $HelpFolderChat = "INFORMATION VISIBLE TO THE TEACHER ONLY:\nThis folder contains all sessions that have been opened in the chat. Although the chat sessions can often be trivial, others can be really interesting and worthy of being incorporated as an additional work document. To do this without changing the visibility of this folder, make the file visible and link it from where you deem appropriate. It is not recommended to make this folder visible to all.";
 $HelpFolderCertificates = "INFORMATION VISIBLE TO THE TEACHER ONLY:\nThis folder contains the various certificates templates that have been created for the rating tool. It is not recommended to make this folder visible to all.";
@@ -6227,8 +6227,8 @@ $Pediaphon = "Use Pediaphon audio services";
 $HelpPediaphon = "Supports text with several thousands characters, in various types of male and female voices (depending on the language). Audio files will be generated and automatically saved to the Chamilo directory in which you are.";
 $FirstSelectALanguage = "Please select a language";
 $MoveUserStats = "Move users results from/to a session";
-$CompareUserResultsBetweenCoursesAndCoursesInASession = "This advanced tool allows you to manually improve the tracking of users results when moving from courses methodology to sessions methodology. In most cases, you won't need to use it.<br />
-On this screen, you can compare results of users between the context of a standalone course, and the context of the same course inside a session.<br />
+$CompareUserResultsBetweenCoursesAndCoursesInASession = "This advanced tool allows you to manually improve the tracking of users results when moving from courses methodology to sessions methodology. In most cases, you won't need to use it.<br />
+On this screen, you can compare results of users between the context of a standalone course, and the context of the same course inside a session.<br />
 Once you are sure about what to do, you can choose to move the tracking data of the students (exercises results and learning paths tracking) from a course to a session.";
 $PDFExportWatermarkEnableTitle = "Enable watermark in PDF export";
 $PDFExportWatermarkEnableComment = "By enabling this option, you can upload an image or a text that will be automatically added as watermark to all PDF exports of documents on the system.";
@@ -6363,8 +6363,8 @@ $MailNotifyInvitation = "Notify by mail on new invitation received";
 $MailNotifyMessage = "Notify by mail on new personal message received";
 $MailNotifyGroupMessage = "Notify by mail on new message received in group";
 $SearchEnabledTitle = "Fulltext search";
-$SearchEnabledComment = "This feature allows you to index most of the documents uploaded to your portal, then provide a search feature for users.<br />
-This feature will not index documents that have already been uploaded, so it is important to enable (if wanted) at the beginning of your implementation.<br />
+$SearchEnabledComment = "This feature allows you to index most of the documents uploaded to your portal, then provide a search feature for users.<br />
+This feature will not index documents that have already been uploaded, so it is important to enable (if wanted) at the beginning of your implementation.<br />
 Once enabled, a search box will appear in the courses list of every user. Searching for a specific term will bring a list of corresponding documents, exercises or forum topics, filtered depending on the availability of these contents to the user.";
 $SpecificSearchFieldsAvailable = "Available custom search fields";
 $XapianModuleInstalled = "Xapian module installed";

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 56 - 56
main/lang/spanish/trad4all.inc.php


+ 1 - 2
main/mySpace/user_add.php

@@ -189,8 +189,7 @@ if (api_is_session_admin()) {
 			$session_list[$session['id']]=$session['name'];
 		}
 	}
-	//asort($session_list);
-	//api_asort($session_list, SORT_STRING);
+
 	api_natsort($session_list);
 	$form->addElement('select', 'session_id', get_lang('Session'), $session_list);
 }

+ 63 - 0
main/template/default/gradebook/my_certificates.tpl

@@ -0,0 +1,63 @@
+{% if course_list is not empty %}
+    <h1 class="page-header">{{ "Courses"|get_lang }}</h1>
+
+    <div class="table-responsive">
+        <table class="table table-hover table-striped">
+            <thead>
+                <tr>
+                    <th>{{ "Course"|get_lang }}</th>
+                    <th class="text-right">{{ "Score"|get_lang }}</th>
+                    <th class="text-center">{{ "Fecha"|get_lang }}</th>
+                    <th class="text-right">&nbsp;</th>
+                </tr>
+            </thead>
+            <tbody>
+                {% for row in course_list %}
+                    <tr>
+                        <td>{{ row.course }}</td>
+                        <td class="text-right">{{ row.score }}</td>
+                        <td class="text-center">{{ row.date }}</td>
+                        <td class="text-right">
+                            <a href="{{ row.link }}" target="_blank" class="btn btn-default">
+                                <i class="fa fa-external-link"></i> {{ 'Certificate'|get_lang }}
+                            </a>
+                        </td>
+                    </tr>
+                {% endfor %}
+            </tbody>
+        </table>
+    </div>
+{% endif %}
+
+{% if session_list is not empty %}
+    <h1 class="page-header">{{ "Sessions"|get_lang }}</h1>
+
+    <div class="table-responsive">
+        <table class="table table-hover table-striped">
+            <thead>
+                <tr>
+                    <th>{{ "Session"|get_lang }}</th>
+                    <th>{{ "Course"|get_lang }}</th>
+                    <th class="text-right">{{ "Score"|get_lang }}</th>
+                    <th class="text-center">{{ "Fecha"|get_lang }}</th>
+                    <th class="text-right">&nbsp;</th>
+                </tr>
+            </thead>
+            <tbody>
+                {% for row in session_list %}
+                    <tr>
+                        <td>{{ row.session }}</td>
+                        <td>{{ row.course }}</td>
+                        <td class="text-right">{{ row.score }}</td>
+                        <td class="text-center">{{ row.date }}</td>
+                        <td class="text-right">
+                            <a href="{{ row.link }}" target="_blank" class="btn btn-default">
+                                <i class="fa fa-external-link"></i> {{ 'Certificate'|get_lang }}
+                            </a>
+                        </td>
+                    </tr>
+                {% endfor %}
+            </tbody>
+        </table>
+    </div>
+{% endif %}

+ 98 - 0
main/template/default/gradebook/search.tpl

@@ -0,0 +1,98 @@
+{{ search_form }}
+
+{% if user_list is not empty %}
+    <div class="table-responsive">
+        <table class="table table-hover table-striped">
+            <thead>
+                <tr>
+                    <th>{{ "FirstName"|get_lang }}</th>
+                    <th>{{ "LastName"|get_lang }}</th>
+                    <th class="text-center">{{ "Username"|get_lang }}</th>
+                    <th class="text-right">&nbsp;</th>
+                </tr>
+            </thead>
+            <tbody>
+                {% for user in user_list %}
+                    <tr>
+                        <td>{{ user.firstname }}</td>
+                        <td>{{ user.lastname }}</td>
+                        <td class="text-center">{{ user.username }}</td>
+                        <td class="text-right">
+                            <a href="{{ _p.web_main }}gradebook/search.php?id={{ user.id }}" class="btn btn-default">
+                                <i class="fa fa-external-link"></i> {{ "Certificates"|get_lang }}
+                            </a>
+                        </td>
+                    </tr>
+                {% endfor %}
+            </tbody>
+        </table>
+    </div>
+{% endif %}
+
+{% if course_list is not empty or session_list is not empty %}
+    <h2>{{ user_info.complete_name }}</h2>
+
+    {% if course_list is not empty %}
+        <h3 class="page-header">{{ "Courses"|get_lang }}</h3>
+
+        <div class="table-responsive">
+            <table class="table table-hover table-striped">
+                <thead>
+                    <tr>
+                        <th>{{ "Course"|get_lang }}</th>
+                        <th class="text-right">{{ "Score"|get_lang }}</th>
+                        <th class="text-center">{{ "Fecha"|get_lang }}</th>
+                        <th class="text-right">&nbsp;</th>
+                    </tr>
+                </thead>
+                <tbody>
+                    {% for row in course_list %}
+                        <tr>
+                            <td>{{ row.course }}</td>
+                            <td class="text-right">{{ row.score }}</td>
+                            <td class="text-center">{{ row.date }}</td>
+                            <td class="text-right">
+                                <a href="{{ row.link }}" target="_blank" class="btn btn-default">
+                                    <i class="fa fa-external-link"></i> {{ 'Certificate'|get_lang }}
+                                </a>
+                            </td>
+                        </tr>
+                    {% endfor %}
+                </tbody>
+            </table>
+        </div>
+    {% endif %}
+
+    {% if session_list is not empty %}
+        <h3 class="page-header">{{ "Sessions"|get_lang }}</h3>
+
+        <div class="table-responsive">
+            <table class="table table-hover table-striped">
+                <thead>
+                    <tr>
+                        <th>{{ "Session"|get_lang }}</th>
+                        <th>{{ "Course"|get_lang }}</th>
+                        <th class="text-right">{{ "Score"|get_lang }}</th>
+                        <th class="text-center">{{ "Fecha"|get_lang }}</th>
+                        <th class="text-right">&nbsp;</th>
+                    </tr>
+                </thead>
+                <tbody>
+                    {% for row in session_list %}
+                        <tr>
+                            <td>{{ row.session }}</td>
+                            <td>{{ row.course }}</td>
+                            <td class="text-right">{{ row.score }}</td>
+                            <td class="text-center">{{ row.date }}</td>
+                            <td class="text-right">
+                                <a href="{{ row.link }}" target="_blank" class="btn btn-default">
+                                    <i class="fa fa-external-link"></i> {{ 'Certificate'|get_lang }}
+                                </a>
+                            </td>
+                        </tr>
+                    {% endfor %}
+                </tbody>
+            </table>
+        </div>
+    {% endif %}
+{% endif %}

+ 3 - 0
main/template/default/layout/layout_2_col.tpl

@@ -42,6 +42,9 @@
         {# Skills #}
         {{ skills_block }}
 
+        {# Certificates search block #}
+        {{ certificates_search_block }}
+
 		{# Notice #}
 		{{ notice_block }}
 

+ 1 - 1
main/wiki/wiki.inc.php

@@ -2134,7 +2134,7 @@ class Wiki
                         $obj->title.'</a>';
                 }
 
-                $row[] = $obj->user_id <> 0 ? UserManager::getUserProfileLink($userinfo) : get_lang('Anonymous').' ('.$obj->user_ip.')';
+                $row[] = $obj->user_id != 0 ? UserManager::getUserProfileLink($userinfo) : get_lang('Anonymous').' ('.$obj->user_ip.')';
 
                 $row[] = $year.'-'.$month.'-'.$day.' '.$hours.":".$minutes.":".$seconds;
 

+ 10 - 216
tests/main/inc/lib/internationalization.lib.test.php

@@ -237,18 +237,6 @@ class TestInternationalization extends UnitTestCase {
 		//var_dump($res);
 	}
 
-	public function test_api_chr() {
-		$encoding = 'UTF-8';
-		$codepoints = array(1048, 1074, 1072, 1085, 32, 73, 118, 97, 110);
-		$characters = array('И', 'в', 'а', 'н', ' ', 'I', 'v', 'a', 'n'); // UTF-8
-		$res = array();
-		foreach ($codepoints as $codepoint) {
-			$res[] = api_chr($codepoint, $encoding);
-		}
-		$this->assertTrue($res == $characters);
-		//var_dump($res);
-	}
-
 	public function test_api_str_ireplace() {
 		$search = 'Á'; // UTF-8
 		$replace = 'a';
@@ -502,17 +490,6 @@ class TestInternationalization extends UnitTestCase {
 		//var_dump($res);
 	}
 
-	public function test_api_ereg_replace() {
-		$pattern = 'file=([^"\'&]*)$';
-		$string = 'http://localhost/dokeos/main/scorm/showinframes.php?id=5&amp;file=test.php';
-		$replacement = 'file=my_test.php';
-		$option = null;
-		$res = api_ereg_replace($pattern, $replacement, $string, $option);
-		$this->assertTrue(is_string($res));
-		$this->assertTrue(strlen($res) == 77);
-		//var_dump($res);
-	}
-
 	public function test_api_eregi() {
 		$pattern = 'scorm/showinframes.php([^"\'&]*)(&|&amp;)file=([^"\'&]*)$';
 		$string = 'http://localhost/dokeos/main/scorm/showinframes.php?id=5&amp;file=test.php';
@@ -523,16 +500,6 @@ class TestInternationalization extends UnitTestCase {
 		//var_dump($res);
 	}
 
-	public function test_api_eregi_replace() {
-		$pattern = 'file=([^"\'&]*)$';
-		$string = 'http://localhost/dokeos/main/scorm/showinframes.php?id=5&amp;file=test.php';
-		$replacement = 'file=my_test.php';
-		$option = null;
-		$res = api_eregi_replace($pattern, $replacement, $string, $option);
-		$this->assertTrue(is_string($res));
-		$this->assertTrue(strlen($res) == 77);
-		//var_dump($res);
-	}
 
 	/**
 	 * ----------------------------------------------------------------------------
@@ -562,17 +529,6 @@ class TestInternationalization extends UnitTestCase {
 		//var_dump($res);
 	}
 
-	public function test_api_strnatcasecmp() {
-		$string1 = '201áéíóu.txt'; // UTF-8
-		$string2 = '30Áéíóu.TXT'; // UTF-8
-		$language = 'english';
-		$encoding = 'UTF-8';
-		$res = api_strnatcasecmp($string1, $string2, $language, $encoding);
-		$this->assertTrue(is_numeric($res));
-		$this->assertTrue($res == 1);
-		//var_dump($res);
-	}
-
 	public function  test_api_strnatcmp() {
 		$string1 = '201áéíóu.txt'; // UTF-8
 		$string2 = '30áéíóu.TXT'; // UTF-8
@@ -585,37 +541,11 @@ class TestInternationalization extends UnitTestCase {
 	}
 
 
-/**
- * ----------------------------------------------------------------------------
- * Sorting arrays
- * ----------------------------------------------------------------------------
- */
-
-	public function test_api_asort() {
-		$array = array('úéo', 'aíó', 'áed'); // UTF-8
-		$sort_flag = SORT_REGULAR;
-		$language = 'english';
-		$encoding = 'UTF-8';
-		$res = api_asort($array, $sort_flag, $language, $encoding);
-		$keys = array_keys($array);
-		$this->assertTrue(is_bool($res));
-		$this->assertTrue($array[$keys[0]] == 'aíó' || $array[$keys[0]] == 'áed'); // The second result is given when intl php-extension is active.
-		//var_dump($array);
-		//var_dump($res);
-	}
-
-	public function test_api_arsort() {
-		$array = array('aíó', 'úéo', 'áed'); // UTF-8
-		$sort_flag = SORT_REGULAR;
-		$language = 'english';
-		$encoding = 'UTF-8';
-		$res = api_arsort($array, $sort_flag, $language, $encoding);
-		$keys = array_keys($array);
-		$this->assertTrue(is_bool($res));
-		$this->assertTrue($array[$keys[0]] == 'úéo');
-		//var_dump($array);
-		//var_dump($res);
-	}
+	/**
+	 * ----------------------------------------------------------------------------
+	 * Sorting arrays
+	 * ----------------------------------------------------------------------------
+	 */
 
 	public function test_api_natsort() {
 		$array = array('img12.png', 'img10.png', 'img2.png', 'img1.png'); // UTF-8
@@ -641,140 +571,11 @@ class TestInternationalization extends UnitTestCase {
 		//var_dump($res);
 	}
 
-	public function test_api_natcasesort() {
-		$array = array('img2.png', 'img10.png', 'Img12.png', 'img1.png'); // UTF-8
-		$language = 'english';
-		$encoding = 'UTF-8';
-		$res = api_natcasesort($array, $language, $encoding);
-		$keys = array_keys($array);
-		$this->assertTrue(is_bool($res));
-		$this->assertTrue($array[$keys[0]] == 'img1.png');
-		//var_dump($array);
-		//var_dump($res);
-	}
-
-	public function test_api_natcasersort() {
-		$array = array('img2.png', 'img10.png', 'Img12.png', 'img1.png'); // UTF-8
-		$language = 'english';
-		$encoding = 'UTF-8';
-		$res = api_natcasersort($array, $language, $encoding);
-		$keys = array_keys($array);
-		$this->assertTrue(is_bool($res));
-		$this->assertTrue($array[$keys[0]] == 'Img12.png');
-		//var_dump($array);
-		//var_dump($res);
-	}
-
-	public function test_api_ksort() {
-		$array = array('aíó' => 'img2.png', 'úéo' => 'img10.png', 'áed' => 'img12.png', 'áedc' => 'img1.png'); // UTF-8
-		$sort_flag = SORT_REGULAR;
-		$language = 'english';
-		$encoding = 'UTF-8';
-		$res = api_ksort($array, $sort_flag, $language, $encoding);
-		$keys = array_keys($array);
-		$this->assertTrue(is_bool($res));
-		$this->assertTrue($array[$keys[0]] == 'img2.png');
-		//var_dump($array);
-		//var_dump($res);
-	}
-
-	public function test_api_krsort() {
-		$array = array('aíó' => 'img2.png', 'úéo' => 'img10.png', 'áed' => 'img12.png', 'áedc' => 'img1.png'); // UTF-8
-		$sort_flag = SORT_REGULAR;
-		$language = 'english';
-		$encoding = 'UTF-8';
-		$res = api_krsort($array, $sort_flag, $language, $encoding);
-		$keys = array_keys($array);
-		$this->assertTrue(is_bool($res));
-		$this->assertTrue($array[$keys[0]] == 'img10.png');
-		//var_dump($array);
-		//var_dump($res);
-	}
-
-	public function test_api_knatsort() {
-		$array = array('img2.png' => 'aíó', 'img10.png' => 'úéo', 'img12.png' => 'áed', 'img1.png' => 'áedc'); // UTF-8
-		$language = 'english';
-		$encoding = 'UTF-8';
-		$res = api_knatsort($array, $language, $encoding);
-		$keys = array_keys($array);
-		$this->assertTrue(is_bool($res));
-		$this->assertTrue($array[$keys[0]] == 'áedc');
-		//var_dump($array);
-		//var_dump($res);
-	}
-
-	public function test_api_knatrsort() {
-		$array = array('img2.png' => 'aíó', 'img10.png' => 'úéo', 'IMG12.PNG' => 'áed', 'img1.png' => 'áedc'); // UTF-8
-		$language = 'english';
-		$encoding = 'UTF-8';
-		$res = api_knatrsort($array, $language, $encoding);
-		$keys = array_keys($array);
-		$this->assertTrue(is_bool($res));
-		$this->assertTrue($array[$keys[0]] == 'úéo' || $array[$keys[0]] == 'áed'); // The second result is given when intl php-extension is active.
-		//var_dump($array);
-		//var_dump($res);
-	}
-
-	public function test_api_knatcasesort() {
-		$array = array('img2.png' => 'aíó', 'img10.png' => 'úéo', 'IMG12.PNG' => 'áed', 'img1.png' => 'áedc'); // UTF-8
-		$language = 'english';
-		$encoding = 'UTF-8';
-		$res = api_knatcasesort($array, $language, $encoding);
-		$keys = array_keys($array);
-		$this->assertTrue(is_bool($res));
-		$this->assertTrue($array[$keys[0]] == 'áedc');
-		//var_dump($array);
-		//var_dump($res);
-	}
-
-	public function test_api_sort() {
-		$array = array('úéo', 'aíó', 'áed', 'áedc'); // UTF-8
-		$sort_flag = SORT_REGULAR;
-		$language = 'english';
-		$encoding = 'UTF-8';
-		$res = api_sort($array, $sort_flag, $language, $encoding);
-		$this->assertTrue(is_bool($res));
-		$this->assertTrue($array[0] == 'aíó' || $array[0] == 'áed');  // The second result is given when intl php-extension is active.
-		//var_dump($array);
-		//var_dump($res);
-	}
-
-	public function testapi_rsort() {
-		$array = array('aíó', 'úéo', 'áed', 'áedc'); // UTF-8
-		$sort_flag = SORT_REGULAR;
-		$language = 'english';
-		$encoding = 'UTF-8';
-		$res = api_rsort($array, $sort_flag, $language, $encoding);
-		$this->assertTrue(is_bool($res));
-		$this->assertTrue($array[0] == 'úéo');
-		//var_dump($array);
-		//var_dump($res);
-	}
-
-
-/**
- * ----------------------------------------------------------------------------
- * Common sting operations with arrays
- * ----------------------------------------------------------------------------
- */
-
-	public function test_api_in_array_nocase() {
-		$needle = 'áéíó'; // UTF-8
-		$haystack = array('Áéíó', 'uáé', 'íóú'); // UTF-8
-		$strict = false;
-		$encoding = 'UTF-8';
-		$res = api_in_array_nocase($needle, $haystack, $strict, $encoding);
-		$this->assertTrue(is_bool($res));
-		$this->assertTrue($res === true);
-		//var_dump($res);
-	}
-
-
-/**
- * ----------------------------------------------------------------------------
- * Encoding management functions
- * ----------------------------------------------------------------------------
- */
+	/**
+	 * ----------------------------------------------------------------------------
+	 * Encoding management functions
+	 * ----------------------------------------------------------------------------
+	 */
 
 	public function test_api_refine_encoding_id() {
 		$encoding = 'koI8-r';
@@ -834,13 +635,6 @@ class TestInternationalization extends UnitTestCase {
 		//var_dump($res);
 	}
 
-	public function test_api_get_file_system_encoding() {
-		$res = api_get_file_system_encoding();
-		$this->assertTrue(is_string($res));
-		$this->assertTrue($res);
-		//var_dump($res);
-	}
-
 	public function test_api_is_encoding_supported() {
 		$encoding1 = 'UTF-8';
 		$encoding2 = 'XXXX#%#%VR^%BBDNdjlrsg;d';

+ 1 - 0
user_portal.php

@@ -183,6 +183,7 @@ $controller->tpl->assign('course_block', $controller->return_course_block());
 $controller->tpl->assign('navigation_course_links', $controller->return_navigation_links());
 $controller->tpl->assign('search_block', $controller->return_search_block());
 $controller->tpl->assign('classes_block', $controller->return_classes_block());
+$controller->tpl->assign('certificates_search_block', $controller->returnCertificatesSearchBlock());
 
 //if (api_is_platform_admin() || api_is_drh()) {
 $controller->tpl->assign('skills_block', $controller->return_skills_links());

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است