Browse Source

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

Julio Montoya 10 years ago
parent
commit
c17906cc26
74 changed files with 1572 additions and 894 deletions
  1. 8 0
      .gitignore
  2. 3 0
      documentation/installation_guide.html
  3. 3 0
      documentation/installation_guide_es_ES.html
  4. 3 0
      documentation/installation_guide_fr_FR.html
  5. 3 0
      documentation/installation_guide_it_IT.html
  6. 4 0
      main/admin/add_users_to_session.php
  7. 2 2
      main/admin/session_edit.php
  8. 4 0
      main/admin/user_list.php
  9. 2 2
      main/admin/user_move_stats.php
  10. 156 149
      main/exercice/admin.php
  11. 1 1
      main/exercice/exercice.php
  12. 17 10
      main/exercice/exercise.class.php
  13. 1 1
      main/exercice/exercise_history.php
  14. 3 1
      main/exercice/exercise_report.php
  15. 1 1
      main/exercice/exercise_result.class.php
  16. 4 2
      main/exercice/exercise_show.php
  17. 2 2
      main/exercice/exercise_submit.php
  18. 1 1
      main/exercice/hotpotatoes_exercise_report.php
  19. 1 1
      main/exercice/mark_free_answer.php
  20. 7 6
      main/exercice/overview.php
  21. 490 490
      main/exercice/question.class.php
  22. 1 1
      main/gradebook/gradebook_result.class.php
  23. 2 2
      main/gradebook/lib/be/exerciselink.class.php
  24. 1 1
      main/inc/ajax/exercise.ajax.php
  25. 1 1
      main/inc/ajax/model.ajax.php
  26. 2 2
      main/inc/lib/api.lib.php
  27. 1 1
      main/inc/lib/course.lib.php
  28. 1 1
      main/inc/lib/database.constants.inc.php
  29. 23 22
      main/inc/lib/events.lib.inc.php
  30. 11 9
      main/inc/lib/exercise.lib.php
  31. 1 1
      main/inc/lib/hook/HookEvent.php
  32. 2 2
      main/inc/lib/hook/HookManagement.php
  33. 1 1
      main/inc/lib/hook/HookObserver.php
  34. 1 1
      main/inc/lib/hook/interfaces/base/HookEventInterface.php
  35. 1 1
      main/inc/lib/hook/interfaces/base/HookObserverInterface.php
  36. 1 1
      main/inc/lib/myspace.lib.php
  37. 4 4
      main/inc/lib/online.inc.php
  38. 32 6
      main/inc/lib/sessionmanager.lib.php
  39. 8 8
      main/inc/lib/tracking.lib.php
  40. 5 2
      main/install/db_main.sql
  41. 19 16
      main/install/db_stats.sql
  42. 12 0
      main/install/install.lib.php
  43. 1 1
      main/install/migrate-db-1.9.0-1.10.0-post.sql
  44. 13 2
      main/install/migrate-db-1.9.0-1.10.0-pre.sql
  45. 1 1
      main/install/update-db-1.9.0-1.10.0.inc.php
  46. 7 0
      main/lang/english/trad4all.inc.php
  47. 7 0
      main/lang/spanish/trad4all.inc.php
  48. 2 2
      main/mySpace/myStudents.php
  49. 1 1
      main/mySpace/progression.php
  50. 1 1
      main/mySpace/reussite.php
  51. 3 3
      main/newscorm/learnpathItem.class.php
  52. 1 1
      main/newscorm/lp_view.php
  53. 1 1
      main/reports/modules/quiz.php
  54. 1 1
      main/tracking/courseLog.php
  55. 1 1
      main/tracking/exams.php
  56. 1 1
      main/tracking/personnalLog.php
  57. 9 7
      plugin/advanced_subscription/ajax/advanced_subscription.ajax.php
  58. 4 0
      plugin/advanced_subscription/config.php
  59. 157 0
      plugin/advanced_subscription/cron/notify_by_mail.php
  60. 4 1
      plugin/advanced_subscription/lang/english.php
  61. 11 8
      plugin/advanced_subscription/lang/spanish.php
  62. 148 48
      plugin/advanced_subscription/src/AdvancedSubscriptionPlugin.php
  63. 66 53
      plugin/advanced_subscription/src/HookAdvancedSubscription.php
  64. 203 0
      plugin/advanced_subscription/src/scripts/insert_session_fields.php
  65. 20 0
      plugin/advanced_subscription/src/scripts/insert_sessions_categories.php
  66. 5 0
      plugin/advanced_subscription/test/mails.php
  67. 49 0
      plugin/advanced_subscription/test/ws_session_user.php
  68. 2 2
      plugin/advanced_subscription/views/admin_view.tpl
  69. 1 1
      plugin/advanced_subscription/views/reminder_notice_superior.tpl
  70. 2 2
      plugin/advanced_subscription/views/reminder_notice_superior_max.tpl
  71. 1 1
      plugin/advanced_subscription/views/student_no_superior_notice_admin.tpl
  72. 1 1
      tests/datafiller/fill_whoisonline.php
  73. 1 1
      tests/scripts/fix_exercise_score_in_lp.php
  74. 1 1
      tests/scripts/move_users.php

+ 8 - 0
.gitignore

@@ -17,6 +17,14 @@ home/*
 main/upload/users/*
 !main/upload/users/index.html
 
+# Session images
+main/upload/sessions/*
+!main/upload/sessions/index.html
+
+# Course images
+main/upload/courses/*
+!main/upload/courses/index.html
+
 # Logs and databases #
 *.log
 

+ 3 - 0
documentation/installation_guide.html

@@ -144,10 +144,13 @@ The following directories need to be readable, writeable and executable by your
 <ul>
   <li>[chamilo]/main/inc/conf/</li>
   <li>[chamilo]/main/upload/users/</li>
+  <li>[chamilo]/main/upload/sessions/</li>
+  <li>[chamilo]/main/upload/courses/</li>
   <li>[chamilo]/main/default_course_document/images/</li>
   <li>[chamilo]/archive/</li>
   <li>[chamilo]/courses/</li>
   <li>[chamilo]/home/</li>
+  <li>[chamilo]/data/</li>
 </ul>
 Optionally, you can do the same to the following directories if you want to
 enable CSS styles package upload and sub-language definition:

+ 3 - 0
documentation/installation_guide_es_ES.html

@@ -132,10 +132,13 @@ Remplace [chamilo] por el directorio en el cual está ubicado su Chamilo:
 <ul>
   <li>[chamilo]/main/inc/conf/</li>
   <li>[chamilo]/main/upload/users/</li>
+  <li>[chamilo]/main/upload/sessions/</li>
+  <li>[chamilo]/main/upload/courses/</li>
   <li>[chamilo]/main/default_course_document/images/</li>
   <li>[chamilo]/archive/</li>
   <li>[chamilo]/courses/</li>
   <li>[chamilo]/home/</li>
+  <li>[chamilo]/data/</li>
 </ul>
 Opcionalmente, puede hacer lo mismo a los directorios siguientes si desea
 activar la subida de paquetes de estilos CSS y la definición de sub-idiomas:

+ 3 - 0
documentation/installation_guide_fr_FR.html

@@ -176,10 +176,13 @@ Remplacez [chamilo] par le répertoire où vous avez placé le contenu du zip:
 <ul>
   <li>[chamilo]/main/inc/conf/</li>
   <li>[chamilo]/main/upload/users/</li>
+  <li>[chamilo]/main/upload/sessions/</li>
+  <li>[chamilo]/main/upload/courses/</li>
   <li>[chamilo]/main/default_course_document/images/</li>
   <li>[chamilo]/archive/</li>
   <li>[chamilo]/courses/</li>
   <li>[chamilo]/home/</li>
+  <li>[chamilo]/data/</li>
 </ul>
 Optionnellement, vous pouvez faire la même chose pour les répertoires suivants
 si vous souhaitez permettre l'envoi de styles CSS ou la définition de nouvelles

+ 3 - 0
documentation/installation_guide_it_IT.html

@@ -108,10 +108,13 @@
 <ul>
   <li class="li2"><span class="s1">[chamilo]/main/inc/conf/</span></li>
   <li class="li2"><span class="s1">[chamilo]/main/upload/users/</span></li>
+  <li clasS="li2">[chamilo]/main/upload/sessions/</li>
+  <li class="li2">[chamilo]/main/upload/courses/</li>
   <li class="li2"><span class="s1">[chamilo]/main/default_course_document/images/</span></li>
   <li class="li2"><span class="s1">[chamilo]/archive/</span></li>
   <li class="li2"><span class="s1">[chamilo]/courses/</span></li>
   <li class="li2"><span class="s1">[chamilo]/home/</span></li>
+  <li class="li2"><span class="s1">[chamilo]/data/</span></li>
 </ul>
 <p class="p3"><span class="s1"></span><br></p>
 <p class="p2"><span class="s1">Opzionalmente puoi fare lo stesso alle seguenti cartelle se vuoi consentire il caricamento dei pacchetti di stile CSS (CSS styles package) e la definizione di sotto-linguaggi (sub-language definition):</span></p>

+ 4 - 0
main/admin/add_users_to_session.php

@@ -96,6 +96,10 @@ function search_users($needle, $type)
 
         $cond_user_id = '';
 
+        if (api_is_session_admin() && api_get_setting('prevent_session_admins_to_manage_all_users')  == 'true') {
+            $order_clause = " AND user.creator_id = ".api_get_user_id().$order_clause;
+        }
+
         // Only for single & multiple
         if (in_array($type, array('single','multiple')))
         if (!empty($id_session)) {

+ 2 - 2
main/admin/session_edit.php

@@ -92,13 +92,13 @@ foreach ($coaches as $coach) {
     $coachesOption[$coach['user_id']] = "$personName ({$coach['username']})";
 }
 
-$Categories = SessionManager::get_all_session_category();
+$categoriesList = SessionManager::get_all_session_category();
 
 $categoriesOption = array(
     '0' => get_lang('None')
 );
 
-if ($Categories != false) {
+if ($categoriesList != false) {
     foreach ($categoriesList as $categoryItem) {
         $categoriesOption[$categoryItem['id']] = $categoryItem['name'];
     }

+ 4 - 0
main/admin/user_list.php

@@ -446,6 +446,10 @@ function get_user_data($from, $number_of_items, $column, $direction) {
     $from 	= intval($from);
     $number_of_items = intval($number_of_items);
 
+    if (api_is_session_admin() && api_get_setting('prevent_session_admins_to_manage_all_users')  == 'true') {
+        $sql .= " WHERE u.creator_id = ".api_get_user_id();
+    }
+
 	$sql .= " ORDER BY col$column $direction ";
 	$sql .= " LIMIT $from,$number_of_items";
 

+ 2 - 2
main/admin/user_move_stats.php

@@ -116,7 +116,7 @@ if (isset($_REQUEST['load_ajax'])) {
                 $course_info = api_get_course_info($origin_course_code);
                 $course_id = $course_info['real_id'];
 
-                $TABLETRACK_EXERCICES       = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+                $TABLETRACK_EXERCICES       = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
                 $TBL_TRACK_ATTEMPT          = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
                 $TBL_TRACK_E_COURSE_ACCESS  = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
                 $TBL_TRACK_E_LAST_ACCESS    = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
@@ -581,7 +581,7 @@ $htmlHeadXtra[] = '<script type="text/javascript">
  </script>';
 
 function get_courses_list_by_user_id_based_in_exercises($user_id) {
-    $TABLETRACK_EXERCICES       = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+    $TABLETRACK_EXERCICES       = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
     $user_id = intval($user_id);
     //$sql = "SELECT DISTINCT exe_user_id, exe_cours_id as code, session_id as id_session FROM $TABLETRACK_EXERCICES WHERE exe_user_id = $user_id GROUP BY exe_user_id, exe_cours_id ORDER by exe_user_id, exe_cours_id ASC";
     $sql = "SELECT DISTINCT exe_user_id, exe_cours_id as code, session_id as id_session

+ 156 - 149
main/exercice/admin.php

@@ -1,49 +1,49 @@
 <?php
 /* For licensing terms, see /license.txt */
 /**
-*	Exercise administration
-* 	This script allows to manage (create, modify) an exercise and its questions
-*
-*	 Following scripts are includes for a best code understanding :
-*
-* 	- exercise.class.php : for the creation of an Exercise object
-* 	- question.class.php : for the creation of a Question object
-* 	- answer.class.php : for the creation of an Answer object
-* 	- exercise.lib.php : functions used in the exercise tool
-* 	- exercise_admin.inc.php : management of the exercise
-* 	- question_admin.inc.php : management of a question (statement & answers)
-* 	- statement_admin.inc.php : management of a statement
-* 	- answer_admin.inc.php : management of answers
-* 	- question_list_admin.inc.php : management of the question list
-*
-* 	Main variables used in this script :
-*
-* 	- $is_allowedToEdit : set to 1 if the user is allowed to manage the exercise
-* 	- $objExercise : exercise object
-* 	- $objQuestion : question object
-* 	- $objAnswer : answer object
-* 	- $aType : array with answer types
-* 	- $exerciseId : the exercise ID
-* 	- $picturePath : the path of question pictures
-* 	- $newQuestion : ask to create a new question
-* 	- $modifyQuestion : ID of the question to modify
-* 	- $editQuestion : ID of the question to edit
-* 	- $submitQuestion : ask to save question modifications
-* 	- $cancelQuestion : ask to cancel question modifications
-* 	- $deleteQuestion : ID of the question to delete
-* 	- $moveUp : ID of the question to move up
-* 	- $moveDown : ID of the question to move down
-* 	- $modifyExercise : ID of the exercise to modify
-* 	- $submitExercise : ask to save exercise modifications
-* 	- $cancelExercise : ask to cancel exercise modifications
-* 	- $modifyAnswers : ID of the question which we want to modify answers for
-* 	- $cancelAnswers : ask to cancel answer modifications
-* 	- $buttonBack : ask to go back to the previous page in answers of type "Fill in blanks"
-*
-*	@package chamilo.exercise
-* 	@author Olivier Brouckaert
-* Modified by Hubert Borderiou 21-10-2011 Question by category
-*/
+ *	Exercise administration
+ * 	This script allows to manage (create, modify) an exercise and its questions
+ *
+ *	 Following scripts are includes for a best code understanding :
+ *
+ * 	- exercise.class.php : for the creation of an Exercise object
+ * 	- question.class.php : for the creation of a Question object
+ * 	- answer.class.php : for the creation of an Answer object
+ * 	- exercise.lib.php : functions used in the exercise tool
+ * 	- exercise_admin.inc.php : management of the exercise
+ * 	- question_admin.inc.php : management of a question (statement & answers)
+ * 	- statement_admin.inc.php : management of a statement
+ * 	- answer_admin.inc.php : management of answers
+ * 	- question_list_admin.inc.php : management of the question list
+ *
+ * 	Main variables used in this script :
+ *
+ * 	- $is_allowedToEdit : set to 1 if the user is allowed to manage the exercise
+ * 	- $objExercise : exercise object
+ * 	- $objQuestion : question object
+ * 	- $objAnswer : answer object
+ * 	- $aType : array with answer types
+ * 	- $exerciseId : the exercise ID
+ * 	- $picturePath : the path of question pictures
+ * 	- $newQuestion : ask to create a new question
+ * 	- $modifyQuestion : ID of the question to modify
+ * 	- $editQuestion : ID of the question to edit
+ * 	- $submitQuestion : ask to save question modifications
+ * 	- $cancelQuestion : ask to cancel question modifications
+ * 	- $deleteQuestion : ID of the question to delete
+ * 	- $moveUp : ID of the question to move up
+ * 	- $moveDown : ID of the question to move down
+ * 	- $modifyExercise : ID of the exercise to modify
+ * 	- $submitExercise : ask to save exercise modifications
+ * 	- $cancelExercise : ask to cancel exercise modifications
+ * 	- $modifyAnswers : ID of the question which we want to modify answers for
+ * 	- $cancelAnswers : ask to cancel answer modifications
+ * 	- $buttonBack : ask to go back to the previous page in answers of type "Fill in blanks"
+ *
+ *	@package chamilo.exercise
+ * 	@author Olivier Brouckaert
+ * Modified by Hubert Borderiou 21-10-2011 Question by category
+ */
 
 use \ChamiloSession as Session;
 
