Browse Source

Merge with 1.9.x

Julio Montoya 12 năm trước cách đây
mục cha
commit
26a1c88aa4
36 tập tin đã thay đổi với 2405 bổ sung1161 xóa
  1. 68 44
      main/admin/add_users_to_session.php
  2. 88 0
      main/admin/change_user_session.php
  3. 78 113
      main/admin/resume_session.php
  4. 3 1
      main/admin/session_course_user.php
  5. 61 73
      main/admin/session_course_user_list.php
  6. 1 1
      main/admin/user_move_stats.php
  7. 1 1
      main/course_info/legal.php
  8. 2 2
      main/css/base.css
  9. 482 261
      main/css/bootstrap-responsive.css
  10. 377 169
      main/css/bootstrap.css
  11. 34 4
      main/document/create_audio.php
  12. 16 0
      main/document/save_pixlr.php
  13. 51 22
      main/inc/lib/course.lib.php
  14. 8 12
      main/inc/lib/document.lib.php
  15. 368 166
      main/inc/lib/javascript/bootstrap/bootstrap.js
  16. 16 2
      main/inc/lib/jpegcam/webcam_receiver.php
  17. 6 0
      main/inc/lib/mail.lib.inc.php
  18. 12 7
      main/inc/lib/main_api.lib.php
  19. 15 33
      main/inc/lib/message.lib.php
  20. 5 0
      main/inc/lib/nanogong/receiver.php
  21. 47 20
      main/inc/lib/notification.lib.php
  22. 13 15
      main/inc/lib/online.inc.php
  23. 318 29
      main/inc/lib/sessionmanager.lib.php
  24. 13 0
      main/inc/lib/svg-edit/extensions/filesave.php
  25. 33 33
      main/inc/lib/usermanager.lib.php
  26. 6 2
      main/inc/lib/userportal.lib.php
  27. 13 0
      main/inc/lib/wami-recorder/record_document.php
  28. 12 11
      main/inc/local.inc.php
  29. 5 1
      main/install/db_main.sql
  30. 2 1
      main/install/db_stats.sql
  31. 2 1
      main/install/install_db.inc.php
  32. 47 0
      main/install/migrate-db-1.9.0-1.10.0-pre.sql
  33. 115 0
      main/install/update-db-1.9.0-1.10.0.inc.php
  34. 2 1
      main/messages/new_message.php
  35. 3 26
      main/user/subscribe_user.php
  36. 82 110
      main/user/user.php

+ 68 - 44
main/admin/add_users_to_session.php