@@ -61,21 +61,21 @@ $is_allowedToEdit = api_is_allowed_to_edit(null,true);
 $sessionId = api_get_session_id();
 
 if (!$is_allowedToEdit) {
-	api_not_allowed(true);
+    api_not_allowed(true);
 }
 
 /*  stripslashes POST data  */
 if($_SERVER['REQUEST_METHOD'] == 'POST') {
-	foreach($_POST as $key=>$val) {
-		if(is_string($val)) {
-			$_POST[$key]=stripslashes($val);
-		} elseif(is_array($val)) {
-			foreach($val as $key2=>$val2) {
-				$_POST[$key][$key2]=stripslashes($val2);
-			}
-		}
-		$GLOBALS[$key]=$_POST[$key];
-	}
+    foreach($_POST as $key=>$val) {
+        if(is_string($val)) {
+            $_POST[$key]=stripslashes($val);
+        } elseif(is_array($val)) {
+            foreach($val as $key2=>$val2) {
+                $_POST[$key][$key2]=stripslashes($val2);
+            }
+        }
+        $GLOBALS[$key]=$_POST[$key];
+    }
 }
 
 if (empty($exerciseId)) {
@@ -109,21 +109,24 @@ $cancelExercise = isset($cancelExercise) ? $cancelExercise : null;
 $cancelAnswers = isset($cancelAnswers) ? $cancelAnswers : null;
 $modifyIn = isset($modifyIn) ? $modifyIn : null;
 $cancelQuestion = isset($cancelQuestion) ? $cancelQuestion : null;
-$_course = api_get_course_info();
 
 /* Cleaning all incomplete attempts of the admin/teacher to avoid weird problems
     when changing the exercise settings, number of questions, etc */
 
 Event::delete_all_incomplete_attempts(
-	api_get_user_id(),
-	$exerciseId,
-	api_get_course_int_id(),
-	api_get_session_id()
+    api_get_user_id(),
+    $exerciseId,
+    api_get_course_int_id(),
+    api_get_session_id()
 );
 
 // get from session
 $objExercise = isset($_SESSION['objExercise']) ? $_SESSION['objExercise'] : null;
 $objQuestion = isset($_SESSION['objQuestion']) ? $_SESSION['objQuestion'] : null;
+if (isset($_REQUEST['convertAnswer'])) {
+    $objQuestion = $objQuestion->swapSimpleAnswerTypes();
+    $_SESSION['objQuestion'] = $objQuestion;
+}
 $objAnswer   = isset($_SESSION['objAnswer']) ? $_SESSION['objAnswer'] : null;
 
 // document path
@@ -173,135 +176,136 @@ if (!empty($_GET['action']) && $_GET['action'] == 'exportqti2' && !empty($_GET['
 
 // Exercise object creation.
 if (!is_object($objExercise)) {
-	// construction of the Exercise object
-	$objExercise = new Exercise();
+    // construction of the Exercise object
+    $objExercise = new Exercise();
 
-	// creation of a new exercise if wrong or not specified exercise ID
-	if ($exerciseId) {
-	    $objExercise->read($exerciseId);
-	}
-	// saves the object into the session
-	Session::write('objExercise', $objExercise);
+    // creation of a new exercise if wrong or not specified exercise ID
+    if ($exerciseId) {
+        $objExercise->read($exerciseId);
+    }
+    // saves the object into the session
+    Session::write('objExercise', $objExercise);
 }
 
 // Exercise can be edited in their course.
 if ($objExercise->sessionId != $sessionId) {
     api_not_allowed(true);
+    /*header('Location: '.api_get_path(WEB_CODE_PATH).'exercice/exercice.php?'.api_get_cidreq());
+    exit;*/
 }
 
 // doesn't select the exercise ID if we come from the question pool
 if (!$fromExercise) {
-	// gets the right exercise ID, and if 0 creates a new exercise
-	if (!$exerciseId = $objExercise->selectId()) {
-		$modifyExercise='yes';
-	}
+    // gets the right exercise ID, and if 0 creates a new exercise
+    if (!$exerciseId = $objExercise->selectId()) {
+        $modifyExercise='yes';
+    }
 }
 
 $nbrQuestions = $objExercise->selectNbrQuestions();
 
 // Question object creation.
 if ($editQuestion || $newQuestion || $modifyQuestion || $modifyAnswers) {
-	if ($editQuestion || $newQuestion) {
+    if ($editQuestion || $newQuestion) {
 
-		// reads question data
-		if ($editQuestion) {
-			// question not found
-			if (!$objQuestion = Question::read($editQuestion)) {
-				api_not_allowed();
-			}
-			// saves the object into the session
-			Session::write('objQuestion',$objQuestion);
-		}
-	}
+        // reads question data
+        if ($editQuestion) {
+            // question not found
+            if (!$objQuestion = Question::read($editQuestion)) {
+                api_not_allowed();
+            }
+            // saves the object into the session
+            Session::write('objQuestion',$objQuestion);
+        }
+    }
 
-	// checks if the object exists
-	if (is_object($objQuestion)) {
-		// gets the question ID
-		$questionId = $objQuestion->selectId();
-	}
+    // checks if the object exists
+    if(is_object($objQuestion)) {
+        // gets the question ID
+        $questionId = $objQuestion->selectId();
+    }
 }
 
 // if cancelling an exercise
 if ($cancelExercise) {
-	// existing exercise
-	if ($exerciseId) {
-		unset($modifyExercise);
-	} else {
+    // existing exercise
+    if($exerciseId) {
+        unset($modifyExercise);
+    } else {
         // new exercise
-		// goes back to the exercise list
-		header('Location: '.api_get_path(WEB_CODE_PATH).'exercice/exercice.php?'.api_get_cidreq());
-		exit();
-	}
+        // goes back to the exercise list
+        header('Location: '.api_get_path(WEB_CODE_PATH).'exercice/exercice.php?'.api_get_cidreq());
+        exit();
+    }
 }
 
 // if cancelling question creation/modification
 if ($cancelQuestion) {
-	// if we are creating a new question from the question pool
-	if (!$exerciseId && !$questionId) {
-		// goes back to the question pool
-		header('Location: question_pool.php');
-		exit();
-	} else {
-		// goes back to the question viewing
-		$editQuestion = $modifyQuestion;
-		unset($newQuestion, $modifyQuestion);
-	}
+    // if we are creating a new question from the question pool
+    if(!$exerciseId && !$questionId) {
+        // goes back to the question pool
+        header('Location: question_pool.php');
+        exit();
+    } else {
+        // goes back to the question viewing
+        $editQuestion=$modifyQuestion;
+        unset($newQuestion,$modifyQuestion);
+    }
 }
 
 if (!empty($clone_question) && !empty($objExercise->id)) {
-	$old_question_obj = Question::read($clone_question);
-	$old_question_obj->question = $old_question_obj->question.' - '.get_lang('Copy');
+    $old_question_obj = Question::read($clone_question);
+    $old_question_obj->question = $old_question_obj->question.' - '.get_lang('Copy');
 
-	$new_id = $old_question_obj->duplicate();
-	$new_question_obj = Question::read($new_id);
-	$new_question_obj->addToList($exerciseId);
+    $new_id = $old_question_obj->duplicate();
+    $new_question_obj = Question::read($new_id);
+    $new_question_obj->addToList($exerciseId);
 
-	// This should be moved to the duplicate function
-	$new_answer_obj = new Answer($clone_question);
-	$new_answer_obj->read();
-	$new_answer_obj->duplicate($new_id);
+    // This should be moved to the duplicate function
+    $new_answer_obj = new Answer($clone_question);
+    $new_answer_obj->read();
+    $new_answer_obj->duplicate($new_id);
 
     //Reloading tne $objExercise obj
     $objExercise->read($objExercise->id);
 
-	header('Location: admin.php?'.api_get_cidreq().'&exerciseId='.$objExercise->id);
-	exit;
+    header('Location: admin.php?'.api_get_cidreq().'&exerciseId='.$objExercise->id);
+    exit;
 }
 
 // if cancelling answer creation/modification
 if ($cancelAnswers) {
-	// goes back to the question viewing
-	$editQuestion=$modifyAnswers;
-	unset($modifyAnswers);
+    // goes back to the question viewing
+    $editQuestion=$modifyAnswers;
+    unset($modifyAnswers);
 }
-
 $nameTools = null;
 // modifies the query string that is used in the link of tool name
 if ($editQuestion || $modifyQuestion || $newQuestion || $modifyAnswers) {
-	$nameTools = get_lang('QuestionManagement');
+    $nameTools = get_lang('QuestionManagement');
 }
 
 if (isset($_SESSION['gradebook'])){
-	$gradebook=	$_SESSION['gradebook'];
+    $gradebook=	$_SESSION['gradebook'];
 }
 
 if (!empty($gradebook) && $gradebook=='view') {
-	$interbreadcrumb[]= array(
+    $interbreadcrumb[]= array(
         'url' => '../gradebook/'.$_SESSION['gradebook_dest'],
         'name' => get_lang('ToolGradebook')
     );
 }
 
-$interbreadcrumb[] = array("url" => "exercice.php?".api_get_cidreq(),"name" => get_lang('Exercices'));
+$interbreadcrumb[] = array("url" => "exercice.php","name" => get_lang('Exercices'));
 if (isset($_GET['newQuestion']) || isset($_GET['editQuestion']) ) {
-    $interbreadcrumb[] = array("url" => "admin.php?exerciseId=".$objExercise->id.'&'.api_get_cidreq(), "name" => $objExercise->name);
+    $interbreadcrumb[] = array("url" => "admin.php?exerciseId=".$objExercise->id, "name" => $objExercise->name);
 } else {
     $interbreadcrumb[] = array("url" => "#", "name" => $objExercise->name);
 }
 
 // shows a link to go back to the question pool
 if (!$exerciseId && $nameTools != get_lang('ExerciseManagement')){
-	$interbreadcrumb[] = array(
+    $interbreadcrumb[]=array(
         "url" => api_get_path(WEB_CODE_PATH)."exercice/question_pool.php?fromExercise=$fromExercise&".api_get_cidreq(),
         "name" => get_lang('QuestionPool')
     );
@@ -309,11 +313,11 @@ if (!$exerciseId && $nameTools != get_lang('ExerciseManagement')){
 
 // if the question is duplicated, disable the link of tool name
 if ($modifyIn == 'thisExercise') {
-	if ($buttonBack)	{
-		$modifyIn='allExercises';
-	} else {
-		$noPHP_SELF=true;
-	}
+    if($buttonBack)	{
+        $modifyIn='allExercises';
+    } else {
+        $noPHP_SELF=true;
+    }
 }
 $htmlHeadXtra[] = '<script>
 
@@ -332,6 +336,8 @@ function multiple_answer_true_false_onchange(variable) {
     }
     document.getElementById(weight_id).value = array_result[result];
 }
+
+
 </script>';
 
 $htmlHeadXtra[] = "<script type=\"text/javascript\" src=\"../plugin/hotspot/JavaScriptFlashGateway.js\"></script>
@@ -493,35 +499,36 @@ if ($inATest) {
     echo '<span style="float:right">'.sprintf(get_lang('XQuestionsWithTotalScoreY'), $objExercise->selectNbrQuestions(), $maxScoreAllQuestions).'</span>';
     echo '</div>';
 } else if (isset($_GET['newQuestion'])) {
-	// we are in create a new question from question pool not in a test
-	echo '<div class="actions">';
-	echo '<a href="'.api_get_path(WEB_CODE_PATH).'exercice/admin.php?'.api_get_cidreq().'">'.
+    // we are in create a new question from question pool not in a test
+    echo '<div class="actions">';
+    echo '<a href="'.api_get_path(WEB_CODE_PATH).'exercice/admin.php?'.api_get_cidreq().'">'.
         Display::return_icon('back.png', get_lang('GoBackToQuestionList'),'',ICON_SIZE_MEDIUM).'</a>';
-	echo '</div>';
+    echo '</div>';
 } else {
-	// If we are in question_pool but not in an test, go back to question create in pool
-	echo '<div class="actions">';
-	echo '<a href="'.api_get_path(WEB_CODE_PATH).'exercice/question_pool.php?'.api_get_cidreq().'">'.
+    // If we are in question_pool but not in an test, go back to question create in pool
+    echo '<div class="actions">';
+    echo '<a href="'.api_get_path(WEB_CODE_PATH).'exercice/question_pool.php?'.api_get_cidreq().'">'.
         Display::return_icon('back.png', get_lang('GoBackToQuestionList'),'',ICON_SIZE_MEDIUM).
         '</a>';
-	echo '</div>';
+    echo '</div>';
 }
 
 if (isset($_GET['message'])) {
-	if (in_array($_GET['message'], array('ExerciseStored', 'ItemUpdated', 'ItemAdded'))) {
-		Display::display_confirmation_message(get_lang($_GET['message']));
-	}
+    if (in_array($_GET['message'], array('ExerciseStored', 'ItemUpdated', 'ItemAdded'))) {
+        Display::display_confirmation_message(get_lang($_GET['message']));
+    }
 }
 
 if ($newQuestion || $editQuestion) {
-	// statement management
-	$type = isset($_REQUEST['answerType']) ? Security::remove_XSS($_REQUEST['answerType']) : null;
-	echo '<input type="hidden" name="Type" value="'.$type.'" />';
+    // statement management
+    $type = isset($_REQUEST['answerType']) ? Security::remove_XSS($_REQUEST['answerType']) : null;
+    echo '<input type="hidden" name="Type" value="'.$type.'" />';
 
     if ($newQuestion == 'yes') {
         $objExercise->edit_exercise_in_lp = true;
     }
-	require 'question_admin.inc.php';
+
+    require 'question_admin.inc.php';
 }
 
 if (isset($_GET['hotspotadmin'])) {
@@ -531,12 +538,12 @@ if (isset($_GET['hotspotadmin'])) {
     if (!$objQuestion) {
         api_not_allowed();
     }
-	require 'hotspot_admin.inc.php';
+    require 'hotspot_admin.inc.php';
 }
 
 if (!$newQuestion && !$modifyQuestion && !$editQuestion && !isset($_GET['hotspotadmin'])) {
-	// question list management
-	require 'question_list_admin.inc.php';
+    // question list management
+    require 'question_list_admin.inc.php';
 }
 
 // if we are in question authoring, display warning to user is feedback not shown at the end of the test -ref #6619

+ 1 - 1
main/exercice/exercice.php

@@ -51,7 +51,7 @@ $TBL_DOCUMENT = Database :: get_course_table(TABLE_DOCUMENT);
 $TBL_ITEM_PROPERTY = Database :: get_course_table(TABLE_ITEM_PROPERTY);
 $TBL_EXERCICE_QUESTION = Database :: get_course_table(TABLE_QUIZ_TEST_QUESTION);
 $TBL_EXERCICES = Database :: get_course_table(TABLE_QUIZ_TEST);
-$TBL_TRACK_EXERCICES = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+$TBL_TRACK_EXERCICES = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
 
 // document path
 $documentPath = api_get_path(SYS_COURSE_PATH).$courseInfo['path']."/document";

+ 17 - 10
main/exercice/exercise.class.php

@@ -1571,7 +1571,7 @@ class Exercise
      */
     public function clean_results($cleanLpTests = false, $cleanResultBeforeDate = null)
     {
-        $table_track_e_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $table_track_e_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $table_track_e_attempt   = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
 
         $sql_where = '  AND
@@ -1617,7 +1617,7 @@ class Exercise
         }
 
         $session_id = api_get_session_id();
-        // delete TRACK_E_EXERCICES table
+        // delete TRACK_E_EXERCISES table
         $sql = "DELETE FROM $table_track_e_exercises
                 WHERE exe_cours_id = '".api_get_course_id()."'
                 AND exe_exo_id = ".$this->id."
@@ -1710,7 +1710,7 @@ class Exercise
         $lp_item_view_id = 0,
         $status = 'incomplete'
     ) {
-        $track_exercises = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $track_exercises = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         if (empty($lp_id)) {
             $lp_id = 0;
         }
@@ -1758,11 +1758,13 @@ class Exercise
         $questionList = array(),
         $weight = 0
     ) {
-        $track_exercises = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $track_exercises = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $safe_lp_id = intval($safe_lp_id);
         $safe_lp_item_id = intval($safe_lp_item_id);
         $safe_lp_item_view_id = intval($safe_lp_item_view_id);
 
+        $trackValues = array();
+
         if (empty($safe_lp_id)) {
             $safe_lp_id = 0;
         }
@@ -1788,6 +1790,7 @@ class Exercise
             'orig_lp_item_id'  => $safe_lp_item_id,
             'orig_lp_item_view_id'  => $safe_lp_item_view_id,
             'exe_weighting'=> $weight,
+            'user_ip' => api_get_real_ip()
         );
 
         if ($this->expired_time != 0) {
@@ -1795,7 +1798,6 @@ class Exercise
         }
 
         $id = Database::insert($track_exercises, $params);
-
         return $id;
     }
 
@@ -3601,7 +3603,7 @@ class Exercise
         }
 
         if ($saved_results) {
-            $stat_table = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+            $stat_table = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
             $sql = 'UPDATE ' . $stat_table . ' SET
                         exe_result = exe_result + ' . floatval($questionScore) . '
                     WHERE exe_id = ' . $exeId;
@@ -3876,9 +3878,10 @@ class Exercise
      * @param array $user_data result of api_get_user_info()
      * @param null $start_date
      * @param null $duration
+     * @param string $ip Optional. The user IP
      * @return string
      */
-    public function show_exercise_result_header($user_data, $start_date = null, $duration = null)
+    public function show_exercise_result_header($user_data, $start_date = null, $duration = null, $ip = null)
     {
         $array = array();
 
@@ -3908,6 +3911,10 @@ class Exercise
             $array[] = array('title' => get_lang("Duration"), 'content' => $duration);
         }
 
+        if (!empty($ip)) {
+            $array[] = array("title" => get_lang("IP"), "content" => $ip);
+        }
+
         $html  = Display::page_header(
             Display::return_icon('quiz_big.png', get_lang('Result')).' '.$this->exercise.' : '.get_lang('Result')
         );
@@ -4283,7 +4290,7 @@ class Exercise
 
     public function get_stat_track_exercise_info_by_exe_id($exe_id)
     {
-        $track_exercises = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $track_exercises = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $exe_id = intval($exe_id);
         $sql_track = "SELECT * FROM $track_exercises WHERE exe_id = $exe_id ";
         $result = Database::query($sql_track);
@@ -4317,7 +4324,7 @@ class Exercise
         $exercise_info = self::get_stat_track_exercise_info_by_exe_id($exe_id);
         $question_id = intval($question_id);
         $exe_id = intval($exe_id);
-        $track_exercises = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $track_exercises = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         if ($exercise_info) {
 
             if (empty($exercise_info['questions_to_check'])) {
@@ -4555,7 +4562,7 @@ class Exercise
         $ids = is_array($quizId) ? $quizId : array($quizId);
         $ids = array_map('intval', $ids);
         $ids = implode(',', $ids);
-        $track_exercises = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $track_exercises = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         if ($sessionId != 0) {
             $sql = "SELECT * FROM $track_exercises te "
               . "INNER JOIN c_quiz cq ON cq.id = te.exe_exo_id "

+ 1 - 1
main/exercice/exercise_history.php

@@ -37,7 +37,7 @@ $interbreadcrumb[]= array ('url' => 'exercise_history.php'.'?exe_id='.intval($_G
 $TBL_USER          	    = Database::get_main_table(TABLE_MAIN_USER);
 $TBL_EXERCICES			= Database::get_course_table(TABLE_QUIZ_TEST);
 $TBL_EXERCICES_QUESTION	= Database::get_course_table(TABLE_QUIZ_QUESTION);
-$TBL_TRACK_EXERCICES	= Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+$TBL_TRACK_EXERCICES	= Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
 $TBL_TRACK_ATTEMPT_RECORDING= Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING);
 Display::display_header($nameTools,get_lang('Exercise'));
 

+ 3 - 1
main/exercice/exercise_report.php

@@ -41,7 +41,7 @@ $is_allowedToEdit = api_is_allowed_to_edit(null, true) || api_is_drh() || api_is
 $is_tutor = api_is_allowed_to_edit(true);
 
 $TBL_QUESTIONS = Database :: get_course_table(TABLE_QUIZ_QUESTION);
-$TBL_TRACK_EXERCICES = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+$TBL_TRACK_EXERCICES = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
 $TBL_TRACK_ATTEMPT = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
 $TBL_TRACK_ATTEMPT_RECORDING = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING);
 $TBL_LP_ITEM_VIEW = Database :: get_course_table(TABLE_LP_ITEM_VIEW);
@@ -415,6 +415,7 @@ if ($is_allowedToEdit || $is_tutor) {
         get_lang('StartDate'),
         get_lang('EndDate'),
         get_lang('Score'),
+        get_lang('IP'),
         get_lang('Status'),
         get_lang('ToolLearnpath'),
         get_lang('Actions')
@@ -440,6 +441,7 @@ if ($is_allowedToEdit || $is_tutor) {
         array('name' => 'start_date', 'index' => 'start_date', 'width' => '60', 'align' => 'left', 'search' => 'true'),
         array('name' => 'exe_date', 'index' => 'exe_date', 'width' => '60', 'align' => 'left', 'search' => 'true'),
         array('name' => 'score', 'index' => 'exe_result', 'width' => '50', 'align' => 'left', 'search' => 'true'),
+        array('name' => 'ip', 'index' => 'user_ip', 'width' => '40', 'align' => 'center', 'search' => 'true'),
         array('name' => 'status', 'index' => 'revised', 'width' => '40', 'align' => 'left', 'search' => 'true', 'stype' => 'select',
             //for the bottom bar
             'searchoptions' => array(

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

@@ -52,7 +52,7 @@ class ExerciseResult
         $TBL_TABLE_LP_MAIN = Database::get_course_table(TABLE_LP_MAIN);
 
         $TBL_USER = Database::get_main_table(TABLE_MAIN_USER);
-        $TBL_TRACK_EXERCISES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $TBL_TRACK_EXERCISES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $TBL_TRACK_ATTEMPT_RECORDING = Database:: get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING);
 
         $cid = api_get_course_id();

+ 4 - 2
main/exercice/exercise_show.php

@@ -33,7 +33,7 @@ if ($origin == 'learnpath') {
 // Database table definitions
 $TBL_EXERCICE_QUESTION 	= Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
 $TBL_QUESTIONS         	= Database::get_course_table(TABLE_QUIZ_QUESTION);
-$TBL_TRACK_EXERCICES    = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+$TBL_TRACK_EXERCICES    = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
 $TBL_TRACK_ATTEMPT		= Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
 
 // General parameters passed via POST/GET
@@ -215,7 +215,9 @@ if ($show_results || $show_only_total_score) {
     //Shows exercise header
     echo $objExercise->show_exercise_result_header(
         $user_info,
-        api_convert_and_format_date($exercise_date)
+        api_convert_and_format_date($exercise_date),
+        null,
+        $track_exercise_info['user_ip']
     );
 }
 

+ 2 - 2
main/exercice/exercise_submit.php

@@ -148,7 +148,7 @@ $current_expired_time_key = ExerciseLib::get_time_control_key($objExercise->id,
 $_SESSION['duration_time'][$current_expired_time_key] = $current_timestamp;
 
 if ($time_control) {
-	// Get the expired time of the current exercice in track_e_exercices
+	// Get the expired time of the current exercice in track_e_exercises
 	$total_seconds = $objExercise->expired_time*60;
 }
 
@@ -358,7 +358,7 @@ if ($time_control) {
 	        if ($debug) {error_log('7.9. $clock_expired_time: '.$clock_expired_time); }
 
 			// First we update the attempt to today
-			/* How the expired time is changed into "track_e_exercices" table,
+			/* How the expired time is changed into "track_e_exercises" table,
                then the last attempt for this student should be changed too */
 	        $sql = "UPDATE $exercice_attemp_table SET
 	                tms = '".api_get_utc_datetime()."'

+ 1 - 1
main/exercice/hotpotatoes_exercise_report.php

@@ -35,7 +35,7 @@ $is_allowedToEdit = api_is_allowed_to_edit(null, true) || api_is_drh();
 $is_tutor = api_is_allowed_to_edit(true);
 
 $TBL_QUESTIONS = Database :: get_course_table(TABLE_QUIZ_QUESTION);
-$TBL_TRACK_EXERCICES = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+$TBL_TRACK_EXERCICES = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
 $TBL_TRACK_HOTPOTATOES_EXERCICES = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_HOTPOTATOES);
 $TBL_LP_ITEM_VIEW = Database :: get_course_table(TABLE_LP_ITEM_VIEW);
 

+ 1 - 1
main/exercice/mark_free_answer.php

@@ -82,7 +82,7 @@ if ($action == 'mark') {
 	if (!empty($_POST['score']) AND $_POST['score'] < $obj_question->selectWeighting() AND $_POST['score'] >= 0) {
 		//mark the user mark into the database using something similar to the following function:
 
-		$exercise_table = Database::get_statistic_table('track_e_exercices');
+		$exercise_table = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
 		#global $origin, $tbl_learnpath_user, $learnpath_id, $learnpath_item_id;
 		$sql = "SELECT * FROM $exercise_table
 			    WHERE exe_user_id = ".intval($my_usr)." AND exe_cours_id = '".Database::escape_string($my_cid)."' AND exe_exo_id = ".intval($my_exe)."

+ 7 - 6
main/exercice/overview.php

@@ -133,7 +133,7 @@ if ($visible_return['value'] == false) {
 $attempts = Event::getExerciseResultsByUser(
     api_get_user_id(),
     $objExercise->id,
-    api_get_course_id(),
+    api_get_course_int_id(),
     api_get_session_id(),
     $learnpath_id,
     $learnpath_item_id,
@@ -182,7 +182,8 @@ if (!empty($attempts) && $visible_return['value'] == true) {
             'date' => api_convert_and_format_date(
                 $attempt_result['start_date'],
                 DATE_TIME_FORMAT_LONG
-            )
+            ),
+            'userIp' => $attempt_result['user_ip']
         );
         $attempt_link .= "&nbsp;&nbsp;&nbsp;" . $teacher_revised;
 
@@ -217,17 +218,17 @@ if (!empty($attempts) && $visible_return['value'] == true) {
 	switch ($objExercise->results_disabled) {
 		case RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS:
         case RESULT_DISABLE_SHOW_FINAL_SCORE_ONLY_WITH_CATEGORIES:
-			$header_names = array(get_lang('Attempt'), get_lang('StartDate'), get_lang('Score'), get_lang('Details'));
+			$header_names = array(get_lang('Attempt'), get_lang('StartDate'), get_lang('IP'), get_lang('Score'), get_lang('Details'));
 			break;
 		case RESULT_DISABLE_NO_SCORE_AND_EXPECTED_ANSWERS:
-			$header_names = array(get_lang('Attempt'), get_lang('StartDate'));
+			$header_names = array(get_lang('Attempt'), get_lang('StartDate'), get_lang('IP'));
 			break;
 		case RESULT_DISABLE_SHOW_SCORE_ONLY:
             if ($objExercise->feedback_type != EXERCISE_FEEDBACK_TYPE_END) {
-			    $header_names = array(get_lang('Attempt'), get_lang('StartDate'), get_lang('Score'));
+			    $header_names = array(get_lang('Attempt'), get_lang('StartDate'), get_lang('IP'), get_lang('Score'));
             }
             else {
-                $header_names = array(get_lang('Attempt'), get_lang('StartDate'), get_lang('Score'), get_lang('Details'));
+                $header_names = array(get_lang('Attempt'), get_lang('StartDate'), get_lang('IP'), get_lang('Score'), get_lang('Details'));
             }
 			break;
 	}

File diff suppressed because it is too large
+ 490 - 490
main/exercice/question.class.php


+ 1 - 1
main/gradebook/gradebook_result.class.php

@@ -88,7 +88,7 @@ class GradeBookResult
         $return = array();
         $TBL_EXERCISES          = Database::get_course_table(TABLE_QUIZ_TEST);
         $TBL_USER          	    = Database::get_main_table(TABLE_MAIN_USER);
-        $TBL_TRACK_EXERCISES	= Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $TBL_TRACK_EXERCISES	= Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $TBL_TRACK_HOTPOTATOES	= Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_HOTPOTATOES);
 
         $cid = api_get_course_id();

+ 2 - 2
main/gradebook/lib/be/exerciselink.class.php

@@ -138,7 +138,7 @@ class ExerciseLink extends AbstractLink
      */
     public function has_results()
     {
-        $tbl_stats = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $tbl_stats = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $session_id = api_get_session_id();
         $sql = 'SELECT count(exe_id) AS number FROM '.$tbl_stats."
                 WHERE
@@ -159,7 +159,7 @@ class ExerciseLink extends AbstractLink
      */
     public function calc_score($stud_id = null)
     {
-        $tblStats = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $tblStats = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $tblHp = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTPOTATOES);
         $tblDoc = Database::get_course_table(TABLE_DOCUMENT);
 

+ 1 - 1
main/inc/ajax/exercise.ajax.php

@@ -42,7 +42,7 @@ switch ($action) {
             $sidx = 1;
         }
 
-        $track_exercise = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $track_exercise = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $user_table = Database::get_main_table(TABLE_MAIN_USER);
         $track_attempt = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
 

+ 1 - 1
main/inc/ajax/model.ajax.php

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

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

@@ -6770,7 +6770,7 @@ function api_user_is_login($user_id = null) {
  * Guess the real ip for register in the database, even in reverse proxy cases.
  * To be recognized, the IP has to be found in either $_SERVER['REMOTE_ADDR'] or
  * in $_SERVER['HTTP_X_FORWARDED_FOR'], which is in common use with rproxies.
- * @return string the real ip of teh user.
+ * @return string the user's real ip (unsafe - escape it before inserting to db)
  * @author Jorge Frisancho Jibaja <jrfdeft@gmail.com>, USIL - Some changes to allow the use of real IP using reverse proxy
  * @version CEV CHANGE 24APR2012
  */
@@ -6779,7 +6779,7 @@ function api_get_real_ip(){
     global $debug;
     $ip = trim($_SERVER['REMOTE_ADDR']);
     if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
-        list($ip1,$ip2) = split(',',$_SERVER['HTTP_X_FORWARDED_FOR']);
+        list($ip1, $ip2) = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
         $ip = trim($ip1);
     }
     if (!empty($debug)) error_log('Real IP: '.$ip);

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

@@ -2211,7 +2211,7 @@ class CourseManager
 
         $table_stats_hotpots = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTPOTATOES);
         $table_stats_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
-        $table_stats_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $table_stats_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $table_stats_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
         $table_stats_lastaccess = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
         $table_stats_course_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);

+ 1 - 1
main/inc/lib/database.constants.inc.php

@@ -134,7 +134,7 @@ define('TABLE_STATISTIC_TRACK_E_LINKS',             'track_e_links');
 define('TABLE_STATISTIC_TRACK_E_ONLINE',            'track_e_online');
 define('TABLE_STATISTIC_TRACK_E_HOTPOTATOES',       'track_e_hotpotatoes');
 define('TABLE_STATISTIC_TRACK_E_COURSE_ACCESS',     'track_e_course_access');
-define('TABLE_STATISTIC_TRACK_E_EXERCICES',         'track_e_exercices');
+define('TABLE_STATISTIC_TRACK_E_EXERCISES',         'track_e_exercises');
 define('TABLE_STATISTIC_TRACK_E_ATTEMPT',           'track_e_attempt');
 define('TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING', 'track_e_attempt_recording');
 define('TABLE_STATISTIC_TRACK_E_DEFAULT',           'track_e_default');

+ 23 - 22
main/inc/lib/events.lib.inc.php

@@ -68,7 +68,7 @@ class Event
 
         $reallyNow = api_get_utc_datetime();
 
-        $sql = "INSERT INTO ".$TABLETRACK_LOGIN." (login_user_id, login_ip, login_date, logout_date) VALUES
+        $sql = "INSERT INTO ".$TABLETRACK_LOGIN." (login_user_id, user_ip, login_date, logout_date) VALUES
                     ('".$userId."',
                     '".Database::escape_string(api_get_real_ip())."',
                     '".$reallyNow."',
@@ -348,7 +348,7 @@ class Event
                 $status = Database::escape_string($status);
             }
 
-            $TABLETRACK_EXERCICES = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+            $TABLETRACK_EXERCICES = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
 
             if (!empty($question_list)) {
                 $question_list = array_map('intval', $question_list);
@@ -374,11 +374,12 @@ class Event
         		   orig_lp_id 			= '".Database::escape_string($learnpath_id)."',
         		   orig_lp_item_id 		= '".Database::escape_string($learnpath_item_id)."',
                    orig_lp_item_view_id = '".Database::escape_string($learnpath_item_view_id)."',
-        		   exe_duration 		= '".Database::escape_string($duration)."',
-        		   exe_date				= '".$end_date."',
-        		   status 				= '".$status."',
-        		   questions_to_check 	= '".$remind_list."',
-        		   data_tracking    	= '".implode(',', $question_list)."'
+        		   exe_duration = '".Database::escape_string($duration)."',
+        		   exe_date = '".$end_date."',
+        		   status = '".$status."',
+        		   questions_to_check = '".$remind_list."',
+        		   data_tracking = '".implode(',', $question_list)."',
+                   user_ip = '" . Database::escape_string(api_get_real_ip()) . "'
         		 WHERE exe_id = '".Database::escape_string($exeid)."'";
             $res = Database::query($sql);
 
@@ -915,7 +916,7 @@ class Event
      */
     public static function get_attempt_count($user_id, $exerciseId, $lp_id, $lp_item_id, $lp_item_view_id)
     {
-        $stat_table = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $stat_table = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $user_id = intval($user_id);
         $exerciseId = intval($exerciseId);
         $lp_id = intval($lp_id);
@@ -950,7 +951,7 @@ class Event
      */
     public static function get_attempt_count_not_finished($user_id, $exerciseId, $lp_id, $lp_item_id)
     {
-        $stat_table = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $stat_table = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $user_id = intval($user_id);
         $exerciseId = intval($exerciseId);
         $lp_id = intval($lp_id);
@@ -995,7 +996,7 @@ class Event
         }
 
         $track_e_exercises = Database::get_main_table(
-            TABLE_STATISTIC_TRACK_E_EXERCICES
+            TABLE_STATISTIC_TRACK_E_EXERCISES
         );
         $track_attempts = Database::get_main_table(
             TABLE_STATISTIC_TRACK_E_ATTEMPT
@@ -1094,7 +1095,7 @@ class Event
      */
     public static function delete_all_incomplete_attempts($user_id, $exercise_id, $course_id, $session_id = 0)
     {
-        $track_e_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $track_e_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $user_id = intval($user_id);
         $exercise_id = intval($exercise_id);
         $course_id = intval($course_id);
@@ -1130,7 +1131,7 @@ class Event
      */
     public static function get_all_exercise_results($exercise_id, $courseId, $session_id = 0, $load_question_list = true, $user_id = null)
     {
-        $TABLETRACK_EXERCICES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $TABLETRACK_EXERCICES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $TBL_TRACK_ATTEMPT = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
         $courseId = intval($courseId);
         $exercise_id = intval($exercise_id);
@@ -1175,7 +1176,7 @@ class Event
      */
     public static function get_all_exercise_results_by_course($courseId, $session_id = 0, $get_count = true)
     {
-        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
         $courseId = intval($courseId);
         $session_id = intval($session_id);
@@ -1219,7 +1220,7 @@ class Event
      */
     public static function get_all_exercise_results_by_user($user_id, $courseId, $session_id = 0)
     {
-        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
         $courseId = intval($courseId);
         $session_id = intval($session_id);
@@ -1258,7 +1259,7 @@ class Event
      */
     public static function get_exercise_results_by_attempt($exe_id, $status = null)
     {
-        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
         $table_track_attempt_recording = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING);
         $exe_id = intval($exe_id);
@@ -1303,7 +1304,7 @@ class Event
      */
     public static function getExerciseResultsByUser($user_id, $exercise_id, $courseId, $session_id = 0, $lp_id = 0, $lp_item_id = 0, $order = null)
     {
-        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
         $table_track_attempt_recording = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING);
         $courseId = intval($courseId);
@@ -1358,7 +1359,7 @@ class Event
      */
     public static function count_exercise_attempts_by_user($user_id, $exercise_id, $courseId, $session_id = 0)
     {
-        $TABLETRACK_EXERCICES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $TABLETRACK_EXERCICES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $courseId = intval($courseId);
         $exercise_id = intval($exercise_id);
         $session_id = intval($session_id);
@@ -1393,7 +1394,7 @@ class Event
      */
     public static function get_best_exercise_results_by_user($exercise_id, $courseId, $session_id = 0)
     {
-        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
         $courseId = intval($courseId);
         $exercise_id = intval($exercise_id);
@@ -1442,7 +1443,7 @@ class Event
      */
     public static function get_best_attempt_exercise_results_per_user($user_id, $exercise_id, $courseId, $session_id = 0)
     {
-        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $courseId = intval($courseId);
         $exercise_id = intval($exercise_id);
         $session_id = intval($session_id);
@@ -1492,7 +1493,7 @@ class Event
      */
     public static function count_exercise_result_not_validated($exercise_id, $courseId, $session_id = 0)
     {
-        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING);
         $courseId = intval($courseId);
         $session_id = intval($session_id);
@@ -1526,7 +1527,7 @@ class Event
      */
     public static function get_count_exercises_attempted_by_course($courseId, $session_id = 0)
     {
-        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $courseId = intval($courseId);
         $session_id = intval($session_id);
 
@@ -1555,7 +1556,7 @@ class Event
      */
     public static function get_all_exercise_event_from_lp($exercise_id, $courseId, $session_id = 0)
     {
-        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
         $courseId = intval($courseId);
         $exercise_id = intval($exercise_id);

+ 11 - 9
main/inc/lib/exercise.lib.php

@@ -1133,7 +1133,7 @@ class ExerciseLib
     {
         $TBL_EXERCICES = Database::get_course_table(TABLE_QUIZ_TEST);
         $TBL_TRACK_EXERCICES = Database::get_main_table(
-            TABLE_STATISTIC_TRACK_E_EXERCICES
+            TABLE_STATISTIC_TRACK_E_EXERCISES
         );
         $TBL_COURSE = Database::get_main_table(TABLE_MAIN_COURSE);
         $exe_id = intval($exe_id);
@@ -1445,7 +1445,7 @@ class ExerciseLib
         $TBL_GROUP_REL_USER = Database:: get_course_table(TABLE_GROUP_USER);
         $TBL_GROUP = Database:: get_course_table(TABLE_GROUP);
         $TBL_TRACK_EXERCICES = Database:: get_main_table(
-            TABLE_STATISTIC_TRACK_E_EXERCICES
+            TABLE_STATISTIC_TRACK_E_EXERCISES
         );
         $TBL_TRACK_HOTPOTATOES = Database:: get_main_table(
             TABLE_STATISTIC_TRACK_E_HOTPOTATOES
@@ -1592,7 +1592,8 @@ class ExerciseLib
                     revised,
                     group_name,
                     group_id,
-                    orig_lp_id";
+                    orig_lp_id,
+                    te.user_ip";
             }
 
             $sql = " $sql_select
@@ -2722,7 +2723,7 @@ class ExerciseLib
         $session_id
     ) {
         $track_exercises = Database::get_main_table(
-            TABLE_STATISTIC_TRACK_E_EXERCICES
+            TABLE_STATISTIC_TRACK_E_EXERCISES
         );
         $track_attempt = Database::get_main_table(
             TABLE_STATISTIC_TRACK_E_ATTEMPT
@@ -2771,7 +2772,7 @@ class ExerciseLib
         $session_id
     ) {
         $track_exercises = Database::get_main_table(
-            TABLE_STATISTIC_TRACK_E_EXERCICES
+            TABLE_STATISTIC_TRACK_E_EXERCISES
         );
         $track_attempt = Database::get_main_table(
             TABLE_STATISTIC_TRACK_E_ATTEMPT
@@ -2841,7 +2842,7 @@ class ExerciseLib
         $session_id
     ) {
         $track_exercises = Database::get_main_table(
-            TABLE_STATISTIC_TRACK_E_EXERCICES
+            TABLE_STATISTIC_TRACK_E_EXERCISES
         );
         $track_hotspot = Database::get_main_table(
             TABLE_STATISTIC_TRACK_E_HOTSPOT
@@ -2915,7 +2916,7 @@ class ExerciseLib
         $current_answer = null
     ) {
         $track_exercises = Database::get_main_table(
-            TABLE_STATISTIC_TRACK_E_EXERCICES
+            TABLE_STATISTIC_TRACK_E_EXERCISES
         );
         $track_attempt = Database::get_main_table(
             TABLE_STATISTIC_TRACK_E_ATTEMPT
@@ -3130,7 +3131,7 @@ class ExerciseLib
         $session_id
     ) {
         $track_exercises = Database::get_main_table(
-            TABLE_STATISTIC_TRACK_E_EXERCICES
+            TABLE_STATISTIC_TRACK_E_EXERCISES
         );
         $track_attempt = Database::get_main_table(
             TABLE_STATISTIC_TRACK_E_ATTEMPT
@@ -3301,7 +3302,8 @@ class ExerciseLib
                     $exercise_stat_info['start_date'],
                     DATE_TIME_FORMAT_LONG
                 ),
-                $exercise_stat_info['duration']
+                $exercise_stat_info['duration'],
+                $exercise_stat_info['user_ip']
             );
         }
 

+ 1 - 1
main/inc/lib/hook/HookEvent.php

@@ -36,7 +36,7 @@ abstract class HookEvent implements HookEventInterface
 
     /**
      * Return the singleton instance of Hook event.
-     * @return HookEventInterface|null
+     * @return static
      */
     public static function create()
     {

+ 2 - 2
main/inc/lib/hook/HookManagement.php

@@ -88,8 +88,8 @@ class HookManagement implements HookManagementInterface
     public function deleteHook($eventName, $observerClassName, $type)
     {
         if ($type === HOOK_EVENT_TYPE_ALL) {
-            $this->insertHook($eventName, $observerClassName, HOOK_EVENT_TYPE_PRE);
-            $this->insertHook($eventName, $observerClassName, HOOK_EVENT_TYPE_POST);
+            $this->deleteHook($eventName, $observerClassName, HOOK_EVENT_TYPE_PRE);
+            $this->deleteHook($eventName, $observerClassName, HOOK_EVENT_TYPE_POST);
         } else {
             $this->insertHookIfNotExist($eventName, $observerClassName);
 

+ 1 - 1
main/inc/lib/hook/HookObserver.php

@@ -34,7 +34,7 @@ abstract class HookObserver implements HookObserverInterface
     /**
      * Return the singleton instance of Hook observer.
      * If Hook Management plugin is not enabled, will return NULL
-     * @return HookEventInterface|null
+     * @return static
      */
     public static function create()
     {

+ 1 - 1
main/inc/lib/hook/interfaces/base/HookEventInterface.php

@@ -33,7 +33,7 @@ interface HookEventInterface
 
     /**
      * Return the singleton instance of Hook event.
-     * @return HookEventInterface|null
+     * @return static
      */
     public static function create();
 

+ 1 - 1
main/inc/lib/hook/interfaces/base/HookObserverInterface.php

@@ -10,7 +10,7 @@ interface HookObserverInterface
 {
     /**
      * Return the singleton instance of Hook observer.
-     * @return HookEventInterface|null
+     * @return static
      */
     public static function create();
 

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

@@ -1878,7 +1878,7 @@ class MySpace
     {
         $questions_answered = 0;
         $sql = 'SELECT exe_result , exe_weighting
-            FROM '.Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES)."
+            FROM '.Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES)."
             WHERE exe_cours_id = '".Database::escape_string($course_code)."'
             AND exe_user_id = '".intval($user_id)."'";
         if($session_id !== false) {

+ 4 - 4
main/inc/lib/online.inc.php

@@ -24,9 +24,9 @@ function LoginCheck($uid) {
 	$uid = (int) $uid;
 	$online_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ONLINE);
     if (!empty($uid)) {
-        $login_ip = '';
+        $user_ip = '';
         if (!empty($_SERVER['REMOTE_ADDR'])) {
-            $login_ip = Database::escape_string($_SERVER['REMOTE_ADDR']);
+            $user_ip = Database::escape_string(api_get_real_ip());
         }
 
 		$login_date = api_get_utc_datetime();
@@ -38,9 +38,9 @@ function LoginCheck($uid) {
 		// if the $_course array exists this means we are in a course and we have to store this in the who's online table also
 		// to have the x users in this course feature working
 		if (is_array($_course) && count($_course)>0 && !empty($_course['id'])) {
-            $query = "REPLACE INTO ".$online_table ." (login_id,login_user_id,login_date,login_ip, c_id, session_id, access_url_id) VALUES ($uid,$uid,'$login_date','$login_ip', '".$_course['real_id']."' , '$session_id' , '$access_url_id' )";
+            $query = "REPLACE INTO ".$online_table ." (login_id,login_user_id,login_date,user_ip, c_id, session_id, access_url_id) VALUES ($uid,$uid,'$login_date','$user_ip', '".$_course['real_id']."' , '$session_id' , '$access_url_id' )";
 		} else {
-            $query = "REPLACE INTO ".$online_table ." (login_id,login_user_id,login_date,login_ip, session_id, access_url_id) VALUES ($uid,$uid,'$login_date','$login_ip', '$session_id', '$access_url_id')";
+            $query = "REPLACE INTO ".$online_table ." (login_id,login_user_id,login_date,user_ip, session_id, access_url_id) VALUES ($uid,$uid,'$login_date','$user_ip', '$session_id', '$access_url_id')";
 		}
 		@Database::query($query);
 	}

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

@@ -434,7 +434,7 @@ class SessionManager
                                 ";
         }
 
-        $select = "SELECT * FROM (SELECT
+        $select = "SELECT DISTINCT * FROM (SELECT
                 IF (
 					(s.date_start <= '$today' AND '$today' <= s.date_end) OR
                     (s.nb_days_access_before_beginning > 0 AND DATEDIFF(s.date_start,'" . $today . "' " . ") <= s.nb_days_access_before_beginning) OR
@@ -1271,17 +1271,17 @@ class SessionManager
 
         foreach ($return as $key => $info) {
             //Search for ip, we do less querys if we iterate the final array
-            $sql = sprintf("SELECT login_ip FROM $track_e_login WHERE login_user_id = %d AND login_date < '%s' ORDER BY login_date DESC LIMIT 1", $info['user_id'], $info['logindate']); //TODO add select by user too
+            $sql = sprintf("SELECT user_ip FROM $track_e_login WHERE login_user_id = %d AND login_date < '%s' ORDER BY login_date DESC LIMIT 1", $info['user_id'], $info['logindate']); //TODO add select by user too
             $result = Database::query($sql);
             $ip = Database::fetch_assoc($result);
             //if no ip founded, we search the closest higher ip
-            if (empty($ip['login_ip'])) {
-                $sql = sprintf("SELECT login_ip FROM $track_e_login WHERE login_user_id = %d AND login_date > '%s'  ORDER BY login_date ASC LIMIT 1", $info['user_id'], $info['logindate']); //TODO add select by user too
+            if (empty($ip['user_ip'])) {
+                $sql = sprintf("SELECT user_ip FROM $track_e_login WHERE login_user_id = %d AND login_date > '%s'  ORDER BY login_date ASC LIMIT 1", $info['user_id'], $info['logindate']); //TODO add select by user too
                 $result = Database::query($sql);
                 $ip = Database::fetch_assoc($result);
             }
             #add ip to final array
-            $return[$key]['ip'] = $ip['login_ip'];
+            $return[$key]['ip'] = $ip['user_ip'];
         }
         return $return;
     }
@@ -5485,7 +5485,19 @@ class SessionManager
                     )
                 )
             );
-
+            $whereFieldVariables = array();
+            $whereFieldIds = array();
+            if (
+                is_array($fieldsArray) &&
+                count($fieldsArray) > 0
+            ) {
+                $whereParams = '?';
+                for ($i = 1; $i < count($fieldsArray); $i++) {
+                    $whereParams .= ', ?';
+                }
+                $whereFieldVariables = 'field_variable IN ( ' . $whereParams .' )';
+                $whereFieldIds = 'field_id IN ( ' . $whereParams .  ' )';
+            }
             // Get session fields
             $extraField = new ExtraField('session');
             $questionMarks = substr(str_repeat('?, ', count($fieldsArray)), 0, -2);
@@ -5794,4 +5806,18 @@ class SessionManager
 
         return $resultData;
     }
+
+    public static function isValidId($sessionId)
+    {
+        $sessionId = intval($sessionId);
+        if ($sessionId > 0) {
+            $rows = Database::select('id', Database::get_main_table(TABLE_MAIN_SESSION), array('where' => array('id = ?' => $sessionId)));
+            if (!empty($rows)) {
+
+                return true;
+            }
+        }
+
+        return false;
+    }
 }

+ 8 - 8
main/inc/lib/tracking.lib.php

@@ -119,7 +119,7 @@ class Tracking
         $TBL_LP_VIEW = Database :: get_course_table(TABLE_LP_VIEW);
         $tbl_quiz_questions = Database :: get_course_table(TABLE_QUIZ_QUESTION);
         $TBL_QUIZ = Database :: get_course_table(TABLE_QUIZ_TEST);
-        $tbl_stats_exercices = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $tbl_stats_exercices = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $tbl_stats_attempts = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
 
         $sql = "SELECT max(view_count)
@@ -1606,7 +1606,7 @@ class Tracking
     	if (!empty($course_info)) {
     		// table definition
     		$tbl_course_quiz     = Database::get_course_table(TABLE_QUIZ_TEST);
-    		$tbl_stats_exercise  = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+    		$tbl_stats_exercise  = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
 
     		// Compose a filter based on optional exercise given
     		$condition_quiz = "";
@@ -1756,7 +1756,7 @@ class Tracking
 
     	$lp_id = intval($lp_id);
         $lp_item_id = intval($lp_item_id);
-    	$tbl_stats_exercices = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+    	$tbl_stats_exercices = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
 
     	$sql = "SELECT COUNT(ex.exe_id) as essais FROM $tbl_stats_exercices AS ex
                 WHERE  ex.exe_cours_id = '$course_code'
@@ -1797,7 +1797,7 @@ class Tracking
         if (empty($exercise_list)) {
             return '0%';
         }
-        $tbl_stats_exercices = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $tbl_stats_exercices = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $exercise_list = array_keys($exercise_list);
         $exercise_list = array_map('intval', $exercise_list);
 
@@ -2123,7 +2123,7 @@ class Tracking
         }
 
         if ($debug) echo '<h1>Tracking::get_avg_student_score</h1>';
-        $tbl_stats_exercices = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $tbl_stats_exercices = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $tbl_stats_attempts = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
 
         $course = api_get_course_info($course_code);
@@ -3724,7 +3724,7 @@ class Tracking
                 'start_date'=> 'login_course_date',
                 'end_date'  => 'logout_course_date',
                 ),*/
-            TABLE_STATISTIC_TRACK_E_EXERCICES => array(
+            TABLE_STATISTIC_TRACK_E_EXERCISES => array(
                 'course'    => 'c_id',
                 'session'   => 'session_id',
                 'user'      => 'exe_user_id',
@@ -5189,7 +5189,7 @@ class Tracking
         $tquiz_answer = Database::get_course_table(TABLE_QUIZ_ANSWER);
         $tquiz_question = Database::get_course_table(TABLE_QUIZ_QUESTION);
         $tquiz_rel_question = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
-        $ttrack_exercises  = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+        $ttrack_exercises  = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
         $ttrack_attempt    = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
 
         $sessions = array();
@@ -6534,7 +6534,7 @@ class TrackingUserLog
             return false;
         }
         $table_login = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
-        $sql_ip = "SELECT login_date, login_ip FROM $table_login WHERE login_user_id = $user_id AND login_date < '$event_date' ORDER BY login_date DESC LIMIT 1";
+        $sql_ip = "SELECT login_date, user_ip FROM $table_login WHERE login_user_id = $user_id AND login_date < '$event_date' ORDER BY login_date DESC LIMIT 1";
         $ip = '';
         $res_ip = Database::query($sql_ip);
         if ($res_ip !== false && Database::num_rows($res_ip)>0) {

+ 5 - 2
main/install/db_main.sql

@@ -883,7 +883,8 @@ VALUES
 ('tool_visible_by_default_at_creation','forums','checkbox','Tools','true','ToolVisibleByDefaultAtCreationTitle','ToolVisibleByDefaultAtCreationComment',NULL,'Forums', 1),
 ('tool_visible_by_default_at_creation','quiz','checkbox','Tools','true','ToolVisibleByDefaultAtCreationTitle','ToolVisibleByDefaultAtCreationComment',NULL,'Quiz', 1),
 ('tool_visible_by_default_at_creation','gradebook','checkbox','Tools','true','ToolVisibleByDefaultAtCreationTitle','ToolVisibleByDefaultAtCreationComment',NULL,'Gradebook', 1),
-('chamilo_database_version', NULL, 'textfield',NULL, '1.10.0.10','DatabaseVersion','', NULL, NULL, 0);
+('prevent_session_admins_to_manage_all_users', NULL, 'radio', 'Session', 'false', 'PreventSessionAdminsToManageAllUsersTitle', 'PreventSessionAdminsToManageAllUsersComment', NULL, NULL, 1),
+('chamilo_database_version', NULL, 'textfield',NULL, '1.10.0.12','DatabaseVersion','', NULL, NULL, 0);
 UNLOCK TABLES;
 /*!40000 ALTER TABLE settings_current ENABLE KEYS */;
 
@@ -1223,7 +1224,9 @@ VALUES
 ('show_hot_courses', 'true', 'Yes'),
 ('show_hot_courses', 'false', 'No'),
 ('enable_webcam_clip', 'true', 'Yes'),
-('enable_webcam_clip', 'false', 'No');
+('enable_webcam_clip', 'false', 'No'),
+('prevent_session_admins_to_manage_all_users', 'true', 'Yes'),
+('prevent_session_admins_to_manage_all_users', 'false', 'No');
 
 UNLOCK TABLES;
 

+ 19 - 16
main/install/db_stats.sql

@@ -58,6 +58,7 @@ CREATE TABLE track_e_access (
   c_id int not null,
   access_tool varchar(30) default NULL,
   access_session_id int NOT NULL default 0,
+  user_ip varchar(39) NOT NULL default '',
   PRIMARY KEY  (access_id),
   KEY access_user_id (access_user_id),
   KEY access_c_id (c_id),
@@ -108,8 +109,8 @@ CREATE TABLE track_e_downloads (
   KEY down_cours_id (down_cours_id)
 );
 
-DROP TABLE IF EXISTS track_e_exercices;
-CREATE TABLE track_e_exercices (
+DROP TABLE IF EXISTS track_e_exercises;
+CREATE TABLE track_e_exercises (
   exe_id int NOT NULL auto_increment,
   exe_user_id int unsigned default NULL,
   exe_date datetime NOT NULL default '0000-00-00 00:00:00',
@@ -118,23 +119,24 @@ CREATE TABLE track_e_exercices (
   exe_exo_id mediumint unsigned NOT NULL default 0,
   exe_result float(6,2) NOT NULL default 0,
   exe_weighting float(6,2) NOT NULL default 0,
+  user_ip varchar(39) NOT NULL default '',
   PRIMARY KEY  (exe_id),
   KEY exe_user_id (exe_user_id),
   KEY exe_cours_id (exe_cours_id)
 );
 
-ALTER TABLE track_e_exercices ADD status varchar(20) NOT NULL default '';
-ALTER TABLE track_e_exercices ADD data_tracking text NOT NULL default '';
-ALTER TABLE track_e_exercices ADD start_date datetime NOT NULL default '0000-00-00 00:00:00';
-ALTER TABLE track_e_exercices ADD steps_counter SMALLINT UNSIGNED NOT NULL default 0;
-ALTER TABLE track_e_exercices ADD session_id SMALLINT UNSIGNED NOT NULL default 0;
-ALTER TABLE track_e_exercices ADD INDEX ( session_id ) ;
-ALTER TABLE track_e_exercices ADD orig_lp_id int  NOT NULL default 0;
-ALTER TABLE track_e_exercices ADD orig_lp_item_id int  NOT NULL default 0;
-ALTER TABLE track_e_exercices ADD exe_duration int UNSIGNED NOT NULL default 0;
-ALTER TABLE track_e_exercices ADD COLUMN expired_time_control datetime NOT NULL DEFAULT '0000-00-00 00:00:00';
-ALTER TABLE track_e_exercices ADD COLUMN orig_lp_item_view_id INT NOT NULL DEFAULT 0;
-ALTER TABLE track_e_exercices ADD COLUMN questions_to_check TEXT  NOT NULL DEFAULT '';
+ALTER TABLE track_e_exercises ADD status varchar(20) NOT NULL default '';
+ALTER TABLE track_e_exercises ADD data_tracking text NOT NULL default '';
+ALTER TABLE track_e_exercises ADD start_date datetime NOT NULL default '0000-00-00 00:00:00';
+ALTER TABLE track_e_exercises ADD steps_counter SMALLINT UNSIGNED NOT NULL default 0;
+ALTER TABLE track_e_exercises ADD session_id SMALLINT UNSIGNED NOT NULL default 0;
+ALTER TABLE track_e_exercises ADD INDEX ( session_id ) ;
+ALTER TABLE track_e_exercises ADD orig_lp_id int  NOT NULL default 0;
+ALTER TABLE track_e_exercises ADD orig_lp_item_id int  NOT NULL default 0;
+ALTER TABLE track_e_exercises ADD exe_duration int UNSIGNED NOT NULL default 0;
+ALTER TABLE track_e_exercises ADD COLUMN expired_time_control datetime NOT NULL DEFAULT '0000-00-00 00:00:00';
+ALTER TABLE track_e_exercises ADD COLUMN orig_lp_item_view_id INT NOT NULL DEFAULT 0;
+ALTER TABLE track_e_exercises ADD COLUMN questions_to_check TEXT  NOT NULL DEFAULT '';
 
 DROP TABLE IF EXISTS track_e_attempt;
 CREATE TABLE track_e_attempt (
@@ -205,7 +207,7 @@ CREATE TABLE track_e_login (
   login_id int NOT NULL auto_increment,
   login_user_id int unsigned NOT NULL default 0,
   login_date datetime NOT NULL default '0000-00-00 00:00:00',
-  login_ip varchar(39) NOT NULL default '',
+  user_ip varchar(39) NOT NULL default '',
   logout_date datetime NULL default NULL,
   PRIMARY KEY  (login_id),
   KEY login_user_id (login_user_id)
@@ -216,7 +218,7 @@ CREATE TABLE track_e_online (
   login_id int NOT NULL auto_increment,
   login_user_id int unsigned NOT NULL default 0,
   login_date datetime NOT NULL default '0000-00-00 00:00:00',
-  login_ip varchar(39) NOT NULL default '',
+  user_ip varchar(39) NOT NULL default '',
   course varchar(40) default NULL,
   c_id int NOT NULL,
   session_id INT NOT NULL DEFAULT 0,
@@ -258,6 +260,7 @@ CREATE TABLE track_e_course_access (
   logout_course_date datetime default NULL,
   counter int NOT NULL,
   session_id int NOT NULL default 0,
+  user_ip varchar(39) NOT NULL default '',
   PRIMARY KEY  (course_access_id)
 );
 

+ 12 - 0
main/install/install.lib.php

@@ -1416,6 +1416,18 @@ function display_requirements($installType, $badUpdatePath, $updatePath = '', $u
             @chmod($checked_writable, $perm);
         }
 
+        $checkedWritable = api_get_path(SYS_CODE_PATH).'upload/sessions/';
+        if (!is_writable($checkedWritable)) {
+            $notwritable[] = $checkedWritable;
+            @chmod($checkedWritable, $perm);
+        }
+
+        $checkedWritable = api_get_path(SYS_CODE_PATH).'upload/courses/';
+        if (!is_writable($checkedWritable)) {
+            $notwritable[] = $checkedWritable;
+            @chmod($checkedWritable, $perm);
+        }
+
         $checked_writable = api_get_path(SYS_CODE_PATH).'default_course_document/images/';
         if (!is_writable($checked_writable)) {
             $notwritable[] = $checked_writable;

+ 1 - 1
main/install/migrate-db-1.9.0-1.10.0-post.sql

@@ -17,7 +17,7 @@
 ALTER TABLE track_e_access DROP COLUMN access_cours_code;
 ALTER TABLE track_e_default DROP COLUMN default_cours_code;
 ALTER TABLE track_e_lastaccess DROP COLUMN access_cours_code;
-ALTER TABLE track_e_exercices DROP COLUMN exe_cours_id;
+ALTER TABLE track_e_exercises DROP COLUMN exe_cours_id;
 ALTER TABLE track_e_downloads DROP COLUMN down_cours_id;
 ALTER TABLE track_e_hotpotatoes DROP COLUMN exe_cours_id;
 ALTER TABLE track_e_links DROP COLUMN links_cours_id;

+ 13 - 2
main/install/migrate-db-1.9.0-1.10.0-pre.sql

@@ -36,12 +36,14 @@ ALTER TABLE skill ADD COLUMN criteria text DEFAULT '';
 
 ALTER TABLE gradebook_category ADD COLUMN generate_certificates TINYINT NOT NULL DEFAULT 0;
 
+RENAME TABLE track_e_exercices TO track_e_exercises;
+
 ALTER TABLE session_rel_user ADD COLUMN duration int;
 
 ALTER TABLE track_e_access ADD COLUMN c_id int NOT NULL;
 ALTER TABLE track_e_default ADD COLUMN c_id int NOT NULL;
 ALTER TABLE track_e_lastaccess ADD COLUMN c_id int NOT NULL;
-ALTER TABLE track_e_exercices ADD COLUMN c_id int NOT NULL;
+ALTER TABLE track_e_exercises ADD COLUMN c_id int NOT NULL;
 ALTER TABLE track_e_downloads ADD COLUMN c_id int NOT NULL;
 ALTER TABLE track_e_hotpotatoes ADD COLUMN c_id int NOT NULL;
 ALTER TABLE track_e_links ADD COLUMN c_id int NOT NULL;
@@ -52,8 +54,17 @@ ALTER TABLE track_e_attempt ADD COLUMN c_id int NOT NULL;
 DELETE FROM settings_current WHERE variable = 'wcag_anysurfer_public_pages';
 DELETE FROM settings_options WHERE variable = 'wcag_anysurfer_public_pages';
 
+INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable) VALUES ('prevent_session_admins_to_manage_all_users', NULL, 'radio', 'Session', 'false', 'PreventSessionAdminsToManageAllUsersTitle', 'PreventSessionAdminsToManageAllUsersComment', NULL, NULL, 1);
+INSERT INTO settings_options (variable, value, display_text) VALUES ('prevent_session_admins_to_manage_all_users', 'true', 'Yes'), ('prevent_session_admins_to_manage_all_users', 'false', 'No');
+
+ALTER TABLE track_e_access ADD COLUMN user_ip varchar(39) NOT NULL default '';
+ALTER TABLE track_e_exercises ADD COLUMN user_ip varchar(39) NOT NULL default '';
+ALTER TABLE track_e_course_access ADD COLUMN user_ip varchar(39) NOT NULL default '';
+ALTER TABLE track_e_online CHANGE COLUMN login_ip user_ip varchar(39) NOT NULL DEFAULT '';
+ALTER TABLE track_e_login CHANGE COLUMN login_ip user_ip varchar(39) NOT NULL DEFAULT '';
+
 -- Do not move this query
-UPDATE settings_current SET selected_value = '1.10.0.10' WHERE variable = 'chamilo_database_version';
+UPDATE settings_current SET selected_value = '1.10.0.12' WHERE variable = 'chamilo_database_version';
 
 -- xxCOURSExx
 

+ 1 - 1
main/install/update-db-1.9.0-1.10.0.inc.php

@@ -112,7 +112,7 @@ if (defined('SYSTEM_INSTALLATION')) {
                     'track_e_course_access' => 'course_code',
                     'track_e_online' => 'course',
                     'track_e_attempt' => 'course_code',
-                    'track_e_exercices' => 'exe_cours_id'
+                    'track_e_exercises' => 'exe_cours_id'
                 );
 
                 foreach ($fields as $table => $key) {

+ 7 - 0
main/lang/english/trad4all.inc.php

@@ -316,7 +316,10 @@ $YourVersionNotUpToDate = "Your version is not up-to-date";
 $Hotpotatoes = "Hotpotatoes";
 $CourseCategoriesAreGlobal = "Course categories are global over multiple portals configurations. Changes are only allowed in the main administrative portal.";
 $UserIsNotATeacher = "User is not a teacher";
+$ConvertToMultipleAnswer = "Convert to multiple answer";
 $ThisItemIsInvisibleForStudentsButYouHaveAccessAsTeacher = "This item is invisible for learner but you have access as teacher.";
+$PreventSessionAdminsToManageAllUsersTitle = "Prevent session admins to manage all users";
+$AllowSessionAdminsToSeeAllUsersComment = "When this option is not enabled (default), session administrators can only see the users they have created.";
 $DeleteAllAttendances = "Delete all created attendances";
 $Unsubscribe = "Unsubscribe";
 $AddForum = "Add a forum";
@@ -1060,9 +1063,12 @@ $CourseProgram = "Description";
 $ThisCourseDescriptionIsEmpty = "There is no course description so far.";
 $QuestionPlan = "Help";
 $NewBloc = "Other";
+$InProcess = "In process";
 $CourseDescriptionUpdated = "The description has been updated";
 $CourseDescriptionDeleted = "Description has been deleted";
+$PreventSessionAdminsToManageAllUsersComment = "By enabling this option, session admins will only be able to see, in the administration page, the users they created.";
 $FieldTypeFile = "File upload";
+$ConvertToUniqueAnswer = "Convert to unique answer";
 $NextWeek = "Next Week";
 $DragAndDropAnElementHere = "Drag and drop an element here";
 $ThereAreNoRegisteredDatetimeYet = "There is no date/time registered yet";
@@ -1076,6 +1082,7 @@ $AttendanceCalendar = "Attendance calendar";
 $QualifyAttendanceGradebook = "Grade the attendance list in the assessment tool";
 $CreateANewAttendance = "Create a new attendance list";
 $Attendance = "Attendance";
+$AllowSessionAdminsToSeeAllUsersTitle = "Allow session administrators to see all users";
 $GeneralDescription = "Description";
 $GeneralDescriptionQuestions = "What is the goal of the training? Are there prerequisites? How is this training connected to other training?";
 $GeneralDescriptionInformation = "Describe the training (number of hours, sser number, location) and trainer (name, office, Tel., e-mail, office hours . . . .).";

+ 7 - 0
main/lang/spanish/trad4all.inc.php

@@ -316,7 +316,10 @@ $YourVersionNotUpToDate = "Su versión está actualizada";
 $Hotpotatoes = "Hotpotatoes";
 $CourseCategoriesAreGlobal = "Las categorías de cursos son globales en la configuración de múltiples portales, pero los cambios son permitidos solamente en la sesión administrativa del portal principal.";
 $UserIsNotATeacher = "El usuario no es un profesor.";
+$ConvertToMultipleAnswer = "Convertir a respuesta múltiple";
 $ThisItemIsInvisibleForStudentsButYouHaveAccessAsTeacher = "Este item no es visible para un estudiante pero podrá acceder a él como profesor";
+$PreventSessionAdminsToManageAllUsersTitle = "Impedir a los admins de sesiones de gestionar todos los usuarios";
+$AllowSessionAdminsToSeeAllUsersComment = "Cuando esta opción está desactivada los administradores de sesión solamente podrán ver sus usuarios.";
 $DeleteAllAttendances = "Eliminar todas las asistencias creadas";
 $Unsubscribe = "Dar de baja";
 $AddForum = "Añadir un foro";
@@ -1060,9 +1063,12 @@ $CourseProgram = "Descripción del curso";
 $ThisCourseDescriptionIsEmpty = "Descripción no disponible";
 $QuestionPlan = "Cuestiones clave";
 $NewBloc = "Apartado personalizado";
+$InProcess = "En proceso";
 $CourseDescriptionUpdated = "La descripción del curso ha sido actualizada";
 $CourseDescriptionDeleted = "La descripción del curso ha sido borrada";
+$PreventSessionAdminsToManageAllUsersComment = "Por activar esta opción, los administradores de sesiones podrán ver, en las páginas de administración, exclúsivamente los usuarios que ellos mismos han creado.";
 $FieldTypeFile = "Subida de archivo";
+$ConvertToUniqueAnswer = "Convertir a respuesta única";
 $NextWeek = "Semana siguiente";
 $DragAndDropAnElementHere = "Arrastrar y soltar un elemento aquí";
 $ThereAreNoRegisteredDatetimeYet = "Aún no hay registrada ninguna fecha/hora";
@@ -1076,6 +1082,7 @@ $AttendanceCalendar = "Calendario de asistencia";
 $QualifyAttendanceGradebook = "Calificar la lista de asistencia";
 $CreateANewAttendance = "Crear una lista de asistencia";
 $Attendance = "Asistencia";
+$AllowSessionAdminsToSeeAllUsersTitle = "Permitir a los administradores de sesión ver todos los usuarios";
 $GeneralDescription = "Descripción general";
 $GeneralDescriptionQuestions = "¿Cuál es el objetivo de este curso? ¿Hay requisitos previos? ¿Qué relación tiene con otros cursos?";
 $GeneralDescriptionInformation = "Descripción del curso (número de horas, código, lugar donde se desarrollará, etc.). Profesorado (nombre, despacho, teléfono, correo electrónico, etc.).";

+ 2 - 2
main/mySpace/myStudents.php

@@ -164,7 +164,7 @@ if (isset($_GET['details'])) {
 
 // Database Table Definitions
 $tbl_course_user = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
-$tbl_stats_exercices = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+$tbl_stats_exercices = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
 
 if (isset($_GET['user_id']) && $_GET['user_id'] != "") {
     $user_id = intval($_GET['user_id']);
@@ -201,7 +201,7 @@ if ($check) {
                     $session_id
                 );
 
-                //@todo delete the stats.track_e_exercices records. First implement this http://support.chamilo.org/issues/1334
+                //@todo delete the stats.track_e_exercises records. First implement this http://support.chamilo.org/issues/1334
                 $message = Display::return_message(
                     get_lang('LPWasReset'),
                     'success'

+ 1 - 1
main/mySpace/progression.php

@@ -29,7 +29,7 @@ $tbl_course 		= Database :: get_main_table(TABLE_MAIN_COURSE);
 $tbl_user 			= Database :: get_main_table(TABLE_MAIN_USER);
 $tbl_session_course = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE);
 $tbl_session 		= Database :: get_main_table(TABLE_MAIN_SESSION);
-$tbl_track_exercice = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+$tbl_track_exercice = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
 
 /*
  	MAIN CODE

+ 1 - 1
main/mySpace/reussite.php

@@ -27,7 +27,7 @@ $tbl_course 		= Database :: get_main_table(TABLE_MAIN_COURSE);
 $tbl_user 			= Database :: get_main_table(TABLE_MAIN_USER);
 $tbl_session_course = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE);
 $tbl_session 		= Database :: get_main_table(TABLE_MAIN_SESSION);
-$tbl_track_exercice = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+$tbl_track_exercice = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
 
 /*
 ===============================================================================

+ 3 - 3
main/newscorm/learnpathItem.class.php

@@ -2511,7 +2511,7 @@ class learnpathItem
                                             if ($returnstatus) {
                                                 //AND origin_lp_item_id = '.$user_id.'
                                                 $sql = 'SELECT exe_result, exe_weighting
-                                                        FROM ' . Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES) . '
+                                                        FROM ' . Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES) . '
                                                     WHERE   exe_exo_id = ' . $items[$refs_list[$prereqs_string]]->path . '
                                                         AND exe_user_id = ' . $user_id . '
                                                         AND orig_lp_id = ' . $this->lp_id . ' AND orig_lp_item_id = ' . $prereqs_string . '
@@ -2542,7 +2542,7 @@ class learnpathItem
                                             // Checking in the database.
                                             $sql = 'SELECT exe_result, exe_weighting
                                                     FROM ' . Database :: get_statistic_table(
-                                                    TABLE_STATISTIC_TRACK_E_EXERCICES
+                                                    TABLE_STATISTIC_TRACK_E_EXERCISES
                                                 ) . '
                                                     WHERE exe_exo_id = ' . $items[$refs_list[$prereqs_string]]->path . '
                                                         AND exe_user_id = ' . $user_id . ' AND orig_lp_id = ' . $this->lp_id . ' AND orig_lp_item_id = ' . $prereqs_string . ' ';
@@ -3867,7 +3867,7 @@ class learnpathItem
                         $my_status = ' ';
                         $total_time = ' ';
                         if (!empty($_REQUEST['exeId'])) {
-                            $TBL_TRACK_EXERCICES = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+                            $TBL_TRACK_EXERCICES = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
 
                             $safe_exe_id = intval($_REQUEST['exeId']);
                             $sql = "SELECT start_date,exe_date

+ 1 - 1
main/newscorm/lp_view.php

@@ -215,7 +215,7 @@ if (!empty($_REQUEST['exeId']) &&
     global $src;
     $_SESSION['oLP']->items[$_SESSION['oLP']->current]->write_to_db();
 
-    $TBL_TRACK_EXERCICES = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+    $TBL_TRACK_EXERCICES = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
     $TBL_LP_ITEM_VIEW = Database::get_course_table(TABLE_LP_ITEM_VIEW);
     $TBL_LP_ITEM = Database::get_course_table(TABLE_LP_ITEM);
     $safe_item_id = intval($_GET['lp_item_id']);

+ 1 - 1
main/reports/modules/quiz.php

@@ -26,7 +26,7 @@ function reports_modules_quiz_quizVal($quiz, $key_id) {
 			'session_id, -1 as attempt, exe_result as score, '.
 			REPORTS_PROGRESS_COMPLETED.' as progress, '.
 			'exe_duration as time, exe_date as ts from '.
-			Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES).
+			Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES).
 			' where exe_cours_id = '."'".$quiz['course_code']."'".
 			' and exe_exo_id='.$quiz['child_id']);
 }

+ 1 - 1
main/tracking/courseLog.php

@@ -150,7 +150,7 @@ $TABLETRACK_ACCESS      = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTA
 $TABLETRACK_LINKS       = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS);
 $TABLETRACK_DOWNLOADS   = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
 $TABLETRACK_ACCESS_2    = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
-$TABLETRACK_EXERCISES 	= Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+$TABLETRACK_EXERCISES 	= Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
 $TABLECOURSUSER	        = Database::get_main_table(TABLE_MAIN_COURSE_USER);
 $TABLECOURSE	        = Database::get_main_table(TABLE_MAIN_COURSE);
 $table_user             = Database::get_main_table(TABLE_MAIN_USER);

+ 1 - 1
main/tracking/exams.php

@@ -468,7 +468,7 @@ function export_complete_report_xls($filename, $array)
 
 function processStudentList($filter_score, $global, $exercise, $courseInfo, $sessionId, $newSessionList)
 {
-    $exerciseStatsTable = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+    $exerciseStatsTable = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
 
     if (empty($sessionId)) {
         $students = CourseManager::get_student_list_from_course_code(

+ 1 - 1
main/tracking/personnalLog.php

@@ -51,7 +51,7 @@ $TABLETRACK_ACCESS      = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCES
 $TABLETRACK_LINKS 		= Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS);
 $TABLETRACK_DOWNLOADS 	= Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
 $TABLETRACK_LOGIN 		= Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
-$TABLETRACK_EXERCICES   = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+$TABLETRACK_EXERCICES   = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
 
 
 $limitOfDisplayedLogins = 25; // number of logins to display

+ 9 - 7
plugin/advanced_subscription/ajax/advanced_subscription.ajax.php

@@ -21,7 +21,9 @@ $data['currentUserId'] = intval($_REQUEST['current_user_id']);
 $data['studentUserId'] = intval($_REQUEST['u']);
 $data['queueId'] = intval($_REQUEST['q']);
 $data['newStatus'] = intval($_REQUEST['e']);
-$data['is_connected'] = isset($_REQUEST['is_connected']) ? boolval($_REQUEST['is_connected']) : false;
+// Student always is connected
+// $data['is_connected'] = isset($_REQUEST['is_connected']) ? boolval($_REQUEST['is_connected']) : false;
+$data['is_connected'] = true;
 $data['profile_completed'] = isset($_REQUEST['profile_completed']) ? floatval($_REQUEST['profile_completed']) : 0;
 // Init result array
 $result = array('error' => true, 'errorMessage' => get_lang('ThereWasAnError'));
@@ -227,20 +229,20 @@ if ($verified) {
                     $data['signature'] = api_get_setting('Institution');
                     $data['admin_view_url'] = api_get_path(WEB_PLUGIN_PATH) . 'advanced_subscription/src/admin_view.php?s=' . $data['sessionId'];
                     // Check if exist and action in data
-                    if (empty($data['action'])) {
+                    if (empty($data['mailAction'])) {
                         // set action in data by new status
                         switch ($data['newStatus']) {
                             case ADVANCED_SUBSCRIPTION_QUEUE_STATUS_BOSS_APPROVED:
-                                $data['action'] = ADVANCED_SUBSCRIPTION_ACTION_SUPERIOR_APPROVE;
+                                $data['mailAction'] = ADVANCED_SUBSCRIPTION_ACTION_SUPERIOR_APPROVE;
                                 break;
                             case ADVANCED_SUBSCRIPTION_QUEUE_STATUS_BOSS_DISAPPROVED:
-                                $data['action'] = ADVANCED_SUBSCRIPTION_ACTION_SUPERIOR_DISAPPROVE;
+                                $data['mailAction'] = ADVANCED_SUBSCRIPTION_ACTION_SUPERIOR_DISAPPROVE;
                                 break;
                             case ADVANCED_SUBSCRIPTION_QUEUE_STATUS_ADMIN_APPROVED:
-                                $data['action'] = ADVANCED_SUBSCRIPTION_ACTION_ADMIN_APPROVE;
+                                $data['mailAction'] = ADVANCED_SUBSCRIPTION_ACTION_ADMIN_APPROVE;
                                 break;
                             case ADVANCED_SUBSCRIPTION_QUEUE_STATUS_ADMIN_DISAPPROVED:
-                                $data['action'] = ADVANCED_SUBSCRIPTION_ACTION_ADMIN_DISAPPROVE;
+                                $data['mailAction'] = ADVANCED_SUBSCRIPTION_ACTION_ADMIN_DISAPPROVE;
                                 break;
                             default:
                                 break;
@@ -253,7 +255,7 @@ if ($verified) {
                     }
 
                     // Send mails
-                    $result['mailIds'] = $plugin->sendMail($data, $data['action']);
+                    $result['mailIds'] = $plugin->sendMail($data, $data['mailAction']);
                     // Check if mails were sent
                     if (!empty($result['mailIds'])) {
                         $result['error'] = false;

+ 4 - 0
plugin/advanced_subscription/config.php

@@ -15,6 +15,10 @@ define('ADVANCED_SUBSCRIPTION_ACTION_SUPERIOR_SELECT', 3);
 define('ADVANCED_SUBSCRIPTION_ACTION_ADMIN_APPROVE', 4);
 define('ADVANCED_SUBSCRIPTION_ACTION_ADMIN_DISAPPROVE', 5);
 define('ADVANCED_SUBSCRIPTION_ACTION_STUDENT_REQUEST_NO_BOSS', 6);
+define('ADVANCED_SUBSCRIPTION_ACTION_REMINDER_STUDENT', 7);
+define('ADVANCED_SUBSCRIPTION_ACTION_REMINDER_SUPERIOR', 8);
+define('ADVANCED_SUBSCRIPTION_ACTION_REMINDER_SUPERIOR_MAX', 9);
+define('ADVANCED_SUBSCRIPTION_ACTION_REMINDER_ADMIN', 10);
 
 define('ADVANCED_SUBSCRIPTION_QUEUE_STATUS_NO_QUEUE', -1);
 define('ADVANCED_SUBSCRIPTION_QUEUE_STATUS_START', 0);

+ 157 - 0
plugin/advanced_subscription/cron/notify_by_mail.php

@@ -0,0 +1,157 @@
+<?php
+/* For license terms, see /license.txt */
+/**
+ * This script generates four session categories.
+ * @package chamilo.plugin.advanced_subscription
+ */
+
+/**
+ * Init
+ */
+
+require_once __DIR__ . '/../config.php';
+$plugin = AdvancedSubscriptionPlugin::create();
+$now = api_get_utc_datetime();
+$weekAgo = api_get_utc_datetime('-1 week');
+$sessionExtraField = new ExtraField('session');
+$sessionExtraFieldValue = new ExtraFieldValue('session');
+/**
+ * Get session list
+ */
+$joinTables = Database::get_main_table(TABLE_MAIN_SESSION) . ' s INNER JOIN ' .
+    Database::get_main_table(TABLE_MAIN_SESSION_USER) . ' su ON s.id = su.id_session INNER JOIN ' .
+    Database::get_main_table(TABLE_MAIN_USER_REL_USER) . ' uu ON su.id_user = uu.user_id INNER JOIN ' .
+    Database::get_main_table(TABLE_ADVANCED_SUBSCRIPTION_QUEUE) . ' asq ON su.id_session = asq.session_id AND su.id_user = asq.user_id';
+$columns = 's.id AS session_id, uu.friend_user_id AS superior_id, uu.user_id AS student_id, asq.id AS queue_id, asq.status AS status';
+$conditions = array(
+    'where' => array(
+        's.date_start >= ? AND uu.relation_type = ? AND asq.updated_at <= ?' => array(
+            $now,
+            USER_RELATION_TYPE_BOSS,
+            $weekAgo,
+        )
+    ),
+    'order' => 's.id',
+);
+
+$queueList = Database::select($columns, $joinTables, $conditions);
+
+/**
+ * Remind students
+ */
+$sessionInfoList = array();
+foreach ($queueList as $queueItem) {
+    if (!isset($sessionInfoList[$queueItem['session_id']])) {
+        $sessionInfoList[$queueItem['session_id']] = api_get_session_info($queueItem['session_id']);
+    }
+}
+
+foreach ($queueList as $queueItem) {
+    switch ($queueItem['status']) {
+        case ADVANCED_SUBSCRIPTION_QUEUE_STATUS_START:
+            // No break
+        case ADVANCED_SUBSCRIPTION_QUEUE_STATUS_BOSS_APPROVED:
+            $data = array('sessionId' => $queueItem['session_id']);
+            $data['session'] = api_get_session_info($queueItem['session_id']);
+            $data['student'] = api_get_user_info($queueItem['student_id']);
+            $plugin->sendMail($data, ADVANCED_SUBSCRIPTION_ACTION_REMINDER_STUDENT);
+            break;
+        default:
+            break;
+    }
+}
+
+/**
+ * Remind superiors
+ */
+// Get recommended number of participants
+$sessionRecommendedNumber = array();
+foreach ($queueList as $queueItem) {
+    $row =
+        $sessionExtraFieldValue->get_values_by_handler_and_field_variable(
+            $queueItem['session_id'],
+            'recommended_number_of_participants'
+    );
+    $sessionRecommendedNumber[$queueItem['session_id']] = $row['field_value'];
+}
+// Group student by superior and session
+$queueBySuperior = array();
+foreach ($queueList as $queueItem) {
+    $queueBySuperior[$queueItem['session_id']][$queueItem['superior_id']][$queueItem['student_id']]['status'] = $queueItem['status'];
+}
+
+foreach ($queueBySuperior as $sessionId => $superiorStudents) {
+    $data = array(
+        'sessionId' => $sessionId,
+        'session' => $sessionInfoList[$sessionId],
+        'students' => array(),
+
+    );
+    $dataUrl = array(
+        'action' => 'confirm',
+        'sessionId' => $sessionId,
+        'currentUserId' => 0,
+        'newStatus' => ADVANCED_SUBSCRIPTION_QUEUE_STATUS_BOSS_APPROVED,
+        'studentUserId' => 0,
+        'is_connected' => true,
+        'profile_completed' => 0,
+    );
+    foreach ($superiorStudents as $superiorId => $students) {
+        $data['superior'] = api_get_user_info($superiorId);
+        // Check if superior has at least one student
+        if (count($students) > 0) {
+            foreach ($students as $studentId => $studentInfo) {
+                if ($studentInfo['status'] == ADVANCED_SUBSCRIPTION_QUEUE_STATUS_START) {
+                    $data['students'][$studentId] = api_get_user_info($studentId);
+                    $dataUrl['studentUserId'] = $studentId;
+                    $dataUrl['newStatus'] = ADVANCED_SUBSCRIPTION_QUEUE_STATUS_BOSS_APPROVED;
+                    $data['students'][$studentId]['acceptUrl'] = $plugin->getQueueUrl($dataUrl);
+                    $dataUrl['newStatus'] = ADVANCED_SUBSCRIPTION_QUEUE_STATUS_BOSS_DISAPPROVED;
+                    $data['students'][$studentId]['rejectUrl'] = $plugin->getQueueUrl($dataUrl);
+                }
+            }
+
+            if (is_array($data['students']) && count($data['students']) > 0) {
+                // Check if superior have more than recommended
+                if ($sessionRecommendedNumber[$sessionId] >= count($students)) {
+                    // Is greater or equal than recommended
+                    $plugin->sendMail($data, ADVANCED_SUBSCRIPTION_ACTION_REMINDER_SUPERIOR);
+                } else {
+                    // Is less than recommended
+                    $plugin->sendMail($data, ADVANCED_SUBSCRIPTION_ACTION_REMINDER_SUPERIOR_MAX);
+                }
+            }
+
+        }
+    }
+}
+
+/**
+ * Remind admins
+ */
+$admins = UserManager::get_all_administrators();
+$isWesternNameOrder = api_is_western_name_order();
+foreach ($admins as &$admin) {
+    $admin['complete_name'] = $isWesternNameOrder ?
+        $admin['firstname'] . ', ' . $admin['lastname'] :
+        $admin['lastname'] . ', ' . $admin['firstname']
+    ;
+}
+unset($admin);
+$queueByAdmin = array();
+foreach ($queueList as $queueItem) {
+    if ($queueItem['status'] == ADVANCED_SUBSCRIPTION_QUEUE_STATUS_BOSS_APPROVED) {
+        $queueByAdmin[$queueItem['session_id']]['students'][$queueItem['student_id']]['user_id'] = $queueItem['student_id'];
+    }
+}
+$data = array(
+    'admins' => $admins,
+);
+foreach ($queueByAdmin as $sessionId => $studentInfo) {
+    $data['sessionId'] = $sessionId;
+    $data['admin_view_url'] = api_get_path(WEB_PLUGIN_PATH) .
+        'advanced_subscription/src/admin_view.php?s=' . $data['sessionId'];
+    $data['session'] = $sessionInfoList[$sessionId];
+    $data['students'] = $studentInfo['students'];
+    $plugin->sendMail($data, ADVANCED_SUBSCRIPTION_ACTION_REMINDER_ADMIN);
+}

+ 4 - 1
plugin/advanced_subscription/lang/english.php

@@ -37,7 +37,7 @@ $strings['AdvancedSubscriptionQueueStart'] = "Your subscription request is pendi
 $strings['AdvancedSubscriptionQueueBossDisapproved'] = "We are sorry, your subscription was rejected by your boss.";
 $strings['AdvancedSubscriptionQueueBossApproved'] = "Your subscription request has been accepted by your boss, now is pending for vacancies.";
 $strings['AdvancedSubscriptionQueueAdminDisapproved'] = "We are sorry, your subscription was rejected by the administrator.";
-$strings['AdvancedSubscriptionQueueAdminApproved'] = "Congratulation, your subscription request has been accepted by administrator";
+$strings['AdvancedSubscriptionQueueAdminApproved'] = "Congratulations!, your subscription request has been accepted by administrator.";
 $strings['AdvancedSubscriptionQueueDefaultX'] = "There was an error, queue status %d is not defined by system.";
 
 // Mail translations
@@ -48,6 +48,9 @@ $strings['MailStudentRequestSelect'] = 'Student registration requests selection'
 $strings['MailAdminAccept'] = 'Registration request accepted by administrator';
 $strings['MailAdminReject'] = 'Registration request rejected by administrator';
 $strings['MailStudentRequestNoBoss'] = 'Student registration request without boss';
+$strings['MailRemindStudent'] = 'Subscription request reminder';
+$strings['MailRemindSuperior'] = 'Subscription request are pending your approval';
+$strings['MailRemindAdmin'] = 'Course subscription are pending your approval';
 
 // TPL langs
 // Admin view

+ 11 - 8
plugin/advanced_subscription/lang/spanish.php

@@ -31,14 +31,14 @@ $strings['AdvancedSubscriptionNotMoreAble'] = "Lo sentimos, usted ya no cumple c
 $strings['AdvancedSubscriptionIncompleteParams'] = "Los parámetros enviados no están completos o no son los correctos.";
 $strings['AdvancedSubscriptionIsNotEnabled'] = "La inscripción avanzada no está activada";
 
-$strings['AdvancedSubscriptionNoQueue'] = "You are not subscribed for this course.";
-$strings['AdvancedSubscriptionNoQueueIsAble'] = "You are not subscribed, but you are qualified for this course.";
-$strings['AdvancedSubscriptionQueueStart'] = "Your subscription request is pending for approval by your boss, please wait attentive.";
-$strings['AdvancedSubscriptionQueueBossDisapproved'] = "We are sorry, your subscription was rejected by your boss.";
-$strings['AdvancedSubscriptionQueueBossApproved'] = "Your subscription request has been accepted by your boss, now is pending for vacancies.";
-$strings['AdvancedSubscriptionQueueAdminDisapproved'] = "We are sorry, your subscription was rejected by the administrator.";
-$strings['AdvancedSubscriptionQueueAdminApproved'] = "Congratulation, your subscription request has been accepted by administrator";
-$strings['AdvancedSubscriptionQueueDefaultX'] = "There was an error, queue status %d is not defined by system.";
+$strings['AdvancedSubscriptionNoQueue'] = "Usted no está inscrito para este curso.";
+$strings['AdvancedSubscriptionNoQueueIsAble'] = "Usted no está inscrito, pero está calificado para este curso.";
+$strings['AdvancedSubscriptionQueueStart'] = "Su solicitud de inscripción está pendiente de la aprobación de su jefe, por favor espere atentamente.";
+$strings['AdvancedSubscriptionQueueBossDisapproved'] = "Lo sentimos, tu inscripción fue rechazada por tu jefe.";
+$strings['AdvancedSubscriptionQueueBossApproved'] = "Tu solicitud de inscripción ha sido aceptado por tu jefe, ahora está en espera de vacantes.";
+$strings['AdvancedSubscriptionQueueAdminDisapproved'] = "Lo sentimos, Tu inscripción ha sido rechazada por el administrador.";
+$strings['AdvancedSubscriptionQueueAdminApproved'] = "¡Felicitaciones! Tu inscripción ha sido aceptada por el administrador.";
+$strings['AdvancedSubscriptionQueueDefaultX'] = "Hubo un error el estado en cola %d no está definido en el sistema.";
 
 // Mail translations
 $strings['MailStudentRequest'] = 'Solicitud de registro de estudiante';
@@ -48,6 +48,9 @@ $strings['MailStudentRequestSelect'] = 'Selección de solicitudes de registro de
 $strings['MailAdminAccept'] = 'Solicitud de registro aceptada por administrador';
 $strings['MailAdminReject'] = 'Solicitud de registro rechazada por administrador';
 $strings['MailStudentRequestNoBoss'] = 'Solicitud de registro de estudiante sin superior';
+$strings['MailRemindStudent'] = 'Recordatorio de la solicitud de inscripción';
+$strings['MailRemindSuperior'] = 'Solicitudes de inscripción estan pendientes de tu aprobación';
+$strings['MailRemindAdmin'] = 'Inscripciones de cursos estan pendientes de tu aprobación';
 
 // TPL translations
 // Admin view

+ 148 - 48
plugin/advanced_subscription/src/AdvancedSubscriptionPlugin.php

@@ -111,64 +111,104 @@ class AdvancedSubscriptionPlugin extends Plugin implements HookPluginInterface
      */
     public function isAllowedToDoRequest($userId, $params = array())
     {
-        if (isset($params['is_connected']) && isset($params['profile_completed'])) {
-            $isAllowed = null;
-            $plugin = self::create();
-            $wsUrl = $plugin->get('ws_url');
-            // @TODO: Get connection status from user by WS
-            $isConnected = $params['is_connected'];
-            if ($isConnected) {
-                $profileCompletedMin = (float) $plugin->get('min_profile_percentage');
-                // @TODO: Get completed profile percentage by WS
+        $isAllowed = null;
+        $plugin = self::create();
+        $wsUrl = $plugin->get('ws_url');
+        // Student always is connected
+        $isConnected = true;
+        if ($isConnected) {
+            $profileCompletedMin = (float) $plugin->get('min_profile_percentage');
+            if (is_string($wsUrl) && !empty($wsUrl)) {
+                $options = array(
+                    'location' => $wsUrl,
+                    'uri' => $wsUrl
+                );
+                $client = new SoapClient(null, $options);
+                $userInfo = UserManager::get_user_info_by_id($userId);
+                try {
+                    $profileCompleted = $client->__soapCall('getProfileCompletionPercentage', $userInfo['extra']['drupal_user_id']);
+                } catch (\Exception $e) {
+                    $profileCompleted = 0;
+                }
+            } elseif (isset($params['profile_completed'])) {
                 $profileCompleted = (float) $params['profile_completed'];
-                if ($profileCompleted > $profileCompletedMin) {
-                    $checkInduction = $plugin->get('check_induction');
-                    // @TODO: check if user have completed at least one induction session
-                    $completedInduction = true;
-                    if (!$checkInduction || $completedInduction) {
-                        $uitMax = $plugin->get('yearly_cost_unit_converter');
-                        $uitMax *= $plugin->get('yearly_cost_limit');
-                        // @TODO: Get UIT completed by user this year by WS
-                        $uitUser = 0;
-                        $extra = new ExtraFieldValue('session');
-                        $var = $extra->get_values_by_handler_and_field_variable($params['session_id'], 'cost');
-                        $uitUser += $var['field_value'];
-                        if ($uitMax >= $uitUser) {
-                            $expendedTimeMax = $plugin->get('yearly_hours_limit');
-                            // @TODO: Get Expended time from user data
-                            $expendedTime = 0;
-                            $var = $extra->get_values_by_handler_and_field_variable($params['session_id'], 'duration');
-                            $expendedTime += $var['field_value'];
-                            if ($expendedTimeMax >= $expendedTime) {
-                                $expendedNumMax = $plugin->get('courses_count_limit');
-                                // @TODO: Get Expended num from user
-                                $expendedNum = 0;
-                                if ($expendedNumMax >= $expendedNum) {
-                                    $isAllowed = true;
-                                } else {
-                                    throw new \Exception($this->get_lang('AdvancedSubscriptionCourseXLimitReached'));
-                                }
+            } else {
+                $profileCompleted = 0;
+            }
+            if ($profileCompleted >= $profileCompletedMin) {
+                $checkInduction = $plugin->get('check_induction');
+                // @TODO: check if user have completed at least one induction session
+                $completedInduction = true;
+                if (!$checkInduction || $completedInduction) {
+                    $uitMax = $plugin->get('yearly_cost_unit_converter');
+                    $uitMax *= $plugin->get('yearly_cost_limit');
+                    $uitUser = 0;
+                    $now = new DateTime(api_get_utc_datetime());
+                    $newYearDate = $plugin->get('course_session_credit_year_start_date');
+                    $newYearDate = !empty($newYearDate) ?
+                        new \DateTime($newYearDate . $now->format('/Y')) :
+                        $now;
+                    $extra = new ExtraFieldValue('session');
+                    $joinSessionTable = Database::get_main_table(TABLE_MAIN_SESSION_USER) . ' su INNER JOIN ' .
+                        Database::get_main_table(TABLE_MAIN_SESSION) . ' s ON s.id = su.id_session';
+                    $whereSessionParams = 'su.relation_type = ? AND s.date_start >= ? AND su.id_user = ?';
+                    $whereSessionParamsValues = array(
+                        0,
+                        $newYearDate->format('Y-m-d'),
+                        $userId
+                    );
+                    $whereSession = array(
+                        'where' => array(
+                            $whereSessionParams => $whereSessionParamsValues
+                        )
+                    );
+                    $selectSession = 's.id AS id';
+                    $sessions = Database::select(
+                        $selectSession,
+                        $joinSessionTable,
+                        $whereSession
+                    );
+
+                    if (is_array($sessions) && count($sessions) > 0) {
+                        foreach ($sessions as $session) {
+                            $var = $extra->get_values_by_handler_and_field_variable($session['id'], 'cost');
+                            $uitUser += $var['field_value'];
+                        }
+                    }
+                    if ($uitMax >= $uitUser) {
+                        $expendedTimeMax = $plugin->get('yearly_hours_limit');
+                        $expendedTime = 0;
+                        if (is_array($sessions) && count($sessions) > 0) {
+                            foreach ($sessions as $session) {
+                                $var = $extra->get_values_by_handler_and_field_variable($session['id'], 'teaching_hours');
+                                $expendedTime += $var['field_value'];
+                            }
+                        }
+                        if ($expendedTimeMax >= $expendedTime) {
+                            $expendedNumMax = $plugin->get('courses_count_limit');
+                            $expendedNum = count($sessions);
+                            if ($expendedNumMax >= $expendedNum) {
+                                $isAllowed = true;
                             } else {
-                                throw new \Exception($this->get_lang('AdvancedSubscriptionTimeXLimitReached'));
+                                throw new \Exception($this->get_lang('AdvancedSubscriptionCourseXLimitReached'));
                             }
                         } else {
-                            throw new \Exception($this->get_lang('AdvancedSubscriptionCostXLimitReached'));
+                            throw new \Exception($this->get_lang('AdvancedSubscriptionTimeXLimitReached'));
                         }
                     } else {
-                        throw new \Exception($this->get_lang('AdvancedSubscriptionIncompleteInduction'));
+                        throw new \Exception($this->get_lang('AdvancedSubscriptionCostXLimitReached'));
                     }
                 } else {
-                    throw new \Exception($this->get_lang('AdvancedSubscriptionProfileIncomplete'));
+                    throw new \Exception($this->get_lang('AdvancedSubscriptionIncompleteInduction'));
                 }
             } else {
-                throw new \Exception($this->get_lang('AdvancedSubscriptionNotConnected'));
+                throw new \Exception($this->get_lang('AdvancedSubscriptionProfileIncomplete'));
             }
-
-            return $isAllowed;
         } else {
-            throw new \Exception($this->get_lang('AdvancedSubscriptionIncompleteParams'));
+            throw new \Exception($this->get_lang('AdvancedSubscriptionNotConnected'));
         }
 
+        return $isAllowed;
     }
 
     /**
@@ -213,6 +253,7 @@ class AdvancedSubscriptionPlugin extends Plugin implements HookPluginInterface
         $queueTable = Database::get_main_table(TABLE_ADVANCED_SUBSCRIPTION_QUEUE);
         $attributes = array(
             'last_message_id' => $mailId,
+            'updated_at' => api_get_utc_datetime(),
         );
 
         $num = Database::update(
@@ -254,7 +295,7 @@ class AdvancedSubscriptionPlugin extends Plugin implements HookPluginInterface
 
     /**
      * Send message for the student subscription approval to a specific session
-     * @param int $studentId
+     * @param int|array $studentId
      * @param int $receiverId
      * @param string $subject
      * @param string $content
@@ -272,7 +313,14 @@ class AdvancedSubscriptionPlugin extends Plugin implements HookPluginInterface
 
         if ($save && !empty($mailId)) {
             // Save as sent message
-            $this->saveLastMessage($mailId, $studentId, $sessionId);
+            if (is_array($studentId) && !empty($studentId)) {
+                foreach ($studentId as $student) {
+                    $this->saveLastMessage($mailId, $student['user_id'], $sessionId);
+                }
+            } else {
+                $studentId = intval($studentId);
+                $this->saveLastMessage($mailId, $studentId, $sessionId);
+            }
         }
         return $mailId;
     }
@@ -542,6 +590,50 @@ class AdvancedSubscriptionPlugin extends Plugin implements HookPluginInterface
                     );
                 }
                 break;
+            case ADVANCED_SUBSCRIPTION_ACTION_REMINDER_STUDENT:
+                $mailIds['render'] = $this->sendMailMessage(
+                    $data['student']['user_id'],
+                    $data['student']['user_id'],
+                    $this->get_lang('MailRemindStudent'),
+                    $template->fetch('/advanced_subscription/views/reminder_notice_student.tpl'),
+                    $data['sessionId'],
+                    true
+                );
+                break;
+            case ADVANCED_SUBSCRIPTION_ACTION_REMINDER_SUPERIOR:
+                $mailIds['render'] = $this->sendMailMessage(
+                    $data['students'],
+                    $data['superior']['user_id'],
+                    $this->get_lang('MailRemindSuperior'),
+                    $template->fetch('/advanced_subscription/views/reminder_notice_superior.tpl'),
+                    $data['sessionId'],
+                    true
+                );
+                break;
+            case ADVANCED_SUBSCRIPTION_ACTION_REMINDER_SUPERIOR_MAX:
+                $mailIds['render'] = $this->sendMailMessage(
+                    $data['students'],
+                    $data['superior']['user_id'],
+                    $this->get_lang('MailRemindSuperior'),
+                    $template->fetch('/advanced_subscription/views/reminder_notice_superior_max.tpl'),
+                    $data['sessionId'],
+                    true
+                );
+                break;
+            case ADVANCED_SUBSCRIPTION_ACTION_REMINDER_ADMIN:
+                // Mail to admin
+                foreach ($data['admins'] as $adminId => $admin) {
+                    $template->assign('admin', $admin);
+                    $mailIds[] = $this->sendMailMessage(
+                        $data['students'],
+                        $adminId,
+                        $this->get_lang('MailRemindAdmin'),
+                        $template->fetch('/advanced_subscription/views/reminder_notice_admin.tpl'),
+                        $data['sessionId'],
+                        true
+                    );
+                }
+                break;
             default:
                 break;
         }
@@ -664,6 +756,8 @@ class AdvancedSubscriptionPlugin extends Plugin implements HookPluginInterface
                 if ($vacancy >= 0) {
 
                     return $vacancy;
+                } else {
+                    return 0;
                 }
             }
         }
@@ -686,7 +780,7 @@ class AdvancedSubscriptionPlugin extends Plugin implements HookPluginInterface
             $extraField = new ExtraField('session');
             // Get session fields
             $fieldList = $extraField->get_all(array(
-                'field_variable IN ( ?, ?, ?, ?, ?)' => $fieldsArray
+                'field_variable IN ( ?, ?, ?, ?, ?, ?, ? )' => $fieldsArray
             ));
             // Index session fields
             $fields = array();
@@ -711,6 +805,12 @@ class AdvancedSubscriptionPlugin extends Plugin implements HookPluginInterface
             }
             $sessionArray['description'] = SessionManager::getDescriptionFromSessionId($sessionId);
 
+            if (isset($sessionArray['brochure'])) {
+                $sessionArray['brochure'] = api_get_path(WEB_CODE_PATH) . $sessionArray['brochure'];
+            }
+            if (isset($sessionArray['banner'])) {
+                $sessionArray['banner'] = api_get_path(WEB_CODE_PATH) . $sessionArray['banner'];
+            }
             return $sessionArray;
         }
 
@@ -783,7 +883,7 @@ class AdvancedSubscriptionPlugin extends Plugin implements HookPluginInterface
             'e=' . intval($params['newStatus']) . '&' .
             'u=' . intval($params['studentUserId']) . '&' .
             'q=' . intval($params['queueId']) . '&' .
-            'is_connected=' . intval($params['is_connected']) . '&' .
+            'is_connected=' . true . '&' .
             'profile_completed=' . intval($params['profile_completed']) . '&' .
             'v=' . $this->generateHash($params);
         return $url;

+ 66 - 53
plugin/advanced_subscription/src/HookAdvancedSubscription.php

@@ -17,14 +17,14 @@ class HookAdvancedSubscription extends HookObserver implements
     HookWSRegistrationObserverInterface,
     HookNotificationContentObserverInterface
 {
-    public $plugin;
+    public static $plugin;
 
     /**
      * Constructor. Calls parent, mainly.
      */
     protected function __construct()
     {
-        $this->plugin = AdvancedSubscriptionPlugin::create();
+        self::$plugin = AdvancedSubscriptionPlugin::create();
         parent::__construct(
             'plugin/advanced_subscription/src/HookAdvancedSubscription.class.php',
             'advanced_subscription'
@@ -93,7 +93,7 @@ class HookAdvancedSubscription extends HookObserver implements
                     // session.date_end
                     'date_end' => array('name' => 'date_end', 'type' => 'xsd:string'),
                     // session.human_text_duration
-                    'duration' => array('name' => 'duration', 'type' => 'xsd:string'),
+                    'human_text_duration' => array('name' => 'human_text_duration', 'type' => 'xsd:string'),
                     // session.vacancies
                     'vacancies' => array('name' => 'vacancies', 'type' => 'xsd:string'),
                     // session.schedule
@@ -167,8 +167,8 @@ class HookAdvancedSubscription extends HookObserver implements
                     'place' => array('name' => 'place', 'type' => 'xsd:string'),
                     // session.allow_visitors
                     'allow_visitors' => array('name' => 'allow_visitors', 'type' => 'xsd:string'),
-                    // session.duration
-                    'duration' => array('name' => 'duration', 'type' => 'xsd:int'),
+                    // session.teaching_hours
+                    'teaching_hours' => array('name' => 'teaching_hours', 'type' => 'xsd:int'),
                     // session.brochure
                     'brochure' => array('name' => 'brochure', 'type' => 'xsd:string'),
                     // session.banner
@@ -402,6 +402,7 @@ class HookAdvancedSubscription extends HookObserver implements
         } else {
             // Nothing to do
         }
+
         return false;
     }
 
@@ -438,13 +439,12 @@ class HookAdvancedSubscription extends HookObserver implements
 
         // Get the session brief List by category
         $fields = array(
+            'id',
             'short_description',
             'mode',
             'human_text_duration',
             'vacancies',
-            'brochure',
-            'target',
-            'schedule'
+            'schedule',
         );
         $sessionList = SessionManager::getShortSessionListAndExtraByCategory(
             $sessionCategoryId,
@@ -459,7 +459,7 @@ class HookAdvancedSubscription extends HookObserver implements
      * @param $params
      * @return null|soap_fault
      */
-    public function WSSessionGetDetailsByUser($params)
+    public static function WSSessionGetDetailsByUser($params)
     {
         global $debug;
 
@@ -475,53 +475,66 @@ class HookAdvancedSubscription extends HookObserver implements
         if (is_array($params) && !empty($params['session_id']) && !empty($params['user_id'])) {
             $userId = (int) $params['user_id'];
             $sessionId = (int) $params['session_id'];
-            // Check if student is already subscribed
-
-            $plugin = AdvancedSubscriptionPlugin::create();
-            $isOpen = $plugin->isSessionOpen($sessionId);
-            $status = $plugin->getQueueStatus($userId, $sessionId);
-            $vacancy = $plugin->getVacancy($sessionId);
-            $data = $plugin->getSessionDetails($sessionId);
-            if (!empty($data) && is_array($data)) {
-                $data['status'] = $status;
-                // 5 Cases:
-                if ($isOpen) {
-                    // Go to Course session
-                    $data['action_url'] = $plugin->getSessionUrl($sessionId);
-                } else {
-                    try {
-                        $isAble = $plugin->isAllowedToDoRequest($userId, $params);
-                        $data['message'] = $plugin->getStatusMessage($status, $isAble);
-                    } catch (\Exception $e) {
-                        $data['message'] = $e->getMessage();
-                    }
-                    $params['action'] = 'subscribe';
-                    $params['sessionId'] = intval($sessionId);
-                    $params['currentUserId'] = 0; // No needed
-                    $params['studentUserId'] = intval($userId);
-                    $params['queueId'] = 0; // No needed
-                    $params['newStatus'] = ADVANCED_SUBSCRIPTION_QUEUE_STATUS_START;
-                    if ($vacancy > 0) {
-                        // Check conditions
-                        if ($status === ADVANCED_SUBSCRIPTION_QUEUE_STATUS_NO_QUEUE) {
-                            // No in Queue, require queue subscription url action
-                            $data['action_url'] = $plugin->getQueueUrl($params);
-                        } elseif ($status === ADVANCED_SUBSCRIPTION_QUEUE_STATUS_ADMIN_APPROVED) {
-                            // send url action
-                            $data['action_url'] = $plugin->getSessionUrl($sessionId);
-                        } else {
-                            // In queue, output status message, no more info.
-                        }
+            // Check if user exists
+            if (
+                UserManager::is_user_id_valid($userId) &&
+                SessionManager::isValidId($sessionId)
+            ) {
+                // Check if student is already subscribed
+                $plugin = AdvancedSubscriptionPlugin::create();
+                $isOpen = $plugin->isSessionOpen($sessionId);
+                $status = $plugin->getQueueStatus($userId, $sessionId);
+                $vacancy = $plugin->getVacancy($sessionId);
+                $data = $plugin->getSessionDetails($sessionId);
+                if (!empty($data) && is_array($data)) {
+                    $data['status'] = $status;
+                    // Vacancy and queue status cases:
+                    if ($isOpen) {
+                        // Go to Course session
+                        $data['action_url'] = self::$plugin->getSessionUrl($sessionId);
                     } else {
-                        if ($status === ADVANCED_SUBSCRIPTION_QUEUE_STATUS_ADMIN_APPROVED) {
-                            $data['action_url'] = $plugin->getSessionUrl($sessionId);
+                        try {
+                            $isAllowed = self::$plugin->isAllowedToDoRequest($userId, $params);
+                            $data['message'] = self::$plugin->getStatusMessage($status, $isAllowed);
+                        } catch (\Exception $e) {
+                            $data['message'] = $e->getMessage();
+                        }
+                        $params['action'] = 'subscribe';
+                        $params['sessionId'] = intval($sessionId);
+                        $params['currentUserId'] = 0; // No needed
+                        $params['studentUserId'] = intval($userId);
+                        $params['queueId'] = 0; // No needed
+                        $params['newStatus'] = ADVANCED_SUBSCRIPTION_QUEUE_STATUS_START;
+                        if ($vacancy > 0) {
+                            // Check conditions
+                            if ($status == ADVANCED_SUBSCRIPTION_QUEUE_STATUS_NO_QUEUE) {
+                                // No in Queue, require queue subscription url action
+                                $data['action_url'] = self::$plugin->getQueueUrl($params);
+                            } elseif ($status == ADVANCED_SUBSCRIPTION_QUEUE_STATUS_ADMIN_APPROVED) {
+                                // send url action
+                                $data['action_url'] = self::$plugin->getSessionUrl($sessionId);
+                            } else {
+                                // In queue, output status message, no more info.
+                            }
                         } else {
-                            // in Queue or not, cannot be subscribed to session
-                            $data['action_url'] = $plugin->getQueueUrl($params);
+                            if ($status == ADVANCED_SUBSCRIPTION_QUEUE_STATUS_ADMIN_APPROVED) {
+                                $data['action_url'] = self::$plugin->getSessionUrl($sessionId);
+                            } elseif ($status == ADVANCED_SUBSCRIPTION_QUEUE_STATUS_NO_QUEUE) {
+                                // in Queue or not, cannot be subscribed to session
+                                $data['action_url'] = self::$plugin->getQueueUrl($params);
+                            } else {
+                                // In queue, output status message, no more info.
+                            }
                         }
                     }
+                    $result = $data;
+                } else {
+                    // Return soap fault No result was found
+                    $result = return_error(WS_ERROR_NOT_FOUND_RESULT);
                 }
-                $result = $data;
+            } else {
+                // Return soap fault No result was found
+                $result = return_error(WS_ERROR_NOT_FOUND_RESULT);
             }
         } else {
             // Return soap fault Not valid input params
@@ -587,14 +600,14 @@ class HookAdvancedSubscription extends HookObserver implements
         $plugin = AdvancedSubscriptionPlugin::create();
         foreach ($sessionList as &$session) {
             // Add validated and queue users count
-            $session['validated_user_num'] = $plugin->countQueueByParams(
+            $session['validated_user_num'] = self::$plugin->countQueueByParams(
                 array(
                     'sessions' => array($session['id']),
                     'status' => array(ADVANCED_SUBSCRIPTION_QUEUE_STATUS_ADMIN_APPROVED)
 
                 )
             );
-            $session['waiting_user_num'] = $plugin->countQueueByParams(
+            $session['waiting_user_num'] = self::$plugin->countQueueByParams(
                 array(
                     'sessions' => array($session['id']),
                     'status' => array(

+ 203 - 0
plugin/advanced_subscription/src/scripts/insert_session_fields.php

@@ -0,0 +1,203 @@
+<?php
+/* For license terms, see /license.txt */
+/**
+ * This script generates session fields needed for this plugin
+ * @package chamilo.plugin.advanced_subscription
+ */
+
+//exit;
+
+require_once __DIR__ . '/../../config.php';
+
+api_protect_admin_script();
+
+$teachingHours = new ExtraField('session');
+$teachingHours->save(array(
+    'field_type' => ExtraField::FIELD_TYPE_INTEGER,
+    'field_variable' => 'teaching_hours',
+    'field_display_text' => get_lang('TeachingHours'),
+    'field_visible' => 1,
+    'field_changeable' => 1
+));
+
+$cost = new ExtraField('session');
+$cost->save(array(
+    'field_type' => ExtraField::FIELD_TYPE_FLOAT,
+    'field_variable' => 'cost',
+    'field_display_text' => get_lang('Cost'),
+    'field_visible' => 1,
+    'field_changeable' => 1
+));
+
+$vacancies = new ExtraField('session');
+$vacancies->save(array(
+    'field_type' => ExtraField::FIELD_TYPE_INTEGER,
+    'field_variable' => 'vacancies',
+    'field_display_text' => get_lang('Vacancies'),
+    'field_visible' => 1,
+    'field_changeable' => 1
+));
+
+$recommendedNumberOfParticipants = new ExtraField('session');
+$recommendedNumberOfParticipants->save(array(
+    'field_type' => ExtraField::FIELD_TYPE_INTEGER,
+    'field_variable' => 'recommended_number_of_participants',
+    'field_display_text' => get_lang('RecommendedNumberOfParticipants'),
+    'field_visible' => 1,
+    'field_changeable' => 1
+));
+
+$place = new ExtraField('session');
+$place->save(array(
+    'field_type' => ExtraField::FIELD_TYPE_TEXT,
+    'field_variable' => 'place',
+    'field_display_text' => get_lang('Place'),
+    'field_visible' => 1,
+    'field_changeable' => 1
+));
+
+$schedule = new ExtraField('session');
+$schedule->save(array(
+    'field_type' => ExtraField::FIELD_TYPE_TEXT,
+    'field_variable' => 'schedule',
+    'field_display_text' => get_lang('Schedule'),
+    'field_visible' => 1,
+    'field_changeable' => 1
+));
+
+$allowVisitors = new ExtraField('session');
+$allowVisitors->save(array(
+    'field_type' => ExtraField::FIELD_TYPE_CHECKBOX,
+    'field_variable' => 'allow_visitors',
+    'field_display_text' => get_lang('AllowVisitors'),
+    'field_visible' => 1,
+    'field_changeable' => 1
+));
+
+$modeOptions = array(
+    get_lang('Online'),
+    get_lang('Presencial'),
+    get_lang('B-Learning')
+);
+
+$mode = new ExtraField('session');
+$mode->save(array(
+    'field_type' => ExtraField::FIELD_TYPE_SELECT,
+    'field_variable' => 'mode',
+    'field_display_text' => get_lang('Mode'),
+    'field_visible' => 1,
+    'field_changeable' => 1,
+    'field_options' => implode('; ', $modeOptions)
+));
+
+$isInductionSession = new ExtraField('session');
+$isInductionSession->save(array(
+    'field_type' => ExtraField::FIELD_TYPE_CHECKBOX,
+    'field_variable' => 'is_induccion_session',
+    'field_display_text' => get_lang('IsInductionSession'),
+    'field_visible' => 1,
+    'field_changeable' => 1
+));
+
+$isOpenSession = new ExtraField('session');
+$isOpenSession->save(array(
+    'field_type' => ExtraField::FIELD_TYPE_CHECKBOX,
+    'field_variable' => 'is_open_session',
+    'field_display_text' => get_lang('IsOpenSession'),
+    'field_visible' => 1,
+    'field_changeable' => 1
+));
+
+$duration = new ExtraField('session');
+$duration->save(array(
+    'field_type' => ExtraField::FIELD_TYPE_TEXT,
+    'field_variable' => 'human_text_duration',
+    'field_display_text' => get_lang('DurationInWords'),
+    'field_visible' => 1,
+    'field_changeable' => 1
+));
+
+$showStatusOptions = array(
+    get_lang('Open'),
+    get_lang('InProcess'),
+    get_lang('Closed')
+);
+
+$showStatus = new ExtraField('session');
+$showStatus->save(array(
+    'field_type' => ExtraField::FIELD_TYPE_SELECT,
+    'field_variable' => 'show_status',
+    'field_display_text' => get_lang('ShowStatus'),
+    'field_visible' => 1,
+    'field_changeable' => 1,
+    'field_options' => implode('; ', $showStatusOptions)
+));
+
+$publicationStartDate = new ExtraField('session');
+$publicationStartDate->save(array(
+    'field_type' => ExtraField::FIELD_TYPE_DATE,
+    'field_variable' => 'publication_start_date',
+    'field_display_text' => get_lang('PublicationStartDate'),
+    'field_visible' => 1,
+    'field_changeable' => 1
+));
+
+$publicationEndDate = new ExtraField('session');
+$publicationEndDate->save(array(
+    'field_type' => ExtraField::FIELD_TYPE_DATE,
+    'field_variable' => 'publication_end_date',
+    'field_display_text' => get_lang('PublicationEndDate'),
+    'field_visible' => 1,
+    'field_changeable' => 1
+));
+
+$banner = new ExtraField('session');
+$banner->save(array(
+    'field_type' => ExtraField::FIELD_TYPE_FILE_IMAGE,
+    'field_variable' => 'banner',
+    'field_display_text' => get_lang('SessionBanner'),
+    'field_visible' => 1,
+    'field_changeable' => 1
+));
+
+$brochure = new ExtraField('session');
+$brochure->save(array(
+    'field_type' => ExtraField::FIELD_TYPE_FILE,
+    'field_variable' => 'brochure',
+    'field_display_text' => get_lang('Brochure'),
+    'field_visible' => 1,
+    'field_changeable' => 1
+));
+
+$targetOptions = array(
+    get_lang('Minedu'),
+    get_lang('Regiones')
+);
+
+$target = new ExtraField('session');
+$target->save(array(
+    'field_type' => ExtraField::FIELD_TYPE_SELECT,
+    'field_variable' => 'target',
+    'field_display_text' => get_lang('Target'),
+    'field_visible' => 1,
+    'field_changeable' => 1,
+    'field_options' => implode('; ', $targetOptions)
+));
+
+$shortDescription = new ExtraField('session');
+$shortDescription->save(array(
+    'field_type' => ExtraField::FIELD_TYPE_TEXT,
+    'field_variable' => 'short_description',
+    'field_display_text' => get_lang('ShortSescription'),
+    'field_visible' => 1,
+    'field_changeable' => 1
+));
+
+$id = new ExtraField('session');
+$id->save(array(
+    'field_type' => ExtraField::FIELD_TYPE_TEXT,
+    'field_variable' => 'id',
+    'field_display_text' => get_lang('Id'),
+    'field_visible' => 1,
+    'field_changeable' => 1
+));

+ 20 - 0
plugin/advanced_subscription/src/scripts/insert_sessions_categories.php

@@ -0,0 +1,20 @@
+<?php
+/* For license terms, see /license.txt */
+/**
+ * This script generates four session categories.
+ * @package chamilo.plugin.advanced_subscription
+ */
+require_once __DIR__ . '/../../config.php';
+
+api_protect_admin_script();
+
+$categories = array(
+    'capacitaciones',
+    'programas',
+    'especializaciones',
+    'cursos prácticos'
+);
+$tableSessionCategory = Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY);
+foreach ($categories as $category) {
+    Database::query("INSERT INTO $tableSessionCategory (name) VALUES ('$category')");
+}

+ 5 - 0
plugin/advanced_subscription/test/mails.php

@@ -1,4 +1,9 @@
 <?php
+/* For license terms, see /license.txt */
+/**
+ * A script to render all mails templates
+ * @package chamilo.plugin.advanced_subscription
+ */
 
 require_once __DIR__ . '/../config.php';
 

+ 49 - 0
plugin/advanced_subscription/test/ws_session_user.php

@@ -0,0 +1,49 @@
+<?php
+/* For license terms, see /license.txt */
+/**
+ * A script to test session details by user web service
+ * @package chamilo.plugin.advanced_subscription
+ */
+
+/**
+ * Init
+ */
+require_once __DIR__ . '/../config.php';
+// Protect test
+api_protect_admin_script();
+
+// exit;
+
+$plugin = AdvancedSubscriptionPlugin::create();
+$hookPlugin = HookAdvancedSubscription::create();
+// Get params from request (GET or POST)
+$params = array();
+// Init result array
+$params['user_id'] = intval($_REQUEST['u']);
+$params['session_id'] = intval($_REQUEST['s']);
+$params['profile_completed'] = 100;
+$params['secret_key'] = 'ed639d402804ffa347b489be3e42f28058e402bf';
+
+// Registration soap wsdl
+$wsUrl = 'http://chamilo19.net/main/webservices/registration.soap.php?wsdl';
+$options = array(
+    'location' => $wsUrl,
+    'uri' => $wsUrl,
+);
+
+/**
+ * WS test
+ */
+try {
+    // Init soap client
+    $client = new SoapClient(null, $options);
+    // Soap call to WS
+    $result = $client->__soapCall('HookAdvancedSubscription..WSSessionGetDetailsByUser', array($params));
+    echo '<pre>', print_r($result, 1) , '</pre>';
+    if (is_object($result) && isset($result->action_url)) {
+        echo '<br />';
+        echo Display::url($result->message, $result->action_url);
+    }
+} catch (\Exception $e) {
+    echo '<pre>', print_r($e, 1) , '</pre>';
+}

+ 2 - 2
plugin/advanced_subscription/views/admin_view.tpl

@@ -54,13 +54,13 @@
                                 class="btn btn-success btn-advanced-subscription btn-accept"
                                 href="{{ student.acceptUrl }}"
                             >
-                                {{ 'Accept' | get_plugin_lang('AdvancedSubscriptionPlugin') }}
+                                {{ 'AcceptInfinitive' | get_plugin_lang('AdvancedSubscriptionPlugin') }}
                             </a>
                             <a
                                 class="btn btn-danger btn-advanced-subscription btn-reject"
                                 href="{{ student.rejectUrl }}"
                             >
-                                {{ 'Reject' | get_plugin_lang('AdvancedSubscriptionPlugin') }}
+                                {{ 'RejectInfinitive' | get_plugin_lang('AdvancedSubscriptionPlugin') }}
                             </a>
                         </td>
                     </tr>

+ 1 - 1
plugin/advanced_subscription/views/reminder_notice_superior.tpl

@@ -54,7 +54,7 @@
                         <table width="100%" border="0" cellspacing="3" cellpadding="4" style="background:#EDE9EA">
                             {% for student in students %}
                             <tr>
-                                <td valign="middle"><img src="{{ student.picture.file }}" width="50" height="50" alt=""></td>
+                                <td valign="middle"><img src="{{ student.avatar }}" width="50" height="50" alt=""></td>
                                 <td valign="middle"><h4>{{ student.complete_name }}</h4></td>
                                 <td valign="middle"><a href="{{ student.acceptUrl }}"><img src="{{ _p.web_plugin }}advanced_subscription/views/img/aprobar.png" width="90" height="25" alt=""></a></td>
                                 <td valign="middle"><a href="{{ student.rejectUrl }}"><img src="{{ _p.web_plugin }}advanced_subscription/views/img/desaprobar.png" width="90" height="25" alt=""></a></td>

+ 2 - 2
plugin/advanced_subscription/views/reminder_notice_superior_max.tpl

@@ -55,9 +55,9 @@
           <table width="100%" border="0" cellspacing="3" cellpadding="4" style="background:#EDE9EA">
             {% for student in students %}
             <tr>
-              <td valign="middle"><img src="{{ student.picture.file }}" width="50" height="50" alt=""></td>
+              <td valign="middle"><img src="{{ student.avatar }}" width="50" height="50" alt=""></td>
               <td valign="middle"><h4>{{ student.complete_name }}</h4></td>
-              <td valign="middle"><a href="{{ student.approveUrl }}"><img src="{{ _p.web_plugin }}advanced_subscription/views/img/aprobar.png" width="90" height="25" alt=""></a></td>
+              <td valign="middle"><a href="{{ student.acceptUrl }}"><img src="{{ _p.web_plugin }}advanced_subscription/views/img/aprobar.png" width="90" height="25" alt=""></a></td>
               <td valign="middle"><a href="{{ student.rejectUrl }}"><img src="{{ _p.web_plugin }}advanced_subscription/views/img/desaprobar.png" width="90" height="25" alt=""></a></td>
             </tr>
             {% endfor %}

+ 1 - 1
plugin/advanced_subscription/views/student_no_superior_notice_admin.tpl

@@ -49,7 +49,7 @@
                     <td height="356">&nbsp;</td>
                     <td valign="top"><p>{{ "MailDear" | get_plugin_lang("AdvancedSubscriptionPlugin") }}</p>
                         <h2>{{ admin.complete_name }}</h2>
-                        <p>{{ "MailContentStudentRequestNoSuperiorToAdmin"| get_plugin_lang("AdvancedSubscriptionPlugin") | format(complete_name_with_username, session.name, admin_view_url) }}</p>
+                        <p>{{ "MailContentStudentRequestNoSuperiorToAdmin"| get_plugin_lang("AdvancedSubscriptionPlugin") | format(student.complete_name_with_username, session.name, admin_view_url) }}</p>
                         <p>{{ "MailThankYou" | get_plugin_lang("AdvancedSubscriptionPlugin") }}</p>
                         <h3>{{ signature }}</h3></td>
                     <td>&nbsp;</td>

+ 1 - 1
tests/datafiller/fill_whoisonline.php

@@ -21,7 +21,7 @@ function fill_whoisonline()
 	//filling the table
 	for ($i=1;$i <=$max;$i++) {
 		$date = api_get_utc_datetime();
-		$sql = "INSERT INTO	$table_e_online (login_id, login_user_id, login_date, login_ip, c_id, session_id, access_url_id)
+		$sql = "INSERT INTO	$table_e_online (login_id, login_user_id, login_date, user_ip, c_id, session_id, access_url_id)
 				VALUES ('$i', '$i', '$date', '127.0.0.1', '', '0','1')";
 		$rs = Database::query($sql);
 	}

+ 1 - 1
tests/scripts/fix_exercise_score_in_lp.php

@@ -11,7 +11,7 @@ require_once '../../main/inc/global.inc.php';
 
 api_protect_admin_script();
 
-$tableExercise = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+$tableExercise = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
 $tableCourse = Database::get_main_table(TABLE_MAIN_COURSE);
 
 $sql = "SELECT

+ 1 - 1
tests/scripts/move_users.php

@@ -66,7 +66,7 @@ function moveUserFromCourseToCourse($originCourse, $destinationCourse, $debug =
     }
     $output .= 'Moving students who have no exe results from course '.$originCourse.' to course '.$destinationCourse.$eol;
     $tableCRU = Database::get_main_table(TABLE_MAIN_COURSE_USER);
-    $tableTEE = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+    $tableTEE = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
     // Get the users who have passed an exam in the course of origin
     $sql = "SELECT distinct(exe_user_id) FROM $tableTEE
         WHERE exe_cours_id = '$originCourse'";

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