@@ -30,8 +30,6 @@ $interbreadcrumb[] = array('url' => 'session_list.php','name' => get_lang('Sessi
 $interbreadcrumb[] = array('url' => "resume_session.php?id_session=".$id_session,"name" => get_lang('SessionOverview'));
 
 // Database Table Definitions
-$tbl_session						= Database::get_main_table(TABLE_MAIN_SESSION);
-$tbl_course							= Database::get_main_table(TABLE_MAIN_COURSE);
 $tbl_user							= Database::get_main_table(TABLE_MAIN_USER);
 $tbl_session_rel_user				= Database::get_main_table(TABLE_MAIN_SESSION_USER);
 
@@ -44,9 +42,9 @@ if(isset($_REQUEST['add_type']) && $_REQUEST['add_type']!=''){
 	$add_type = Security::remove_XSS($_REQUEST['add_type']);
 }
 
-//checking for extra field with filter on
+//Checking for extra field with filter on
 
-$extra_field_list= UserManager::get_extra_fields();
+$extra_field_list = UserManager::get_extra_fields();
 $new_field_list = array();
 if (is_array($extra_field_list)) {
 	foreach ($extra_field_list as $extra_field) {
@@ -101,7 +99,7 @@ function search_users($needle, $type) {
                 // search users where username or firstname or lastname begins likes $needle
                 $sql = 'SELECT user.user_id, username, lastname, firstname FROM '.$tbl_user.' user
                         WHERE (username LIKE "'.$needle.'%" OR firstname LIKE "'.$needle.'%"
-                            OR lastname LIKE "'.$needle.'%") AND user.status<>6 AND user.status<>'.DRH.''.
+                            OR lastname LIKE "'.$needle.'%") AND user.status <> 6 AND user.status<>'.DRH.' '.$cond_user_id.' '.
                             $order_clause.
                             ' LIMIT 11';
                 break;
@@ -165,7 +163,6 @@ function search_users($needle, $type) {
 	            	$return .= '...<br />';
 	            }
 			}
-
 			$xajax_response -> addAssign('ajax_list_users_single','innerHTML',api_utf8_encode($return));
 		} else {
 			global $nosessionUsersList;
@@ -181,11 +178,11 @@ function search_users($needle, $type) {
 	return $xajax_response;
 }
 
-$xajax -> processRequests();
+$xajax->processRequests();
 
 $htmlHeadXtra[] = $xajax->getJavascript('../inc/lib/xajax/');
 $htmlHeadXtra[] = '
-<script type="text/javascript">
+<script>
 function add_user_to_session (code, content) {
 	document.getElementById("user_to_add").value = "";
 	document.getElementById("ajax_list_users_single").innerHTML = "";
@@ -212,9 +209,9 @@ function remove_item(origin) {
 }
 
 function validate_filter() {
-		document.formulaire.add_type.value = \''.$add_type.'\';
-		document.formulaire.form_sent.value=0;
-		document.formulaire.submit();
+    document.formulaire.add_type.value = \''.$add_type.'\';
+    document.formulaire.form_sent.value=0;
+    document.formulaire.submit();
 }
 
 function checked_in_no_session(checked) {
@@ -235,17 +232,17 @@ function change_select(val) {
 $form_sent=0;
 $errorMsg=$firstLetterUser=$firstLetterSession='';
 $UserList=$SessionList=array();
-$sessions=array();
-$noPHP_SELF=true;
+$sessions = array();
+$noPHP_SELF = true;
 
-if($_POST['form_sent']) {
+if ($_POST['form_sent']) {
     $form_sent             = $_POST['form_sent'];
     $firstLetterUser       = $_POST['firstLetterUser'];
     $firstLetterSession    = $_POST['firstLetterSession'];
     $UserList              = $_POST['sessionUsersList'];
 
     if (!is_array($UserList)) {
-	$UserList=array();
+        $UserList=array();
     }
 
     if ($form_sent == 1) {
@@ -271,7 +268,11 @@ if ($ajax_search) {
             INNER JOIN $tbl_session_rel_user
                 ON $tbl_session_rel_user.id_user = u.user_id AND $tbl_session_rel_user.relation_type<>".SESSION_RELATION_TYPE_RRHH."
                 AND $tbl_session_rel_user.id_session = ".intval($id_session)."
-                WHERE u.status<>".DRH." AND u.status<>6 $order_clause";
+                WHERE u.status<>".DRH." AND 
+                    u.status<>6 AND
+                    $tbl_session_rel_user.moved_to = 0 AND
+                    $tbl_session_rel_user.moved_status <> ".SessionManager::SESSION_CHANGE_USER_REASON_ENROLLMENT_ANNULATION."                        
+                $order_clause";
 
     if ($_configuration['multiple_access_urls']) {
         $tbl_user_rel_access_url= Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
@@ -283,7 +284,11 @@ if ($ajax_search) {
                 ON $tbl_session_rel_user.id_user = u.user_id AND $tbl_session_rel_user.relation_type<>".SESSION_RELATION_TYPE_RRHH."
                 AND $tbl_session_rel_user.id_session = ".intval($id_session)."
                 INNER JOIN $tbl_user_rel_access_url url_user ON (url_user.user_id=u.user_id)
-                WHERE access_url_id = $access_url_id AND u.status<>".DRH." AND u.status<>6
+                WHERE   access_url_id = $access_url_id AND 
+                        u.status<>".DRH." AND 
+                        u.status<>6 AND 
+                        $tbl_session_rel_user.moved_to = 0 AND
+                        $tbl_session_rel_user.moved_status <> ".SessionManager::SESSION_CHANGE_USER_REASON_ENROLLMENT_ANNULATION."
                 $order_clause";
         }
     }
@@ -298,7 +303,7 @@ if ($ajax_search) {
     $use_extra_fields = false;
     if (is_array($extra_field_list)) {
         if (is_array($new_field_list) && count($new_field_list)>0 ) {
-            $result_list=array();
+            $result_list = array();
             foreach ($new_field_list as $new_field) {
                 $varname = 'field_'.$new_field['variable'];
                 if (UserManager::is_extra_field_available($new_field['variable'])) {
@@ -345,18 +350,26 @@ if ($ajax_search) {
         $sql = "SELECT  user_id, lastname, firstname, username, id_session
                FROM $tbl_user u
                     LEFT JOIN $tbl_session_rel_user
-                    ON $tbl_session_rel_user.id_user = u.user_id AND $tbl_session_rel_user.id_session = '$id_session' AND $tbl_session_rel_user.relation_type<>".SESSION_RELATION_TYPE_RRHH."
-                    $where_filter AND u.status<>".DRH." AND u.status<>6
+                    ON  $tbl_session_rel_user.id_user = u.user_id AND 
+                        $tbl_session_rel_user.id_session = '$id_session' AND 
+                        $tbl_session_rel_user.relation_type<>".SESSION_RELATION_TYPE_RRHH."
+                    $where_filter AND 
+                    u.status<>".DRH." AND 
+                    u.status<>6                    
                     $order_clause";
 
     } else {
         $sql = "SELECT  user_id, lastname, firstname, username, id_session
                 FROM $tbl_user u
                 LEFT JOIN $tbl_session_rel_user
-                ON $tbl_session_rel_user.id_user = u.user_id AND $tbl_session_rel_user.id_session = '$id_session' AND $tbl_session_rel_user.relation_type<>".SESSION_RELATION_TYPE_RRHH."
-                WHERE u.status<>".DRH." AND u.status<>6
+                ON  $tbl_session_rel_user.id_user = u.user_id AND 
+                    $tbl_session_rel_user.id_session = '$id_session' AND 
+                    $tbl_session_rel_user.relation_type<>".SESSION_RELATION_TYPE_RRHH."
+                WHERE   u.status<>".DRH." AND 
+                        u.status<>6                         
                 $order_clause";
     }
+    
     if ($_configuration['multiple_access_urls']) {
         $tbl_user_rel_access_url= Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
         $access_url_id = api_get_current_access_url_id();
@@ -364,30 +377,40 @@ if ($ajax_search) {
             $sql = "SELECT  u.user_id, lastname, firstname, username, id_session
                     FROM $tbl_user u
                     LEFT JOIN $tbl_session_rel_user
-                        ON $tbl_session_rel_user.id_user = u.user_id AND $tbl_session_rel_user.id_session = '$id_session' AND $tbl_session_rel_user.relation_type<>".SESSION_RELATION_TYPE_RRHH."
-                    INNER JOIN $tbl_user_rel_access_url url_user ON (url_user.user_id=u.user_id)
-                    WHERE access_url_id = $access_url_id  $where_filter AND u.status<>".DRH." AND u.status<>6 
+                        ON  $tbl_session_rel_user.id_user = u.user_id AND 
+                            $tbl_session_rel_user.id_session = '$id_session' AND 
+                            $tbl_session_rel_user.relation_type<>".SESSION_RELATION_TYPE_RRHH."
+                        INNER JOIN $tbl_user_rel_access_url url_user ON (url_user.user_id=u.user_id)
+                    WHERE   access_url_id = $access_url_id  $where_filter AND 
+                            u.status<>".DRH." AND 
+                            u.status<>6                            
                     $order_clause";
         }
     }
 
     $result   = Database::query($sql);
     $users    = Database::store_result($result,'ASSOC');
-
+    
     foreach ($users as $uid => $user) {
         if ($user['id_session'] != $id_session) {
             $nosessionUsersList[$user['user_id']] = array('fn'=>$user['firstname'],'ln'=>$user['lastname'],'un'=>$user['username']) ;
             unset($users[$uid]);
-	}
+        }
     }
     unset($users); //clean to free memory
 
-    //filling the correct users in list
-    $sql="SELECT  user_id, lastname, firstname, username, id_session
+    //Filling the correct users in list
+    $sql = "SELECT  user_id, lastname, firstname, username, id_session
           FROM $tbl_user u
           LEFT JOIN $tbl_session_rel_user
-          ON $tbl_session_rel_user.id_user = u.user_id AND $tbl_session_rel_user.id_session = '$id_session' AND $tbl_session_rel_user.relation_type<>".SESSION_RELATION_TYPE_RRHH."
-          WHERE u.status<>".DRH." AND u.status<>6 $order_clause";
+          ON    $tbl_session_rel_user.id_user = u.user_id AND 
+                $tbl_session_rel_user.id_session = '$id_session' AND 
+                $tbl_session_rel_user.relation_type<>".SESSION_RELATION_TYPE_RRHH."
+          WHERE u.status <> ".DRH." AND 
+                u.status <> 6 AND 
+                $tbl_session_rel_user.moved_to = 0 AND
+                $tbl_session_rel_user.moved_status <> ".SessionManager::SESSION_CHANGE_USER_REASON_ENROLLMENT_ANNULATION." 
+          $order_clause";
 
     if ($_configuration['multiple_access_urls']) {
         $tbl_user_rel_access_url= Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
@@ -398,12 +421,18 @@ if ($ajax_search) {
                 LEFT JOIN $tbl_session_rel_user
                     ON $tbl_session_rel_user.id_user = u.user_id AND $tbl_session_rel_user.id_session = '$id_session' AND $tbl_session_rel_user.relation_type<>".SESSION_RELATION_TYPE_RRHH."
                 INNER JOIN $tbl_user_rel_access_url url_user ON (url_user.user_id=u.user_id)
-                WHERE access_url_id = $access_url_id AND u.status<>".DRH." AND u.status<>6
+                WHERE   access_url_id = $access_url_id AND 
+                        u.status<>".DRH." AND 
+                        u.status<>6 AND 
+                        $tbl_session_rel_user.moved_to = 0 AND
+                        $tbl_session_rel_user.moved_status <> ".SessionManager::SESSION_CHANGE_USER_REASON_ENROLLMENT_ANNULATION." 
+                                                
                 $order_clause";
         }
     }
-    $result=Database::query($sql);
-    $users=Database::store_result($result,'ASSOC');
+    
+    $result = Database::query($sql);
+    $users = Database::store_result($result,'ASSOC');
     foreach ($users as $uid => $user) {
         if ($user['id_session'] == $id_session) {
             $sessionUsersList[$user['user_id']] = $user;
@@ -416,6 +445,7 @@ if ($ajax_search) {
     unset($users); //clean to free memory
 }
 
+
 if ($add_type == 'multiple') {
 	$link_add_type_unique = '<a href="'.api_get_self().'?id_session='.$id_session.'&add='.Security::remove_XSS($_GET['add']).'&add_type=unique">'.Display::return_icon('single.gif').get_lang('SessionAddTypeUnique').'</a>';
 	$link_add_type_multiple = Display::return_icon('multiple.gif').get_lang('SessionAddTypeMultiple');
@@ -428,6 +458,7 @@ if ($add_type == 'multiple') {
 <div class="actions">
 	<?php echo $link_add_type_unique ?>&nbsp;|&nbsp;<?php echo $link_add_type_multiple ?>&nbsp;|&nbsp;<?php echo $link_add_group; ?>
 </div>
+
 <form name="formulaire" method="post" action="<?php echo api_get_self(); ?>?page=<?php echo Security::remove_XSS($_GET['page']); ?>&id_session=<?php echo $id_session; ?><?php if(!empty($_GET['add'])) echo '&add=true' ; ?>" style="margin:0px;" <?php if($ajax_search){echo ' onsubmit="valide();"';}?>>
 <?php echo '<legend>'.$tool_name.' ('.$session_info['name'].') </legend>'; ?>
 <?php
@@ -562,7 +593,6 @@ unset($sessionUsersList);
         } else {
             //@todo see that the call to "valide()" doesn't duplicate the onsubmit of the form (necessary to avoid delete on "enter" key pressed)
 			echo '<button class="save" type="button" value="" onclick="valide()" >'.get_lang('SubscribeUsersToSession').'</button>';
-
         }
 		?>
 	</td>
@@ -570,11 +600,10 @@ unset($sessionUsersList);
 </table>
 </form>
 
-<script type="text/javascript">
+<script>
 <!--
 function moveItem(origin , destination){
-
-	for(var i = 0 ; i<origin.options.length ; i++) {
+	for (var i = 0 ; i<origin.options.length ; i++) {
 		if(origin.options[i].selected) {
 			destination.options[destination.length] = new Option(origin.options[i].text,origin.options[i].value);
 			origin.options[i]=null;
@@ -587,7 +616,6 @@ function moveItem(origin , destination){
 }
 
 function sortOptions(options) {
-
 	newOptions = new Array();
 	for (i = 0 ; i<options.length ; i++)
 		newOptions[i] = options[i];
@@ -618,9 +646,7 @@ function valide(){
 
 
 function loadUsersInSelect(select){
-
 	var xhr_object = null;
-
 	if(window.XMLHttpRequest) // Firefox
 		xhr_object = new XMLHttpRequest();
 	else if(window.ActiveXObject) // Internet Explorer
@@ -633,7 +659,6 @@ function loadUsersInSelect(select){
 
 	xhr_object.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
 
-
 	nosessionUsers = makepost(document.getElementById('origin_users'));
 	sessionUsers = makepost(document.getElementById('destination_users'));
 	nosessionClasses = makepost(document.getElementById('origin_classes'));
@@ -648,8 +673,7 @@ function loadUsersInSelect(select){
 	}
 }
 
-function makepost(select){
-
+function makepost(select) {
 	var options = select.options;
 	var ret = "";
 	for (i = 0 ; i<options.length ; i++)

+ 88 - 0
main/admin/change_user_session.php

@@ -0,0 +1,88 @@
+<?php
+
+/* For licensing terms, see /license.txt */
+$language_file = 'admin';
+$cidReset = true;
+require_once '../inc/global.inc.php';
+
+$user_id = intval($_REQUEST['user_id']);
+$session_id = intval($_REQUEST['id_session']);
+
+if (empty($user_id) && empty($session_id)) {
+    api_not_allowed(true);
+}
+
+SessionManager::protect_session_edit($session_id);
+
+if (api_is_platform_admin()) {
+    $sessions = SessionManager::get_sessions_admin();
+} else {
+    $sessions = SessionManager::get_sessions_by_coach(api_get_session_id());
+}
+
+$message = null;
+$session_to_select = array();
+foreach ($sessions as $session) {
+    if ($session_id != $session['id']) {
+        $session_to_select[$session['id']] = $session['name'];
+    }
+}
+
+$session_name = api_get_session_name($session_id);
+$user_info = api_get_user_info($user_id);
+
+//Check if user was already moved
+$user_status = SessionManager::get_user_status_in_session($session_id, $user_id);
+if (isset($user_status['moved_to']) && $user_status['moved_to'] != 0 || $user_status['moved_status'] == SessionManager::SESSION_CHANGE_USER_REASON_ENROLLMENT_ANNULATION) {
+    api_not_allowed(true);
+}
+
+$form = new FormValidator('change_user_session', 'post', api_get_self());
+$form->addElement('hidden', 'user_id', $user_id);
+$form->addElement('hidden', 'id_session', $session_id);
+$form->addElement('header', get_lang('ChangeUserSession'));
+$form->addElement('label', get_lang('User'), '<b>'.$user_info['complete_name'].'</b>');
+$form->addElement('label', get_lang('CurrentSession'), $session_name);
+
+$form->addElement('select', 'reason_id', get_lang('Action'), SessionManager::get_session_change_user_reasons(), array('id' => 'reason_id'));
+$form->addElement('select', 'new_session_id', get_lang('SessionDestination'), $session_to_select, array('id' => 'new_session_id'));
+
+$form->addElement('button', 'submit', get_lang('Change'));
+
+$content = $form->return_form();
+
+if ($form->validate()) {
+    $values = $form->getSubmitValues();
+    $result = SessionManager::change_user_session($values['user_id'], $values['id_session'], $values['new_session_id'], $values['reason_id']);
+    if ($result) {
+        $message = Display::return_message(get_lang('UserSessionWasChanged'));
+    }
+    header('Location: resume_session.php?id_session='.$values['id_session']);
+    exit;
+}
+
+$interbreadcrumb[] = array('url' => 'index.php', 'name' => get_lang('PlatformAdmin'));
+$interbreadcrumb[] = array('url' => 'session_list.php','name' => get_lang('SessionList'));
+$interbreadcrumb[] = array('url' => 'resume_session.php?id_session='.$session_id,'name' => get_lang('SessionOverview'));
+$interbreadcrumb[] = array('url' => '#','name' => get_lang('ChangeUserSession'));
+
+$htmlHeadXtra[] = '<script>
+
+$(document).ready(function() {
+    $("#reason_id").change(function() {
+        value = $(this).val();
+        if (value == "'.SessionManager::SESSION_CHANGE_USER_REASON_ENROLLMENT_ANNULATION.'") {
+            $("#new_session_id").parent().parent().hide();
+        } else {
+            $("#new_session_id").parent().parent().show();
+        }
+    });
+});
+
+</script>';
+
+$tpl = new Template();
+
+$tpl->assign('message', $message);
+$tpl->assign('content', $content);
+$tpl->display_one_col_template();

+ 78 - 113
main/admin/resume_session.php

@@ -23,42 +23,18 @@ $tool_name = get_lang('SessionOverview');
 $interbreadcrumb[] = array('url' => 'index.php','name' => get_lang('PlatformAdmin'));
 $interbreadcrumb[] = array('url' => 'session_list.php','name' => get_lang('SessionList'));
 
-// Database Table Definitions
-$tbl_session						= Database::get_main_table(TABLE_MAIN_SESSION);
-$tbl_session_rel_class				= Database::get_main_table(TABLE_MAIN_SESSION_CLASS);
-$tbl_session_rel_course				= Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
-$tbl_course							= Database::get_main_table(TABLE_MAIN_COURSE);
-$tbl_user							= Database::get_main_table(TABLE_MAIN_USER);
-$tbl_session_rel_user				= Database::get_main_table(TABLE_MAIN_SESSION_USER);
-$tbl_session_rel_course_rel_user	= Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
-$tbl_session_category				= Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY);
-
-$table_access_url_user              = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
-
-$sql = 'SELECT name, nbr_courses, nbr_users, nbr_classes, DATE_FORMAT(date_start,"%d-%m-%Y") as date_start, DATE_FORMAT(date_end,"%d-%m-%Y") as date_end, lastname, firstname, username, session_admin_id, nb_days_access_before_beginning, nb_days_access_after_end, session_category_id, visibility
-		FROM '.$tbl_session.' LEFT JOIN '.$tbl_user.' ON id_coach = user_id
-		WHERE '.$tbl_session.'.id='.$id_session;
-
-$rs      = Database::query($sql);
-$session = Database::store_result($rs);
-$session = $session[0];
-
-$sql = 'SELECT name FROM  '.$tbl_session_category.' WHERE id = "'.intval($session['session_category_id']).'"';
-$rs = Database::query($sql);
-$session_category = '';
-
-if (Database::num_rows($rs)>0) {
-	$rows_session_category = Database::store_result($rs);
-	$rows_session_category = $rows_session_category[0];
-	$session_category = $rows_session_category['name'];
+$session = SessionManager::get_session_info($id_session);
+$session_cat_info = SessionManager::get_session_category($session['session_category_id']);
+$session_category = null;
+if (!empty($session_cat_info)) {
+    $session_category = $session_cat_info['name'];
 }
 
 $action = $_GET['action'];
 
 $url_id = api_get_current_access_url_id();     
 
-
-switch($action) {
+switch ($action) {
     case 'add_user_to_url':        
         $user_id = $_REQUEST['user_id'];
         $result = UrlManager::add_user_to_url($user_id, $url_id);
@@ -68,39 +44,11 @@ switch($action) {
         }
         break;
     case 'delete':
-        $idChecked = $_GET['idChecked'];
-        if(is_array($idChecked)) {
-            $my_temp = array();
-            foreach ($idChecked as $id){
-                $my_temp[]= Database::escape_string($id);// forcing the escape_string
-            }
-            $idChecked = $my_temp;
-
-            $idChecked="'".implode("','",$idChecked)."'";
-
-            Database::query("DELETE FROM $tbl_session_rel_course WHERE id_session='$id_session' AND course_code IN($idChecked)");
-            $nbr_affected_rows=Database::affected_rows();
-
-            Database::query("DELETE FROM $tbl_session_rel_course_rel_user WHERE id_session='$id_session' AND course_code IN($idChecked)");
-            Database::query("UPDATE $tbl_session SET nbr_courses=nbr_courses-$nbr_affected_rows WHERE id='$id_session'");
+        if (isset($_GET['course_code_to_delete'])) {
+            SessionManager::delete_course_in_session($id_session, $_GET['course_code_to_delete']);
         }
-
-        if(!empty($_GET['class'])){
-            Database::query("DELETE FROM $tbl_session_rel_class WHERE session_id='$id_session' AND class_id=".Database::escape_string($_GET['class']));
-            $nbr_affected_rows=Database::affected_rows();
-            Database::query("UPDATE $tbl_session SET nbr_classes=nbr_classes-$nbr_affected_rows WHERE id='$id_session'");
-        }
-
         if (!empty($_GET['user'])) {
-            Database::query("DELETE FROM $tbl_session_rel_user WHERE relation_type<>".SESSION_RELATION_TYPE_RRHH." AND id_session='$id_session' AND id_user=".intval($_GET['user']));
-            $nbr_affected_rows=Database::affected_rows();
-
-            Database::query("UPDATE $tbl_session SET nbr_users=nbr_users-$nbr_affected_rows WHERE id='$id_session'");
-
-            Database::query("DELETE FROM $tbl_session_rel_course_rel_user WHERE id_session='$id_session' AND id_user=".intval($_GET['user']));
-            $nbr_affected_rows=Database::affected_rows();
-
-            Database::query("UPDATE $tbl_session_rel_course SET nbr_users=nbr_users-$nbr_affected_rows WHERE id_session='$id_session'");
+            SessionManager::unsubscribe_user_from_session($id_session, $_GET['user']);            
         }
         break;
 }
@@ -177,13 +125,25 @@ echo Display::page_subheader(get_lang('GeneralProperties').$url);
 		<?php echo api_ucfirst(get_lang('SessionVisibility')) ?> :
 	</td>
 	<td>
-		<?php if ($session['visibility']==1) echo get_lang('ReadOnly'); elseif($session['visibility']==2) echo get_lang('Visible');elseif($session['visibility']==3) echo api_ucfirst(get_lang('Invisible'))  ?>
+		<?php        
+        if (isset($session['date_end']) && $session['date_end'] != '00-00-0000') {
+            if ($session['visibility'] == 1) 
+                echo get_lang('ReadOnly'); 
+             elseif($session['visibility'] == 2) 
+                 echo get_lang('Visible');
+             elseif($session['visibility'] == 3) 
+                echo api_ucfirst(get_lang('Invisible'))  ;
+        } else {
+            //By default course sessions can be access normally see function api_get_session_visibility() when no date_end is proposed            
+            echo get_lang('Visible'); 
+        }
+        ?>
 	</td>
 </tr>
 
 <?php 
 
-$multiple_url_is_on = api_get_multiple_access_url();
+$multiple_url_is_on = api_is_multiple_url_enabled();
 
 if ($multiple_url_is_on) {
     echo '<tr><td>';   
@@ -220,60 +180,26 @@ if ($session['nbr_courses'] == 0){
 	echo '<tr>
 			<td colspan="4">'.get_lang('NoCoursesForThisSession').'</td>
 		</tr>';
-} else {
-	// select the courses
-	$sql = "SELECT code,title,visual_code, nbr_users
-			FROM $tbl_course,$tbl_session_rel_course
-			WHERE course_code = code
-			AND	id_session='$id_session'
-			ORDER BY title";
-	$result=Database::query($sql);
-	$courses=Database::store_result($result);
+} else {    
+    $courses = SessionManager::get_course_list_by_session_id($id_session);	
 	foreach ($courses as $course) {
-		//select the number of users
-
-		$sql = " SELECT count(*) FROM $tbl_session_rel_user sru, $tbl_session_rel_course_rel_user srcru
-				WHERE srcru.id_user = sru.id_user AND srcru.id_session = sru.id_session AND srcru.course_code = '".Database::escape_string($course['code'])."'
-				AND sru.relation_type<>".SESSION_RELATION_TYPE_RRHH." AND srcru.id_session = '".intval($id_session)."'";
-
-		$rs = Database::query($sql);
-		$course['nbr_users'] = Database::result($rs,0,0);
-
-		// Get coachs of the courses in session
-
-		$sql = "SELECT user.lastname,user.firstname,user.username FROM $tbl_session_rel_course_rel_user session_rcru, $tbl_user user
-				WHERE session_rcru.id_user = user.user_id AND session_rcru.id_session = '".intval($id_session)."' AND session_rcru.course_code ='".Database::escape_string($course['code'])."' AND session_rcru.status=2";
-		$rs = Database::query($sql);
-
-		$coachs = array();
-		if (Database::num_rows($rs) > 0) {
-			while($info_coach = Database::fetch_array($rs)) {
-				$coachs[] = api_get_person_name($info_coach['firstname'], $info_coach['lastname']).' ('.$info_coach['username'].')';
-			}
-		} else {
-			$coach = get_lang('None');
-		}
-
-		if (count($coachs) > 0) {
-			$coach = implode('<br />',$coachs);
-		} else {
-			$coach = get_lang('None');
-		}
+        $count_users = SessionManager::get_count_users_in_course_session($course['code'], $id_session);
+        $coaches = SessionManager::get_session_course_coaches_to_string($course['code'], $id_session);
 
 		$orig_param = '&origin=resume_session';
 		//hide_course_breadcrumb the parameter has been added to hide the name of the course, that appeared in the default $interbreadcrumb
 		echo '
 		<tr>
 			<td>'.Display::url($course['title'].' ('.$course['visual_code'].')', api_get_path(WEB_COURSE_PATH).$course['code'].'/?id_session='.$id_session),'</td>
-			<td>'.$coach.'</td>
-			<td>'.$course['nbr_users'].'</td>
+			<td>'.$coaches.'</td>
+			<td>'.$count_users.'</td>
 			<td>
                 <a href="'.api_get_path(WEB_COURSE_PATH).$course['code'].'/?id_session='.$id_session.'">'.Display::return_icon('course_home.gif', get_lang('Course')).'</a>   
                 <a href="session_course_user_list.php?id_session='.$id_session.'&course_code='.$course['code'].'">'.Display::return_icon('user.png', get_lang('Edit'), '', ICON_SIZE_SMALL).'</a>
                 <a href="'.api_get_path(WEB_CODE_PATH).'/user/user_import.php?action=import&cidReq='.$course['code'].'&id_session='.$id_session.'">'.Display::return_icon('import_csv.png', get_lang('ImportUsersToACourse'), null, ICON_SIZE_SMALL).'</a>   
 				<a href="../tracking/courseLog.php?id_session='.$id_session.'&cidReq='.$course['code'].$orig_param.'&hide_course_breadcrumb=1">'.Display::return_icon('statistics.gif', get_lang('Tracking')).'</a>&nbsp;                
 				<a href="session_course_edit.php?id_session='.$id_session.'&page=resume_session.php&course_code='.$course['code'].''.$orig_param.'">'.Display::return_icon('edit.png', get_lang('Edit'), '', ICON_SIZE_SMALL).'</a>
-				<a href="'.api_get_self().'?id_session='.$id_session.'&action=delete&idChecked[]='.$course['code'].'" onclick="javascript:if(!confirm(\''.get_lang('ConfirmYourChoice').'\')) return false;">'.Display::return_icon('delete.png', get_lang('Delete')).'</a>
+				<a href="'.api_get_self().'?id_session='.$id_session.'&action=delete&course_code_to_delete='.$course['code'].'" onclick="javascript:if(!confirm(\''.get_lang('ConfirmYourChoice').'\')) return false;">'.Display::return_icon('delete.png', get_lang('Delete')).'</a>
 			</td>
 		</tr>';
 	}
@@ -297,19 +223,28 @@ echo Display::page_subheader(get_lang('UserList').$url);
         <th>
             <?php echo get_lang('User'); ?>
         </th>
+        <th>
+            <?php echo get_lang('Information'); ?>
+        </th>
+        <th>
+            <?php echo get_lang('MovedAt'); ?>
+        </th>
+        <th>
+            <?php echo get_lang('Destination'); ?>
+        </th>
         <th>
             <?php echo get_lang('Actions'); ?>
         </th>
     </tr>
 <?php
 
-if ($session['nbr_users']==0) {
+if ($session['nbr_users'] == 0) {
 	echo '<tr>
 			<td colspan="2">'.get_lang('NoUsersForThisSession').'</td>
 		</tr>';
 } else {    
-	$order_clause = api_sort_by_first_name() ? ' ORDER BY firstname, lastname' : ' ORDER BY lastname, firstname';
-    
+	/*$order_clause = api_sort_by_first_name() ? ' ORDER BY firstname, lastname' : ' ORDER BY lastname, firstname';
+     *     
     if ($multiple_url_is_on) {           
         $sql = "SELECT u.user_id, lastname, firstname, username, access_url_id
                 FROM $tbl_user u
@@ -327,13 +262,40 @@ if ($session['nbr_users']==0) {
     }
 
 	$result = Database::query($sql);
-	$users  = Database::store_result($result);
+	$users  = Database::store_result($result);*/
 	$orig_param = '&origin=resume_session&id_session='.$id_session; // change breadcrumb in destination page
-	foreach ($users as $user){
+    
+    $users = SessionManager::get_users_by_session($id_session, 0);    
+    $reasons = SessionManager::get_session_change_user_reasons();
+    
+    if (!empty($users))
+	foreach ($users as $user) {        
         $user_link = '';
         if (!empty($user['user_id'])) {
             $user_link = '<a href="'.api_get_path(WEB_CODE_PATH).'admin/user_information.php?user_id='.intval($user['user_id']).'">'.api_htmlentities(api_get_person_name($user['firstname'], $user['lastname']),ENT_QUOTES,$charset).' ('.$user['username'].')</a>';
         }
+        $information = null;
+        $origin_destination = null;
+        
+        $row_class = null;
+        $moved_date = '-';
+        
+        $moved_link =  '<a href="change_user_session.php?user_id='.$user['user_id'].'&id_session='.$id_session.'">'.Display::return_icon('move.png', get_lang('ChangeUserSession')).'</a>&nbsp;';
+        
+        if (isset($user['moved_to']) && !empty($user['moved_to']) || $user['moved_status'] == SessionManager::SESSION_CHANGE_USER_REASON_ENROLLMENT_ANNULATION) {
+            $information = $reasons[$user['moved_status']];
+            
+            $moved_date = isset($user['moved_at']) && $user['moved_at'] != '0000-00-00 00:00:00' ? api_get_local_time($user['moved_at']) : '-';                        
+            $session_info = SessionManager::fetch($user['moved_to']);
+            
+            if ($session_info) {
+                $url = api_get_path(WEB_CODE_PATH).'admin/resume_session.php?id_session='.$session_info['id'];
+                $origin_destination = Display::url($session_info['name'], $url);
+            }
+            $row_class = 'row_odd';
+            
+            $moved_link =  Display::return_icon('move_na.png', get_lang('ChangeUserSession')).'&nbsp;';
+        }
         
         $link_to_add_user_in_url = '';
         
@@ -344,13 +306,17 @@ if ($session['nbr_users']==0) {
                 $link_to_add_user_in_url = '<a href="resume_session.php?action=add_user_to_url&id_session='.$id_session.'&user_id='.$user['user_id'].'">'.$add.'</a>';
             }                
         }
-		echo '<tr>
-                <td width="90%">
+		echo '<tr class="'.$row_class.'">
+                <td width="50%">
                     '.$user_link.'
                 </td>
-                <td>               
+                <td>'.$information.'</td>
+                <td>'.$moved_date.'</td>                    
+                <td>'.$origin_destination.'</td>
+                <td>
                     <a href="../mySpace/myStudents.php?student='.$user['user_id'].''.$orig_param.'">'.Display::return_icon('statistics.gif', get_lang('Reporting')).'</a>&nbsp;
                     <a href="session_course_user.php?id_user='.$user['user_id'].'&id_session='.$id_session.'">'.Display::return_icon('course.gif', get_lang('BlockCoursesForThisUser')).'</a>&nbsp;
+                    '.$moved_link.'
                     <a href="'.api_get_self().'?id_session='.$id_session.'&action=delete&user='.$user['user_id'].'" onclick="javascript:if(!confirm(\''.get_lang('ConfirmYourChoice').'\')) return false;">'.Display::return_icon('delete.png', get_lang('Delete')).'</a>
                     '.$link_to_add_user_in_url.'
                 </td>
@@ -360,5 +326,4 @@ if ($session['nbr_users']==0) {
 ?>
 </table>
 <?php
-// footer
 Display :: display_footer();

+ 3 - 1
main/admin/session_course_user.php

@@ -93,7 +93,8 @@ if ($_POST['formSent']) {
 			}
 		}
 	}
-	foreach($existingCourses as $existingCourse) {
+    
+	foreach ($existingCourses as $existingCourse) {
 		//$sql_insert_rel_course= "INSERT INTO $tbl_session_rel_course(id_session,course_code, id_coach) VALUES('$id_session','$enreg_course','$id_coach')";
 		if(!in_array($existingCourse['code'], $CourseList)){
 			$existingCourse = Database::escape_string($existingCourse['code']);
@@ -121,6 +122,7 @@ if (!empty($_GET['msg'])) {
 // the form header
 $session_info = SessionManager::fetch($id_session);
 $user_info = api_get_user_info($id_user);
+
 echo '<legend>'.$tool_name.': '.$session_info['name'].' - '.$user_info['complete_name'].'</legend>';
 
 $nosessionCourses = $sessionCourses = array();

+ 61 - 73
main/admin/session_course_user_list.php

@@ -11,24 +11,24 @@ $cidReset = true;
 
 require_once '../inc/global.inc.php';
 
-$tbl_user                           = Database::get_main_table(TABLE_MAIN_USER);
-$tbl_course                         = Database::get_main_table(TABLE_MAIN_COURSE);
-$tbl_session                        = Database::get_main_table(TABLE_MAIN_SESSION);
-$tbl_session_rel_course             = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
-$tbl_session_rel_user               = Database::get_main_table(TABLE_MAIN_SESSION_USER);
-$tbl_session_rel_course_rel_user    = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
-
 $id_session = intval($_GET['id_session']);
+
 SessionManager::protect_session_edit($id_session);
 
-if (empty($id_session )) {
-    api_not_allowed();
+if (empty($id_session)) {
+    api_not_allowed(true);
+}
+
+$course_info = api_get_course_info($_GET['course_code']);
+
+if (empty($course_info)) {
+    api_not_allowed(true);
 }
 
-$course_code    = Database::escape_string(trim($_GET['course_code']));
+$course_code    = $course_info['code'];
 $page           = intval($_GET['page']);
 $action         = $_REQUEST['action'];
-$default_sort = api_sort_by_first_name() ? 'firstname':'lastname';
+$default_sort   = api_sort_by_first_name() ? 'firstname':'lastname';
 $sort           = in_array($_GET['sort'], array('lastname','firstname','username')) ? $_GET['sort'] : $default_sort;
 $idChecked      = (is_array($_GET['idChecked']) ? $_GET['idChecked'] : (is_array($_POST['idChecked']) ? $_POST['idChecked'] : null));
 
@@ -42,32 +42,19 @@ if (is_array($idChecked)) {
 	$idChecked = $my_temp;
 }
 
-$sql = "SELECT s.name, c.title  FROM $tbl_session_rel_course src
-		INNER JOIN $tbl_session s ON s.id = src.id_session
-		INNER JOIN $tbl_course c ON c.code = src.course_code
-		WHERE src.id_session='$id_session' AND src.course_code='".Database::escape_string($course_code)."' ";
-
-$result = Database::query($sql);
+$session_info = SessionManager::fetch($id_session);
+$courses = SessionManager::get_course_list_by_session_id($id_session);
 
-if (!list($session_name,$course_title)=Database::fetch_row($result)) {
+if (!isset($courses[$course_info['real_id']])) {
 	header('Location: session_course_list.php?id_session='.$id_session);
 	exit();
 }
 
-
-switch($action) {
+switch ($action) {
     case 'delete':
-        if (is_array($idChecked) && count($idChecked)>0 ) {
-            array_map('intval', $idChecked);
-            $idChecked = implode(',',$idChecked);
-        }
-        if (!empty($idChecked)) {
-            Database::query("DELETE FROM $tbl_session_rel_course_rel_user WHERE id_session='$id_session' AND course_code='".$course_code."' AND id_user IN($idChecked)");
-            $nbr_affected_rows = Database::affected_rows();
-            Database::query("UPDATE $tbl_session_rel_course SET nbr_users=nbr_users-$nbr_affected_rows WHERE id_session='$id_session' AND course_code='".$course_code."'");
-        }
+        SessionManager::unsubscribe_user_from_course_session($id_session, $idChecked, $course_code);        
         header('Location: '.api_get_self().'?id_session='.$id_session.'&course_code='.urlencode($course_code).'&sort='.$sort);
-        exit();
+        exit;
         break;
     case 'add':
         SessionManager::subscribe_users_to_session_course($idChecked, $id_session, $course_code);
@@ -81,29 +68,30 @@ $limit  = 20;
 $from   = $page * $limit;
 $is_western_name_order = api_is_western_name_order();
 
-//scru.status<>2  scru.course_code='".$course_code."'
+$Users = SessionManager::get_users_in_course_session($course_code, $id_session, $sort, $direction, $from, $limit);
+        
+/*
+
 $sql = "SELECT DISTINCT u.user_id,".($is_western_name_order ? 'u.firstname, u.lastname' : 'u.lastname, u.firstname').", u.username, scru.id_user as is_subscribed
-             FROM $tbl_session_rel_user s INNER JOIN $tbl_user u ON (u.user_id=s.id_user) LEFT JOIN $tbl_session_rel_course_rel_user scru ON (u.user_id=scru.id_user AND  scru.course_code = '".$course_code."' )
-             WHERE s.id_session='$id_session'
+             FROM $tbl_session_rel_user s INNER JOIN $tbl_user u ON (u.user_id=s.id_user) 
+                    LEFT JOIN $tbl_session_rel_course_rel_user scru ON (u.user_id=scru.id_user AND  scru.course_code = '".$course_code."' )
+             WHERE s.id_session='$id_session' 
              ORDER BY $sort $direction LIMIT $from,".($limit+1);
-
+*/
 if ($direction == 'desc') {
     $direction = 'asc';
 } else {
     $direction = 'desc';
 }
 
-$result = Database::query($sql);
-$Users  = Database::store_result($result);
-
 $nbr_results = sizeof($Users);
 
-$tool_name = get_lang('Session').': '.$session_name.' - '.get_lang('Course').': '.$course_title;
+$tool_name = get_lang('Session').': '.$session_info['name'].' - '.get_lang('Course').': '.$course_info['title'];
 
 $interbreadcrumb[] = array("url" => "index.php","name" => get_lang('PlatformAdmin'));
 $interbreadcrumb[] = array("url" => "session_list.php","name" => get_lang('SessionList'));
 $interbreadcrumb[] = array('url' => "resume_session.php?id_session=".$id_session,"name" => get_lang('SessionOverview'));
-//$interbreadcrumb[]=array("url" => "session_course_list.php?id_session=$id_session","name" => get_lang('ListOfCoursesOfSession')." &quot;".api_htmlentities($session_name,ENT_QUOTES,$charset)."&quot;");
+
 
 Display::display_header($tool_name);
 
@@ -122,7 +110,7 @@ if($page) {
 ?>
 |
 <?php
-if($nbr_results > $limit) {
+if ($nbr_results > $limit) {
 ?>
 <a href="<?php echo api_get_self(); ?>?id_session=<?php echo $id_session; ?>&course_code=<?php echo urlencode($course_code); ?>&page=<?php echo $page+1; ?>&sort=<?php echo $sort; ?>"><?php echo get_lang('Next');?></a>
 <?php
@@ -149,38 +137,38 @@ if($nbr_results > $limit) {
 
 <?php
 $i=0;
-
-foreach ($Users as $key=>$enreg) {
-	if ($key == $limit) {
-		break;
-	}
-    ?>
-
-    <tr class="<?php echo $i?'row_odd':'row_even'; ?>">
-        <td><input type="checkbox" name="idChecked[]" value="<?php echo $enreg['user_id']; ?>"></td>
-        <?php if ($is_western_name_order) { ?>
-        <td><?php echo api_htmlentities($enreg['firstname'],ENT_QUOTES,$charset); ?></td>
-        <td><?php echo api_htmlentities($enreg['lastname'],ENT_QUOTES,$charset); ?></td>
-        <?php } else { ?>
-        <td><?php echo api_htmlentities($enreg['lastname'],ENT_QUOTES,$charset); ?></td>
-        <td><?php echo api_htmlentities($enreg['firstname'],ENT_QUOTES,$charset); ?></td>
-        <?php } ?>
-        <td><?php echo api_htmlentities($enreg['username'],ENT_QUOTES,$charset); ?></td>
-        <td>
-        <?php if ($enreg['is_subscribed']) { ?>
-            <a href="<?php echo api_get_self(); ?>?id_session=<?php echo $id_session; ?>&course_code=<?php echo urlencode($course_code); ?>&sort=<?php echo $sort; ?>&action=delete&idChecked[]=<?php echo $enreg['user_id']; ?>" onclick="javascript:if(!confirm('<?php echo get_lang('ConfirmYourChoice'); ?>')) return false;">
-                <?php Display::display_icon('delete.png', get_lang('Delete')); ?>
-            </a>
-        <?php } else  { ?>
-            <a href="<?php echo api_get_self(); ?>?id_session=<?php echo $id_session; ?>&course_code=<?php echo urlencode($course_code); ?>&sort=<?php echo $sort; ?>&action=add&idChecked[]=<?php echo $enreg['user_id']; ?>" onclick="javascript:if(!confirm('<?php echo get_lang('ConfirmYourChoice'); ?>')) return false;">
-                <?php Display::display_icon('add.png', get_lang('Add'), array(), ICON_SIZE_SMALL); ?>
-            </a>
-        <?php }  ?>
-
-        </td>
-    </tr>
-    <?php
-        $i=$i ? 0 : 1;
+if (!empty($Users)) {
+    foreach ($Users as $key=>$enreg) {
+        if ($key == $limit) {
+            break;
+        }
+        ?>
+        <tr class="<?php echo $i?'row_odd':'row_even'; ?>">
+            <td><input type="checkbox" name="idChecked[]" value="<?php echo $enreg['user_id']; ?>"></td>
+            <?php if ($is_western_name_order) { ?>
+            <td><?php echo api_htmlentities($enreg['firstname'],ENT_QUOTES,$charset); ?></td>
+            <td><?php echo api_htmlentities($enreg['lastname'],ENT_QUOTES,$charset); ?></td>
+            <?php } else { ?>
+            <td><?php echo api_htmlentities($enreg['lastname'],ENT_QUOTES,$charset); ?></td>
+            <td><?php echo api_htmlentities($enreg['firstname'],ENT_QUOTES,$charset); ?></td>
+            <?php } ?>
+            <td><?php echo api_htmlentities($enreg['username'],ENT_QUOTES,$charset); ?></td>
+            <td>
+            <?php if ($enreg['is_subscribed']) { ?>
+                <a href="<?php echo api_get_self(); ?>?id_session=<?php echo $id_session; ?>&course_code=<?php echo urlencode($course_code); ?>&sort=<?php echo $sort; ?>&action=delete&idChecked[]=<?php echo $enreg['user_id']; ?>" onclick="javascript:if(!confirm('<?php echo get_lang('ConfirmYourChoice'); ?>')) return false;">
+                    <?php Display::display_icon('delete.png', get_lang('Delete')); ?>
+                </a>
+            <?php } else  { ?>
+                <a href="<?php echo api_get_self(); ?>?id_session=<?php echo $id_session; ?>&course_code=<?php echo urlencode($course_code); ?>&sort=<?php echo $sort; ?>&action=add&idChecked[]=<?php echo $enreg['user_id']; ?>" onclick="javascript:if(!confirm('<?php echo get_lang('ConfirmYourChoice'); ?>')) return false;">
+                    <?php Display::display_icon('add.png', get_lang('Add'), array(), ICON_SIZE_SMALL); ?>
+                </a>
+            <?php }  ?>
+
+            </td>
+        </tr>
+        <?php
+            $i=$i ? 0 : 1;
+    }
 }
 unset($Users);
 ?>
@@ -216,4 +204,4 @@ unset($Users);
 <button class="save" type="submit"> <?php echo get_lang('Ok'); ?></button>
 </form>
 <?php
-Display::display_footer();
+Display::display_footer();

+ 1 - 1
main/admin/user_move_stats.php

@@ -105,7 +105,7 @@ if (isset($_REQUEST['load_ajax'])) {
                 if (empty($result) || !in_array($user_id, array_keys($result))) {
                     if ($debug) echo 'User added to the session'; 
                     //Registering user to the new session
-                    SessionManager::suscribe_users_to_session($new_session_id,array($user_id),false);                    
+                    SessionManager::suscribe_users_to_session($new_session_id, array($user_id), false);                    
                 }            
                            
                 //Begin with the import process

+ 1 - 1
main/course_info/legal.php

@@ -67,7 +67,7 @@ if (empty($session_id)) {
         header('Location: '.$url);
     }
     
-    $user_session_status = SessionManager::get_user_status_in_session($user_id, $course_code, $session_id);
+    $user_session_status = SessionManager::get_user_status_in_course_session($user_id, $course_code, $session_id);
     
     if (isset($user_session_status) || api_check_user_access_to_legal($course_info['visibility'])) {        
         $user_accepted_legal = CourseManager::is_user_accepted_legal($user_id, $course_code, $session_id);        

+ 2 - 2
main/css/base.css

@@ -48,8 +48,8 @@ legend {
 }
 
 .subnav {
-    font-size: 11px;
-    font-weight: bold;
+    /*font-size: 11px;
+    font-weight: bold;*/
 }
 
 .subnav .btn-navbar {

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 482 - 261
main/css/bootstrap-responsive.css


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 377 - 169
main/css/bootstrap.css


+ 34 - 4
main/document/create_audio.php

@@ -199,6 +199,7 @@ $(document).ready(function(){
 
     $options = $options_pedia = array();
     $selected_language = null;
+	$options_pedia['defaultmessage'] = get_lang('FirstSelectALanguage');//need read before platform languages
 	
     while ($row = Database::fetch_array($result_select)) {       
         if (api_get_setting('platformLanguage')==$row['english_name']) {        
@@ -238,8 +239,8 @@ $(document).ready(function(){
 	if(Security::remove_XSS($_GET['dt2a'])=='pediaphon'){
 		//lang default is a default message
 		$selected_language = "defaultmessage";
-		$options_pedia['defaultmessage'] =get_lang('FirstSelectALanguage');
-		$options['defaultmessage'] =get_lang('FirstSelectALanguage'); 
+		
+		$options['defaultmessage'] = get_lang('FirstSelectALanguage'); 
 		echo '<div>';
 		
 		$form = new FormValidator('form2', 'post', null, '', array('id' => 'form2'));
@@ -413,9 +414,25 @@ function downloadMP3_google($filepath, $dir) {
     // Replacing remaining dangerous non-letter characters.
     $clean_text = str_replace($search, $replace, $filename);
 	
+	$returntext2voice=file_get_contents("http://translate.google.com/translate_tts?tl=".$clean_lang."&q=".urlencode($clean_text)."");
+	
+	//make a temporal file for get the file size
+		$tmpfname = tempnam("/tmp", "CTF");
+		$handle = fopen($tmpfname, "w");
+		fwrite($handle, $returntext2voice);
+		fclose($handle);
+		// Check if there is enough space in the course to save the file
+		if (!DocumentManager::enough_space(filesize($tmpfname), DocumentManager::get_course_quota())) {
+			unlink($tmpfname);
+			die(get_lang('UplNotEnoughSpace'));
+		}
+		//erase temporal file
+		unlink($tmpfname);
+		
+	
 	//adding the file
 		//add new file to disk
-		file_put_contents($documentPath, file_get_contents("http://translate.google.com/translate_tts?tl=".$clean_lang."&q=".urlencode($clean_text).""));
+		file_put_contents($documentPath, $returntext2voice);
 		//add document to database
 		$current_session_id = api_get_session_id();
 		$groupId=$_SESSION['_gid'];
@@ -520,7 +537,20 @@ function downloadMP3_pediaphon($filepath, $dir){
 		$search_source=preg_match($find_t2v, $previous_returntext2voice, $hits);
 		$souce_end=substr($hits[0], 0,-1);
 		$returntext2voice = file_get_contents($souce_end);
-				
+		
+		//make a temporal file for get the file size
+			$tmpfname = tempnam("/tmp", "CTF");
+			$handle = fopen($tmpfname, "w");
+			fwrite($handle, $returntext2voice);
+			fclose($handle);
+			// Check if there is enough space in the course to save the file
+			if (!DocumentManager::enough_space(filesize($tmpfname), DocumentManager::get_course_quota())) {
+				unlink($tmpfname);
+				die(get_lang('UplNotEnoughSpace'));
+			}
+			//erase temporal file
+			unlink($tmpfname);
+		
 		//save file
 		file_put_contents($documentPath, $returntext2voice);
 		

+ 16 - 0
main/document/save_pixlr.php

@@ -110,6 +110,22 @@ if(strpos($current_mime, 'image')===false) {
 }
 
 
+//make a temporal file for get the file size
+$tmpfname = tempnam("/tmp", "CTF");
+$handle = fopen($tmpfname, "w");
+fwrite($handle, $contents);
+fclose($handle);
+
+// Check if there is enough space in the course to save the file
+if (!DocumentManager::enough_space(filesize($tmpfname), DocumentManager::get_course_quota())) {
+	unlink($tmpfname);
+	die(get_lang('UplNotEnoughSpace'));
+}
+
+//erase temporal file
+unlink($tmpfname);
+
+
 //path, file and title
 $paintFileName = $filename.'.'.$extension;
 $title = $title.'.'.$extension;

+ 51 - 22
main/inc/lib/course.lib.php

@@ -714,9 +714,10 @@ class CourseManager {
                     }
                 } else {
                     $students_in_course = SessionManager::get_users_by_session($session_id, '0');
-
-                    foreach($students_in_course as $user_item) {
-                        $students_in_courses[$user_item['user_id']] = $user_item['user_id'];
+                    foreach ($students_in_course as $user_item) {
+                        if ($user_item['moved_to'] == 0) {
+                            $students_in_courses[$user_item['user_id']] = $user_item['user_id'];
+                        }                        
                     }
                 }
             }
@@ -1120,11 +1121,11 @@ class CourseManager {
      * @param int       if using the session_id: 0 or 2 (student, coach), if using session_id = 0 STUDENT or COURSEMANAGER 
      * @return array
      */
-    public static function get_user_list_from_course_code($course_code, $session_id = 0, $limit = '', $order_by = '', $filter_by_status = null) {
-        // variable initialisation
+    public static function get_user_list_from_course_code($course_code, $session_id = 0, $limit = null, $order_by =null, $filter_by_status = null, $keyword = null) {
         $session_id     = intval($session_id);
         $course_code    = Database::escape_string($course_code);
-        $where          = array();
+        $keyword        = Database::escape_string($keyword);
+        $where          = array();        
 
         // if the $order_by does not contain 'ORDER BY' we have to check if it is a valid field that can be sorted on
         if (!strstr($order_by,'ORDER BY')) {
@@ -1140,22 +1141,27 @@ class CourseManager {
         if (!empty($session_id)) {
             $sql = 'SELECT DISTINCT user.user_id, session_course_user.status as status_session, user.*  ';
             $sql .= ' FROM '.Database::get_main_table(TABLE_MAIN_USER).' as user ';            
-            $sql .= ' LEFT JOIN '.Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER).' as session_course_user
+            $sql .= ' LEFT JOIN '.Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER).' as session_course_user                      
                       ON user.user_id = session_course_user.id_user
                       AND session_course_user.course_code="'.$course_code.'"
-                      AND session_course_user.id_session = '.$session_id;
-            $where[] = ' session_course_user.course_code IS NOT NULL ';
+                      AND session_course_user.id_session = '.$session_id.' 
+                      INNER JOIN '.Database::get_main_table(TABLE_MAIN_SESSION_USER).' as su 
+                      ON (  su.id_session = session_course_user.id_session AND 
+                            user.user_id = su.id_user AND 
+                            su.moved_to = 0 AND
+                            su.moved_status <> '.SessionManager::SESSION_CHANGE_USER_REASON_ENROLLMENT_ANNULATION.'
+                      ) ';
+            $where[] = ' AND session_course_user.course_code IS NOT NULL ';
             
             // 2 = coach
             // 0 = student            
             if (isset($filter_by_status)) {                
                 $filter_by_status = intval($filter_by_status);
-                $filter_by_status_condition = " session_course_user.status = $filter_by_status AND ";                
+                $filter_by_status_condition = " AND session_course_user.status = $filter_by_status AND ";                
             }
         } else {            
             $sql = 'SELECT DISTINCT course_rel_user.status as status_rel, user.user_id, course_rel_user.role, course_rel_user.tutor_id, user.*  ';
-            $sql .= ' FROM '.Database::get_main_table(TABLE_MAIN_USER).' as user ';
-            
+            $sql .= ' FROM '.Database::get_main_table(TABLE_MAIN_USER).' as user ';            
             $sql .= ' LEFT JOIN '.Database::get_main_table(TABLE_MAIN_COURSE_USER).' as course_rel_user
                         ON user.user_id = course_rel_user.user_id AND course_rel_user.relation_type<>'.COURSE_RELATION_TYPE_RRHH.'
                         AND course_rel_user.course_code="'.$course_code.'"';
@@ -1163,7 +1169,7 @@ class CourseManager {
             
             if (isset($filter_by_status) && $filter_by_status != '') {
                 $filter_by_status = intval($filter_by_status);
-                $filter_by_status_condition = " course_rel_user.status = $filter_by_status AND ";
+                $filter_by_status_condition = " AND course_rel_user.status = $filter_by_status AND ";
             }
         }
         
@@ -1171,15 +1177,35 @@ class CourseManager {
         if ($multiple_access_url) {
             $sql  .= ' LEFT JOIN '.Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER).'  au ON (au.user_id = user.user_id) ';
         }
+        
+        $keyword_condition = null;
+        if (!empty($keyword)) {
+            $where_keyword = array();
+            $where_keyword[] = "firstname LIKE '%$keyword%'";
+            $where_keyword[] = "lastname LIKE '%$keyword%'";
+            $where_keyword[] = "username LIKE '%$keyword%'";
+            $where_keyword[] = "official_code LIKE '%$keyword%'";    
+            $keyword_condition = ' AND ('.implode(' OR ', $where_keyword).') ';
+        }
+        
+        $where_condition = null;
+        if (!empty($where)) {
+            $where_condition = implode(' OR ', $where);
+        }
+
+        $sql .= " WHERE 1=1 $filter_by_status_condition $where_condition $keyword_condition";
 
-        $sql .= ' WHERE '.$filter_by_status_condition.' '.implode(' OR ', $where);
-                
         if ($multiple_access_url) {
             $current_access_url_id = api_get_current_access_url_id();
             $sql .= " AND (access_url_id =  $current_access_url_id ) ";
         }
-        $sql .= ' '.$order_by.' '.$limit;
-
+        
+        $sql .= ' '.$order_by;
+        
+        if (!empty($keyword)) {
+            $sql .= ' '.$limit;
+        }
+        
         $rs = Database::query($sql);
         $users = array();
 
@@ -1194,11 +1220,9 @@ class CourseManager {
                 if (isset($user['tutor_id'])) {
                     $user_info['tutor_id'] = $user['tutor_id'];
                 }
-
                 if (!empty($session_id)) {
                     $user_info['status_session'] = $user['status_session'];
                 }
-
                 $users[$user['user_id']] = $user_info;
             }
         }
@@ -1212,8 +1236,7 @@ class CourseManager {
      * @param   int       $session_id
      * @return  int
      */
-    public static function get_users_count_in_course($course_code, $session_id = 0) {
-        // variable initialisation
+    public static function get_users_count_in_course($course_code, $session_id = 0) {        
         $session_id     = intval($session_id);
         $course_code    = Database::escape_string($course_code);
 
@@ -1223,7 +1246,13 @@ class CourseManager {
             $sql .= ' LEFT JOIN '.Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER).' as session_course_user
                       ON user.user_id = session_course_user.id_user
                       AND session_course_user.course_code = "'.$course_code.'"
-                      AND session_course_user.id_session  = '.$session_id;
+                      AND session_course_user.id_session  = '.$session_id.'  
+                      INNER JOIN '.Database::get_main_table(TABLE_MAIN_SESSION_USER).' as su 
+                      ON ( su.id_session = session_course_user.id_session AND 
+                           user.user_id = su.id_user AND 
+                           su.moved_to = 0 AND
+                           su.moved_status <> '.SessionManager::SESSION_CHANGE_USER_REASON_ENROLLMENT_ANNULATION.'
+                         )';
 
             $where[] = ' session_course_user.course_code IS NOT NULL ';
         } else {

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

@@ -22,7 +22,7 @@ class DocumentManager {
      */
     public static function get_course_quota($course_code = null) {
         if (empty($course_code)) {
-            $course_info = api_get_course_info();
+        $course_info = api_get_course_info();
         } else {
             $course_info = api_get_course_info($course_code);
         }
@@ -1166,7 +1166,7 @@ class DocumentManager {
         //When using hotpotatoes files, new files are generated in the hotpotatoe folder, if user_id=1 does the exam a new html file will be generated: hotpotatoe.html.(user_id).t.html
         //so we remove that string in order to find correctly the origin file
         if (strpos($doc_path, 'HotPotatoes_files')) {
-//            $doc_path = substr($doc_path, 0, strlen($doc_path) - 8);
+            // $doc_path = substr($doc_path, 0, strlen($doc_path) - 8); // issue #5359
             $doc_path = substr($doc_path, 0, strlen($doc_path) - 7 - strlen(api_get_user_id()));
         }
 
@@ -1328,7 +1328,7 @@ class DocumentManager {
         if ($num == 0) {
             return null;
         }
-        $row = Database::fetch_array($rs);
+        $row    = Database::fetch_array($rs);
         return $row['document_id'];
     }
 
@@ -1337,7 +1337,7 @@ class DocumentManager {
      * @param string The course code
      * @return string The html content of the certificate
      */
-    static function replace_user_info_into_html($user_id, $course_code, $is_preview = false) {
+    function replace_user_info_into_html($user_id, $course_code, $is_preview = false) {
         $user_id 		= intval($user_id);
         $course_info 	= api_get_course_info($course_code);
         $tbl_document 	= Database::get_course_table(TABLE_DOCUMENT);
@@ -1350,7 +1350,7 @@ class DocumentManager {
             $new_content = '';
             $all_user_info = array();
             if (Database::num_rows($rs)) {
-                $row = Database::fetch_array($rs);
+                $row=Database::fetch_array($rs);
                 $filepath = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/document'.$row['path'];
                 if (is_file($filepath)) {
                     $my_content_html = file_get_contents($filepath);
@@ -1406,9 +1406,7 @@ class DocumentManager {
             $date_long_certificate = api_convert_and_format_date(api_get_utc_datetime());
         }
 
-        $url = api_get_path(WEB_PATH).'certificates/index.php?id='.$info_grade_certificate['id'];
-
-        
+        $url = api_get_path(WEB_PATH).'certificates/?id='.$info_grade_certificate['id'];
         //replace content
         $info_to_replace_in_content_html     = array($first_name,
                                                      $last_name,
@@ -1425,7 +1423,6 @@ class DocumentManager {
                                                      '<a href="'.$url.'" target="_blank">'.get_lang('CertificateOnlineLink').'</a>',
                                                      '((certificate_barcode))',
                                                     );
-        
         $info_to_be_replaced_in_content_html = array('((user_firstname))',
         											 '((user_lastname))',
         											 '((gradebook_institution))',
@@ -1448,7 +1445,6 @@ class DocumentManager {
                 $info_to_replace_in_content_html[]=$value_extra;
             }
         }
-            
         $info_list[]=$info_to_be_replaced_in_content_html;
         $info_list[]=$info_to_replace_in_content_html;
         return $info_list;
@@ -1498,7 +1494,7 @@ class DocumentManager {
             
             if (!is_dir($base_work_dir_test)) {
                 $created_dir = create_unexisting_directory($course_info, api_get_user_id(), api_get_session_id(), $to_group_id,$to_user_id,$base_work_dir,$dir_name,$post_dir_name);                
-                $update_id = DocumentManager::get_document_id_of_directory_certificate();                
+                $update_id = self::get_document_id_of_directory_certificate();                
                 api_item_property_update($course_info, TOOL_DOCUMENT, $update_id, $visibility_command, api_get_user_id());
             }
         }
@@ -1509,7 +1505,7 @@ class DocumentManager {
      * @param string The course id
      * @return int The document id of the directory certificate
      */
-    function get_document_id_of_directory_certificate () {
+    static function get_document_id_of_directory_certificate () {
         $tbl_document=Database::get_course_table(TABLE_DOCUMENT);
         $course_id = api_get_course_int_id();
         $sql = "SELECT id FROM $tbl_document WHERE c_id = $course_id AND path='/certificates' ";

+ 368 - 166
main/inc/lib/javascript/bootstrap/bootstrap.js

@@ -1,5 +1,5 @@
 /* ===================================================
- * bootstrap-transition.js v2.0.4
+ * bootstrap-transition.js v2.1.0
  * http://twitter.github.com/bootstrap/javascript.html#transitions
  * ===================================================
  * Copyright 2012 Twitter, Inc.
@@ -36,8 +36,7 @@
           , transEndEventNames = {
                'WebkitTransition' : 'webkitTransitionEnd'
             ,  'MozTransition'    : 'transitionend'
-            ,  'OTransition'      : 'oTransitionEnd'
-            ,  'msTransition'     : 'MSTransitionEnd'
+            ,  'OTransition'      : 'oTransitionEnd otransitionend'
             ,  'transition'       : 'transitionend'
             }
           , name
@@ -59,7 +58,7 @@
   })
 
 }(window.jQuery);/* ==========================================================
- * bootstrap-alert.js v2.0.4
+ * bootstrap-alert.js v2.1.0
  * http://twitter.github.com/bootstrap/javascript.html#alerts
  * ==========================================================
  * Copyright 2012 Twitter, Inc.
@@ -148,7 +147,7 @@
   })
 
 }(window.jQuery);/* ============================================================
- * bootstrap-button.js v2.0.4
+ * bootstrap-button.js v2.1.0
  * http://twitter.github.com/bootstrap/javascript.html#buttons
  * ============================================================
  * Copyright 2012 Twitter, Inc.
@@ -243,7 +242,7 @@
   })
 
 }(window.jQuery);/* ==========================================================
- * bootstrap-carousel.js v2.0.4
+ * bootstrap-carousel.js v2.1.0
  * http://twitter.github.com/bootstrap/javascript.html#carousel
  * ==========================================================
  * Copyright 2012 Twitter, Inc.
@@ -290,7 +289,7 @@
     }
 
   , to: function (pos) {
-      var $active = this.$element.find('.active')
+      var $active = this.$element.find('.item.active')
         , children = $active.parent().children()
         , activePos = children.index($active)
         , that = this
@@ -312,6 +311,10 @@
 
   , pause: function (e) {
       if (!e) this.paused = true
+      if (this.$element.find('.next, .prev').length && $.support.transition.end) {
+        this.$element.trigger($.support.transition.end)
+        this.cycle()
+      }
       clearInterval(this.interval)
       this.interval = null
       return this
@@ -328,13 +331,15 @@
     }
 
   , slide: function (type, next) {
-      var $active = this.$element.find('.active')
+      var $active = this.$element.find('.item.active')
         , $next = next || $active[type]()
         , isCycling = this.interval
         , direction = type == 'next' ? 'left' : 'right'
         , fallback  = type == 'next' ? 'first' : 'last'
         , that = this
-        , e = $.Event('slide')
+        , e = $.Event('slide', {
+            relatedTarget: $next[0]
+          })
 
       this.sliding = true
 
@@ -382,9 +387,10 @@
       var $this = $(this)
         , data = $this.data('carousel')
         , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option)
+        , action = typeof option == 'string' ? option : options.slide
       if (!data) $this.data('carousel', (data = new Carousel(this, options)))
       if (typeof option == 'number') data.to(option)
-      else if (typeof option == 'string' || (option = options.slide)) data[option]()
+      else if (action) data[action]()
       else if (options.interval) data.cycle()
     })
   }
@@ -411,7 +417,7 @@
   })
 
 }(window.jQuery);/* =============================================================
- * bootstrap-collapse.js v2.0.4
+ * bootstrap-collapse.js v2.1.0
  * http://twitter.github.com/bootstrap/javascript.html#collapse
  * =============================================================
  * Copyright 2012 Twitter, Inc.
@@ -479,7 +485,7 @@
 
       this.$element[dimension](0)
       this.transition('addClass', $.Event('show'), 'shown')
-      this.$element[dimension](this.$element[0][scroll])
+      $.support.transition && this.$element[dimension](this.$element[0][scroll])
     }
 
   , hide: function () {
@@ -556,18 +562,19 @@
   * ==================== */
 
   $(function () {
-    $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) {
+    $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function (e) {
       var $this = $(this), href
         , target = $this.attr('data-target')
           || e.preventDefault()
           || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
         , option = $(target).data('collapse') ? 'toggle' : $this.data()
+      $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
       $(target).collapse(option)
     })
   })
 
 }(window.jQuery);/* ============================================================
- * bootstrap-dropdown.js v2.0.4
+ * bootstrap-dropdown.js v2.1.0
  * http://twitter.github.com/bootstrap/javascript.html#dropdowns
  * ============================================================
  * Copyright 2012 Twitter, Inc.
@@ -594,7 +601,7 @@
  /* DROPDOWN CLASS DEFINITION
   * ========================= */
 
-  var toggle = '[data-toggle="dropdown"]'
+  var toggle = '[data-toggle=dropdown]'
     , Dropdown = function (element) {
         var $el = $(element).on('click.dropdown.data-api', this.toggle)
         $('html').on('click.dropdown.data-api', function () {
@@ -609,34 +616,82 @@
   , toggle: function (e) {
       var $this = $(this)
         , $parent
-        , selector
         , isActive
 
       if ($this.is('.disabled, :disabled')) return
 
-      selector = $this.attr('data-target')
+      $parent = getParent($this)
 
-      if (!selector) {
-        selector = $this.attr('href')
-        selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+      isActive = $parent.hasClass('open')
+
+      clearMenus()
+
+      if (!isActive) {
+        $parent.toggleClass('open')
+        $this.focus()
       }
 
-      $parent = $(selector)
-      $parent.length || ($parent = $this.parent())
+      return false
+    }
+
+  , keydown: function (e) {
+      var $this
+        , $items
+        , $active
+        , $parent
+        , isActive
+        , index
+
+      if (!/(38|40|27)/.test(e.keyCode)) return
+
+      $this = $(this)
+
+      e.preventDefault()
+      e.stopPropagation()
+
+      if ($this.is('.disabled, :disabled')) return
+
+      $parent = getParent($this)
 
       isActive = $parent.hasClass('open')
 
-      clearMenus()
+      if (!isActive || (isActive && e.keyCode == 27)) return $this.click()
 
-      if (!isActive) $parent.toggleClass('open')
+      $items = $('[role=menu] li:not(.divider) a', $parent)
 
-      return false
+      if (!$items.length) return
+
+      index = $items.index($items.filter(':focus'))
+
+      if (e.keyCode == 38 && index > 0) index--                                        // up
+      if (e.keyCode == 40 && index < $items.length - 1) index++                        // down
+      if (!~index) index = 0
+
+      $items
+        .eq(index)
+        .focus()
     }
 
   }
 
   function clearMenus() {
-    $(toggle).parent().removeClass('open')
+    getParent($(toggle))
+      .removeClass('open')
+  }
+
+  function getParent($this) {
+    var selector = $this.attr('data-target')
+      , $parent
+
+    if (!selector) {
+      selector = $this.attr('href')
+      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+    }
+
+    $parent = $(selector)
+    $parent.length || ($parent = $this.parent())
+
+    return $parent
   }
 
 
@@ -659,14 +714,16 @@
    * =================================== */
 
   $(function () {
-    $('html').on('click.dropdown.data-api', clearMenus)
+    $('html')
+      .on('click.dropdown.data-api touchstart.dropdown.data-api', clearMenus)
     $('body')
-      .on('click.dropdown', '.dropdown form', function (e) { e.stopPropagation() })
-      .on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle)
+      .on('click.dropdown touchstart.dropdown.data-api', '.dropdown', function (e) { e.stopPropagation() })
+      .on('click.dropdown.data-api touchstart.dropdown.data-api'  , toggle, Dropdown.prototype.toggle)
+      .on('keydown.dropdown.data-api touchstart.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown)
   })
 
 }(window.jQuery);/* =========================================================
- * bootstrap-modal.js v2.0.4
+ * bootstrap-modal.js v2.1.0
  * http://twitter.github.com/bootstrap/javascript.html#modals
  * =========================================================
  * Copyright 2012 Twitter, Inc.
@@ -693,10 +750,11 @@
  /* MODAL CLASS DEFINITION
   * ====================== */
 
-  var Modal = function (content, options) {
+  var Modal = function (element, options) {
     this.options = options
-    this.$element = $(content)
+    this.$element = $(element)
       .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this))
+    this.options.remote && this.$element.find('.modal-body').load(this.options.remote)
   }
 
   Modal.prototype = {
@@ -719,8 +777,9 @@
 
         this.isShown = true
 
-        escape.call(this)
-        backdrop.call(this, function () {
+        this.escape()
+
+        this.backdrop(function () {
           var transition = $.support.transition && that.$element.hasClass('fade')
 
           if (!that.$element.parent().length) {
@@ -734,7 +793,12 @@
             that.$element[0].offsetWidth // force reflow
           }
 
-          that.$element.addClass('in')
+          that.$element
+            .addClass('in')
+            .attr('aria-hidden', false)
+            .focus()
+
+          that.enforceFocus()
 
           transition ?
             that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) :
@@ -758,90 +822,98 @@
 
         $('body').removeClass('modal-open')
 
-        escape.call(this)
+        this.escape()
 
-        this.$element.removeClass('in')
+        $(document).off('focusin.modal')
+
+        this.$element
+          .removeClass('in')
+          .attr('aria-hidden', true)
 
         $.support.transition && this.$element.hasClass('fade') ?
-          hideWithTransition.call(this) :
-          hideModal.call(this)
+          this.hideWithTransition() :
+          this.hideModal()
       }
 
-  }
-
-
- /* MODAL PRIVATE METHODS
-  * ===================== */
+    , enforceFocus: function () {
+        var that = this
+        $(document).on('focusin.modal', function (e) {
+          if (that.$element[0] !== e.target && !that.$element.has(e.target).length) {
+            that.$element.focus()
+          }
+        })
+      }
 
-  function hideWithTransition() {
-    var that = this
-      , timeout = setTimeout(function () {
-          that.$element.off($.support.transition.end)
-          hideModal.call(that)
-        }, 500)
+    , escape: function () {
+        var that = this
+        if (this.isShown && this.options.keyboard) {
+          this.$element.on('keyup.dismiss.modal', function ( e ) {
+            e.which == 27 && that.hide()
+          })
+        } else if (!this.isShown) {
+          this.$element.off('keyup.dismiss.modal')
+        }
+      }
 
-    this.$element.one($.support.transition.end, function () {
-      clearTimeout(timeout)
-      hideModal.call(that)
-    })
-  }
+    , hideWithTransition: function () {
+        var that = this
+          , timeout = setTimeout(function () {
+              that.$element.off($.support.transition.end)
+              that.hideModal()
+            }, 500)
 
-  function hideModal(that) {
-    this.$element
-      .hide()
-      .trigger('hidden')
+        this.$element.one($.support.transition.end, function () {
+          clearTimeout(timeout)
+          that.hideModal()
+        })
+      }
 
-    backdrop.call(this)
-  }
+    , hideModal: function (that) {
+        this.$element
+          .hide()
+          .trigger('hidden')
 
-  function backdrop(callback) {
-    var that = this
-      , animate = this.$element.hasClass('fade') ? 'fade' : ''
+        this.backdrop()
+      }
 
-    if (this.isShown && this.options.backdrop) {
-      var doAnimate = $.support.transition && animate
+    , removeBackdrop: function () {
+        this.$backdrop.remove()
+        this.$backdrop = null
+      }
 
-      this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
-        .appendTo(document.body)
+    , backdrop: function (callback) {
+        var that = this
+          , animate = this.$element.hasClass('fade') ? 'fade' : ''
 
-      if (this.options.backdrop != 'static') {
-        this.$backdrop.click($.proxy(this.hide, this))
-      }
+        if (this.isShown && this.options.backdrop) {
+          var doAnimate = $.support.transition && animate
 
-      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
+          this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
+            .appendTo(document.body)
 
-      this.$backdrop.addClass('in')
+          if (this.options.backdrop != 'static') {
+            this.$backdrop.click($.proxy(this.hide, this))
+          }
 
-      doAnimate ?
-        this.$backdrop.one($.support.transition.end, callback) :
-        callback()
+          if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
 
-    } else if (!this.isShown && this.$backdrop) {
-      this.$backdrop.removeClass('in')
+          this.$backdrop.addClass('in')
 
-      $.support.transition && this.$element.hasClass('fade')?
-        this.$backdrop.one($.support.transition.end, $.proxy(removeBackdrop, this)) :
-        removeBackdrop.call(this)
+          doAnimate ?
+            this.$backdrop.one($.support.transition.end, callback) :
+            callback()
 
-    } else if (callback) {
-      callback()
-    }
-  }
+        } else if (!this.isShown && this.$backdrop) {
+          this.$backdrop.removeClass('in')
 
-  function removeBackdrop() {
-    this.$backdrop.remove()
-    this.$backdrop = null
-  }
+          $.support.transition && this.$element.hasClass('fade')?
+            this.$backdrop.one($.support.transition.end, $.proxy(this.removeBackdrop, this)) :
+            this.removeBackdrop()
 
-  function escape() {
-    var that = this
-    if (this.isShown && this.options.keyboard) {
-      $(document).on('keyup.dismiss.modal', function ( e ) {
-        e.which == 27 && that.hide()
-      })
-    } else if (!this.isShown) {
-      $(document).off('keyup.dismiss.modal')
-    }
+        } else if (callback) {
+          callback()
+        }
+      }
   }
 
 
@@ -873,17 +945,23 @@
 
   $(function () {
     $('body').on('click.modal.data-api', '[data-toggle="modal"]', function ( e ) {
-      var $this = $(this), href
-        , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
-        , option = $target.data('modal') ? 'toggle' : $.extend({}, $target.data(), $this.data())
+      var $this = $(this)
+        , href = $this.attr('href')
+        , $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7
+        , option = $target.data('modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
 
       e.preventDefault()
-      $target.modal(option)
+
+      $target
+        .modal(option)
+        .one('hide', function () {
+          $this.focus()
+        })
     })
   })
 
 }(window.jQuery);/* ===========================================================
- * bootstrap-tooltip.js v2.0.4
+ * bootstrap-tooltip.js v2.1.0
  * http://twitter.github.com/bootstrap/javascript.html#tooltips
  * Inspired by the original jQuery.tipsy by Jason Frame
  * ===========================================================
@@ -928,11 +1006,13 @@
       this.options = this.getOptions(options)
       this.enabled = true
 
-      if (this.options.trigger != 'manual') {
-        eventIn  = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'
+      if (this.options.trigger == 'click') {
+        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
+      } else if (this.options.trigger != 'manual') {
+        eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'
         eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur'
-        this.$element.on(eventIn, this.options.selector, $.proxy(this.enter, this))
-        this.$element.on(eventOut, this.options.selector, $.proxy(this.leave, this))
+        this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
+        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
       }
 
       this.options.selector ?
@@ -1032,20 +1112,11 @@
       }
     }
 
-  , isHTML: function(text) {
-      // html string detection logic adapted from jQuery
-      return typeof text != 'string'
-        || ( text.charAt(0) === "<"
-          && text.charAt( text.length - 1 ) === ">"
-          && text.length >= 3
-        ) || /^(?:[^<]*<[\w\W]+>[^>]*$)/.exec(text)
-    }
-
   , setContent: function () {
       var $tip = this.tip()
         , title = this.getTitle()
 
-      $tip.find('.tooltip-inner')[this.isHTML(title) ? 'html' : 'text'](title)
+      $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
       $tip.removeClass('fade in top bottom left right')
     }
 
@@ -1069,6 +1140,8 @@
       $.support.transition && this.$tip.hasClass('fade') ?
         removeWithAnimation() :
         $tip.remove()
+
+      return this
     }
 
   , fixTitle: function () {
@@ -1128,6 +1201,10 @@
       this[this.tip().hasClass('in') ? 'hide' : 'show']()
     }
 
+  , destroy: function () {
+      this.hide().$element.off('.' + this.type).removeData(this.type)
+    }
+
   }
 
 
@@ -1154,11 +1231,12 @@
   , trigger: 'hover'
   , title: ''
   , delay: 0
+  , html: true
   }
 
 }(window.jQuery);
 /* ===========================================================
- * bootstrap-popover.js v2.0.4
+ * bootstrap-popover.js v2.1.0
  * http://twitter.github.com/bootstrap/javascript.html#popovers
  * ===========================================================
  * Copyright 2012 Twitter, Inc.
@@ -1185,7 +1263,7 @@
  /* POPOVER PUBLIC CLASS DEFINITION
   * =============================== */
 
-  var Popover = function ( element, options ) {
+  var Popover = function (element, options) {
     this.init('popover', element, options)
   }
 
@@ -1202,8 +1280,8 @@
         , title = this.getTitle()
         , content = this.getContent()
 
-      $tip.find('.popover-title')[this.isHTML(title) ? 'html' : 'text'](title)
-      $tip.find('.popover-content > *')[this.isHTML(content) ? 'html' : 'text'](content)
+      $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
+      $tip.find('.popover-content > *')[this.options.html ? 'html' : 'text'](content)
 
       $tip.removeClass('fade top bottom left right in')
     }
@@ -1230,6 +1308,10 @@
       return this.$tip
     }
 
+  , destroy: function () {
+      this.hide().$element.off('.' + this.type).removeData(this.type)
+    }
+
   })
 
 
@@ -1250,12 +1332,13 @@
 
   $.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, {
     placement: 'right'
+  , trigger: 'click'
   , content: ''
   , template: '<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p></p></div></div></div>'
   })
 
 }(window.jQuery);/* =============================================================
- * bootstrap-scrollspy.js v2.0.4
+ * bootstrap-scrollspy.js v2.1.0
  * http://twitter.github.com/bootstrap/javascript.html#scrollspy
  * =============================================================
  * Copyright 2012 Twitter, Inc.
@@ -1279,15 +1362,15 @@
   "use strict"; // jshint ;_;
 
 
-  /* SCROLLSPY CLASS DEFINITION
-   * ========================== */
+ /* SCROLLSPY CLASS DEFINITION
+  * ========================== */
 
-  function ScrollSpy( element, options) {
+  function ScrollSpy(element, options) {
     var process = $.proxy(this.process, this)
       , $element = $(element).is('body') ? $(window) : $(element)
       , href
     this.options = $.extend({}, $.fn.scrollspy.defaults, options)
-    this.$scrollElement = $element.on('scroll.scroll.data-api', process)
+    this.$scrollElement = $element.on('scroll.scroll-spy.data-api', process)
     this.selector = (this.options.target
       || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
       || '') + ' .nav li > a'
@@ -1314,7 +1397,7 @@
               , href = $el.data('target') || $el.attr('href')
               , $href = /^#\w/.test(href) && $(href)
             return ( $href
-              && href.length
+              && $href.length
               && [[ $href.position().top, href ]] ) || null
           })
           .sort(function (a, b) { return a[0] - b[0] })
@@ -1364,7 +1447,7 @@
           .parent('li')
           .addClass('active')
 
-        if (active.parent('.dropdown-menu'))  {
+        if (active.parent('.dropdown-menu').length)  {
           active = active.closest('li.dropdown').addClass('active')
         }
 
@@ -1377,7 +1460,7 @@
  /* SCROLLSPY PLUGIN DEFINITION
   * =========================== */
 
-  $.fn.scrollspy = function ( option ) {
+  $.fn.scrollspy = function (option) {
     return this.each(function () {
       var $this = $(this)
         , data = $this.data('scrollspy')
@@ -1397,7 +1480,7 @@
  /* SCROLLSPY DATA-API
   * ================== */
 
-  $(function () {
+  $(window).on('load', function () {
     $('[data-spy="scroll"]').each(function () {
       var $spy = $(this)
       $spy.scrollspy($spy.data())
@@ -1405,7 +1488,7 @@
   })
 
 }(window.jQuery);/* ========================================================
- * bootstrap-tab.js v2.0.4
+ * bootstrap-tab.js v2.1.0
  * http://twitter.github.com/bootstrap/javascript.html#tabs
  * ========================================================
  * Copyright 2012 Twitter, Inc.
@@ -1432,7 +1515,7 @@
  /* TAB CLASS DEFINITION
   * ==================== */
 
-  var Tab = function ( element ) {
+  var Tab = function (element) {
     this.element = $(element)
   }
 
@@ -1539,7 +1622,7 @@
   })
 
 }(window.jQuery);/* =============================================================
- * bootstrap-typeahead.js v2.0.4
+ * bootstrap-typeahead.js v2.1.0
  * http://twitter.github.com/bootstrap/javascript.html#typeahead
  * =============================================================
  * Copyright 2012 Twitter, Inc.
@@ -1617,17 +1700,23 @@
     }
 
   , lookup: function (event) {
-      var that = this
-        , items
-        , q
+      var items
 
       this.query = this.$element.val()
 
-      if (!this.query) {
+      if (!this.query || this.query.length < this.options.minLength) {
         return this.shown ? this.hide() : this
       }
 
-      items = $.grep(this.source, function (item) {
+      items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source
+
+      return items ? this.process(items) : this
+    }
+
+  , process: function (items) {
+      var that = this
+
+      items = $.grep(items, function (item) {
         return that.matcher(item)
       })
 
@@ -1709,7 +1798,7 @@
         .on('keyup',    $.proxy(this.keyup, this))
 
       if ($.browser.webkit || $.browser.msie) {
-        this.$element.on('keydown', $.proxy(this.keypress, this))
+        this.$element.on('keydown', $.proxy(this.keydown, this))
       }
 
       this.$menu
@@ -1717,6 +1806,40 @@
         .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
     }
 
+  , move: function (e) {
+      if (!this.shown) return
+
+      switch(e.keyCode) {
+        case 9: // tab
+        case 13: // enter
+        case 27: // escape
+          e.preventDefault()
+          break
+
+        case 38: // up arrow
+          e.preventDefault()
+          this.prev()
+          break
+
+        case 40: // down arrow
+          e.preventDefault()
+          this.next()
+          break
+      }
+
+      e.stopPropagation()
+    }
+
+  , keydown: function (e) {
+      this.suppressKeyPressRepeat = !~$.inArray(e.keyCode, [40,38,9,13,27])
+      this.move(e)
+    }
+
+  , keypress: function (e) {
+      if (this.suppressKeyPressRepeat) return
+      this.move(e)
+    }
+
   , keyup: function (e) {
       switch(e.keyCode) {
         case 40: // down arrow
@@ -1742,32 +1865,6 @@
       e.preventDefault()
   }
 
-  , keypress: function (e) {
-      if (!this.shown) return
-
-      switch(e.keyCode) {
-        case 9: // tab
-        case 13: // enter
-        case 27: // escape
-          e.preventDefault()
-          break
-
-        case 38: // up arrow
-          if (e.type != 'keydown') break
-          e.preventDefault()
-          this.prev()
-          break
-
-        case 40: // down arrow
-          if (e.type != 'keydown') break
-          e.preventDefault()
-          this.next()
-          break
-      }
-
-      e.stopPropagation()
-    }
-
   , blur: function (e) {
       var that = this
       setTimeout(function () { that.hide() }, 150)
@@ -1805,12 +1902,13 @@
   , items: 8
   , menu: '<ul class="typeahead dropdown-menu"></ul>'
   , item: '<li><a href="#"></a></li>'
+  , minLength: 1
   }
 
   $.fn.typeahead.Constructor = Typeahead
 
 
- /* TYPEAHEAD DATA-API
+ /*   TYPEAHEAD DATA-API
   * ================== */
 
   $(function () {
@@ -1822,4 +1920,108 @@
     })
   })
 
+}(window.jQuery);
+/* ==========================================================
+ * bootstrap-affix.js v2.1.0
+ * http://twitter.github.com/bootstrap/javascript.html#affix
+ * ==========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================================================== */
+
+
+!function ($) {
+
+  "use strict"; // jshint ;_;
+
+
+ /* AFFIX CLASS DEFINITION
+  * ====================== */
+
+  var Affix = function (element, options) {
+    this.options = $.extend({}, $.fn.affix.defaults, options)
+    this.$window = $(window).on('scroll.affix.data-api', $.proxy(this.checkPosition, this))
+    this.$element = $(element)
+    this.checkPosition()
+  }
+
+  Affix.prototype.checkPosition = function () {
+    if (!this.$element.is(':visible')) return
+
+    var scrollHeight = $(document).height()
+      , scrollTop = this.$window.scrollTop()
+      , position = this.$element.offset()
+      , offset = this.options.offset
+      , offsetBottom = offset.bottom
+      , offsetTop = offset.top
+      , reset = 'affix affix-top affix-bottom'
+      , affix
+
+    if (typeof offset != 'object') offsetBottom = offsetTop = offset
+    if (typeof offsetTop == 'function') offsetTop = offset.top()
+    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom()
+
+    affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ?
+      false    : offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ?
+      'bottom' : offsetTop != null && scrollTop <= offsetTop ?
+      'top'    : false
+
+    if (this.affixed === affix) return
+
+    this.affixed = affix
+    this.unpin = affix == 'bottom' ? position.top - scrollTop : null
+
+    this.$element.removeClass(reset).addClass('affix' + (affix ? '-' + affix : ''))
+  }
+
+
+ /* AFFIX PLUGIN DEFINITION
+  * ======================= */
+
+  $.fn.affix = function (option) {
+    return this.each(function () {
+      var $this = $(this)
+        , data = $this.data('affix')
+        , options = typeof option == 'object' && option
+      if (!data) $this.data('affix', (data = new Affix(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  $.fn.affix.Constructor = Affix
+
+  $.fn.affix.defaults = {
+    offset: 0
+  }
+
+
+ /* AFFIX DATA-API
+  * ============== */
+
+  $(window).on('load', function () {
+    $('[data-spy="affix"]').each(function () {
+      var $spy = $(this)
+        , data = $spy.data()
+
+      data.offset = data.offset || {}
+
+      data.offsetBottom && (data.offset.bottom = data.offsetBottom)
+      data.offsetTop && (data.offset.top = data.offsetTop)
+
+      $spy.affix(data)
+    })
+  })
+
+
 }(window.jQuery);

+ 16 - 2
main/inc/lib/jpegcam/webcam_receiver.php

@@ -75,13 +75,27 @@ if (!$content) {
 	exit();
 }
 
+
+//make a temporal file for get the file size
+	$tmpfname = tempnam("/tmp", "CTF");
+	$handle = fopen($tmpfname, "w");
+	fwrite($handle, $content);
+	fclose($handle);
+	
+	// Check if there is enough space in the course to save the file
+	if (!DocumentManager::enough_space(filesize($tmpfname), DocumentManager::get_course_quota())) {
+		unlink($tmpfname);
+		die(get_lang('UplNotEnoughSpace'));
+	}
+	
+	//erase temporal file
+	unlink($tmpfname);
+
 //add to disk
 $fh = fopen($documentPath, 'w') or die("can't open file");
 fwrite($fh, $content);
 fclose($fh);
 
-
-//
 //add document to database
 	$doc_id = add_document($_course, $webcamdir.'/'.$webcamname_to_save, 'file', filesize($documentPath), $title_to_save);
 	api_item_property_update($_course, TOOL_DOCUMENT, $doc_id, 'DocumentAdded', $_user['user_id'], $groupId, null, null, null, $current_session_id);

+ 6 - 0
main/inc/lib/mail.lib.inc.php

@@ -163,6 +163,12 @@ function api_mail_html($recipient_name, $recipient_email, $subject, $message, $s
     if (is_array($extra_headers) && count($extra_headers) > 0) {
         foreach ($extra_headers as $key => $value) {
             switch (strtolower($key)) {
+                case 'reply-to':
+                    //the value here is the result of api_get_user_info()
+                    $sender_email = $value['email'];
+                    $sender_name  = $value['complete_name'];
+                    $mail->AddReplyTo($sender_email, $sender_name);
+                    break;
                 case 'encoding':
                 case 'content-transfer-encoding':
                     $mail->Encoding = $value;

+ 12 - 7
main/inc/lib/main_api.lib.php

@@ -810,9 +810,11 @@ function api_protect_course_script($print_headers = false, $allow_session_admins
     if (api_is_drh()) {
         return true;
     }
+    
     if (api_is_platform_admin($allow_session_admins)) {
     	return true;
     }
+    
     $course_info = api_get_course_info();
 
     if (isset($course_info) && isset($course_info['visibility'])) {
@@ -838,7 +840,7 @@ function api_protect_course_script($print_headers = false, $allow_session_admins
     			break;
     	}
     }
-        
+    
     //Check session visibility
     $session_id = api_get_session_id();
     
@@ -1836,7 +1838,7 @@ function api_get_session_visibility($session_id) {
 
         if (Database::num_rows($result) > 0 ) {
             $row = Database::fetch_array($result, 'ASSOC');
-            $visibility = $row['visibility'];
+            $visibility = $original_visibility = $row['visibility'];
 
             //I don't care the field visibility
             if ($row['date_start'] == '0000-00-00' && $row['date_end'] == '0000-00-00') {
@@ -1908,7 +1910,14 @@ function api_get_session_visibility($session_id) {
                         $visibility = SESSION_INVISIBLE;
                     }
                 }
+            } else {
+                //Student - check the moved_to variable
+                $user_status = SessionManager::get_user_status_in_session($session_id, api_get_user_id());
+                if (isset($user_status['moved_to']) && $user_status['moved_to'] != 0) {
+                    return $original_visibility;
+                }
             }
+            
         } else {
             $visibility = SESSION_INVISIBLE;
         }
@@ -2612,10 +2621,6 @@ function api_is_allowed_to_session_edit($tutor = false, $coach = false) {
             // Get the session visibility
             $session_visibility = api_get_session_visibility($session_id);  // if 5 the session is still available
             
-            //@todo We could load the session_rel_course_rel_user permission to increase the level of detail.
-            //echo api_get_user_id();
-            //echo api_get_course_id();
-
             switch ($session_visibility) {
                 case SESSION_VISIBLE_READ_ONLY: // 1
                     return false;
@@ -2623,7 +2628,7 @@ function api_is_allowed_to_session_edit($tutor = false, $coach = false) {
                     return true;
                 case SESSION_INVISIBLE:         // 3
                     return false;
-                case SESSION_AVAILABLE:         //5
+                case SESSION_AVAILABLE:         //4
                     return true;
             }
 

+ 15 - 33
main/inc/lib/message.lib.php

@@ -43,34 +43,7 @@ class MessageManager
 		}
 		return $online_user_list;
 	}
-
-	/**
-	* Displays info stating that the message is sent successfully.
-	*/
-	public static function display_success_message($uid) {
-			global $charset;
-		if ($_SESSION['social_exist']===true) {
-			$redirect="#remote-tab-2";
-			if (api_get_setting('allow_social_tool')=='true' && api_get_setting('allow_message_tool')=='true') {
-				$success=get_lang('MessageSentTo').
-				"&nbsp;<b>".
-				GetFullUserName($uid).
-				"</b>";
-			}else {
-				$success=get_lang('MessageSentTo').
-				"&nbsp;<b>".
-				GetFullUserName($uid).
-				"</b>";
-			}
-		} else {
-				$success=get_lang('MessageSentTo').
-				"&nbsp;<b>".
-				GetFullUserName($uid).
-				"</b>";
-		}
-		return Display::return_message(api_xml_http_response_encode($success), 'confirmation', false);
-	}
-
+    
 	/**
 	* Displays the wysiwyg html editor.
 	*/
@@ -207,7 +180,7 @@ class MessageManager
      * @param int    sender id (optional) the default value is the current user_id
 	 * @return bool
 	 */
-	public static function send_message($receiver_user_id, $subject, $content, $file_attachments = array(), $file_comments = array(), $group_id = 0, $parent_id = 0, $edit_message_id = 0, $topic_id = 0, $sender_id = null) {        
+	public static function send_message($receiver_user_id, $subject, $content, $file_attachments = array(), $file_comments = array(), $group_id = 0, $parent_id = 0, $edit_message_id = 0, $topic_id = 0, $sender_id = null) {
 		$table_message      = Database::get_main_table(TABLE_MESSAGE);
         $group_id           = intval($group_id);
         $receiver_user_id   = intval($receiver_user_id);
@@ -215,6 +188,10 @@ class MessageManager
         $edit_message_id    = intval($edit_message_id);
         $topic_id   		= intval($topic_id);
         
+        //Capturing the original sender id 
+        $original_sender_id = $user_sender_id;
+        
+        //Saving the user id for the chamilo inbox, if the sender is null we asume that the current user is the one that sent the message
         if (empty($sender_id)) {        
             $user_sender_id     = api_get_user_id();
         } else {
@@ -292,9 +269,14 @@ class MessageManager
 						
 			//Load user settings			
 			$notification = new Notification();
-			$sender_info = api_get_user_info($user_sender_id);
-			
-		    if (empty($group_id)) {	    	
+            
+		    if (empty($group_id)) {
+                
+                $sender_info = array();
+                if (!empty($original_sender_id)) {
+                    $sender_info = api_get_user_info($original_sender_id);
+                }
+
                 $notification->save_notification(NOTIFICATION_TYPE_MESSAGE, array($receiver_user_id), $subject, $content, $sender_info);                
 		    } else {
 		        $group_info = GroupPortalManager::get_group_data($group_id);
@@ -310,7 +292,7 @@ class MessageManager
                 foreach($user_list as $user_data) {
                     $new_user_list[] = $user_data['user_id'];
                 }
-                $group_info = array('group_info'=>$group_info, 'user_info' => $sender_info);
+                $group_info = array('group_info' => $group_info, 'user_info' => $sender_info);
                 $notification->save_notification(NOTIFICATION_TYPE_GROUP, $new_user_list, $subject, $content, $group_info);                     		
 		    }
 			return $inbox_last_id;

+ 5 - 0
main/inc/lib/nanogong/receiver.php

@@ -57,6 +57,11 @@ if ($nano_user_id!= api_get_user_id() || api_get_user_id()==0 || $nano_user_id==
 
 //Do not use here check Fileinfo method because return: text/plain
 
+// Check if there is enough space in the course to save the file
+if (!DocumentManager::enough_space(filesize($_FILES['voicefile']['tmp_name']), DocumentManager::get_course_quota())) {
+	die(get_lang('UplNotEnoughSpace'));
+}
+
 if (!file_exists($documentPath)){
 	//add document to disk
 	move_uploaded_file($_FILES['voicefile']['tmp_name'], $documentPath);

+ 47 - 20
main/inc/lib/notification.lib.php

@@ -41,26 +41,30 @@ define('NOTIFICATION_TYPE_GROUP',         3);
 class Notification extends Model {
     
     var $table;
-    var $columns             = array('id','dest_user_id','dest_mail','title','content','send_freq','created_at','sent_at');
+    var $columns             = array('id', 'dest_user_id', 'sender_id', 'dest_mail', 'title', 'content', 'send_freq', 'created_at', 'sent_at');
     var $max_content_length  = 254; //Max lenght of the notification.content field
     var $debug               = false;
     
     /* message, invitation, group messages */
     var $type;    
-    var $admin_name;
-    var $admin_email;
+    var $sender_name;
+    var $sender_email;
+    
+    var $extra_headers = array();
+    
+    var $send_email_as_user = false; //False, chamilo will sent an email as the user (not recommended)
     
 	public function __construct() {
         $this->table       = Database::get_main_table(TABLE_NOTIFICATION);
            
-        $this->admin_email  = api_get_setting('noreply_email_address');
-        $this->admin_name   = api_get_setting('siteName');
+        $this->sender_email  = api_get_setting('noreply_email_address');
+        $this->sender_name   = api_get_setting('siteName');
         
         // If no-reply  email doesn't exist use the admin email
-        if (empty($this->admin_email)) {            
-            $this->admin_email = api_get_setting('emailAdministrator');
-            $this->admin_name  = api_get_person_name(api_get_setting('administratorName'), api_get_setting('administratorSurname'), null, PERSON_NAME_EMAIL_ADDRESS);            
-        }
+        if (empty($this->sender_email)) {            
+            $this->sender_email = api_get_setting('emailAdministrator');
+            $this->sender_name  = api_get_person_name(api_get_setting('administratorName'), api_get_setting('administratorSurname'), null, PERSON_NAME_EMAIL_ADDRESS);            
+        }        
 	}  
 	  
     /**
@@ -68,19 +72,21 @@ class Notification extends Model {
      *  @param int notification frecuency 
      */	
     public function send($frec = NOTIFY_MESSAGE_DAILY) {
-        $notifications = $this->find('all',array('where'=>array('sent_at IS NULL AND send_freq = ?'=>$frec)));
-     
+        $notifications = $this->find('all', array('where'=> array('sent_at IS NULL AND send_freq = ?' => $frec)));     
         
         if (!empty($notifications)) {
             foreach ($notifications as $item_to_send) {
                 
+                $this->set_sender_info($item_to_send['sender_id']);
+                
                 //Sending email
                 api_mail_html($item_to_send['dest_mail'], 
                               $item_to_send['dest_mail'], 
                               Security::filter_terms($item_to_send['title']), 
                               Security::filter_terms($item_to_send['content']), 
-                              $this->admin_name, 
-                              $this->admin_email
+                              $this->sender_name, 
+                              $this->sender_email, 
+                              $this->extra_headers
                             );
                 if ($this->debug) { error_log('Sending message to: '.$item_to_send['dest_mail']); }
                 
@@ -92,6 +98,21 @@ class Notification extends Model {
         }                
     }
     
+    /**
+     * Sets the sender info in order to add the reply-to
+     */
+    function set_sender_info($user_id) {
+        if (!empty($user_id)) {
+            $sender_user_info = api_get_user_info($user_id);            
+            if ($this->send_email_as_user) {                
+                $this->sender_email = $sender_user_info['email'];
+                $this->sender_name  = $sender_user_info['complete_name'];          
+            } else {
+                $this->extra_headers = array('reply-to' => $sender_user_info);
+            }
+        }
+    }
+    
     /**
      * Save message notification
      * @param	array	message type NOTIFICATION_TYPE_MESSAGE, NOTIFICATION_TYPE_INVITATION, NOTIFICATION_TYPE_GROUP
@@ -103,11 +124,17 @@ class Notification extends Model {
     public function save_notification($type, $user_list, $title, $content, $sender_info = array()) {
         $this->type = intval($type);
         $content    = $this->format_content($content, $sender_info);
+        
+        $sender_id = 0;
+        if (!empty($sender_info) && isset($sender_info['user_id'])) {
+            $sender_id = $sender_info['user_id'];
+            $this->set_sender_info($sender_id);
+        }        
                 
         $setting_to_check = '';
         $avoid_my_self  = false;
         
-        switch($this->type) {
+        switch ($this->type) {
             case NOTIFICATION_TYPE_MESSAGE;
                 $setting_to_check = 'mail_notify_message';
                 break;
@@ -145,7 +172,7 @@ class Notification extends Model {
                     case NOTIFY_GROUP_AT_ONCE:                     
                         if (!empty($user_info['mail'])) {
                             $name = api_get_person_name($user_info['firstname'], $user_info['lastname']);                            
-                            api_mail_html($name, $user_info['mail'], Security::filter_terms($title), Security::filter_terms($content), $this->admin_name, $this->admin_email);
+                            api_mail_html($name, $user_info['mail'], Security::filter_terms($title), Security::filter_terms($content), $this->sender_name, $this->sender_email, $this->extra_headers);
                         }
                         $params['sent_at']       = api_get_utc_datetime();
                     //Saving the notification to be sent some day 
@@ -154,7 +181,8 @@ class Notification extends Model {
                 	    $params['dest_mail']     = $user_info['mail'];
                 	    $params['title']         = $title;
                 	    $params['content']       = cut($content, $this->max_content_length);
-                	    $params['send_freq']     = $user_setting;    			 
+                	    $params['send_freq']     = $user_setting;  			 
+                        $params['sender_id']     = $sender_id;
                 	    $this->save($params);
                 	    break;
                 }          
@@ -170,11 +198,10 @@ class Notification extends Model {
     public function format_content($content, $sender_info) {
         $new_message_text = $link_to_new_message = '';        
         
-        switch($this->type) {
+        switch ($this->type) {
             case NOTIFICATION_TYPE_MESSAGE:           
                 if (!empty($sender_info)) {
-                    $sender_name = api_get_person_name($sender_info['firstname'], $sender_info['lastname'], null, PERSON_NAME_EMAIL_ADDRESS);
-                    //$sender_mail = $sender_info['email'] ;            
+                    $sender_name = api_get_person_name($sender_info['firstname'], $sender_info['lastname'], null, PERSON_NAME_EMAIL_ADDRESS);                             
                     $new_message_text = sprintf(get_lang('YouHaveANewMessageFromX'), $sender_name);            
                 }
                 $link_to_new_message = Display::url(get_lang('SeeMessage'), api_get_path(WEB_CODE_PATH).'messages/inbox.php');
@@ -214,7 +241,7 @@ class Notification extends Model {
         }
               
         // You have received this message because you are subscribed text
-        $content        = $content.'<br /><hr><i>'.
+        $content = $content.'<br /><hr><i>'.
                           sprintf(get_lang('YouHaveReceivedThisNotificationBecauseYouAreSubscribedOrInvolvedInItToChangeYourNotificationPreferencesPleaseClickHereX'), Display::url($preference_url, $preference_url)).'</i>';
         return $content;        
     }

+ 13 - 15
main/inc/lib/online.inc.php

@@ -20,7 +20,7 @@
 use \ChamiloSession as Session;
 
 function LoginCheck($uid) {
-	global $_course, $_configuration;
+	global $_course;
 	$uid = (int) $uid;
 	$online_table = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_ONLINE);
 	if (!empty($uid)) {
@@ -52,7 +52,7 @@ function LoginCheck($uid) {
  * @author Fernando P. García <fernando@develcuy.com>
  */
 function online_logout($user_id = null, $logout_redirect = false) {
-    global $_configuration, $extAuthSource;
+    global $extAuthSource;
   
     // Database table definition
     $tbl_track_login = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_LOGIN);
@@ -129,21 +129,19 @@ function user_is_online($user_id) {
 	$current_date		= api_get_utc_datetime();	
 	$access_url_id		= api_get_current_access_url_id();	
 	$time_limit			= api_get_setting('time_limit_whosonline');
-	//$time_limit = 1; changing this value there is no time limit 
-	
+		
 	$query = " SELECT login_user_id,login_date FROM ".$track_online_table ." track INNER JOIN ".$table_user ." u ON (u.user_id=track.login_user_id)
                WHERE track.access_url_id =  $access_url_id AND 
-                    DATE_ADD(login_date,INTERVAL $time_limit MINUTE) >= '".$current_date."'  AND 
+                    DATE_ADD(login_date, INTERVAL $time_limit MINUTE) >= '".$current_date."'  AND 
                     u.user_id =  $user_id 
-               LIMIT 1 ";
-	
+               LIMIT 1 ";	
 	$result = Database::query($query);
 	if (Database::num_rows($result)) {
 		return true;
 	}
-	return false;
-	
+	return false;	
 }
+
 /**
  * Gives a list of people online now (and in the last $valid minutes) 
  * @return  array       For each line, a list of user IDs and login dates, or FALSE on error or empty results
@@ -279,16 +277,16 @@ function who_is_online_count($time_limit = null, $friends = false) {
 				$query = "SELECT DISTINCT count(login_user_id) as count
 							FROM $track_online_table track
 							INNER JOIN $friend_user_table ON (friend_user_id = login_user_id)
-							WHERE track.access_url_id =  $access_url_id AND login_date >= '".$current_date."' AND friend_user_id <> '".api_get_user_id()."' AND relation_type='".USER_RELATION_TYPE_FRIEND."'  ";
+							WHERE track.access_url_id = $access_url_id AND login_date >= '".$current_date."' AND friend_user_id <> '".api_get_user_id()."' AND relation_type='".USER_RELATION_TYPE_FRIEND."'  ";
 			} else {
 				// all users online
-				$query = "SELECT count(login_id) as count FROM $track_online_table  track
-						  WHERE login_user_id <> 2 AND track.access_url_id =  $access_url_id AND login_date >= '$current_date' ";
+				$query = "SELECT count(login_id) as count FROM $track_online_table track
+						  WHERE login_user_id <> 2 AND track.access_url_id = $access_url_id AND login_date >= '$current_date' ";
 			}
 		}
 	}
     
-    //dev purposes show all users online
+    //Dev purposes show all users online
     
     /*$table_user = Database::get_main_table(TABLE_MAIN_USER);
     $query = "SELECT count(*)  as count FROM ".$table_user ."   ";*/
@@ -322,7 +320,7 @@ function who_is_online_in_this_course($from, $number_of_items, $uid, $time_limit
     $online_time 		= time() - $time_limit*60;
     $current_date		= api_get_utc_datetime($online_time);	
     $track_online_table = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_ONLINE);
-    $course_code         = Database::escape_string($course_code);
+    $course_code        = Database::escape_string($course_code);
     
     $from            = intval($from);
     $number_of_items = intval($number_of_items);
@@ -338,7 +336,7 @@ function who_is_online_in_this_course($from, $number_of_items, $uid, $time_limit
         $valid_date_time->sub(new DateInterval($diff));
 		$users_online = array();
 
-		while(list($login_user_id, $login_date) = Database::fetch_row($result)) {
+		while (list($login_user_id, $login_date) = Database::fetch_row($result)) {
             $user_login_date = new DateTime($login_date);            
 			if ($user_login_date > $valid_date_time) {
 				$users_online[] = $login_user_id;

+ 318 - 29
main/inc/lib/sessionmanager.lib.php

@@ -11,10 +11,35 @@
  * Code
  */
 
-class SessionManager {    
-	private function __construct() {
+class SessionManager {
+    
+    //See BT#4871
+    CONST SESSION_CHANGE_USER_REASON_SCHEDULE = 1;
+    CONST SESSION_CHANGE_USER_REASON_CLASSROOM = 2;
+    CONST SESSION_CHANGE_USER_REASON_LOCATION = 3;
+    CONST SESSION_CHANGE_USER_REASON_ENROLLMENT_ANNULATION = 4;    
+
+	private function __construct() {        
 	}
     
+    public static function get_session_info($session_id) {
+        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
+        $tbl_user    = Database::get_main_table(TABLE_MAIN_USER);
+        
+        $sql = 'SELECT name, nbr_courses, nbr_users, nbr_classes, 
+                DATE_FORMAT(date_start,"%d-%m-%Y") as date_start, 
+                DATE_FORMAT(date_end,"%d-%m-%Y") as date_end, lastname, firstname, username, session_admin_id, 
+                nb_days_access_before_beginning, 
+                nb_days_access_after_end, 
+                session_category_id, 
+                visibility
+                FROM '.$tbl_session.' LEFT JOIN '.$tbl_user.' ON id_coach = user_id
+                WHERE '.$tbl_session.'.id='.$session_id;
+        $rs      = Database::query($sql);
+        $session = Database::store_result($rs);
+        return $session[0];
+    }
+    
     /**
      * Fetches a session from the database
      * @param   int     Session ID
@@ -218,12 +243,12 @@ class SessionManager {
      * Gets the admin session list callback of the admin/session_list.php page
      * @param array order and limit keys
      */
-	public static function get_sessions_admin($options) {
+	public static function get_sessions_admin($options = array()) {
 		$tbl_session            = Database::get_main_table(TABLE_MAIN_SESSION);
 		$tbl_session_category   = Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY);        
 		$tbl_user               = Database::get_main_table(TABLE_MAIN_USER);        
 
-		$where = 'WHERE 1=1 ';
+		$where = 'WHERE 1 = 1 ';
 		$user_id = api_get_user_id();
         
 		if (api_is_session_admin() && api_get_setting('allow_session_admins_to_manage_all_sessions') == 'false') {
@@ -273,9 +298,11 @@ class SessionManager {
 		if (!empty($options['where'])) {
 		   $query .= ' WHERE '.$options['where']; 
 		}
-
-		$query .= " ORDER BY ".$options['order']." LIMIT ".$options['limit'];
-
+        
+        if (!empty($options['order']) && !empty($options['limit'])) {
+            $query .= " ORDER BY ".$options['order']." LIMIT ".$options['limit'];
+        }
+        
 		$result = Database::query($query);
 		$formatted_sessions = array();
 		if (Database::num_rows($result)) {
@@ -648,6 +675,7 @@ class SessionManager {
 	                $enreg_user = Database::escape_string($enreg_user);
 					$insert_sql = "INSERT IGNORE INTO $tbl_session_rel_course_rel_user(id_session, course_code, id_user, visibility, status) VALUES('$id_session','$enreg_course','$enreg_user','$session_visibility', '0')";
 					Database::query($insert_sql);
+                    
 					if(Database::affected_rows()) {
 						$nbr_users++;
 					}
@@ -670,10 +698,14 @@ class SessionManager {
 		// Insert missing users into session
 		$nbr_users = 0;		
 		foreach ($user_list as $enreg_user) {
-	        $enreg_user = Database::escape_string($enreg_user);
-			$nbr_users++;
-			$insert_sql = "INSERT IGNORE INTO $tbl_session_rel_user (id_session, id_user) VALUES ('$id_session','$enreg_user')";
-			Database::query($insert_sql);
+	        $enreg_user = Database::escape_string($enreg_user);			
+			$insert_sql = "INSERT IGNORE INTO $tbl_session_rel_user (id_session, id_user) VALUES ('$id_session','$enreg_user')";			
+            Database::query($insert_sql);
+            
+            //Reset moved_to just in case
+            $update_sql = "UPDATE $tbl_session_rel_user SET moved_to = 0 , moved_status = 0, moved_at ='0000-00-00 00:00:00' WHERE  id_session = $id_session AND id_user = $enreg_user";                        
+            Database::query($update_sql);
+            $nbr_users++;
 		}
 
 		// update number of users in the session
@@ -686,6 +718,8 @@ class SessionManager {
             $update_sql = "UPDATE $tbl_session SET nbr_users= nbr_users + $nbr_users WHERE id='$id_session' ";
             Database::query($update_sql);           
         }
+
+
 	}
     
     function subscribe_users_to_session_course($user_list, $session_id, $course_code, $session_visibility = SESSION_VISIBLE_READ_ONLY ) {
@@ -724,13 +758,15 @@ class SessionManager {
 	/**
 	 * Unsubscribe user from session
 	 *
-	 * @param int Session id
-	 * @param int User id
-	 * @return bool True in case of success, false in case of error
+	 * @param int session id
+	 * @param int user id
+     * @param int reason of unsubscription see function get_session_change_user_reasons()
+	 * @return bool true in case of success, false in case of error
 	 */
 	public static function unsubscribe_user_from_session($session_id, $user_id) {
-		$session_id = (int)$session_id;
-		$user_id = (int)$user_id;
+		$session_id = intval($session_id);
+		$user_id = intval($user_id);
+        $reason_id = intval($reason_id);
 
 		$tbl_session_rel_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
 		$tbl_session_rel_course	= Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
@@ -742,26 +778,52 @@ class SessionManager {
 		$return = Database::affected_rows();
 
 		// Update number of users
-		$update_sql = "UPDATE $tbl_session SET nbr_users= nbr_users - $return WHERE id='$session_id' ";
+		$update_sql = "UPDATE $tbl_session SET nbr_users = nbr_users - $return WHERE id='$session_id' ";
 		Database::query($update_sql);
 
 		// Get the list of courses related to this session
 		$course_list = SessionManager::get_course_list_by_session_id($session_id);
-		if(!empty($course_list)) {
+        
+		if (!empty($course_list)) {
 			foreach($course_list as $course) {
 				$course_code = $course['code'];
 				// Delete user from course
 				Database::query("DELETE FROM $tbl_session_rel_course_rel_user WHERE id_session='$session_id' AND course_code='$course_code' AND id_user='$user_id'");
+                
 				if(Database::affected_rows()) {
 					// Update number of users in this relation
 					Database::query("UPDATE $tbl_session_rel_course SET nbr_users=nbr_users - 1 WHERE id_session='$session_id' AND course_code='$course_code'");
 				}
 			}
-		}
-
+		}  
 		return true;
-
 	}
+    
+    /**
+     * 
+     * @param int $session_id
+     * @param array user id list
+     * @param string $course_code
+     */
+    static function unsubscribe_user_from_course_session($session_id, $user_list, $course_code) {
+        $tbl_session_rel_course             = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
+        $tbl_session_rel_course_rel_user    = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
+
+        if (is_array($user_list) && count($user_list)>0 ) {
+            array_map('intval', $user_list);
+            $user_list = implode(',', $user_list);
+        }
+        $session_id = intval($session_id);
+        $course_code = Database::escape_string($course_code);
+        
+        if (!empty($user_list)) {
+            Database::query("DELETE FROM $tbl_session_rel_course_rel_user WHERE id_session='$session_id' AND course_code='".$course_code."' AND id_user IN($user_list)");
+            $nbr_affected_rows = Database::affected_rows();
+            Database::query("UPDATE $tbl_session_rel_course SET nbr_users=nbr_users-$nbr_affected_rows WHERE id_session='$session_id' AND course_code='".$course_code."'");
+        }        
+    }
+    
+    
 
 	 /** Subscribes courses to the given session and optionally (default) unsubscribes previous users
 	 * @author Carlos Vargas from existing code
@@ -1518,20 +1580,36 @@ class SessionManager {
     public static function get_users_by_session($id, $with_status = null) {
         if (empty($id)) {
             return array();
-        }
-        $id = intval($id);
+        }     
         $tbl_user               = Database::get_main_table(TABLE_MAIN_USER);
         $tbl_session_rel_user   = Database::get_main_table(TABLE_MAIN_SESSION_USER);
-
-        $sql = "SELECT $tbl_user.user_id, lastname, firstname, username
-                FROM $tbl_user INNER JOIN $tbl_session_rel_user
-                    ON $tbl_user.user_id = $tbl_session_rel_user.id_user 
-                    AND $tbl_session_rel_user.id_session = $id";
+        
+        $id = intval($id);
+        
+        if (api_is_multiple_url_enabled()) {
+            $url_id = api_get_current_access_url_id();   
+            $sql = "SELECT u.user_id, lastname, firstname, username, access_url_id, moved_to, moved_status, moved_at
+                FROM $tbl_user u
+                INNER JOIN $tbl_session_rel_user su
+                ON u.user_id = su.id_user AND su.relation_type<>".SESSION_RELATION_TYPE_RRHH."
+                LEFT OUTER JOIN $tbl_session_rel_user uu ON (uu.user_id = u.user_id)
+                WHERE su.id_session = $id AND (access_url_id = $url_id OR access_url_id is null )";
+        } else {
+            $sql = "SELECT u.user_id, lastname, firstname, username, moved_to, moved_status, moved_at
+                    FROM $tbl_user u INNER JOIN $tbl_session_rel_user su
+                    ON  u.user_id = su.id_user  AND 
+                        su.id_session = $id                                            
+                    ";
+        }
         
         if (isset($with_status) && $with_status != '') {
         	$with_status = intval($with_status);
         	$sql .= " WHERE relation_type = $with_status ";
         }
+        
+        $order_clause = api_sort_by_first_name() ? ' ORDER BY firstname, lastname' : ' ORDER BY lastname, firstname';
+    
+        $sql .= $order_clause;
                 
         $result = Database::query($sql);
         while ($row = Database::fetch_array($result,'ASSOC')) {
@@ -1570,7 +1648,7 @@ class SessionManager {
      * @param $session_id
      * @return unknown_type
      */
-    public static function get_user_status_in_session($user_id, $course_code, $session_id) {
+    public static function get_user_status_in_course_session($user_id, $course_code, $session_id) {
         $tbl_session_rel_course_rel_user    = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
         $tbl_user                           = Database::get_main_table(TABLE_MAIN_USER);        
         $sql = "SELECT session_rcru.status
@@ -1587,6 +1665,17 @@ class SessionManager {
         }
         return $status;
     }
+            
+    static function get_user_status_in_session($session_id, $user_id) {
+        $tbl_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
+        $sql = "SELECT * FROM $tbl_session_rel_user WHERE id_user = $user_id AND id_session = $session_id";
+        $result = Database::query($sql);
+        if (Database::num_rows($result)) {
+            $result = Database::store_result($result, 'ASSOC');
+            return $result[0];
+        }
+        return array();
+    }
     
     function get_all_sessions_by_promotion($id) {
         $t = Database::get_main_table(TABLE_MAIN_SESSION);
@@ -1774,6 +1863,9 @@ class SessionManager {
     static function protect_session_edit($id) {
         api_protect_admin_script(true);
         $session_info = self::fetch($id);
+        if (empty($session_info)) {
+            api_not_allowed(true);
+        }
         if (!api_is_platform_admin() && api_get_setting('allow_session_admins_to_manage_all_sessions') != 'true') {
             if ($session_info['session_admin_id'] != api_get_user_id()) {
                 api_not_allowed(true);
@@ -1791,6 +1883,201 @@ class SessionManager {
         return Database::store_result($result);
     }
     
+    /**
+     *  @todo Add constatns in a DB table
+     */
+    static function get_session_change_user_reasons() {
+        return array (
+            self::SESSION_CHANGE_USER_REASON_SCHEDULE => get_lang('ScheduleChanged'),
+            self::SESSION_CHANGE_USER_REASON_CLASSROOM => get_lang('ClassRoomChanged'),
+            self::SESSION_CHANGE_USER_REASON_LOCATION => get_lang('LocationChanged'),
+            self::SESSION_CHANGE_USER_REASON_ENROLLMENT_ANNULATION => get_lang('EnrollmentAnnulation'),
+        );
+    }
+    
+    /** 
+     * Gets the reason name 
+     * @param int reason id
+     */
+    static function get_session_change_user_reason($id) {
+        $reasons = self::get_session_change_user_reasons();
+        return isset($reasons[$id]) ? $reasons[$id] : null;        
+    }
+    
+    /**
+     * Changes the user from one session to another due a reason
+     */
+    static function change_user_session($user_id, $old_session_id, $new_session_id, $reason_id) {
+        if (!empty($user_id) && !empty($old_session_id) && !empty($new_session_id)) {
+            $user_id = intval($user_id);
+            $old_session_id = intval($old_session_id);
+            $new_session_id = intval($new_session_id);
+            $reason_id = intval($reason_id);
+            
+            //self::unsubscribe_user_from_session($old_session_id, $user_id, $reason_id);             
+            
+            //$tbl_session_rel_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
+            $tbl_session_rel_course	= Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
+            $tbl_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
+            $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
+
+            // Update number of users
+            $update_sql = "UPDATE $tbl_session SET nbr_users = nbr_users - 1 WHERE id = '$old_session_id' ";
+            Database::query($update_sql);
+
+            // Get the list of courses related to this session
+            $course_list = SessionManager::get_course_list_by_session_id($old_session_id);
+            if (!empty($course_list)) {
+                foreach ($course_list as $course) {
+                    $course_code = $course['code'];
+                    // Delete user from course
+                    //Database::query("DELETE FROM $tbl_session_rel_course_rel_user WHERE id_session='$session_id' AND course_code='$course_code' AND id_user='$user_id'");
+                    //if (Database::affected_rows()) {
+                        // Update number of users in this relation
+                        $sql = "UPDATE $tbl_session_rel_course SET nbr_users = nbr_users - 1 WHERE id_session = '$old_session_id' AND course_code='$course_code'";                    
+                        Database::query($sql);
+                    //}
+                }
+            }
+            
+            //Deal with reasons
+            switch ($reason_id) {
+                case self::SESSION_CHANGE_USER_REASON_SCHEDULE:
+                case self::SESSION_CHANGE_USER_REASON_CLASSROOM:
+                case self::SESSION_CHANGE_USER_REASON_LOCATION:                       
+                    //Adding to the new session
+                    self::suscribe_users_to_session($new_session_id, array($user_id), null, false);
+                    
+                    //Setting move_to if session was provided
+                    $sql = "UPDATE $tbl_session_rel_user SET moved_to = '$new_session_id'
+                            WHERE id_session = '$old_session_id' AND id_user ='$user_id'";
+                    Database::query($sql);
+                    break;               
+                case self::SESSION_CHANGE_USER_REASON_ENROLLMENT_ANNULATION:
+                    UserManager::deactivate_users(array($user_id));
+                    break;
+            }
+            
+            $now = api_get_utc_datetime();            
+            //Setting the moved_status
+            $sql = "UPDATE $tbl_session_rel_user SET moved_status = $reason_id, moved_at = '$now'
+                    WHERE id_session = '$old_session_id' AND id_user ='$user_id'";            
+            Database::query($sql);
+            
+            return true;            
+        }
+        return;
+    }
+
+    
+    /**
+     * Get users inside a course session
+     */    
+    static function get_users_in_course_session($course_code, $id_session, $sort, $direction, $from = null, $limit = null) {
+        $tbl_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
+        $tbl_session_rel_course_rel_user	= Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
+        $tbl_user                           = Database::get_main_table(TABLE_MAIN_USER);
+        
+        $course_code = Database::escape_string($course_code);
+        $id_session  = Database::escape_string($id_session);
+        $from = intval($from);
+        $limit = intval($limit);
+        
+        $is_western_name_order = api_is_western_name_order();
+                
+        //Select the number of users
+		$sql = " SELECT DISTINCT u.user_id,".($is_western_name_order ? 'u.firstname, u.lastname' : 'u.lastname, u.firstname').", u.username, scru.id_user as is_subscribed 
+                 FROM $tbl_session_rel_user sru INNER JOIN $tbl_user u ON (u.user_id=sru.id_user) 
+                      LEFT JOIN $tbl_session_rel_course_rel_user scru ON (u.user_id = scru.id_user AND  scru.course_code = '".$course_code."' )
+                 WHERE  sru.id_session = '$id_session' AND
+                        sru.moved_to = 0 AND sru.moved_status <> ".SessionManager::SESSION_CHANGE_USER_REASON_ENROLLMENT_ANNULATION." AND
+                        sru.relation_type<>".SESSION_RELATION_TYPE_RRHH;
+        $sql .= " ORDER BY $sort $direction ";
+        
+        if (!empty($from) && !empty($limit)) {
+            $sql .= " LIMIT $from, $limit";    
+        }        
+        
+		$result = Database::query($sql);
+        if (Database::num_rows($result)) {
+            return Database::store_result($result);
+        }
+        return false;
+    }
+    
+    static function get_count_users_in_course_session($course_code, $id_session) {
+        $tbl_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
+        $tbl_session_rel_course_rel_user	= Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
+        
+        //Select the number of users
+		$sql = " SELECT count(*) FROM $tbl_session_rel_user sru, $tbl_session_rel_course_rel_user srcru
+				 WHERE  srcru.id_user = sru.id_user AND 
+                        srcru.id_session = sru.id_session AND 
+                        srcru.course_code = '".Database::escape_string($course_code)."' AND 
+                        srcru.id_session = '".intval($id_session)."'  AND
+                        (sru.moved_to = 0 AND sru.moved_status <> ".SessionManager::SESSION_CHANGE_USER_REASON_ENROLLMENT_ANNULATION.") AND
+                        sru.relation_type<>".SESSION_RELATION_TYPE_RRHH;
+
+		$result = Database::query($sql);
+        if (Database::num_rows($result)) {
+            return Database::result($result,0,0);
+        }
+        return 0;        
+    }
+    
+    /** 
+     * Get the list of coaches (only user ids)
+     * @param string course_code
+     * @param in session_id
+     * @return array
+     */
+    static function get_session_course_coaches($course_code, $session_id) {
+        $tbl_user							= Database::get_main_table(TABLE_MAIN_USER);
+        $tbl_session_rel_course_rel_user	= Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
+        
+        // Get coachs of the courses in session
+		$sql = "SELECT user.user_id FROM $tbl_session_rel_course_rel_user session_rcru, $tbl_user user
+				WHERE   session_rcru.id_user = user.user_id AND 
+                        session_rcru.id_session = '".intval($session_id)."' AND 
+                        session_rcru.course_code ='".Database::escape_string($course_code)."' AND 
+                        session_rcru.status=2";
+		$result = Database::query($sql);
+        return Database::store_result($result);        
+    }
+    
+    static function get_session_course_coaches_to_string($course_code, $session_id) {
+        $coaches = self::get_session_course_coaches($course_code, $session_id);
+        if (!empty($coaches)) {
+            $coach_list = array();            
+            foreach ($coaches as $coach_info) {
+                $user_info = api_get_user_info($coach_info['user_id']);
+                $coach_list[] = $user_info['complete_name'];
+            }            
+            if (!empty($coach_list)) {
+                return implode(', ', $coach_list);
+            }            
+        }        
+        return get_lang('None');
+    }
+    
+    static function delete_course_in_session($id_session, $course_code) {
+        $tbl_session_rel_course				= Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
+        $tbl_session_rel_course_rel_user	= Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
+        $tbl_session						= Database::get_main_table(TABLE_MAIN_SESSION);
+        
+        $id_session = intval($id_session);
+        $course_code = Database::escape_string($course_code);
+        
+        if (!empty($id_session) && !empty($course_code)) {
+
+            Database::query("DELETE FROM $tbl_session_rel_course WHERE id_session='$id_session' AND course_code = '$course_code'");
+            $nbr_affected_rows=Database::affected_rows();
+
+            Database::query("DELETE FROM $tbl_session_rel_course_rel_user WHERE id_session='$id_session' AND course_code = '$course_code'");
+            Database::query("UPDATE $tbl_session SET nbr_courses=nbr_courses-$nbr_affected_rows WHERE id='$id_session'");
+        }
+    }  
+
     static function get_sessions_by_user($user_id) {
        $session_categories = UserManager::get_sessions_by_category($user_id);
        $session_array = array();
@@ -1805,4 +2092,6 @@ class SessionManager {
        }
        return $session_array;
     }
+
+  
 }

+ 13 - 0
main/inc/lib/svg-edit/extensions/filesave.php

@@ -110,6 +110,19 @@ if (file_exists($saveDir.'/'.$filename.$i.'.'.$extension) && $currentTool=='docu
 }
 $documentPath = $saveDir.'/'.$drawFileName;
 
+//make a temporal file for get the file size
+	$tmpfname = tempnam("/tmp", "CTF");
+	$handle = fopen($tmpfname, "w");
+	fwrite($handle, $contents);
+	fclose($handle);
+	// Check if there is enough space in the course to save the file
+	if (!DocumentManager::enough_space(filesize($tmpfname), DocumentManager::get_course_quota())) {
+		unlink($tmpfname);
+		die(get_lang('UplNotEnoughSpace'));
+	}
+	//erase temporal file
+	unlink($tmpfname);
+
 //add new document to disk
 file_put_contents( $documentPath, $contents );
 

+ 33 - 33
main/inc/lib/usermanager.lib.php

@@ -390,14 +390,11 @@ class UserManager {
      * @return boolean 
      * @author Laurent Opprecht
      */
-    static function deactivate_users($ids = array())
-    {
+    static function deactivate_users($ids = array()) {
         if (empty($ids)) {
             return false;
         }
-
         $table_user = Database :: get_main_table(TABLE_MAIN_USER);
-
         $ids = is_array($ids) ? $ids : func_get_args();
         $ids = array_map('intval', $ids);
         $ids = implode(',', $ids);
@@ -1929,41 +1926,41 @@ class UserManager {
 	public static function get_sessions_by_category($user_id, $is_time_over = false) {
 		// Database Table Definitions		
 		$tbl_session				= Database :: get_main_table(TABLE_MAIN_SESSION);
-		$tbl_session_course_user	= Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);        
+		$tbl_session_course_user	= Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);      
+        $tbl_session_user           = Database :: get_main_table(TABLE_MAIN_SESSION_USER);
         $tbl_session_category       = Database :: get_main_table(TABLE_MAIN_SESSION_CATEGORY);
         
 		if ($user_id != strval(intval($user_id))) return array();
 
 		$categories = array();
         
-		// Get the list of sessions per user
         $now = api_get_utc_datetime();
         
+		// Get the list of sessions per user
 		$condition_date_end = "";
+        
 		if ($is_time_over) {
-			$condition_date_end = " AND (session.date_end < '$now' AND session.date_end != '0000-00-00')  ";
+			$condition_date_end = " AND ( (session.date_end < '$now' AND session.date_end != '0000-00-00') OR moved_to <> 0) ";
 		} else {
-			$condition_date_end = " AND (session.date_end >= '$now' OR session.date_end = '0000-00-00') ";
-		}
-        		
-        //ORDER BY session_category_id, date_start, date_end 
-        $sql = "SELECT DISTINCT session.id, 
-                                session.name, 
-                                session.date_start, 
-                                session.date_end, 
-                                session_category_id, 
+			$condition_date_end = " AND (session.date_end >= '$now' OR session.date_end = '0000-00-00') AND moved_to = 0 ";
+		}
+
+        $sql = "SELECT DISTINCT session.id, session.name, session.date_start, session.date_end, session_category_id, 
                                 session_category.name as session_category_name,
                                 session_category.date_start session_category_date_start,
                                 session_category.date_end session_category_date_end,
-                                nb_days_access_before_beginning
+                                nb_days_access_before_beginning,
+                                moved_to,
+                                moved_status
                                 
-                              FROM $tbl_session as session LEFT JOIN $tbl_session_category session_category ON (session_category_id = session_category.id) 
-                                    INNER JOIN $tbl_session_course_user as session_rel_course_user ON (session_rel_course_user.id_session = session.id)                             
-                              WHERE (
-                                        session_rel_course_user.id_user = $user_id OR session.id_coach = $user_id
-                                    )  $condition_date_end
-                              ORDER BY session_category_name, name";
-        
+                FROM $tbl_session as session LEFT JOIN $tbl_session_category session_category ON (session_category_id = session_category.id) 
+                      INNER JOIN $tbl_session_course_user as scu ON (scu.id_session = session.id)
+                      INNER JOIN $tbl_session_user su ON su.id_session = session.id AND su.id_user = scu.id_user
+                WHERE (
+                         scu.id_user = $user_id OR session.id_coach = $user_id
+                      )  $condition_date_end
+                ORDER BY session_category_name, name";
+        //var_dump($sql);
         $result = Database::query($sql);
         if (Database::num_rows($result) > 0) {
             while ($row = Database::fetch_array($result)) {
@@ -1979,6 +1976,9 @@ class UserManager {
                 $categories[$row['session_category_id']]['sessions'][$row['id']]['nb_days_access_before_beginning']     = $row['nb_days_access_before_beginning'];
                 $categories[$row['session_category_id']]['sessions'][$row['id']]['courses']         = UserManager::get_courses_list_by_session($user_id, $row['id']);
                 
+                $categories[$row['session_category_id']]['sessions'][$row['id']]['moved_to']         = $row['moved_to'];
+                $categories[$row['session_category_id']]['sessions'][$row['id']]['moved_status']     = $row['moved_status'];
+                
             }
         }
 		return $categories;
@@ -2017,10 +2017,10 @@ class UserManager {
 
 		$personal_course_list_sql = "SELECT course.code, course_rel_user.status course_rel_status, course_rel_user.sort sort, course_rel_user.user_course_cat user_course_cat		                                      
 			                         FROM ".$tbl_course_user." course_rel_user
-				                     LEFT JOIN ".$tbl_course." course
-					                 ON course.code = course_rel_user.course_code
-				                     LEFT JOIN ".$tbl_user_course_category." user_course_category
-					                 ON course_rel_user.user_course_cat = user_course_category.id
+                                            LEFT JOIN ".$tbl_course." course
+                                            ON course.code = course_rel_user.course_code
+                                            LEFT JOIN ".$tbl_user_course_category." user_course_category
+                                            ON course_rel_user.user_course_cat = user_course_category.id
 				                     $join_access_url
 			                         WHERE  course_rel_user.user_id = '".$user_id."' AND 
 			                                course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH."  $where_access_url
@@ -2138,13 +2138,14 @@ class UserManager {
 				$where_access_url=" AND access_url_id = $access_url_id AND url_rel_session.session_id = $session_id ";
 			}
 		}
-		
+
+		// variable initialisation
+		$personal_course_list_sql = '';
 		$personal_course_list = array();
 		$courses = array();
 
 		// this query is very similar to the above query, but it will check the session_rel_course_user table if there are courses registered to our user or not
-		$personal_course_list_sql = "SELECT DISTINCT scu.course_code as code 
-                                    FROM $tbl_session_course_user as scu $join_access_url
+		$personal_course_list_sql = "SELECT DISTINCT scu.course_code as code FROM $tbl_session_course_user as scu $join_access_url
 									WHERE scu.id_user = $user_id AND scu.id_session = $session_id $where_access_url
 									ORDER BY code";
         
@@ -2161,8 +2162,7 @@ class UserManager {
 		}
 
 		if (api_is_allowed_to_create_course()) {
-			$personal_course_list_sql = "SELECT DISTINCT scu.course_code as code 
-                                        FROM $tbl_session_course_user as scu, $tbl_session as s $join_access_url
+			$personal_course_list_sql = "SELECT DISTINCT scu.course_code as code FROM $tbl_session_course_user as scu, $tbl_session as s $join_access_url
 										WHERE s.id = $session_id AND scu.id_session = s.id AND ((scu.id_user=$user_id AND scu.status=2) OR s.id_coach = $user_id)
 										$where_access_url
 										ORDER BY code";						            

+ 6 - 2
main/inc/lib/userportal.lib.php

@@ -857,7 +857,7 @@ class IndexManager {
 	 *  
 	 * */
 	function return_courses_and_sessions($user_id) {		       
-        $session_categories = array();        
+        $session_categories = array();     
         $load_history = (isset($_GET['history']) && intval($_GET['history']) == 1) ? true : false;
 		
 		if ($load_history) {
@@ -954,7 +954,11 @@ class IndexManager {
                             }
 
                             $params['title'] = $session_link;
-                            $params['subtitle'] = $extra_info;                            
+                            
+                            $moved_status = SessionManager::get_session_change_user_reason($session['moved_status']);
+                            $moved_status = isset($moved_status) && !empty($moved_status) ? ' ('.$moved_status.')' : null;
+                            
+                            $params['subtitle'] = $extra_info.$moved_status;
 
                             $params['right_actions'] = '';
                             if (api_is_platform_admin()) {

+ 13 - 0
main/inc/lib/wami-recorder/record_document.php

@@ -65,6 +65,19 @@ if (file_exists($saveDir.'/'.$waminame_noex.'.'.$ext)){
 
 $documentPath = $saveDir.'/'.$waminame_to_save;
 
+//make a temporal file for get the file size
+	$tmpfname = tempnam("/tmp", "CTF");
+	$handle = fopen($tmpfname, "w");
+	fwrite($handle, $content);
+	fclose($handle);
+	// Check if there is enough space in the course to save the file
+	if (!DocumentManager::enough_space(filesize($tmpfname), DocumentManager::get_course_quota())) {
+		unlink($tmpfname);
+		die(get_lang('UplNotEnoughSpace'));
+	}
+	//erase temporal file
+	unlink($tmpfname);
+
 
 //add to disk
 $fh = fopen($documentPath, 'w') or die("can't open file");

+ 12 - 11
main/inc/local.inc.php

@@ -883,7 +883,7 @@ if ((isset($uidReset) && $uidReset) || (isset($cidReset) && $cidReset)) {
                 // this user has no status related to this course
                 // The user is subscribed in a session? The user is a Session coach a Session admin ?
 
-                $tbl_session             = Database :: get_main_table(TABLE_MAIN_SESSION);
+                $tbl_session             = Database :: get_main_table(TABLE_MAIN_SESSION);                
                 $tbl_session_course      = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE);
                 $tbl_session_course_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
 
@@ -894,7 +894,8 @@ if ((isset($uidReset) && $uidReset) || (isset($cidReset) && $cidReset)) {
                                session_rcru.course_code = '$_cid' AND
                                session_rcru.id_user     = '$user_id' AND
                                session_rcru.id_session  = $session_id AND
-                               session_rcru.status      = 2";
+                               session_rcru.status      = 2                               
+                        ";
 
                 $result = Database::query($sql);
                 $row     = Database::store_result($result);
@@ -909,16 +910,16 @@ if ((isset($uidReset) && $uidReset) || (isset($cidReset) && $cidReset)) {
                     $is_sessionAdmin     = true;
                 } else {
                     //Im a coach or a student?
-                    $sql = "SELECT id_user, status FROM ".$tbl_session_course_user."
+                    $sql = "SELECT cu.id_user, cu.status FROM $tbl_session_course_user cu                             
                             WHERE   course_code = '$_cid' AND
-                                    id_user     = '".$user_id."' AND
-                                    id_session  = '".$session_id."'
+                                    cu.id_user     = '".$user_id."' AND
+                                    cu.id_session  = '".$session_id."'
                             LIMIT 1";
                     $result = Database::query($sql);
 
                     if (Database::num_rows($result)) {
                         $row = Database::fetch_array($result, 'ASSOC');
-
+                        
                         $session_course_status = $row['status'];
 
                         switch ($session_course_status) {
@@ -936,13 +937,14 @@ if ((isset($uidReset) && $uidReset) || (isset($cidReset) && $cidReset)) {
                                 }
                                 Session::write('_courseUser', $_courseUser);
                                 break;
-                            case '0': //student
+                            case '0': //Student
                                 $_courseUser['role'] = '';
                                 $is_courseMember     = true;
                                 $is_courseTutor      = false;
                                 $is_courseAdmin      = false;
                                 $is_courseCoach      = false;
                                 $is_sessionAdmin     = false;
+                      
                                 Session::write('_courseUser', $_courseUser);
                                 break;
                             default:
@@ -1016,8 +1018,8 @@ if ((isset($uidReset) && $uidReset) || (isset($cidReset) && $cidReset)) {
         if ($session_id != 0) {
             if (!$is_platformAdmin) {
                 // admin is not affected to the invisible session mode
-                $session_visibility = api_get_session_visibility($session_id);
-
+                $session_visibility = api_get_session_visibility($session_id);                
+                
                 switch ($session_visibility) {
                     case SESSION_INVISIBLE:
                         $is_allowed_in_course = false;
@@ -1104,5 +1106,4 @@ if (isset($_cid)) {
     Database::query($sql);
 }
 
-Redirect::session_request_uri($logging_in, $user_id);
-
+Redirect::session_request_uri($logging_in, $user_id);

+ 5 - 1
main/install/db_main.sql

@@ -514,8 +514,11 @@ CREATE TABLE IF NOT EXISTS session_rel_course_rel_user (
 DROP TABLE IF EXISTS session_rel_user;
 CREATE TABLE IF NOT EXISTS session_rel_user (
   id_session mediumint unsigned NOT NULL default '0',
-  id_user mediumint unsigned NOT NULL default '0',
+  id_user int unsigned NOT NULL default '0',
   relation_type int default 0,
+  moved_to int default 0,
+  moved_status int default 0,
+  moved_at datetime NOT NULL default '0000-00-00 00:00:00',
   PRIMARY KEY (id_session, id_user, relation_type)
 );
 
@@ -2826,6 +2829,7 @@ CREATE TABLE IF NOT EXISTS notification (
 	dest_user_id INT NOT NULL,
  	dest_mail 	CHAR(255),
  	title 		CHAR(255),
+    sender_id   INT NOT NULL DEFAULT 0,
  	content 	CHAR(255),
  	send_freq 	SMALLINT DEFAULT 1,
  	created_at 	DATETIME NOT NULL,

+ 2 - 1
main/install/db_stats.sql

@@ -287,6 +287,7 @@ ALTER TABLE track_e_access ADD INDEX (access_session_id);
 
 ALTER TABLE track_e_online ADD INDEX (course);
 ALTER TABLE track_e_online ADD INDEX (session_id);
+ALTER TABLE track_e_online ADD INDEX idx_trackonline_uat (login_user_id, access_url_id, login_date);
 
 ALTER TABLE track_e_item_property ADD INDEX (course_id, item_property_id, session_id);
 ALTER TABLE track_e_downloads ADD INDEX (down_session_id);  
@@ -326,4 +327,4 @@ CREATE TABLE track_e_attempt_coeff (
     id int unsigned not null auto_increment primary key,
     attempt_id INT NOT NULL, 
     marks_coeff float(6,2)
-);
+);

+ 2 - 1
main/install/install_db.inc.php

@@ -77,7 +77,8 @@ if (!defined('CLI_INSTALLATION')) {
     }	
 	//Create database
 	if ($create_database) {
-		$sql = "CREATE DATABASE IF NOT EXISTS `$mysqlMainDb`";
+        $charset_clause = ' DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci';
+		$sql = "CREATE DATABASE IF NOT EXISTS `$mysqlMainDb` $charset_clause";   
 		Database::query($sql) or die(Database::error());
 	}	
 }

+ 47 - 0
main/install/migrate-db-1.9.0-1.10.0-pre.sql

@@ -0,0 +1,47 @@
+-- This script updates the databases structure before migrating the data from
+-- version 1.9.0 (or version 1.9.2) to version 1.10.0
+-- it is intended as a standalone script, however, because of the multiple
+-- databases related difficulties, it should be parsed by a PHP script in
+-- order to connect to and update the right databases.
+-- There is one line per query, allowing the PHP function file() to read
+-- all lines separately into an array. The xxMAINxx-type markers are there
+-- to tell the PHP script which database we're talking about.
+-- By always using the keyword "TABLE" in the queries, we should be able
+-- to retrieve and modify the table name from the PHP script if needed, which
+-- will allow us to deal with the unique-database-type installations
+--
+-- This first part is for the main database
+
+-- xxMAINxx
+
+-- Optimize tracking query very often queried on busy campuses
+ALTER TABLE track_e_online ADD INDEX idx_trackonline_uat (login_user_id, access_url_id, login_date);
+
+-- Do not move this query
+
+-- Main changes
+
+-- Courses changes c_XXX
+
+ALTER TABLE c_lp_item ADD INDEX idx_c_lp_item_cid_lp_id (c_id, lp_id);
+ALTER TABLE c_lp_item_view ADD INDEX idx_c_lp_item_view_cid_lp_view_id_lp_item_id(c_id, lp_view_id, lp_item_id);
+ALTER TABLE c_tool_intro MODIFY COLUMN intro_text MEDIUMTEXT NOT NULL;
+ALTER TABLE notification ADD COLUMN sender_id INT NOT NULL DEFAULT 0;
+
+ALTER TABLE session_rel_user ADD COLUMN moved_to INT NOT NULL DEFAULT 0;
+ALTER TABLE session_rel_user ADD COLUMN moved_status INT NOT NULL DEFAULT 0;
+ALTER TABLE session_rel_user ADD COLUMN moved_at datetime NOT NULL default '0000-00-00 00:00:00';
+
+
+-- Normal tables
+
+UPDATE settings_current SET selected_value = '1.10.xx' WHERE variable = 'chamilo_database_version';
+
+-- xxSTATSxx
+-- All stats DB changes will be added in the "main zone"
+
+-- xxUSERxx
+-- All user DB changes will be added in the "main zone"
+
+-- xxCOURSExx
+-- All course DB changes will be added in the "main zone"

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

@@ -0,0 +1,115 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+/**
+ * Chamilo LMS
+ *
+ * Update the Chamilo database from an older Chamilo version
+ * Notice : This script has to be included by index.php
+ * or update_courses.php (deprecated).
+ *
+ * @package chamilo.install
+ * @todo
+ * - conditional changing of tables. Currently we execute for example
+ * ALTER TABLE $dbNameForm.cours
+ * instructions without checking wether this is necessary.
+ * - reorganise code into functions
+ * @todo use database library
+ */
+Log::notice('Entering file');
+
+$old_file_version = '1.9.0';
+$new_file_version = '1.10.0';
+
+// Check if we come from index.php or update_courses.php - otherwise display error msg
+if (defined('SYSTEM_INSTALLATION')) {
+
+    // Check if the current Chamilo install is eligible for update
+    if (!file_exists('../inc/conf/configuration.php')) {
+        echo '<strong>'.get_lang('Error').' !</strong> Chamilo '.implode('|', $updateFromVersion).' '.get_lang('HasNotBeenFound').'.<br /><br />
+                                '.get_lang('PleasGoBackToStep1').'.
+                                <p><button type="submit" class="back" name="step1" value="&lt; '.get_lang('Back').'">'.get_lang('Back').'</button></p>
+                                </td></tr></table></form></body></html>';
+        exit ();
+    }
+
+    $_configuration['db_glue'] = get_config_param('dbGlu');
+    
+    if ($singleDbForm) {
+        $_configuration['table_prefix'] 	= get_config_param('courseTablePrefix');
+        $_configuration['main_database'] 	= get_config_param('mainDbName');
+        $_configuration['db_prefix'] 		= get_config_param('dbNamePrefix');
+    }
+
+	$dbScormForm = preg_replace('/[^a-zA-Z0-9_\-]/', '', $dbScormForm);
+
+	if (!empty($dbPrefixForm) && strpos($dbScormForm, $dbPrefixForm) !== 0) {
+        $dbScormForm = $dbPrefixForm.$dbScormForm;
+    }
+
+    if (empty($dbScormForm) || $dbScormForm == 'mysql' || $dbScormForm == $dbPrefixForm) {
+        $dbScormForm = $dbPrefixForm.'scorm';
+    }
+
+    /*   Normal upgrade procedure: start by updating main, statistic, user databases */
+
+    // If this script has been included by index.php, not update_courses.php, so
+    // that we want to change the main databases as well...
+    $only_test = false;
+    if (defined('SYSTEM_INSTALLATION')) {
+        
+        if ($singleDbForm) {
+            $dbStatsForm = $dbNameForm;
+            $dbScormForm = $dbNameForm;
+            $dbUserForm  = $dbNameForm;
+        }        
+        /**
+         * Update the databases "pre" migration
+         */
+        include '../lang/english/create_course.inc.php';
+        
+        if ($languageForm != 'english') {
+            // languageForm has been escaped in index.php
+            include '../lang/'.$languageForm.'/create_course.inc.php';
+        }
+        
+        // Get the main queries list (m_q_list)
+        $m_q_list = get_sql_file_contents('migrate-db-'.$old_file_version.'-'.$new_file_version.'-pre.sql', 'main');
+        
+        if (count($m_q_list) > 0) {
+            // Now use the $m_q_list
+            /**
+             * We connect to the right DB first to make sure we can use the queries
+             * without a database name
+             */
+            if (strlen($dbNameForm) > 40) {
+                Log::error('Database name '.$dbNameForm.' is too long, skipping');
+            } elseif (!in_array($dbNameForm, $dblist)) {
+                Log::error('Database '.$dbNameForm.' was not found, skipping');
+            } else {
+                iDatabase::select_db($dbNameForm);
+                foreach ($m_q_list as $query){
+                    if ($only_test) {
+                        Log::notice("iDatabase::query($dbNameForm,$query)");
+                    } else {
+                        $res = iDatabase::query($query);
+                        if ($res === false) {
+                        	Log::error('Error in '.$query.': '.iDatabase::error());
+                        }
+                    }
+                }
+            }
+        }
+        
+        if (INSTALL_TYPE_UPDATE == 'update') {
+            
+            //Migrate classes to the new classes (usergroups)
+            
+        }
+        
+    }    
+    
+} else {
+    echo 'You are not allowed here !' . __FILE__;
+}
+

+ 2 - 1
main/messages/new_message.php

@@ -241,7 +241,8 @@ function manage_form($default, $select_from_user_list = null, $sent_to = null) {
 						if (is_string($res)) {
 							$html .= Display::return_message($res, 'error');
 						} else {
-							$html .= MessageManager::display_success_message($user);
+                            $user_info = api_get_user_info($user);
+							$html .= Display::return_message(get_lang('MessageSentTo')." &nbsp;<b>".$user_info['complete_name']."</b>", 'confirmation', false);
 						}
 					}
 				}       

+ 3 - 26
main/user/subscribe_user.php

@@ -16,7 +16,6 @@ $current_course_tool  = TOOL_USER;
 // the section (for the tabs)
 $this_section = SECTION_COURSES;
 
-
 // notice for unauthorized people.
 api_protect_course_script(true);
 
@@ -40,9 +39,6 @@ if ($_GET['keyword']) {
 
 Display :: display_header($tool_name, "User");
 
-// api_display_tool_title($tool_name);
-
-
 // Build search-form
 echo '<div class="actions">';
 
@@ -77,13 +73,11 @@ $list_not_register_user='';
 
 if (isset ($_REQUEST['register'])) {
 	if (isset($_REQUEST['type']) && $_REQUEST['type']=='teacher') {
-
 		if (!empty($current_session_id)) {
 			$result_simple_sub = SessionManager::set_coach_to_course_session(intval($_REQUEST['user_id']), $current_session_id, $_course['sysCode']);
 		} else {
 			$result_simple_sub = CourseManager :: subscribe_user(intval($_REQUEST['user_id']), $_course['sysCode'],COURSEMANAGER);
 		}
-
 	} else {
 		$result_simple_sub=CourseManager :: subscribe_user(intval($_REQUEST['user_id']), $_course['sysCode']);
 	}
@@ -180,12 +174,9 @@ if (!empty($_SESSION['session_user_name'])) {
 	unset($_SESSION['session_user_name']);
 }
 
-
-
 $is_western_name_order = api_is_western_name_order();
 $sort_by_first_name = api_sort_by_first_name();
 
-
 // Build table
 $table = new SortableTable('subscribe_users', 'get_number_of_users', 'get_user_data', ($is_western_name_order xor $sort_by_first_name) ? 3 : 2);
 $parameters['keyword'] = Security::remove_XSS($_REQUEST['keyword']);
@@ -359,20 +350,7 @@ function get_number_of_users() {
     if ($res) {	
 	   $row = Database::fetch_row($res);
 	   $count_user = $row[0];	   
-	}
-	
-	/* @todo seems not to be used
-	// we add 1 for every additional user (a user where the keyword matches one of the additional profile fields)
-	// that is not yet in the course and not yet in the search result
-	if (isset ($_REQUEST['keyword']) AND api_get_setting('ProfilingFilterAddingUsers') == 'true') {
-		foreach($additional_users as $additional_user_key=>$additional_user_value){
-			if (!in_array($additional_user_key,$users) AND !in_array($additional_user_key,$users_of_course)){
-				$result++;
-			}
-		}
-	}
-    */
-    
+	}   
 	return $count_user;
 }
 /**
@@ -413,8 +391,7 @@ function get_user_data($from, $number_of_items, $column, $direction) {
                 u.active               AS col4,
                 u.user_id              AS col5";
     }
-
-	
+    
 	if (isset($_REQUEST['type']) && $_REQUEST['type']=='teacher') {
 		// adding a teacher through a session
 		if (!empty($_SESSION["id_session"])) {
@@ -640,7 +617,7 @@ function active_filter($active, $url_params, $row) {
 		$image='error';
 	}
 	if ($row['0']<>$_user['user_id']) { // you cannot lock yourself out otherwise you could disable all the accounts including your own => everybody is locked out and nobody can change it anymore.
-		$result = '<center>'.Display::return_icon($image.'.png',  get_lang(ucfirst($action)), array('border'=>'0', 'style'=>'vertical-align: middle;') , 16).'</center>';
+		$result = Display::return_icon($image.'.png',  get_lang(ucfirst($action)), array('border'=>'0', 'style'=>'vertical-align: middle;') , 16);
 	}
 	return $result;
 }

+ 82 - 110
main/user/user.php

@@ -48,7 +48,7 @@ if (!api_is_platform_admin(true)) {
 /*
 	Constants and variables
 */
-$course_code            = Database::escape_string(api_get_course_id());
+$course_code            = api_get_course_id();
 $session_id             = api_get_session_id();
 $is_western_name_order 	= api_is_western_name_order();
 $sort_by_first_name 	= api_sort_by_first_name();
@@ -134,13 +134,17 @@ if (api_is_allowed_to_edit(null, true)) {
 				
                 if (api_get_session_id()) {	
                     $table_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
+                    $table_session_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
                     $sql_query = "SELECT DISTINCT user.user_id, ".($is_western_name_order ? "user.firstname, user.lastname" : "user.lastname, user.firstname").",  user.username, $select_email_condition phone, user.official_code, active $legal
-                                  FROM $table_session_course_user as session_course_user, $table_users as user ";
+                                  FROM $table_session_course_user as session_course_user, $table_users as user,  $table_session_user as su";
                     if ($_configuration['multiple_access_urls']) {
                         $sql_query .= ' , '.Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER).' au ';
                     }
-                    $sql_query .=" WHERE course_code = '$course_code' AND session_course_user.id_user = user.user_id ";
-                    $sql_query .= ' AND id_session = '.$session_id;							
+                    $sql_query .=" WHERE course_code = '$course_code' AND 
+                                        session_course_user.id_user = user.user_id AND 
+                                        su.id_user =  session_course_user.id_user AND session_course_user.id_session = su.id_session AND
+                                        su.moved_to = 0 AND su.moved_status <> ".SessionManager::SESSION_CHANGE_USER_REASON_ENROLLMENT_ANNULATION."  AND
+                                        session_course_user.id_session = $session_id";
 
                     if ($_configuration['multiple_access_urls']) {				
                         $sql_query .= " AND user.user_id = au.user_id AND access_url_id =  $current_access_url_id  ";
@@ -343,7 +347,6 @@ if (api_is_allowed_to_edit(null, true)) {
     }
 }
 
-
 /*		FUNCTIONS	*/
 
 function display_user_search_form() {
@@ -354,10 +357,6 @@ function display_user_search_form() {
 	echo '</form>';	
 }
 
-if (!$is_allowed_in_course) {
-	api_not_allowed(true);
-}
-
 /*	Header */
 if ($origin != 'learnpath') {
 	if (isset($_GET['keyword']) && !empty($_GET['keyword'])) {
@@ -416,31 +415,10 @@ if ( api_is_allowed_to_edit(null, true)) {
 /**
  *  * Get the users to display on the current page.
  */
-function get_number_of_users() {
-	$counter = 0;
-	if (!empty($_SESSION["id_session"])){
-		$a_course_users = CourseManager :: get_user_list_from_course_code($_SESSION['_course']['id'], $_SESSION['id_session']);
-
-	} else {
-		$a_course_users = CourseManager :: get_user_list_from_course_code($_SESSION['_course']['id'], 0);
-	}
-	foreach ($a_course_users as $user_id => $o_course_user) {
-		if ((isset($_GET['keyword']) && search_keyword($o_course_user['firstname'], $o_course_user['lastname'], $o_course_user['username'], $o_course_user['official_code'], $_GET['keyword'])) || !isset($_GET['keyword']) || empty($_GET['keyword'])) {
-			$counter++;
-		}
-	}
-	return $counter;
-}
-
-function search_keyword($firstname, $lastname, $username, $official_code, $keyword) {
-	if (api_strripos($firstname, $keyword) !== false || api_strripos($lastname, $keyword) !== false || api_strripos($username, $keyword) !== false || api_strripos($official_code, $keyword) !== false) {
-		return true;
-	} else {
-		return false;
-	}
+function get_number_of_users() {	    
+    return CourseManager::get_users_count_in_course(api_get_course_id(), api_get_session_id(), null, null, null, $_GET['keyword']);    
 }
 
-
 /**
  * Get the users to display on the current page.
  */
@@ -453,9 +431,7 @@ function get_user_data($from, $number_of_items, $column, $direction) {
 	$a_users = array();
 
 	// limit
-	if (!isset($_GET['keyword']) || empty($_GET['keyword'])) {
-		$limit = 'LIMIT '.intval($from).','.intval($number_of_items);
-	}
+	$limit = 'LIMIT '.intval($from).','.intval($number_of_items);	
 
 	if (!in_array($direction, array('ASC', 'DESC'))) {
 		$direction = 'ASC';
@@ -494,86 +470,83 @@ function get_user_data($from, $number_of_items, $column, $direction) {
     $session_id = api_get_session_id();
     $course_code = api_get_course_id();
     
-    $a_course_users = CourseManager :: get_user_list_from_course_code($course_code, $session_id, $limit, $order_by);
+    $a_course_users = CourseManager :: get_user_list_from_course_code($course_code, $session_id, $limit, $order_by, null, $_REQUEST['keyword']);
 
 	foreach ($a_course_users as $user_id => $o_course_user) {
-		if ((isset($_GET['keyword']) && search_keyword($o_course_user['firstname'], $o_course_user['lastname'], $o_course_user['username'], $o_course_user['official_code'], $_GET['keyword'])) || !isset($_GET['keyword']) || empty($_GET['keyword'])) {
-
-			$groups_name = GroupManager :: get_user_group_name($user_id);
-			$temp = array();
-			if (api_is_allowed_to_edit(null, true)) {
-				//if (api_get_setting('allow_user_course_subscription_by_course_admin') == 'true') {
-                	$temp[] = $user_id;
-                //}
-				$image_path = UserManager::get_user_picture_path_by_id($user_id, 'web', false, true);
-				$user_profile = UserManager::get_picture_user($user_id, $image_path['file'], 22, USER_IMAGE_SIZE_SMALL, ' width="22" height="22" ');
-				if (!api_is_anonymous()) {
-					$photo = '<a href="userInfo.php?'.api_get_cidreq().'&origin='.$origin.'&amp;uInfo='.$user_id.'" title="'.get_lang('Info').'"  ><img src="'.$user_profile['file'].'" '.$user_profile['style'].' alt="'.api_get_person_name($o_course_user['firstname'], $o_course_user['lastname']).'"  title="'.api_get_person_name($o_course_user['firstname'], $o_course_user['lastname']).'" /></a>';
-				} else {
-					$photo = '<img src="'.$user_profile['file'].'" '.$user_profile['style'].' alt="'.api_get_person_name($o_course_user['firstname'], $o_course_user['lastname']).'" title="'.api_get_person_name($o_course_user['firstname'], $o_course_user['lastname']).'" />';
-				}
-                
-				$temp[] = $photo;
-				$temp[] = $o_course_user['official_code'];
-				
-				if ($is_western_name_order) {
-					$temp[] = $o_course_user['firstname'];
-					$temp[] = $o_course_user['lastname'];
-				} else {
-					$temp[] = $o_course_user['lastname'];
-					$temp[] = $o_course_user['firstname'];
-				}
+        $groups_name = GroupManager :: get_user_group_name($user_id);
+        $temp = array();
+        if (api_is_allowed_to_edit(null, true)) {
+            //if (api_get_setting('allow_user_course_subscription_by_course_admin') == 'true') {
+                $temp[] = $user_id;
+            //}
+            $image_path = UserManager::get_user_picture_path_by_id($user_id, 'web', false, true);
+            $user_profile = UserManager::get_picture_user($user_id, $image_path['file'], 22, USER_IMAGE_SIZE_SMALL, ' width="22" height="22" ');
+            if (!api_is_anonymous()) {
+                $photo = '<a href="userInfo.php?'.api_get_cidreq().'&origin='.$origin.'&amp;uInfo='.$user_id.'" title="'.get_lang('Info').'"  ><img src="'.$user_profile['file'].'" '.$user_profile['style'].' alt="'.api_get_person_name($o_course_user['firstname'], $o_course_user['lastname']).'"  title="'.api_get_person_name($o_course_user['firstname'], $o_course_user['lastname']).'" /></a>';
+            } else {
+                $photo = '<img src="'.$user_profile['file'].'" '.$user_profile['style'].' alt="'.api_get_person_name($o_course_user['firstname'], $o_course_user['lastname']).'" title="'.api_get_person_name($o_course_user['firstname'], $o_course_user['lastname']).'" />';
+            }
 
-                $temp[] = $o_course_user['username'];                
-				$temp[] = isset($o_course_user['role']) ? $o_course_user['role'] : null; //Description
-				$temp[] = implode(', ', $groups_name); //Group				
+            $temp[] = $photo;
+            $temp[] = $o_course_user['official_code'];
 
-				// Status
-                $default_status = '-';
-				if ((isset($o_course_user['status_rel']) && $o_course_user['status_rel'] == 1) || (isset($o_course_user['status_session']) && $o_course_user['status_session'] == 2)) {
-					$default_status = get_lang('CourseManager');
-				} elseif (isset($o_course_user['tutor_id']) && $o_course_user['tutor_id'] == 1) {
-					$default_status = get_lang('Tutor');
-				}
-                $temp[] = $default_status;
-                
-                //Active
-				$temp[] = $o_course_user['active'];
-                
+            if ($is_western_name_order) {
+                $temp[] = $o_course_user['firstname'];
+                $temp[] = $o_course_user['lastname'];
+            } else {
+                $temp[] = $o_course_user['lastname'];
+                $temp[] = $o_course_user['firstname'];
+            }
+
+            $temp[] = $o_course_user['username'];                
+            $temp[] = isset($o_course_user['role']) ? $o_course_user['role'] : null; //Description
+            $temp[] = implode(', ', $groups_name); //Group				
+
+            // Status
+            $default_status = '-';
+            if ((isset($o_course_user['status_rel']) && $o_course_user['status_rel'] == 1) || (isset($o_course_user['status_session']) && $o_course_user['status_session'] == 2)) {
+                $default_status = get_lang('CourseManager');
+            } elseif (isset($o_course_user['tutor_id']) && $o_course_user['tutor_id'] == 1) {
+                $default_status = get_lang('Tutor');
+            }
+            $temp[] = $default_status;
+
+            //Active
+            $temp[] = $o_course_user['active'];
+
+            //User id for actions
+            $temp[] = $user_id;
+        } else {
+            $image_path = UserManager::get_user_picture_path_by_id($user_id, 'web', false, true);
+            $image_repository = $image_path['dir'];
+            $existing_image = $image_path['file'];
+            if (!api_is_anonymous()) {
+                $photo= '<a href="userInfo.php?'.api_get_cidreq().'&origin='.$origin.'&amp;uInfo='.$user_id.'" title="'.get_lang('Info').'"  ><img src="'.$image_repository.$existing_image.'" alt="'.api_get_person_name($o_course_user['firstname'], $o_course_user['lastname']).'"  width="22" height="22" title="'.api_get_person_name($o_course_user['firstname'], $o_course_user['lastname']).'" /></a>';
+            } else {
+                $photo= '<img src="'.$image_repository.$existing_image.'" alt="'.api_get_person_name($o_course_user['firstname'], $o_course_user['lastname']).'"  width="22" height="22" title="'.api_get_person_name($o_course_user['firstname'], $o_course_user['lastname']).'" />';
+            }
+            $temp[] = $user_id;
+            $temp[] = $photo;
+            $temp[] = $o_course_user['official_code'];
+
+            if ($is_western_name_order) {
+                $temp[] = $o_course_user['firstname'];
+                $temp[] = $o_course_user['lastname'];
+            } else {
+                $temp[] = $o_course_user['lastname'];
+                $temp[] = $o_course_user['firstname'];
+            }				
+            $temp[] = $o_course_user['username'];
+            $temp[] = $o_course_user['role'];
+            $temp[] = implode(', ', $groups_name);//Group
+
+            if ($course_info['unsubscribe'] == 1) {
                 //User id for actions
-				$temp[] = $user_id;
-			} else {
-				$image_path = UserManager::get_user_picture_path_by_id($user_id, 'web', false, true);
-				$image_repository = $image_path['dir'];
-				$existing_image = $image_path['file'];
-				if (!api_is_anonymous()) {
-					$photo= '<a href="userInfo.php?'.api_get_cidreq().'&origin='.$origin.'&amp;uInfo='.$user_id.'" title="'.get_lang('Info').'"  ><img src="'.$image_repository.$existing_image.'" alt="'.api_get_person_name($o_course_user['firstname'], $o_course_user['lastname']).'"  width="22" height="22" title="'.api_get_person_name($o_course_user['firstname'], $o_course_user['lastname']).'" /></a>';
-				} else {
-					$photo= '<img src="'.$image_repository.$existing_image.'" alt="'.api_get_person_name($o_course_user['firstname'], $o_course_user['lastname']).'"  width="22" height="22" title="'.api_get_person_name($o_course_user['firstname'], $o_course_user['lastname']).'" />';
-				}
                 $temp[] = $user_id;
-				$temp[] = $photo;
-                $temp[] = $o_course_user['official_code'];
-
-				if ($is_western_name_order) {
-					$temp[] = $o_course_user['firstname'];
-					$temp[] = $o_course_user['lastname'];
-				} else {
-					$temp[] = $o_course_user['lastname'];
-					$temp[] = $o_course_user['firstname'];
-				}				
-				$temp[] = $o_course_user['username'];
-				$temp[] = $o_course_user['role'];
-				$temp[] = implode(', ', $groups_name);//Group
-                
-                if ($course_info['unsubscribe'] == 1) {
-                    //User id for actions
-                    $temp[] = $user_id;
-                }
-				//$temp[] = $o_course_user['official_code'];				
-			}
-			$a_users[$user_id] = $temp;
-		}
+            }
+            //$temp[] = $o_course_user['official_code'];				
+        }
+        $a_users[$user_id] = $temp;
 	}
 	return $a_users;
 }
@@ -605,7 +578,6 @@ function active_filter($active, $url_params, $row) {
 	return $result;
 }
 
-
 /**
  * Build the modify-column of the table
  * @param int $user_id The user id

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác