Juan Carlos Raña 14 gadi atpakaļ
vecāks
revīzija
a6a04623ad

+ 1 - 1
main/admin/promotions.php

@@ -42,7 +42,7 @@ Display::display_header($tool_name);
 // Tool name
 if (isset($_GET['action']) && $_GET['action'] == 'add') {
     $tool = 'Add';
-    $interbreadcrumb[] = array ('url' => api_get_self(), 'name' => get_lang('Promotion'));
+    $interbreadcrumb[] = array ('url' => api_get_self(), 'name' => get_lang('Promotion'));    
 }
 if (isset($_GET['action']) && $_GET['action'] == 'edit') {
     $tool = 'Modify';

+ 1 - 0
main/auth/my_progress.php

@@ -11,6 +11,7 @@ require_once api_get_path(LIBRARY_PATH).'tracking.lib.php';
 require_once api_get_path(LIBRARY_PATH).'course.lib.php';
 require_once api_get_path(LIBRARY_PATH).'usermanager.lib.php';
 require_once api_get_path(SYS_CODE_PATH).'newscorm/learnpath.class.php';
+require_once api_get_path(SYS_CODE_PATH).'exercice/exercise.lib.php';
       
 $this_section = SECTION_TRACKING;
 $nameTools = get_lang('MyProgress');

+ 130 - 37
main/exercice/exercise.lib.php

@@ -3,6 +3,8 @@
 
 /**
  *	Exercise library
+ *  @todo convert this lib into a static class
+ *  
  * 	shows a question and its answers
  *	@package dokeos.exercise
  * 	@author Olivier Brouckaert <oli.brouckaert@skynet.be>
@@ -1139,10 +1141,12 @@ function get_exam_results_data($from, $number_of_items, $column, $direction) {
  * @param	bool	use or not the platform settings
  * @return  string  an html with the score modified
  */
-function show_score($score, $weight, $show_porcentage = true, $use_platform_settings = true) {
+function show_score($score, $weight, $show_percentage = true, $use_platform_settings = true) {
+    if (is_null($score) && is_null($weight)) {
+        return '-';
+    }
     $html  = '';
-    $score_rounded = $score;
-     
+    $score_rounded = $score;     
     $max_note =  api_get_setting('exercise_max_score');
     $min_note =  api_get_setting('exercise_min_score');
     
@@ -1152,49 +1156,62 @@ function show_score($score, $weight, $show_porcentage = true, $use_platform_sett
     	       $score        = $min_note + ($max_note - $min_note) * $score /$weight;
             } else {
                $score        = $min_note;
-            }
-            $score_rounded  = float_format($score, 1);
+            }            
             $weight         = $max_note;
         }
-    }
-    if ($show_porcentage) {
-        $html = float_format(($score / ($weight != 0 ? $weight : 1)) * 100, 1) . '% (' . $score_rounded . ' / ' . $weight . ')';	
-    } else {            
-        $weight = float_format($weight, 1);
+    }    
+    $score_rounded = float_format($score, 1);    
+    $weight = float_format($weight, 1);    
+    if ($show_percentage) {        
+        $parent = '(' . $score_rounded . ' / ' . $weight . ')';
+        $html = float_format(($score / ($weight != 0 ? $weight : 1)) * 100, 1) . "%  $parent";	
+    } else {    
     	$html = $score_rounded . ' / ' . $weight;
-    }
+    }    
     return $html;	
 }
 
 /**
- * Converts a score to the platform scale 
+ * Converts a numeric value in a percentage example 0.66666 to 66.67 %
+ * @param $value
+ * @return unknown_type
+ */
+function convert_to_percentage($value) {
+    $return = '-';
+    if ($value != '') {
+        $return = float_format($value * 100, 1).' %';
+    }
+    return $return;    
+}
+
+/**
+ * Converts a score/weight values to the platform scale 
  * @param   float   score
  * @param   float   weight
  * @return  float   the score rounded converted to the new range
  */
-function convert_score($score, $weight) {  
-    if ($score != '' && $weight != '') {
-        $max_note =  api_get_setting('exercise_max_score');
-        $min_note =  api_get_setting('exercise_min_score');  
-        if ($max_note != '' && $min_note != '') {
-           
+function convert_score($score, $weight) {
+    $max_note =  api_get_setting('exercise_max_score');
+    $min_note =  api_get_setting('exercise_min_score');  
+          
+    if ($score != '' && $weight != '') {        
+        if ($max_note != '' && $min_note != '') {           
            if (!empty($weight)) {          
-               $score   = $min_note + ($max_note - $min_note) * $score /$weight;
+               $score   = $min_note + ($max_note - $min_note) * $score / $weight;
            } else {
                $score   = $min_note;
-           }
-                   
+           }                   
         }           
-    }
-    $score_rounded  = round($score, 2);  
+    }    
+    $score_rounded  = float_format($score, 1);  
     return $score_rounded;
 }
 
 /**
- * Getting all exercises from a course from a session (if a session_id is provided we will show all the exercise)
+ * Getting all active exercises from a course from a session (if a session_id is provided we will show all the exercises in the course + all exercises in the session)
  * @param   array   course data
  * @param   int     session id
- * @return  array   exercise data
+ * @return  array   array with exercise data
  */
 function get_all_exercises($course_info = null, $session_id = 0) {
     if(!empty($course_info)) {
@@ -1205,32 +1222,33 @@ function get_all_exercises($course_info = null, $session_id = 0) {
     if ($session_id == -1) {
     	$session_id  = 0;
     }
-    //var_dump($session_id);
     if ($session_id == 0) {
-    	$conditions = array('where'=>array('active <> ? AND session_id = ? '=>array('-1', $session_id)), 'order'=>'title');
+    	$conditions = array('where'=>array('active = ? AND session_id = ? '=>array('1', $session_id)), 'order'=>'title');
     } else {
         //All exercises
-    	$conditions = array('where'=>array('active <> ? AND (session_id = 0 OR session_id = ? )' =>array('-1', $session_id)), 'order'=>'title');
+    	$conditions = array('where'=>array('active = ? AND (session_id = 0 OR session_id = ? )' =>array('1', $session_id)), 'order'=>'title');
     }
     //var_dump($conditions);
     return Database::select('*',$TBL_EXERCICES, $conditions);
 }
 
 /**
- * Gets the position of the score based in a given score (result/weight) and the exe_id
- * @param   float   user score to be compared
- * @param   int     exe id of the exercise (this is necesary becase if 2 students have the same score the one with the minor exe_id will have a best position)
+ * Gets the position of the score based in a given score (result/weight) and the exe_id 
+ * (NO Exercises in LPs )
+ * @param   float   user score to be compared attention => score/weight
+ * @param   int     exe id of the exercise (this is necesary because if 2 students have the same score the one with the minor exe_id will have a best position, just to be fair and FIFO)
  * @param   int     exercise id
  * @param   string  course code
  * @param   int     session id
  * @return  int     the position of the user between his friends in a course (or course within a session)
  */
-function get_exercise_result_ranking($my_score, $my_exe_id, $exercise_id, $course_code, $session_id = 0) {
+function get_exercise_result_ranking($my_score, $my_exe_id, $exercise_id, $course_code, $session_id = 0, $return_string = true) {
     //Getting all exercise results
     if (empty($session_id)) {
     	$session_id = 0;
     }
     $user_results = get_all_exercise_results($exercise_id, $course_code, $session_id);
+    $position_data = array();
     if (empty($user_results)) {
     	return 1;
     } else {
@@ -1238,15 +1256,15 @@ function get_exercise_result_ranking($my_score, $my_exe_id, $exercise_id, $cours
         $my_ranking = array();
         foreach($user_results as $result) {
             //print_r($result);
-            if (empty($result['exe_weighting']) || $result['exe_weighting'] == '0.00') {
+            if (empty($result['exe_weighting']) || $result['exe_weighting'] == '0.00') {                
                 $my_ranking[$result['exe_id']] = 0;               
             } else {
                 $my_ranking[$result['exe_id']] = $result['exe_result']/$result['exe_weighting'];
-            }           
-        }    
+            }         
+        }        
         asort($my_ranking);
         $position = count($my_ranking);
-        if (!empty($my_ranking))      
+        if (!empty($my_ranking)) {        
             foreach($my_ranking as $exe_id=>$ranking) {
             	if ($my_score >= $ranking) {
                     if ($my_score == $ranking) {
@@ -1258,6 +1276,81 @@ function get_exercise_result_ranking($my_score, $my_exe_id, $exercise_id, $cours
                     }
             	}
             }        
-        return $position;    
+        }
+        $return_value = array('position'=>$position, 'count'=>count($my_ranking)); 
+        if ($return_string) {
+            if (!empty($position) && !empty($my_ranking)) {
+               return $position.'/'.count($my_ranking); 
+            }
+        }
+        return $return_string;    
+    }
+}
+
+/*
+ *  Get the best score in a exercise (NO Exercises in LPs )
+ */
+function get_best_score($exercise_id, $course_code, $session_id) { 
+    $user_results = get_all_exercise_results($exercise_id, $course_code, $session_id);
+    $best_score_data = array();
+    $best_score = 0;
+    if (!empty($user_results)) {
+        foreach($user_results as $result) {
+            if ($result['exe_weighting'] != '') {
+                $score = $result['exe_result']/$result['exe_weighting'];
+                if ($score > $best_score) {
+                    $best_score = $score;
+                    $best_score_data = $result;
+                }
+            }
+        }
+    }
+    return $best_score_data;
+}
+
+/**
+ * Get average score (NO Exercises in LPs )
+ * @param 	int		exercise id
+ * @param 	string	course code
+ * @param 	int		session id
+ * @return 
+ */
+function get_average_score($exercise_id, $course_code, $session_id) { 
+    $user_results = get_all_exercise_results($exercise_id, $course_code, $session_id);
+    $avg_score_data = array();    
+    $avg_score = 0;
+    if (!empty($user_results)) {        
+        foreach($user_results as $result) {
+            if ($result['exe_weighting'] != '') {
+                $score = $result['exe_result']/$result['exe_weighting'];
+                $avg_score +=$score;                
+            }
+        }
+        $avg_score = float_format($avg_score / count($user_results), 1);
+    }
+    return $avg_score;
+}
+
+/**
+ * Get average score by score (NO Exercises in LPs )
+ * @param 	int		exercise id
+ * @param 	string	course code
+ * @param 	int		session id
+ * @return 
+ */
+function get_average_score_by_course($course_code, $session_id) { 
+    $user_results = get_all_exercise_results_by_course($course_code, $session_id, false);        
+    $avg_score = 0;
+    if (!empty($user_results)) {        
+        foreach($user_results as $result) {
+            if ($result['exe_weighting'] != '') {                
+                $score = $result['exe_result']/$result['exe_weighting'];
+                $avg_score +=$score;                
+            }
+        }
+        //We asume that all exe_weighting
+        //$avg_score = show_score( $avg_score / count($user_results) , $result['exe_weighting']);
+        $avg_score = ($avg_score / count($user_results));
     }
+    return $avg_score;
 }

BIN
main/img/view_choose.gif


BIN
main/img/view_choose_na.gif


+ 48 - 2
main/inc/lib/events.lib.inc.php

@@ -606,7 +606,7 @@ function get_last_attempt_date_of_exercise($exe_id) {
 }
 
 /**
- * Gets how many attempts exists by user, exercise
+ * Gets how many attempts exists by user, exercise, learning path
  * @param   int user id
  * @param   int exercise id
  * @param   int lp id
@@ -710,6 +710,46 @@ function get_all_exercise_results($exercise_id, $course_code, $session_id = 0) {
 	return $list;
 }
 
+
+
+/**
+ * Gets all exercise results (NO Exercises in LPs ) from a given exercise id, course, session
+ * @param   int     exercise id
+ * @param   string  course code
+ * @param   int     session id
+ * @return  array   with the results
+ * 
+ */
+function get_all_exercise_results_by_course($course_code, $session_id = 0, $get_count = true) {
+	$TABLETRACK_EXERCICES  = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
+	$TBL_TRACK_ATTEMPT     = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
+	$course_code           = Database::escape_string($course_code);
+	
+	$session_id = intval($session_id);
+	$select = '*';
+	if ($get_count) {
+	    $select = 'count(*) as count';    
+	}	
+	$sql = "SELECT $select FROM $TABLETRACK_EXERCICES WHERE status = ''  AND exe_cours_id = '$course_code' AND session_id = $session_id  AND orig_lp_id =0 AND orig_lp_item_id = 0 ORDER BY exe_id";	
+	$res = Database::query($sql);	
+	if ($get_count) {
+	    $row = Database::fetch_array($res,'ASSOC');	    
+	    return $row['count'];
+	} else {
+    	$list = array();	
+    	while($row = Database::fetch_array($res,'ASSOC')) {	    	   	
+    		$list[$row['exe_id']] = $row;		
+    		$sql = "SELECT * FROM $TBL_TRACK_ATTEMPT WHERE exe_id = {$row['exe_id']}";
+    		$res_question = Database::query($sql);
+    		while($row_q = Database::fetch_array($res_question,'ASSOC')) {
+    			$list[$row['exe_id']]['question_list'][$row_q['question_id']] = $row_q;
+    		}		    	    
+        }    
+	    return $list;
+	}
+}
+
+
 /**
  * Gets all exercise results (NO Exercises in LPs) from a given exercise id, course, session
  * @param   int     exercise id
@@ -743,7 +783,13 @@ function get_all_exercise_results_by_user($user_id, $exercise_id, $course_code,
 }
 
 
-
+/**
+ * Gets all exercise events from a Learning Path within a Course 	nd Session
+ * @param	int		exercise id
+ * @param	string	course_code
+ * @param 	int		session id
+ * @return 	array
+ */
 function get_all_exercise_event_from_lp($exercise_id, $course_code, $session_id = 0) {
     $TABLETRACK_EXERCICES = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
     $TBL_TRACK_ATTEMPT = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);

+ 98 - 93
main/inc/lib/fckeditor/fcktemplates.xml.php

@@ -32,13 +32,13 @@ $css = loadCSS(api_get_setting('stylesheets'));
 /* This libraries will be loaded in the showinframes.php file
 $js = '';
 if (api_get_setting('show_glossary_in_documents') != 'none') {
-	$js .= '<script language="javascript" src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/jquery.js"/>'.PHP_EOL;
-	if (api_get_setting('show_glossary_in_documents') == 'ismanual') {
-		$js .= '<script language="javascript" src="'.api_get_path(WEB_LIBRARY_PATH).'fckeditor/editor/plugins/glossary/fck_glossary_manual.js"/>';
-	} else {
+    $js .= '<script language="javascript" src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/jquery.js"/>'.PHP_EOL;
+    if (api_get_setting('show_glossary_in_documents') == 'ismanual') {
+        $js .= '<script language="javascript" src="'.api_get_path(WEB_LIBRARY_PATH).'fckeditor/editor/plugins/glossary/fck_glossary_manual.js"/>';
+    } else {
     $js .= '<script language="javascript" src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/jquery.highlight.js"/>'.PHP_EOL;
-		$js .= '<script language="javascript" src="'.api_get_path(WEB_LIBRARY_PATH).'fckeditor/editor/plugins/glossary/fck_glossary_automatic.js"/>';
-	}
+        $js .= '<script language="javascript" src="'.api_get_path(WEB_LIBRARY_PATH).'fckeditor/editor/plugins/glossary/fck_glossary_automatic.js"/>';
+    }
 }
 */
 
@@ -55,17 +55,17 @@ echo '<Templates imagesBasePath="">';
 // Load empty template.
 load_empty_template();
 
-if($is_allowed_to_edit){	
-	// Load the templates that were defined by the platform admin.
-	load_platform_templates();	
+if($is_allowed_to_edit){
+    // Load the templates that were defined by the platform admin.
+    load_platform_templates();
 }
 else{
-	// Load student templates.
-	load_student_templates();	
+    // Load student templates.
+    load_student_templates();
 }
 // Load the personal templates.
-	load_personal_templates(api_get_user_id());
-	
+    load_personal_templates(api_get_user_id());
+
 // End the templates node.
 echo '</Templates>';
 
@@ -79,9 +79,14 @@ exit;
  * @return html code for adding a css style <style ...
  */
 function loadCSS($css_name) {
-	$template_css = ' <style type="text/css">'.str_replace('../../img/', api_get_path(REL_CODE_PATH).'img/', file_get_contents(api_get_path(SYS_PATH).'main/css/'.$css_name.'/default.css')).'</style>';
-	$template_css = str_replace('images/', api_get_path(REL_CODE_PATH).'css/'.$css_name.'/images/', $template_css);
-	return $template_css;
+    $template_css = file_get_contents(api_get_path(SYS_PATH).'main/css/'.$css_name.'/default.css');
+    $template_css = str_replace('../../img/', api_get_path(REL_CODE_PATH).'img/', $template_css);
+    $template_css = str_replace('images/', api_get_path(REL_CODE_PATH).'css/'.$css_name.'/images/', $template_css);
+
+    // Reseting the body's background color to be in white, see Task #1885 and http://www.chamilo.org/en/node/713
+    $template_css .= "\n".'body { background: #fff; } /* Resetting the background. */'."\n";
+
+    return ' <style type="text/css">'.$template_css.'</style>';
 }
 
 /**
@@ -118,30 +123,30 @@ function s2($var) {
  */
 function load_platform_templates() {
 
-	global $css, $img_dir, $default_course_dir, $js;
+    global $css, $img_dir, $default_course_dir, $js;
 
-	$table_template = Database::get_main_table('system_template');
-	$sql = "SELECT title, image, comment, content FROM $table_template";
-	$result = Database::query($sql);
+    $table_template = Database::get_main_table('system_template');
+    $sql = "SELECT title, image, comment, content FROM $table_template";
+    $result = Database::query($sql);
 
-	$search = array('{CSS}', '{IMG_DIR}', '{REL_PATH}', '{COURSE_DIR}');
-	$replace = array($css.$js, $img_dir, api_get_path(REL_PATH), $default_course_dir);
-	$template_thumb = api_get_path(WEB_PATH).'home/default_platform_document/template_thumb/';
+    $search = array('{CSS}', '{IMG_DIR}', '{REL_PATH}', '{COURSE_DIR}');
+    $replace = array($css.$js, $img_dir, api_get_path(REL_PATH), $default_course_dir);
+    $template_thumb = api_get_path(WEB_PATH).'home/default_platform_document/template_thumb/';
 
-	while ($row = Database::fetch_array($result)) {
-		$image = empty($row['image']) ? $template_thumb.'empty.gif' : $template_thumb.$row['image'];
+    while ($row = Database::fetch_array($result)) {
+        $image = empty($row['image']) ? $template_thumb.'empty.gif' : $template_thumb.$row['image'];
         $row['content'] = str_replace($search, $replace, $row['content']);
 
-		echo '
-				<Template title="'.s($row['title']).'" image="'.$image.'">
-					<Description>'.s($row['comment']).'</Description>
-					<Html>
-						<![CDATA[
-							    '.$row['content'].'
-						]]>
-					</Html>
-				</Template>';
-	}
+        echo '
+                <Template title="'.s($row['title']).'" image="'.$image.'">
+                    <Description>'.s($row['comment']).'</Description>
+                    <Html>
+                        <![CDATA[
+                                '.$row['content'].'
+                        ]]>
+                    </Html>
+                </Template>';
+    }
 }
 
 /**
@@ -155,68 +160,68 @@ function load_platform_templates() {
  * @since Dokeos 1.8.6 The code already existed but not in a function and a lot less performant.
  */
 function load_personal_templates($user_id = 0) {
-	global $_course;
-
-	// the templates that the user has defined are only available inside the course itself
-	if (empty($_course)) {
-		return false;
-	}
-
-	// For which user are we getting the templates?
-	if ($user_id == 0) {
-		$user_id = api_get_user_id();
-	}
-
-	$table_template = Database::get_main_table(TABLE_MAIN_TEMPLATES);
-	$table_document = Database::get_course_table(TABLE_DOCUMENT, $_course['dbName']);
-
-	// The sql statement for getting all the user defined templates
-	$sql = "SELECT template.id, template.title, template.description, template.image, template.ref_doc, document.path
-			FROM ".$table_template." template, ".$table_document." document
-			WHERE user_id='".Database::escape_string($user_id)."'
-			AND course_code='".Database::escape_string(api_get_course_id())."'
-			AND document.id = template.ref_doc";
-
-	$result_template = Database::query($sql);
-
-	while ($row = Database::fetch_array($result_template)) {
-
-		$row['content'] = file_get_contents(api_get_path(SYS_COURSE_PATH).$_course['path'].'/document'.$row['path']);
-		//$row['content'] = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document'.$row['path'];
-
-		if (!empty($row['image'])) {
-			$image = api_get_path(WEB_PATH).'courses/'.$_course['path'].'/upload/template_thumbnails/'.$row['image'];
-		} else {
-			$image = api_get_path(WEB_PATH).'home/default_platform_document/template_thumb/noimage.gif';
-		}
-
-		echo '
-				<Template title="'.s2($row['title']).'" image="'.$image.'">
-					<Description>'.s2($row['Description']).'</Description>
-					<Html>
-						<![CDATA[
-							    '.$row['content'].'
-						]]>
-					</Html>
-				</Template>';
-	}
+    global $_course;
+
+    // the templates that the user has defined are only available inside the course itself
+    if (empty($_course)) {
+        return false;
+    }
+
+    // For which user are we getting the templates?
+    if ($user_id == 0) {
+        $user_id = api_get_user_id();
+    }
+
+    $table_template = Database::get_main_table(TABLE_MAIN_TEMPLATES);
+    $table_document = Database::get_course_table(TABLE_DOCUMENT, $_course['dbName']);
+
+    // The sql statement for getting all the user defined templates
+    $sql = "SELECT template.id, template.title, template.description, template.image, template.ref_doc, document.path
+            FROM ".$table_template." template, ".$table_document." document
+            WHERE user_id='".Database::escape_string($user_id)."'
+            AND course_code='".Database::escape_string(api_get_course_id())."'
+            AND document.id = template.ref_doc";
+
+    $result_template = Database::query($sql);
+
+    while ($row = Database::fetch_array($result_template)) {
+
+        $row['content'] = file_get_contents(api_get_path(SYS_COURSE_PATH).$_course['path'].'/document'.$row['path']);
+        //$row['content'] = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document'.$row['path'];
+
+        if (!empty($row['image'])) {
+            $image = api_get_path(WEB_PATH).'courses/'.$_course['path'].'/upload/template_thumbnails/'.$row['image'];
+        } else {
+            $image = api_get_path(WEB_PATH).'home/default_platform_document/template_thumb/noimage.gif';
+        }
+
+        echo '
+                <Template title="'.s2($row['title']).'" image="'.$image.'">
+                    <Description>'.s2($row['Description']).'</Description>
+                    <Html>
+                        <![CDATA[
+                                '.$row['content'].'
+                        ]]>
+                    </Html>
+                </Template>';
+    }
 }
 
 function load_empty_template() {
-	global $css, $js;
-	?>
+    global $css, $js;
+    ?>
 <Template title="<?php echo s2('Empty'); ?>" image="<?php echo api_get_path(WEB_PATH).'home/default_platform_document/template_thumb/empty.gif'; ?>">
     <Description></Description>
     <Html>
-	    <![CDATA[
-		   <html>
-		   <head>
-			<?php echo $css; ?>
-			<?php echo $js; ?>
-		   <body></body>
-		   </head>
-		   </html>
-	   ]]>
+        <![CDATA[
+           <html>
+           <head>
+            <?php echo $css; ?>
+            <?php echo $js; ?>
+           <body></body>
+           </head>
+           </html>
+       ]]>
     </Html>
 </Template>
 <?php
@@ -226,8 +231,8 @@ function load_empty_template() {
  * Loads the student templates
  */
 function load_student_templates() {
-	$fckeditor_template_path='/main/inc/lib/fckeditor/editor/dialog/fck_template/images/';
-	?>
+    $fckeditor_template_path='/main/inc/lib/fckeditor/editor/dialog/fck_template/images/';
+    ?>
     <Template title="Image and Title" image="<?php echo api_get_path(WEB_PATH).$fckeditor_template_path.'template1.gif';?>">
         <Description>One main image with a title and text that surround the image.</Description>
         <Html>

+ 2 - 1
main/inc/lib/promotion.lib.php

@@ -43,7 +43,8 @@ class Promotion extends Model {
 		// action links
 		echo '<div class="actions" style="margin-bottom:20px">';
         echo '<a href="career_dashboard.php">'.Display::return_icon('back.png',get_lang('Back')).get_lang('Back').'</a>';
-		echo '<a href="'.api_get_self().'?action=add">'.Display::return_icon('filenew.gif',get_lang('Add')).get_lang('Add').'</a>';	
+		echo '<a href="'.api_get_self().'?action=add">'.Display::return_icon('filenew.gif',get_lang('Add')).get_lang('Add').'</a>';			
+		echo '<a href="'.api_get_path(WEB_CODE_PATH).'admin/session_add.php">'.Display::return_icon('view_more_stats.gif',get_lang('AddSession')).get_lang('AddSession').'</a>';			
 		echo '</div>';
         echo Display::grid_html('promotions');  
 	}

+ 4 - 34
main/inc/lib/statsUtils.lib.inc.php

@@ -1,41 +1,11 @@
 <?php
-/*
-==============================================================================
-	Dokeos - elearning and course management software
-
-	Copyright (c) 2004 Dokeos S.A.
-	Copyright (c) 2003 Ghent University (UGent)
-	Copyright (c) 2001 Universite catholique de Louvain (UCL)
-	Copyright (c) various contributors
-
-	For a full list of contributors, see "credits.txt".
-	The full license can be read in "license.txt".
-
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
-
-	See the GNU General Public License for more details.
-
-	Contact: Dokeos, 181 rue Royale, B-1000 Brussels, Belgium, info@dokeos.com
-==============================================================================
-*/
+/* For licensing terms, see /license.txt */
 /**
-==============================================================================
-*	This is the statistic utility functions library for Dokeos.
+*	This is the statistic utility functions library for Chamilo.
 *	Include/require it in your code to use its functionality.
-*
-*	@package dokeos.library
-==============================================================================
-*/
-
-/*
-==============================================================================
-		FUNCTIONS
-==============================================================================
+*	@package chamilo.library
 */
-
+/* FUNCTIONS */
 /**
  * @author Sebastien Piraux <piraux_seb@hotmail.com>
  * @param sql : a sql query (as a string)

+ 185 - 131
main/inc/lib/tracking.lib.php

@@ -1908,27 +1908,20 @@ class Tracking {
         $rs = Database::query($sql);
         while($row = Database :: fetch_array($rs)) {
             $course_in_session[$row['session_id']][$row['course_code']] = CourseManager::get_course_information($row['course_code']);
-        }
-        
+        }        
         
         $html  = '';
-        if ($show_courses) {            
-         
-            /*echo '<div class="actions-title" >';
-            echo $nameTools;
-            echo '</div>';*/       
-                    
+        if ($show_courses) {                   
             if (!empty($courses)) {
-    
-                $html = '<table class="data_table" width="100%">';
+                $html .= '<table class="data_table" width="100%">';
                 $html .= '<tr class="tableName">
                             <td colspan="6">
-                                <h1>'.get_lang('MyCourses').'</h1>
+                                '.Display::tag('h1', get_lang('MyCourses')).'
                             </td>
                         </tr>';
                 $html .= '
-                <tr>
-                  <th width="300px">'.get_lang('Course').'</th>
+                <tr>                  
+                  '.Display::tag('th', get_lang('Course'),          array('width'=>'300px')).'
                   '.Display::tag('th', get_lang('Time'),            array('class'=>'head')).'
                   '.Display::tag('th', get_lang('Progress'),        array('class'=>'head')).'
                   '.Display::tag('th', get_lang('Score').Display :: return_icon('info3.gif', get_lang('ScormAndLPTestTotalAverage'), array('align' => 'absmiddle', 'hspace' => '3px')),array('class'=>'head')).'
@@ -1982,6 +1975,7 @@ class Tracking {
             }
         }
         
+        //Session
         if (!empty($course_in_session)) {
             $html .= '<br />';
             $html .= Display::tag('h1',get_lang('Sessions'));
@@ -1993,22 +1987,62 @@ class Tracking {
                     }
                 }                
                 $html .= Display::tag('h2',api_get_session_name($key));
+                
+                $html .= '<table class="data_table" width="100%">';    
+                $html .= '
+                <tr>                  
+                  '.Display::tag('th', get_lang('PublishedExercises'),       array('width'=>'300px')).'
+                  '.Display::tag('th', get_lang('DoneExercises'),            array('class'=>'head')).'
+                  '.Display::tag('th', get_lang('AverageExerciseResult'),    array('class'=>'head')).'                  
+                </tr>';
+                
+
+                $all_exercises = 0;
+                $all_done_exercise = 0;
+                $all_average = 0;
+                
+                $stats_array = array();
+                
+                foreach ($session as $enreg) {    
+                    //All exercises in the course
+                    $exercises      = count(get_all_exercises($enreg, $key));
+                    //Count of user results
+                    $done_exercises = get_all_exercise_results_by_course($enreg['code'], $key);
+                    //Average
+                    $average        = get_average_score_by_course($enreg['code'], $key);
+                    
+                    $all_exercises +=$exercises;
+                    $all_done_exercise +=$done_exercises;
+                    $all_average +=$average;
+                    $stats_array[$enreg['code']] = array('exercises'=>$exercises, 'done_exercises'=>$done_exercises, 'average'=>$average);
+                }         
+                $all_average = $all_average /  count($session);     
+                $html .= Display::tag('td', $all_exercises);
+                $html .= Display::tag('td', $all_done_exercise);
+                $html .= Display::tag('td', convert_to_percentage($all_average));
+                $html .='</table><br />';
+                    
+                
+                $html .= Display::tag('h2',get_lang('CourseList'));
+                
                 $html .= '        
                 <table class="data_table" width="100%">';
                 $html .= '
                     <tr>
                       <th width="300px">'.get_lang('Course').'</th>
-                      '.Display::tag('th', get_lang('Time')         , array('class'=>'head')).'
-                      '.Display::tag('th', get_lang('Progress')     , array('class'=>'head')).'
+                      '.Display::tag('th', get_lang('PublishedExercises'),array('class'=>'head')).'
+                      '.Display::tag('th', get_lang('DoneExercises'),     array('class'=>'head')).'
+                      '.Display::tag('th', get_lang('AverageExerciseResult'),     array('class'=>'head')).'
+                      '.Display::tag('th', get_lang('Time')         ,     array('class'=>'head')).'
+                      '.Display::tag('th', get_lang('LPProgress')     ,   array('class'=>'head')).'
                       '.Display::tag('th', get_lang('Score').Display :: return_icon('info3.gif', get_lang('ScormAndLPTestTotalAverage'), array ('align' => 'absmiddle', 'hspace' => '3px')), array('class'=>'head')).'
-                      '.Display::tag('th', get_lang('LastConnexion'), array('class'=>'head')).'      
-                      '.Display::tag('th', get_lang('Details'),       array('class'=>'head')).'
+                      '.Display::tag('th', get_lang('LastConnexion'),     array('class'=>'head')).'      
+                      '.Display::tag('th', get_lang('Details'),           array('class'=>'head')).'
                     </tr>';
                 foreach ($session as $enreg) {               
                     $weighting = 0;
                     $last_connection       = Tracking :: get_last_connection_date_on_the_course($user_id, $enreg['code'], $key);
-                    $progress              = Tracking :: get_avg_student_progress($user_id, $enreg['code'],array(), $key);
-                    
+                    $progress              = Tracking :: get_avg_student_progress($user_id, $enreg['code'],array(), $key);                    
                     $total_time_login      = Tracking :: get_time_spent_on_the_course($user_id, $enreg['code'], $key);
                     $time                  = api_time_to_hms($total_time_login);
                     $percentage_score      = Tracking :: get_avg_student_score($user_id, $enreg['code'], array(), $key);
@@ -2019,35 +2053,44 @@ class Tracking {
                         $html .= '<tr  class="row_even">';
                     }
                     
+                    $html .= Display::tag('td', $enreg['title']);/*
+                    //All exercises in the course
+                    $exercises = get_all_exercises($enreg, $key);
+                    //Count of user results
+                    $done_exercises = get_all_exercise_results_by_course($enreg['code'], $key);
+                    //Average
+                    $average = get_average_score_by_course($enreg['code'], $key);*/
                     
-                    $html .= '<td>'.$enreg['title'].' </td>';        
-                    $html .= '<td align="center">'.$time.'</td>';
-                    
+                    $html .= Display::tag('td', $stats_array[$enreg['code']]['exercises']);
+                    $html .= Display::tag('td', $stats_array[$enreg['code']]['done_exercises']);
+                    $html .= Display::tag('td', convert_to_percentage($stats_array[$enreg['code']]['average']));
+                    $html .= Display::tag('td', $time, array('align'=>'center'));
+                                        
                     if (is_numeric($progress)) {
                         $progress = $progress.'%';
                     } else {
                         $progress = '0%';
                     }
-                    
-                    $html .= '<td align="center">'.$progress.'</td>';
-                    $html .= '<td align="center">';
+                    $html .= Display::tag('td', $progress, array('align'=>'center'));                    
                     if (is_numeric($percentage_score)) {
-                        $html .= $percentage_score.'%';
+                        $percentage_score = $percentage_score.'%';
                     } else {
-                        $html .= '0%';
+                        $percentage_score = '0%';
                     }   
-                    $html .= '</td>';        
-                    $html .= '<td align="center">'.$last_connection.'</td>';        
-                    $html .= '<td align="center">';     
+                    $html .= Display::tag('td', $percentage_score, array('align'=>'center'));                         
+                    $html .= Display::tag('td', $last_connection, array('align'=>'center')); 
+                        
                     if ($enreg['code'] == $_GET['course'] && $_GET['session_id'] == $key) {
-                        $html .= '<a href="#">';
-                        $html .=Display::return_icon('2rightarrow_na.gif', get_lang('Details'));
+                        $details = '<a href="#">';
+                        $details .=Display::return_icon('2rightarrow_na.gif', get_lang('Details'));
                     } else {
-                        $html .= '<a href="'.api_get_self().'?course='.$enreg['code'].'&session_id='.$key.$extra_params.'">';
-                        $html .=Display::return_icon('2rightarrow.gif', get_lang('Details'));
+                        $details = '<a href="'.api_get_self().'?course='.$enreg['code'].'&session_id='.$key.$extra_params.'">';
+                        $details .=Display::return_icon('2rightarrow.gif', get_lang('Details'));
                     }
-                    $html .= '</a>';
-                    $html .= '</td>';
+                    $details .= '</a>';                    
+               
+                    $html .= Display::tag('td', $details, array('align'=>'center')); 
+                    
                     $i = $i ? 0 : 1;
                     $html .= '</tr>';
                 }
@@ -2068,19 +2111,21 @@ class Tracking {
     function show_course_detail($user_id, $course_code, $session_id) {        
         $html = '';
         if (isset($course_code)) {
-            $session_id = intval($session_id);
-            $user_id    = intval($user_id);
-    
-            $course                     = Database::escape_string($course_code);
+            require_once api_get_path(SYS_CODE_PATH).'exercice/exercise.lib.php';
+            
+            $user_id                    = intval($user_id);
+            $session_id                 = intval($session_id);
+            $course                     = Database::escape_string($course_code);            
             $course_info                = CourseManager::get_course_information($course);
+            
             $tbl_user                   = Database :: get_main_table(TABLE_MAIN_USER);
             $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);
-            $tbl_course_lp_view         = Database :: get_course_table(TABLE_LP_VIEW, $course_info['db_name']);
+            $tbl_course_lp_view         = Database :: get_course_table(TABLE_LP_VIEW,   $course_info['db_name']);
             $tbl_course_lp_view_item    = Database :: get_course_table(TABLE_LP_ITEM_VIEW, $course_info['db_name']);
-            $tbl_course_lp              = Database :: get_course_table(TABLE_LP_MAIN, $course_info['db_name']);
-            $tbl_course_lp_item         = Database :: get_course_table(TABLE_LP_ITEM, $course_info['db_name']);
+            $tbl_course_lp              = Database :: get_course_table(TABLE_LP_MAIN,   $course_info['db_name']);
+            $tbl_course_lp_item         = Database :: get_course_table(TABLE_LP_ITEM,   $course_info['db_name']);
             $tbl_course_quiz            = Database :: get_course_table(TABLE_QUIZ_TEST, $course_info['db_name']);
     
             //get coach and session_name if there is one and if session_mode is activated
@@ -2140,7 +2185,7 @@ class Tracking {
             //$tableTitle = $course_info['title'].' | '.get_lang('Coach').' : '.$course_info['tutor_name'].((!empty($session_name)) ? ' | '.get_lang('Session').' : '.$session_name : '');
             
             $session_name = api_get_session_name($session_id);
-            $tableTitle = ((!empty($session_name)) ? ' '.get_lang('Session').' : '.$session_name.' | ' : '').''.$course_info['title'];
+            $tableTitle = $course_info['title'];
     
             $html .='
             <table class="data_table" width="100%">
@@ -2150,9 +2195,9 @@ class Tracking {
                     </td>
                 </tr><tr>';                
                 
-            $html .= Display::tag('th', get_lang('Learnpath'), array('class'=>'head', 'style'=>'color:#000'));
-            $html .= Display::tag('th', get_lang('Time'), array('class'=>'head', 'style'=>'color:#000'));
-            $html .= Display::tag('th', get_lang('Progress'), array('class'=>'head', 'style'=>'color:#000'));
+            $html .= Display::tag('th', get_lang('Learnpath'),     array('class'=>'head', 'style'=>'color:#000'));
+            $html .= Display::tag('th', get_lang('Time'),          array('class'=>'head', 'style'=>'color:#000'));
+            $html .= Display::tag('th', get_lang('Progress'),      array('class'=>'head', 'style'=>'color:#000'));
             $html .= Display::tag('th', get_lang('LastConnexion'), array('class'=>'head', 'style'=>'color:#000'));
             $html .= '</tr>';
             
@@ -2164,41 +2209,38 @@ class Tracking {
             
             $result_learnpath = Database::query($sql_learnpath);
             if (Database::num_rows($result_learnpath) > 0) {
-                while($learnpath = Database::fetch_array($result_learnpath)) {
-                    //$progress = learnpath :: get_db_progress($learnpath['id'], $user_id, 'abs', $course_info['db_name'], false, $session_id);                        
+                while($learnpath = Database::fetch_array($result_learnpath)) {                       
                     $progress               = Tracking::get_avg_student_progress($user_id, $course, array($learnpath['id']), $session_id);                        
                     $last_connection_in_lp  = Tracking::get_last_connection_time_in_lp($user_id, $course, $learnpath['id'], $session_id);
                     $time_spent_in_lp       = Tracking::get_time_spent_in_lp($user_id, $course, array($learnpath['id']), $session_id);
                     $time_spent_in_lp       = api_time_to_hms($time_spent_in_lp);                            
                                   
-                    $html .= "<tr><td>";
-                    $html .= $learnpath['name'];
-                    $html .= "  </td>
-                            <td align='center'>";
-                    $html .= $time_spent_in_lp;
-                    $html .= "  </td>
-                            <td align='center'>";
+                    $html .= "<tr>";
+                    $html .= Display::tag('td', $learnpath['name']);
+                    $html .= Display::tag('td', $time_spent_in_lp, array('align'=>'center'));
                     if (is_numeric($progress)) {
                         $progress = $progress.'%';
-                    }
-                    $html .= $progress;
-                    $html .= "  </td>
-                            <td align='center' width=180px >";
-                                            
+                    }                    
+                    $html .= Display::tag('td', $progress, array('align'=>'center'));
+                    $last_connection = '-';                                                                
                     if (!empty($last_connection_in_lp)) {
-                        $html .= api_get_utc_datetime($last_connection_in_lp);
-                    } else {
-                        $html .= '-';
+                        $last_connection = api_get_utc_datetime($last_connection_in_lp);
                     }
-                    $html .= "</td></tr>";
+                    $html .= Display::tag('td', $last_connection, array('align'=>'center','width'=>'180px'));
+                    $html .= "</tr>";
                 }
             } else {
-                $html .= '  <tr>
-                            <td colspan="4" align="center">
-                                '.get_lang('NoLearnpath').'
-                            </td>
-                        </tr>';
+                $html .= '<tr>
+                          	<td colspan="4" align="center">
+                            	'.get_lang('NoLearnpath').'
+							</td>
+						  </tr>';
             }
+            
+            $html .='</table><br />
+            <table class="data_table" width="100%">
+                <tr>';     
+                     
                         
             // This code was commented on purpose see BT#924
 
@@ -2206,81 +2248,93 @@ class Tracking {
             $result_visibility_tests = Database::query($sql);
 
             if (Database::result($result_visibility_tests, 0, 'visibility') == 1) {*/
+            
             if (empty($session_id)) {
                 $sql_exercices = "SELECT quiz.title,id, results_disabled FROM ".$tbl_course_quiz." AS quiz WHERE active='1' AND session_id = 0";
             } else {
                 $sql_exercices = "SELECT quiz.title,id, results_disabled FROM ".$tbl_course_quiz." AS quiz WHERE active='1'";
-            }
-                $html .= '<tr>
-                    <th class="head" style="color:#000">'.get_lang('Exercices').'</th>
-                    <th class="head" style="color:#000">'.get_lang('Score').'</th>
-                    <th class="head" style="color:#000">'.get_lang('Attempts').'</th>
-                    <th class="head" style="color:#000">'.get_lang('LatestAttempt').'</th>
-                    </tr>';
-                $result_exercices = Database::query($sql_exercices);
-                if (Database::num_rows($result_exercices) > 0) {
-                    while ($exercices = Database::fetch_array($result_exercices)) {
-                        $score = 0;
-                        $weighting = 0;
-                        $exercise_stats = get_all_exercise_results($exercices['id'],$course_info['code'], $session_id);
-                        $attempts = 0;
-                        foreach($exercise_stats as $exercise_stat) {
+            }            
+            $html .= '<tr>                
+                <th class="head" style="color:#000">'.get_lang('Exercices').'</th>
+                <th class="head" style="color:#000">'.get_lang('Attempts').'</th>                    
+                <th class="head" style="color:#000">'.get_lang('LatestAttempt').'</th>
+                <th class="head" style="color:#000">'.get_lang('Position').'</th>
+                <th class="head" style="color:#000">'.get_lang('BestResultInCourse').'</th>                                       
+                </tr>';
+            $result_exercices = Database::query($sql_exercices);
+            if (Database::num_rows($result_exercices) > 0) {
+                while ($exercices = Database::fetch_array($result_exercices)) {
+                    $score = $weighting = $attempts = 0;                        
+                    $exercise_stats = get_all_exercise_results($exercices['id'], $course_info['code'], $session_id);
+                    //User attempts we assume the latest item in the loop is the latest attempt
+                    if (!empty($exercise_stats)) {
+                        //$best_score = 0; $best_score_array = array();
+                        foreach($exercise_stats as $exercise_stat) {                        
                             if ($exercise_stat['exe_user_id'] == $user_id) {
-                               $score          = $score + $exercise_stat['exe_result'];
-                               $weighting      = $weighting + $exercise_stat['exe_weighting'];
+                                
+                               //Always getting the latest attempt
+                               $score          = $exercise_stat['exe_result'];
+                               $weighting      = $exercise_stat['exe_weighting'];                               
                                $exe_id         = $exercise_stat['exe_id'];
+                               
+                               //Use this to take the average
+                               //$score          = $score + $exercise_stat['exe_result'];
+                               //$weighting      = $weighting + $exercise_stat['exe_weighting'];
+                               
+                               //Getting my best score
+                               /*
+                               if ($score > $best_score ) {
+                                   $best_score = $score;
+                                   $best_score_array = $exercise_stat;
+                               }*/                       
                                $attempts++;
                             }
-                        }                            
-                        if  ($weighting > 0) {
-                            // i.e 10.50%
-                            $percentage_score = round(($score * 100) / $weighting, 2);
-                        } else {
-                            $percentage_score = 0;
-                        }
-                        $html .= '<tr>
-                                <td>';
-                        $html .= $exercices['title'];
-                        $html .= '</td>';
-                        if ($exercices['results_disabled'] == 0) {
-                            $html .= '<td align="center">';
-                            if ($attempts > 0) {
-                                $html .= $percentage_score.'%';
-                            } else {
-                                $html .= '/';
-                            }
-                            $html .= '</td>';
-                            $html .= '<td align="center">';
-                            $html .=  $attempts;
-                            $html .= '</td>
-                                    <td align="center" width="25">';
-                            if ($attempts > 0) {
-                                $html .= '<a href="../exercice/exercise_show.php?origin=myprogress&id='.$exe_id.'&cidReq='.$course_info['code'].'&id_session='.$session_id.'"> '.Display::return_icon('quiz.gif', get_lang('Quiz')).' </a>';
+                        }   
+                    }
+                    
+                    $html .= '<tr>';                                
+                    $html .= Display::tag('td', $exercices['title']);
+                    //Exercise configuration show results
+                    if ($exercices['results_disabled'] == 0) {
+                        $latest_attempt_url = '';
+                        $percentage_score_result  = '-';
+                        $position = '-';
+                        $best_score = '-';
+                        
+                        $best_score_data = get_best_score($exercices['id'], $course_info['code'], $session_id);     
+                        $best_score      = show_score($best_score_data['exe_result'], $best_score_data['exe_weighting']);                       
+                        if ($attempts > 0) {
+                            $latest_attempt_url .= '<a href="../exercice/exercise_show.php?origin=myprogress&id='.$exe_id.'&cidReq='.$course_info['code'].'&id_session='.$session_id.'"> '.Display::return_icon('quiz.gif', get_lang('Quiz')).' </a>';
+                            $percentage_score_result = show_score($score, $weighting).' '.$latest_attempt_url;
+                            $my_score = 0;
+                            if (!empty($weighting)) {                           
+                                $my_score = $score/$weighting;
                             }
-                            $html .= '</td>';
-                        } else {
-                            // we show or not the results if the teacher wants to
-                            $html .= '<td align="center">';
-                            $html .= get_lang('CantShowResults');
-                            $html .= '</td>';
-                            $html .= '<td align="center">';
-                            $html .= ' -- ';
-                            $html .= '</td>
-                                    <td align="center" width="25">';
-                            $html .= ' -- ';
-                            $html .= '</td>';
-                        }
-                        $html .= '</tr>';
+                            $position = get_exercise_result_ranking($my_score, $exe_id, $exercices['id'], $course_info['code'], $session_id);                            
+                        }             
+                        $html .= Display::tag('td', $attempts,                 array('align'=>'center'));                                          
+                        $html .= Display::tag('td', $percentage_score_result,  array('align'=>'center'));
+                        $html .= Display::tag('td', $position,                 array('align'=>'center'));                            
+                        $html .= Display::tag('td', $best_score,               array('align'=>'center'));
+                        //$html .= Display::tag('td', $latest_attempt_url,       array('align'=>'center', 'width'=>'25'));                           
+                        
+                    } else {
+                        // Exercise configuration NO results
+                        $html .= Display::tag('td', get_lang('CantShowResults'), array('align'=>'center'));  
+                        $html .= Display::tag('td', '--', array('align'=>'center'));                            
+                        $html .= Display::tag('td', '--', array('align'=>'center'));
+                        $html .= Display::tag('td', '--', array('align'=>'center'));
+                        $html .= Display::tag('td', '--', array('align'=>'center'));                            
                     }
-                } else {
-                    $html .= '<tr><td colspan="4" align="center">'.get_lang('NoEx').'</td></tr>';
+                    $html .= '</tr>';
                 }
-                $html .= '</table>';
+            } else {
+                $html .= '<tr><td colspan="5" align="center">'.get_lang('NoEx').'</td></tr>';
+            }
+            $html .= '</table>';
         }
         return $html;
     }
-    
-
 }
 
 class TrackingCourseLog {

+ 7 - 9
main/newscorm/lp_stats.php

@@ -287,8 +287,7 @@ if (is_array($list) && count($list) > 0) {
                         $view_score = Display::return_icon('invisible.gif', get_lang('ResultsHiddenByExerciseSetting'));
                     } else {
                         //$view_score = ($score == 0 ? '/' : ($maxscore === 0 ? $score : $score . '/' . float_format($maxscore, 1)));
-                        $view_score = show_score($score,$maxscore, false);
-                        
+                        $view_score = show_score($score, $maxscore, false);                        
                     }
                     $output .= "<tr class='$oddclass'>\n" . "<td></td>\n" . "<td>$extend_attempt_link</td>\n" . '<td colspan="3">' . get_lang('Attempt') . ' ' . $row['iv_view_count'] . "</td>\n"
                      . '<td colspan="2"><font color="' . $color . '"><div class="mystatus">' . $my_lesson_status . "</div></font></td>\n" . '<td colspan="2"><div class="mystatus" align="center">' . $view_score . "</div></td>\n" . '<td colspan="2"><div class="mystatus">'.$time.'</div></td><td></td></tr>';
@@ -308,7 +307,6 @@ if (is_array($list) && count($list) > 0) {
                         } else {
                             $temp[] = ($score == 0 ? '/' : ($maxscore == 0 ? $score : $score . '/' . float_format($maxscore, 1)));
                         }
-
                         $temp[] = $time;
                         $csv_content[] = $temp;
                     }
@@ -638,18 +636,18 @@ if (is_array($list) && count($list) > 0) {
                                 $view_score =  Display::return_icon('invisible.gif', get_lang('ResultsHiddenByExerciseSetting'));
                             } else {
                                 // Show only float when need it.
-                                $my_score  = float_format( $my_score, 1);
-                                $my_maxscore =float_format($my_maxscore, 1);
+                                //$my_score  = float_format( $my_score, 1);
+                                //$my_maxscore =float_format($my_maxscore, 1);
                                 if ($my_score == 0 ) {
-                                    $view_score = 	'0/'.$my_maxscore;
+                                    //$view_score = 	'0/'.$my_maxscore;
+                                    $view_score = show_score(0, $my_maxscore, false);
                                 } else {
                                     if ($my_maxscore == 0) {
                                         $view_score = $my_score;
                                     } else {
                                         //$view_score = $my_score . '/' . $my_maxscore;
                                         $view_score = show_score($my_score, $my_maxscore, false);
-                                    }
-                                    
+                                    }                                    
                                 }
                                 //$view_score = ($my_score == 0 ? '0.00/'.$my_maxscore : ($my_maxscore == 0 ? $my_score : $my_score . '/' . $my_maxscore));
                             }
@@ -676,7 +674,7 @@ if (is_array($list) && count($list) > 0) {
                                     $output .= '<td><a href="../exercice/exercise_show.php?origin=correct_exercise_in_lp&id=' . $my_exe_id . '" target="_parent"><img src="' . api_get_path(WEB_IMG_PATH) . 'quiz.gif" alt="'.get_lang('ShowAndQualifyAttempt').'" title="'.get_lang('ShowAndQualifyAttempt').'"></a></td>';
                                 }
                             }
-                             $output .= '</tr>';
+                            $output .= '</tr>';
                             $n++;
                         }
                     }

+ 29 - 24
main/session/index.php

@@ -153,24 +153,28 @@ foreach($final_array as $session_data) {
         $row = 1;
         $column = 0;
         $table->setCellContents($row, $column, $course_data['name']);
-        $column++;*/           
+        $column++;*/      
+        
         if (!empty($course_data['exercises'])) {
             //Exercises            
             foreach ($course_data['exercises'] as $my_exercise_id => $exercise_data) {
+                $best_score_data = get_best_score($my_exercise_id, $my_course_code, $session_id);     
+                $best_score      = show_score($best_score_data['exe_result'], $best_score_data['exe_weighting']);
                 //Exercise results                              
                 $counter = 1;                    
                 foreach ($exercise_data['data'] as $exercise_result) {                    
                     $my_exercise_result = array($exercise_data['name'], $exercise_result['exe_id']);
-                    $column = 1;      
-                    $score          = $exercise_result['exe_result'].' / '.$exercise_result['exe_weighting'];
-                    $platform_score = show_score($exercise_result['exe_result'], $exercise_result['exe_weighting'], false);
-                    if (!empty($exercise_result['exe_weighting']) && intval($exercise_result['exe_weighting']) != 0 ) {                        
-                        $my_score = $exercise_result['exe_result']/$exercise_result['exe_weighting'];
-                    } else {
-                    	$my_score = 0;
-                    }
+                    $column = 1;   
+                    $platform_score = show_score($exercise_result['exe_result'], $exercise_result['exe_weighting']);        
                     $position       = get_exercise_result_ranking($my_score, $exercise_result['exe_id'], $my_exercise_id,  $my_course_code,$session_id);
-                    $my_real_array[]= array('course'=>$course_data['name'], 'exercise'=>$exercise_data['name'],'attempt'=>$counter,'result'=>$score,'note'=>$platform_score,'position'=>$position);
+                    $my_real_array[]= array(	'date'        => api_get_local_time($exercise_result['exe_date']), 
+                    							'course'      => $course_data['name'], 
+                    						    'exercise'    => $exercise_data['name'],
+                    						    'attempt'     => $counter,
+                    						    'result'      => $platform_score,
+                    						    'best_result' => $best_score,
+                    						    'position'    => $position
+                                        );
                     $counter++;   
                     foreach ($my_exercise_result as $data) {                            
                         //$my_real_array[]= array('session'=>$session_data['name'],'course'=>$course_data['name'], 'exercise'=>$exercise_data['name'],'result'=>$exercise_result['exe_id'])  ;                                                     
@@ -221,22 +225,23 @@ $column_week_model  = array (
                           
 $extra_params_week['grouping'] = 'true';
 $extra_params_week['groupingView'] = array('groupField'=>array('week'),
-                                            'groupColumnShow'=>'false',
-                                            'groupText' => array('<b>'.get_lang('PeriodWeek').' {0}</b>'));
+                                           'groupColumnShow'=>'false',
+                                           'groupText' => array('<b>'.get_lang('PeriodWeek').' {0}</b>'));
 //$extra_params_week['autowidth'] = 'true'; //use the width of the parent
 
 //MyQCM grid
-$column_exercise        = array(get_lang('Course'),get_lang('Exercise'), get_lang('Attempts'), get_lang('Result'), get_lang('Score'), get_lang('Position'));
+$column_exercise        = array(get_lang('PublicationDate'), get_lang('Course'), get_lang('Exercise'),get_lang('Attempts'), get_lang('Result'), get_lang('BestResultInCourse'), get_lang('Position'));
 $column_exercise_model  = array(
-                                array('name'=>'course',     'index'=>'course',    'width'=>'450','align'=>'left',   'sortable'=>'true'),
-                                array('name'=>'exercise',   'index'=>'exercise',  'width'=>'250','align'=>'left',   'sortable'=>'true'),
-                                array('name'=>'attempt',    'index'=>'attempt',   'width'=>'50', 'align'=>'center', 'sortable'=>'true'),
-                                array('name'=>'result',     'index'=>'result',    'width'=>'50', 'align'=>'center', 'sortable'=>'true'),
-                                array('name'=>'note',       'index'=>'note',      'width'=>'50', 'align'=>'center', 'sortable'=>'true'),
-                                array('name'=>'position',   'index'=>'position',  'width'=>'50', 'align'=>'center', 'sortable'=>'true')
+                                array('name'=>'date',       'index'=>'date',      'width'=>'130','align'=>'left',   'sortable'=>'true'),
+                                array('name'=>'course',     'index'=>'course',    'width'=>'200','align'=>'left',   'sortable'=>'true'),
+                                array('name'=>'exercise',   'index'=>'exercise',  'width'=>'200','align'=>'left',   'sortable'=>'true'),                                
+                                array('name'=>'attempt',    'index'=>'attempt',   'width'=>'60', 'align'=>'center', 'sortable'=>'true'),
+                                array('name'=>'result',     'index'=>'result',    'width'=>'140', 'align'=>'center', 'sortable'=>'true'),
+                                array('name'=>'best_result','index'=>'best_result','width'=>'140','align'=>'center', 'sortable'=>'true'),
+                                array('name'=>'position',   'index'=>'position',  'width'=>'60', 'align'=>'center', 'sortable'=>'true')
                                 );                        
-$extra_params_exercise['grouping'] = 'true';
-$extra_params_exercise['groupingView'] = array('groupField'=>array('course'),'groupColumnShow'=>'false','groupText' => array('<b>'.get_lang('Course').' {0}</b>'));
+//$extra_params_exercise['grouping'] = 'true';
+//$extra_params_exercise['groupingView'] = array('groupField'=>array('course'),'groupColumnShow'=>'false','groupText' => array('<b>'.get_lang('Course').' {0}</b>'));
 //$extra_params_exercise['groupingView'] = array('groupField'=>array('course'),'groupColumnShow'=>'false','groupText' => array('<b>'.get_lang('Course').' {0} - {1} Item(s)</b>'));
    
                                           
@@ -270,13 +275,13 @@ $my_reporting   = Tracking::show_user_progress(api_get_user_id(), $session_id, '
 $my_reporting   .= '<br />'.Tracking::show_course_detail(api_get_user_id(), $_GET['course'], $_GET['session_id']);
 
 //Main headers
-$headers        = array(get_lang('LearningPaths'), get_lang('MyQCM'), get_lang('MyResults'));
+$headers        = array(get_lang('LearningPaths'), get_lang('MyQCM'), get_lang('MyStatistics'));
 //Subheaders
 $sub_header     = array(get_lang('AllLearningPaths'), get_lang('PerWeek'), get_lang('ByCourse'));
 
-//Sub header tab
+//Sub headers data
 $tabs           =  Display::tabs($sub_header, array(Display::grid_html('list_default'), Display::grid_html('list_week'), Display::grid_html('list_course')),'sub_tab');
-//Main tabs
+//Main headers data
 echo Display::tabs($headers, array($tabs, Display::grid_html('exercises'),$my_reporting));
 
 Display :: display_footer();

+ 20 - 11
main/tracking/lp_results_by_user.php

@@ -1,5 +1,12 @@
 <?php
 /* For licensing terms, see /license.txt */
+/**
+ * 
+ * Exercise results from Learning paths
+ * 
+ * @todo implement pagination
+ * 
+ */
 
 $language_file = array ('registration', 'index', 'tracking', 'exercice','survey');
 
@@ -12,15 +19,15 @@ $this_section = SECTION_TRACKING;
 
 $is_allowedToTrack = $is_courseAdmin || $is_platformAdmin || $is_courseCoach || $is_sessionAdmin;
 
-if(!$is_allowedToTrack) {
+if (!$is_allowedToTrack) {
 	Display :: display_header(null);
 	api_not_allowed();
 	Display :: display_footer();
 }
 
-$export_to_xls = false;
+$export_to_csv = false;
 if (isset($_GET['export'])) {
-	$export_to_xls = true;
+	$export_to_csv = true;
 }
 
 $TBL_EXERCICES			= Database::get_course_table(TABLE_QUIZ_TEST);
@@ -75,7 +82,7 @@ if (!empty($selected_course)) {
     $course_list = array($selected_course); 
 }
 
-if (!$export_to_xls) {
+if (!$export_to_csv) {
 	Display :: display_header(get_lang('Reporting'));
 	echo '<div class="actions" style ="font-size:10pt;">';
 	if ($global) {
@@ -202,24 +209,26 @@ if (!empty($main_result)) {
     $html_result .='</table>';
 }
 
-if (!$export_to_xls) {
+if (!$export_to_csv) {
 	echo $html_result;	
 }
-$filename = 'exam-reporting-'.date('Y-m-d-h:i:s').'.xls';
-if ($export_to_xls) {
-    export_complete_report_xls($filename, $export_array);
+$filename = 'learning_path_results-'.date('Y-m-d-h:i:s').'.xls';
+if ($export_to_csv) {
+    export_complete_report_csv($filename, $export_array);
 	exit;
 }
-
-function export_complete_report_xls($filename, $array) {	
+function export_complete_report_csv($filename, $array) {	
         require_once api_get_path(LIBRARY_PATH).'export.lib.inc.php';
         $header[] = array(get_lang('Course'),get_lang('LearningPath'), get_lang('Exercise'), get_lang('User'),get_lang('Attempt'), get_lang('Date'),get_lang('Results'));
         if (!empty($array)) {
             $array = array_merge($header, $array);            
-            Export :: export_table_csv($array, 'reporting_learning_path_details');
+            Export :: export_table_csv($array, $filename);
         }
         exit;
         /*    
+         * Too much encoding problems while exporting to XLS, keep it simple 
+         * 
+         * 
 		global $global, $filter_score;
 		$workbook = new Spreadsheet_Excel_Writer();
 		$workbook ->setTempDir(api_get_path(SYS_ARCHIVE_PATH));

+ 7 - 6
main/webservices/courses_list.rest.php

@@ -1,13 +1,14 @@
-<?php //$id: $
+<?php
+/* For licensing terms, see /license.txt */
 /**
  * This script provides the caller service with a list
  * of courses that have a certain level of visibility
- * on this dokeos portal.
- * It is set to work with the Dokeos module for Drupal:
- * http://drupal.org/project/dokeos
+ * on this chamilo portal.
+ * It is set to work with the Chamilo module for Drupal:
+ * http://drupal.org/project/chamilo
  *
- * See license terms in /dokeos_license.txt
- * @author Yannick Warnier <yannick.warnier@dokeos.com>
+ * @author Yannick Warnier <yannick.warnier@beeznest.com>
+ * @package chamilo.webservices
  */
 
 require_once '../inc/global.inc.php';

+ 7 - 6
main/webservices/courses_list.soap.php

@@ -1,13 +1,14 @@
-<?php //$id: $
+<?php
+/* For licensing terms, see /license.txt */
 /**
  * This script provides the caller service with a list
  * of courses that have a certain level of visibility
- * on this dokeos portal.
- * It is set to work with the Dokeos module for Drupal:
- * http://drupal.org/project/dokeos
+ * on this chamilo portal.
+ * It is set to work with the Chamilo module for Drupal:
+ * http://drupal.org/project/chamilo
  *
- * See license terms in /dokeos_license.txt
- * @author Yannick Warnier <yannick.warnier@dokeos.com>
+ * @author Yannick Warnier <yannick.warnier@beeznest.com>
+ * @package chamilo.webservices
  */
 require_once '../inc/global.inc.php';
 $libpath = api_get_path(LIBRARY_PATH);

+ 5 - 2
main/webservices/http-auth.php

@@ -1,5 +1,8 @@
-<?php //$id: $
-
+<?php
+/* For licensing terms, see /license.txt */
+/**
+ * @package chamilo.webservices
+ */
 $realm = 'The batcave';
 
 // Just a random id

+ 32 - 29
main/webservices/registration.soap.php

@@ -1,6 +1,8 @@
 <?php
 /* For licensing terms, see /license.txt */
-
+/**
+ * @package chamilo.webservices
+ */
 require '../inc/global.inc.php';
 $libpath = api_get_path(LIBRARY_PATH);
 require_once $libpath.'nusoap/nusoap.php';
@@ -140,7 +142,7 @@ $server->register('WSCreateUsers',			// method name
 // Define the method WSCreateUsers
 function WSCreateUsers($params) {
 
-    global $_user, $userPasswordCrypted;
+    global $_user, $userPasswordCrypted, $_configuration;
 
     if(!WSHelperVerifyKey($params)) {
         return -1;
@@ -350,7 +352,7 @@ $server->register('WSCreateUser',				// method name
 // Define the method WSCreateUser
 function WSCreateUser($params) {
 
-    global $_user, $userPasswordCrypted;
+    global $_user, $userPasswordCrypted, $_configuration;
 
     if(!WSHelperVerifyKey($params)) {
         return -1;
@@ -589,7 +591,7 @@ $server->register('WSCreateUsersPasswordCrypted',						    // method name
 // Define the method WSCreateUsersPasswordCrypted
 function WSCreateUsersPasswordCrypted($params) {
 
-    global $_user, $userPasswordCrypted;
+    global $_user, $userPasswordCrypted, $_configuration;
 
     if(!WSHelperVerifyKey($params)) {
         return -1;
@@ -834,7 +836,7 @@ $server->register('WSCreateUserPasswordCrypted',						// method name
 // Define the method WSCreateUserPasswordCrypted
 function WSCreateUserPasswordCrypted($params) {
 
-    global $_user, $userPasswordCrypted;
+    global $_user, $userPasswordCrypted, $_configuration;
 
     if(!WSHelperVerifyKey($params)) {
         return -1;
@@ -1889,7 +1891,7 @@ $server->register('WSCreateCourse',			// method name
 // Define the method WSCreateCourse
 function WSCreateCourse($params) {
 
-    global $firstExpirationDelay;
+    global $firstExpirationDelay, $_configuration;
 
     if(!WSHelperVerifyKey($params)) {
         return -1;
@@ -1921,7 +1923,7 @@ function WSCreateCourse($params) {
         $extra_list = $course_param['extra'];
 
         // Check whether exits $x_course_code into user_field_values table.
-        $course_id = CourseManager::get_course_id_from_original_id($original_course_id['original_course_id_value'], $original_course_id['original_course_id_name']);
+        $course_id = CourseManager::get_course_id_from_original_id($course_param['original_course_id_value'], $course_param['original_course_id_name']);
         if($course_id > 0) {
             // Check whether course is not active.
             $sql = "SELECT code FROM $table_course WHERE id ='$course_id' AND visibility= '0'";
@@ -2107,7 +2109,7 @@ $server->register('WSCreateCourseByTitle',					// method name
 // Define the method WSCreateCourseByTitle
 function WSCreateCourseByTitle($params) {
 
-    global $firstExpirationDelay;
+    global $firstExpirationDelay, $_configuration;
 
     if(!WSHelperVerifyKey($params)) {
         return -1;
@@ -2326,6 +2328,7 @@ $server->register('WSEditCourse',			// method name
 // Define the method WSEditCourse
 function WSEditCourse($params){
 
+    global $_configuration;
     if(!WSHelperVerifyKey($params)) {
         return -1;
     }
@@ -2528,7 +2531,7 @@ function WSCourseDescription($params) {
     $sql = "SELECT * FROM $t_course_desc";
     $result = Database::query($sql);
 
-    /*$default_titles = array(
+    $default_titles = array(
                             get_lang('GeneralDescription'),
                             get_lang('Objectives'),
                             get_lang('Topics'),
@@ -2536,10 +2539,10 @@ function WSCourseDescription($params) {
                             get_lang('CourseMaterial'),
                             get_lang('HumanAndTechnicalResources'),
                             get_lang('Assessment'),
-                            get_lang('AddCat'));*/
+                            get_lang('AddCat'));
 
     // TODO: Hard-coded Spanish texts.
-    $default_titles = array('Descripcion general', 'Objetivos', 'Contenidos', 'Metodologia', 'Materiales', 'Recursos humanos y tecnicos', 'Evaluacion', 'Apartado');
+    //$default_titles = array('Descripcion general', 'Objetivos', 'Contenidos', 'Metodologia', 'Materiales', 'Recursos humanos y tecnicos', 'Evaluacion', 'Apartado');
 
     for ($x = 1; $x < 9; $x++) {
         $array_course_desc_id[$x] = $x;
@@ -3608,19 +3611,19 @@ function WSUnsubscribeUserFromCourse($params) {
 
         // Get user id from original user id
         $usersList = array();
-        foreach ($original_user_id_values as $row_original_user_list) {
-            $user_id = UserManager::get_user_id_from_original_id($original_user_id_value, $original_user_id_name);
+        foreach ($original_user_id_values as $key => $row_original_user_id) {
+            $user_id = UserManager::get_user_id_from_original_id($original_user_id_values[$key], $original_user_id_name[$key]);
              if ($user_id == 0) {
                 continue; // user_id doesn't exist.
             } else {
-                $sql = "SELECT user_id FROM $user_table WHERE user_id ='".$row_user[0]."' AND active= '0'";
+                $sql = "SELECT user_id FROM $user_table WHERE user_id ='".$user_id."' AND active= '0'";
                 $resu = Database::query($sql);
                 $r_check_user = Database::fetch_row($resu);
                 if (!empty($r_check_user[0])) {
                     continue; // user_id is not active.
                 }
             }
-            $usersList[] = $row_user[0];
+            $usersList[] = $user_id;
          }
 
         $orig_user_id_value[] = implode(',',$usersList);
@@ -3786,19 +3789,19 @@ function WSSuscribeUsersToSession($params){
         }
 
          $usersList = array();
-         foreach ($original_user_id_values as $row_original_user_list) {
-             $user_id = UserManager::get_user_id_from_original_id($original_user_id_value, $original_user_id_name);
+         foreach ($original_user_id_values as $key => $row_original_user_list) {
+             $user_id = UserManager::get_user_id_from_original_id($original_user_id_values[$key], $original_user_id_name[$key]);
              if ($user_id == 0) {
                 continue; // user_id doesn't exist.
             } else {
-                $sql = "SELECT user_id FROM $user_table WHERE user_id ='".$row_user[0]."' AND active= '0'";
+                $sql = "SELECT user_id FROM $user_table WHERE user_id ='".$user_id."' AND active= '0'";
                 $resu = Database::query($sql);
                 $r_check_user = Database::fetch_row($resu);
                 if (!empty($r_check_user[0])) {
                     continue; // user_id is not active.
                 }
             }
-            $usersList[] = $row_user[0];
+            $usersList[] = $user_id;
          }
 
         if (empty($usersList)) {
@@ -3977,38 +3980,38 @@ function WSUnsuscribeUsersFromSession($params) {
 
     foreach ($userssessions_params as $usersession_params) {
 
-           $original_session_id_value = $usersession_params['original_session_id_value'];
+        $original_session_id_value = $usersession_params['original_session_id_value'];
         $original_session_id_name = $usersession_params['original_session_id_name'];
         $original_user_id_name = $usersession_params['original_user_id_name'];
         $original_user_id_values = $usersession_params['original_user_id_values'];
-           $orig_session_id_value[] = $original_session_id_value;
+        $orig_session_id_value[] = $original_session_id_value;
         // get session id from original session id
         $sql_session = "SELECT session_id FROM $t_sf sf,$t_sfv sfv WHERE sfv.field_id=sf.id AND field_variable='$original_session_id_name' AND field_value='$original_session_id_value'";
         $res_session = Database::query($sql_session);
         $row_session = Database::fetch_row($res_session);
 
-         $id_session = $row_session[0];
+        $id_session = $row_session[0];
 
-         if (Database::num_rows($res_session) < 1) {
+        if (Database::num_rows($res_session) < 1) {
             $results[] = 0;
             continue;
         }
 
-         $usersList = array();
-         foreach ($original_user_id_values as $row_original_user_list) {
-             $user_id = UserManager::get_user_id_from_original_id($original_user_id_value, $original_user_id_name);
+        $usersList = array();
+        foreach ($original_user_id_values as $key => $row_original_user_list) {
+             $user_id = UserManager::get_user_id_from_original_id($original_user_id_values[$key], $original_user_id_name[$key]);
              if ($user_id == 0) {
                 continue; // user_id doesn't exist.
             } else {
-                $sql = "SELECT user_id FROM $user_table WHERE user_id ='".$row_user[0]."' AND active= '0'";
+                $sql = "SELECT user_id FROM $user_table WHERE user_id ='".$user_id."' AND active= '0'";
                 $resu = Database::query($sql);
                 $r_check_user = Database::fetch_row($resu);
                 if (!empty($r_check_user[0])) {
                     continue; // user_id is not active.
                 }
             }
-            $usersList[] = $row_user[0];
-         }
+            $usersList[] = $user_id;
+        }
 
         if (empty($usersList)) {
             $results[] = 0;

+ 4 - 1
main/webservices/soap.php

@@ -1,5 +1,8 @@
 <?php
-
+/* For licensing terms, see /license.txt */
+/**
+ * @package chamilo.webservices
+ */
 require_once '../inc/global.inc.php';
 require_once(dirname(__FILE__).'/webservice.php');
 $libpath = api_get_path(LIBRARY_PATH);

+ 5 - 1
main/webservices/soap_course.php

@@ -1,5 +1,9 @@
 <?php
-
+/* For licensing terms, see /license.txt */
+/**
+ * Configures the WSCourse SOAP service
+ * @package chamilo.webservices
+ */
 require_once(dirname(__FILE__).'/webservice_course.php');
 require_once(dirname(__FILE__).'/soap.php');
 

+ 236 - 0
main/webservices/soap_report.php

@@ -0,0 +1,236 @@
+<?php
+/* For licensing terms, see /license.txt */
+/**
+ * Configures the WSReport SOAP service
+ * @package chamilo.webservices
+ */
+require_once(dirname(__FILE__).'/webservice_report.php');
+require_once(dirname(__FILE__).'/soap.php');
+
+/**
+ * Configures the WSUser SOAP service
+ * @package chamilo.webservices
+ */
+$s = WSSoapServer::singleton();
+
+$s->wsdl->addComplexType(
+	'user_id',
+	'complexType',
+	'struct',
+	'all',
+	'',
+	array(
+		'user_id_field_name' => array('name' => 'user_id_field_name', 'type' => 'xsd:string'),
+		'user_id_value' => array('name' => 'user_id_value', 'type' => 'xsd:string')
+	)
+);
+
+$s->wsdl->addComplexType(
+	'user_result',
+	'complexType',
+	'struct',
+	'all',
+	'',
+	array(
+		'user_id_value' => array('name' => 'user_id_value', 'type' => 'xsd:string'),
+		'result' => array('name' => 'result', 'type' => 'tns:result')
+	)
+);
+
+$s->wsdl->addComplexType(
+	'user_result_array',
+	'complexType',
+	'array',
+	'',
+	'SOAP-ENC:Array',
+	array(),
+	array(array('ref'=>'SOAP-ENC:arrayType', 'wsdl:arrayType' => 'tns:user_result[]')),
+	'tns:user_result'
+);
+
+$s->register(
+	'WSUser.DisableUser',
+	array('secret_key' => 'xsd:string', 'user_id_field_name' => 'xsd:string', 'user_id_value' => 'xsd:string')
+);
+
+$s->register(
+	'WSUser.DisableUsers',
+	array('secret_key' => 'xsd:string', 'users' => 'tns:user_id[]'),
+	array('return' => 'tns:user_result_array')
+);
+
+$s->register(
+	'WSUser.EnableUser',
+	array('secret_key' => 'xsd:string', 'user_id_field_name' => 'xsd:string', 'user_id_value' => 'xsd:string')
+);
+
+$s->register(
+	'WSUser.EnableUsers',
+	array('secret_key' => 'xsd:string', 'users' => 'tns:user_id[]'),
+	array('return' => 'tns:user_result_array')
+);
+
+$s->register(
+	'WSUser.DeleteUser',
+	array('secret_key' => 'xsd:string', 'user_id_field_name' => 'xsd:string', 'user_id_value' => 'xsd:string')
+);
+
+$s->register(
+	'WSUser.DeleteUsers',
+	array('secret_key' => 'xsd:string', 'users' => 'tns:user_id[]'),
+	array('return' => 'tns:user_result_array')
+);
+
+$s->register(
+	'WSUser.CreateUser',
+	array(
+		'secret_key' => 'xsd:string',
+		'firstname' => 'xsd:string',
+		'lastname' => 'xsd:string',
+		'status' => 'xsd:int',
+		'loginname' => 'xsd:string',
+		'password' => 'xsd:string',
+		'encrypt_method' => 'xsd:string',
+		'user_id_field_name' => 'xsd:string',
+		'user_id_value' => 'xsd:string',
+		'visibility' => 'xsd:int',
+		'email' => 'xsd:string',
+		'language' => 'xsd:string',
+		'phone' => 'xsd:string',
+		'expiration_date' => 'xsd:string',
+		'extras' => 'tns:extra_field[]'
+	),
+	array('return' => 'xsd:int')
+);
+
+$s->wsdl->addComplexType(
+	'user_create',
+	'complexType',
+	'struct',
+	'all',
+	'',
+	array(
+		'firstname' => array('name' => 'firstname', 'type' => 'xsd:string'),
+		'lastname' => array('name' => 'lastname', 'type' => 'xsd:string'),
+		'status' => array('name' => 'status', 'type' => 'xsd:int'),
+		'loginname' => array('name' => 'loginname', 'type' => 'xsd:string'),
+		'password' => array('name' => 'password', 'type' => 'xsd:string'),
+		'encrypt_method' => array('name' => 'encrypt_method', 'type' => 'xsd:string'),
+		'user_id_field_name' => array('name' => 'user_id_field_name', 'type' => 'xsd:string'),
+		'user_id_value' => array('name' => 'user_id_value', 'type' => 'xsd:string'),
+		'visibility' => array('name' => 'visibility', 'type' => 'xsd:int'),
+		'email' => array('name' => 'email', 'type' => 'xsd:string'),
+		'language' => array('name' => 'language', 'type' => 'xsd:string'),
+		'phone' => array('name' => 'phone', 'type' => 'xsd:string'),
+		'expiration_date' => array('name' => 'expiration_date', 'type' => 'xsd:string'),
+		'extras' => array('name' => 'extras', 'type' => 'tns:extra_field[]')
+	)
+);
+
+$s->wsdl->addComplexType(
+	'user_create_result',
+	'complexType',
+	'struct',
+	'all',
+	'',
+	array(
+		'user_id_value' => array('name' => 'user_id_value', 'type' => 'xsd:string'),
+		'user_id_generated' => array('name' => 'user_id_generated', 'type' => 'xsd:int'),
+		'result' => array('name' => 'result', 'type' => 'tns:result')
+	)
+);
+
+$s->wsdl->addComplexType(
+	'user_create_result_array',
+	'complexType',
+	'array',
+	'',
+	'SOAP-ENC:Array',
+	array(),
+	array(array('ref'=>'SOAP-ENC:arrayType', 'wsdl:arrayType' => 'tns:user_create_result[]')),
+	'tns:user_create_result'
+);
+
+$s->register(
+	'WSUser.CreateUsers',
+	array(
+		'secret_key' => 'xsd:string',
+		'users' => 'tns:user_create[]'
+	),
+	array('return' => 'tns:user_create_result_array')
+);
+
+$s->register(
+	'WSUser.EditUser',
+	array(
+		'secret_key' => 'xsd:string',
+		'user_id_field_name' => 'xsd:string',
+		'user_id_value' => 'xsd:string',
+		'firstname' => 'xsd:string',
+		'lastname' => 'xsd:string',
+		'status' => 'xsd:int',
+		'loginname' => 'xsd:string',
+		'password' => 'xsd:string',
+		'encrypt_method' => 'xsd:string',
+		'email' => 'xsd:string',
+		'language' => 'xsd:string',
+		'phone' => 'xsd:string',
+		'expiration_date' => 'xsd:string',
+		'extras' => 'tns:extra_field[]'
+	)
+);
+
+$s->wsdl->addComplexType(
+	'user_edit',
+	'complexType',
+	'struct',
+	'all',
+	'',
+	array(
+		'user_id_field_name' => array('name' => 'user_id_field_name', 'type' => 'xsd:string'),
+		'user_id_value' => array('name' => 'user_id_value', 'type' => 'xsd:string'),
+		'firstname' => array('name' => 'firstname', 'type' => 'xsd:string'),
+		'lastname' => array('name' => 'lastname', 'type' => 'xsd:string'),
+		'status' => array('name' => 'status', 'type' => 'xsd:int'),
+		'loginname' => array('name' => 'loginname', 'type' => 'xsd:string'),
+		'password' => array('name' => 'password', 'type' => 'xsd:string'),
+		'encrypt_method' => array('name' => 'encrypt_method', 'type' => 'xsd:string'),
+		'email' => array('name' => 'email', 'type' => 'xsd:string'),
+		'language' => array('name' => 'language', 'type' => 'xsd:string'),
+		'phone' => array('name' => 'phone', 'type' => 'xsd:string'),
+		'expiration_date' => array('name' => 'expiration_date', 'type' => 'xsd:string'),
+		'extras' => array('name' => 'extras', 'type' => 'tns:extra_field[]')
+	)
+);
+
+$s->wsdl->addComplexType(
+	'user_edit_result',
+	'complexType',
+	'struct',
+	'all',
+	'',
+	array(
+		'user_id_value' => array('name' => 'user_id_value', 'type' => 'xsd:string'),
+		'result' => array('name' => 'result', 'type' => 'tns:result')
+	)
+);
+
+$s->wsdl->addComplexType(
+	'user_edit_result_array',
+	'complexType',
+	'array',
+	'',
+	'SOAP-ENC:Array',
+	array(),
+	array(array('ref'=>'SOAP-ENC:arrayType', 'wsdl:arrayType' => 'tns:user_edit_result[]')),
+	'tns:user_edit_result'
+);
+
+$s->register(
+	'WSUser.EditUsers',
+	array(
+		'secret_key' => 'xsd:string',
+		'users' => 'tns:user_edit[]'
+	),
+	array('return' => 'tns:user_edit_result_array')
+);

+ 5 - 3
main/webservices/soap_session.php

@@ -1,11 +1,13 @@
 <?php
+/* For licensing terms, see /license.txt */
+/**
+ * Configures the WSSession SOAP service
+ * @package chamilo.webservices
+ */
 
 require_once(dirname(__FILE__).'/webservice_session.php');
 require_once(dirname(__FILE__).'/soap.php');
 
-/**
- * Configures the WSSession SOAP service
- */
 $s = WSSoapServer::singleton();
 
 $s->register(

+ 6 - 1
main/webservices/soap_user.php

@@ -1,10 +1,15 @@
 <?php
-
+/* For licensing terms, see /license.txt */
+/**
+ * Configures the WSUser SOAP service
+ * @package chamilo.webservices
+ */
 require_once(dirname(__FILE__).'/webservice_user.php');
 require_once(dirname(__FILE__).'/soap.php');
 
 /**
  * Configures the WSUser SOAP service
+ * @package chamilo.webservices
  */
 $s = WSSoapServer::singleton();
 

+ 4 - 0
main/webservices/testip.php

@@ -1,3 +1,7 @@
 <?php
+/* For licensing terms, see /license.txt */
+/**
+ *  @package chamilo.webservices
+ */
 echo htmlentities($_SERVER['REMOTE_ADDR'])."\n";
 echo '<br />This is your IP address, as detected by this server';

+ 7 - 8
main/webservices/user_info.soap.php

@@ -1,13 +1,12 @@
-<?php //$id: $
+<?php
+/* For licensing terms, see /license.txt */
 /**
- * This script provides the caller service with a list
- * of courses that have a certain level of visibility
- * on this dokeos portal.
- * It is set to work with the Dokeos module for Drupal:
- * http://drupal.org/project/dokeos
- *
- * See license terms in /dokeos_license.txt
+ * This script provides the caller service with user details.
+ * It is set to work with the Chamilo module for Drupal:
+ * http://drupal.org/project/chamilo
+ * 
  * @author Yannick Warnier <yannick.warnier@dokeos.com>
+ * @package chamilo.webservices
  */
 require_once '../inc/global.inc.php';
 $libpath = api_get_path(LIBRARY_PATH);

+ 4 - 0
main/webservices/webservice.php

@@ -1,4 +1,8 @@
 <?php
+/* For licensing terms, see /license.txt */
+/**
+ * @package chamilo.webservices
+ */
 require_once(dirname(__FILE__).'/../inc/global.inc.php');
 $libpath = api_get_path(LIBRARY_PATH);
 require_once $libpath.'usermanager.lib.php';

+ 4 - 1
main/webservices/webservice_course.php

@@ -1,5 +1,8 @@
 <?php
-
+/* For licensing terms, see /license.txt */
+/**
+ * @package chamilo.webservices
+ */
 require_once(dirname(__FILE__).'/../inc/global.inc.php');
 $libpath = api_get_path(LIBRARY_PATH);
 require_once $libpath.'course.lib.php';

+ 418 - 0
main/webservices/webservice_report.php

@@ -0,0 +1,418 @@
+<?php
+/* For licensing terms, see /license.txt */
+/**
+ * @package chamilo.webservices
+ */
+require_once(dirname(__FILE__).'/../inc/global.inc.php');
+$libpath = api_get_path(LIBRARY_PATH);
+require_once $libpath.'usermanager.lib.php';
+require_once $libpath.'tracking.lib.php';
+require_once(dirname(__FILE__).'/webservice.php');
+
+/**
+ * Web services available for the User module. This class extends the WS class
+ */
+class WSReport extends WS {
+
+	/**
+	 * Enables or disables a user
+	 *
+	 * @param string User id field name
+	 * @param string User id value
+	 * @param int Set to 1 to enable and to 0 to disable
+	 */
+	protected function get_time_spent_on_platform($user_id_field_name, $user_id_value) {
+		$user_id = $this->getUserId($user_id_field_name, $user_id_value);
+		if($user_id instanceof WSError) {
+			return $user_id;
+		} else {
+            return Tracking::get_time_spent_on_the_platform($user_id);
+		}
+	}
+
+	/**
+	 * Enables or disables multiple users
+	 *
+	 * @param array Users
+	 * @param int Set to 1 to enable and to 0 to disable
+	 * @return array Array of results
+	 */
+	protected function get_time_spent_on_the_course($user_id_field_name, $user_id_value) {
+		$results = array();
+		foreach($users as $user) {
+			$result_tmp = array();
+			$result_op = $this->changeUserActiveState($user['user_id_field_name'], $user['user_id_value'], $state);
+			$result_tmp['user_id_value'] = $user['user_id_value'];
+			if($result_op instanceof WSError) {
+				// Return the error in the results
+				$result_tmp['result'] = $result_op->toArray();
+			} else {
+				$result_tmp['result'] = $this->getSuccessfulResult();
+			}
+			$results[] = $result_tmp;
+		}
+		return $results;
+	}
+
+	/**
+	 * Disables a user
+	 *
+	 * @param string API secret key
+	 * @param string User id field name. Use "chamilo_user_id" as the field name if you want to use the internal user_id
+	 * @param string User id value
+	 */
+	public function DisableUser($secret_key, $user_id_field_name, $user_id_value) {
+		$verifKey = $this->verifyKey($secret_key);
+		if($verifKey instanceof WSError) {
+			// Let the implementation handle it
+			$this->handleError($verifKey);
+		} else {
+			$result = $this->changeUserActiveState($user_id_field_name, $user_id_value, 0);
+			if($result instanceof WSError) {
+				$this->handleError($result);
+			}
+		}
+	}
+
+	/**
+	 * Disables multiple users
+	 *
+	 * @param string API secret key
+	 * @param array Array of users with elements of the form array('user_id_field_name' => 'name_of_field', 'user_id_value' => 'value')
+	 * @return array Array with elements like array('user_id_value' => 'value', 'result' => array('code' => 0, 'message' => 'Operation was successful')). Note that if the result array contains a code different
+	 * than 0, an error occured
+	 */
+	public function DisableUsers($secret_key, $users) {
+		$verifKey = $this->verifyKey($secret_key);
+		if($verifKey instanceof WSError) {
+			// Let the implementation handle it
+			$this->handleError($verifKey);
+		} else {
+			return $this->changeUsersActiveState($users, 0);
+		}
+	}
+
+	/**
+	 * Enables a user
+	 *
+	 * @param string API secret key
+	 * @param string User id field name. Use "chamilo_user_id" as the field name if you want to use the internal user_id
+	 * @param string User id value
+	 */
+	public function EnableUser($secret_key, $user_id_field_name, $user_id_value) {
+		$verifKey = $this->verifyKey($secret_key);
+		if($verifKey instanceof WSError) {
+			$this->handleError($verifKey);
+		} else {
+			$result = $this->changeUserActiveState($user_id_field_name, $user_id_value, 1);
+			if($result instanceof WSError) {
+				$this->handleError($result);
+			}
+		}
+	}
+
+	/**
+	 * Enables multiple users
+	 *
+	 * @param string API secret key
+	 * @param array Array of users with elements of the form array('user_id_field_name' => 'name_of_field', 'user_id_value' => 'value')
+	 * @return array Array with elements like array('user_id_value' => 'value', 'result' => array('code' => 0, 'message' => 'Operation was successful')). Note that if the result array contains a code different
+	 * than 0, an error occured
+	 */
+	public function EnableUsers($secret_key, $users) {
+		$verifKey = $this->verifyKey($secret_key);
+		if($verifKey instanceof WSError) {
+			// Let the implementation handle it
+			$this->handleError($verifKey);
+		} else {
+			return $this->changeUsersActiveState($users, 1);
+		}
+	}
+
+	/**
+	 * Deletes a user (helper method)
+	 *
+	 * @param string User id field name. Use "chamilo_user_id" as the field name if you want to use the internal user_id
+	 * @param string User id value
+	 * @return mixed True if user was successfully deleted, WSError otherwise
+	 */
+	protected function deleteUserHelper($user_id_field_name, $user_id_value) {
+		$user_id = $this->getUserId($user_id_field_name, $user_id_value);
+		if($user_id instanceof WSError) {
+			return $user_id;
+		} else {
+			if(!UserManager::delete_user($user_id)) {
+				return new WSError(101, "There was a problem while deleting this user");
+			} else {
+				return true;
+			}
+		}
+	}
+
+	/**
+	 * Deletes a user
+	 *
+	 * @param string API secret key
+	 * @param string User id field name. Use "chamilo_user_id" as the field name if you want to use the internal user_id
+	 * @param string User id value
+	 */
+	public function DeleteUser($secret_key, $user_id_field_name, $user_id_value) {
+		$verifKey = $this->verifyKey($secret_key);
+		if($verifKey instanceof WSError) {
+			$this->handleError($verifKey);
+		} else {
+			$result = $this->deleteUserHelper($user_id_field_name, $user_id_value);
+			if($result instanceof WSError) {
+				$this->handleError($result);
+			}
+		}
+	}
+
+	/**
+	 * Deletes multiple users
+	 *
+	 * @param string API secret key
+	 * @param array Array of users with elements of the form array('user_id_field_name' => 'name_of_field', 'user_id_value' => 'value')
+	 * @return array Array with elements like array('user_id_value' => 'value', 'result' => array('code' => 0, 'message' => 'Operation was successful')). Note that if the result array contains a code different
+	 * than 0, an error occured
+	 */
+	public function DeleteUsers($secret_key, $users) {
+		$verifKey = $this->verifyKey($secret_key);
+		if($verifKey instanceof WSError) {
+			$this->handleError($verifKey);
+		} else {
+			$results = array();
+			foreach($users as $user) {
+				$result_tmp = array();
+				$result_op = $this->deleteUserHelper($user['user_id_field_name'], $user['user_id_value']);
+				$result_tmp['user_id_value'] = $user['user_id_value'];
+				if($result_op instanceof WSError) {
+					// Return the error in the results
+					$result_tmp['result'] = $result_op->toArray();
+				} else {
+					$result_tmp['result'] = $this->getSuccessfulResult();
+				}
+				$results[] = $result_tmp;
+			}
+			return $results;
+		}
+	}
+
+	/**
+	 * Creates a user (helper method)
+	 *
+	 * @param string User first name
+	 * @param string User last name
+	 * @param int User status
+	 * @param string Login name
+	 * @param string Password (encrypted or not)
+	 * @param string Encrypt method. Leave blank if you are passing the password in clear text, set to the encrypt method used to encrypt the password otherwise. Remember
+	 * to include the salt in the extra fields if you are encrypting the password
+	 * @param string User id field name. Use "chamilo_user_id" as the field name if you want to use the internal user_id
+	 * @param string User id value. Leave blank if you are using the internal user_id
+	 * @param int Visibility.
+	 * @param string User email.
+	 * @param string Language.
+	 * @param string Phone.
+	 * @param string Expiration date
+	 * @param array Extra fields. An array with elements of the form ('field_name' => 'name_of_the_field', 'field_value' => 'value_of_the_field').
+	 * @return mixed New user id generated by the system, WSError otherwise
+	 */
+	protected function createUserHelper($firstname, $lastname, $status, $login, $password, $encrypt_method, $user_id_field_name, $user_id_value, $visibility, $email, $language, $phone, $expiration_date, $extras) {
+		// Add the original user id field name and value to the extra fields if needed
+		$extras_associative = array();
+		if($user_id_field_name != "chamilo_user_id") {
+			$extras_associative[$user_id_field_name] = $user_id_value;
+		}
+		foreach($extras as $extra) {
+			$extras_associative[$extra['field_name']] = $extra['field_value'];
+		}
+		$result = UserManager::create_user($firstname, $lastname, $status, $email, $login, $password, '', $language, $phone, '', PLATFORM_AUTH_SOURCE, $expiration_date, $visibility, 0, $extras_associative, $encrypt_method);
+		if (!$result) {
+			$failure = $api_failureList[0];
+			if($failure == 'login-pass already taken') {
+				return new WSError(102, 'This username is already taken');
+			} else if($failure == 'encrypt_method invalid') {
+				return new WSError(103, 'The encryption of the password is invalid');
+			} else {
+				return new WSError(104, 'There was an error creating the user');
+			}
+		} else {
+			return $result;
+		}
+	}
+
+	/**
+	 * Creates a user
+	 *
+	 * @param string API secret key
+	 * @param string User first name
+	 * @param string User last name
+	 * @param int User status
+	 * @param string Login name
+	 * @param string Password (encrypted or not)
+	 * @param string Encrypt method. Leave blank if you are passing the password in clear text, set to the encrypt method used to encrypt the password otherwise. Remember
+	 * to include the salt in the extra fields if you are encrypting the password
+	 * @param string User id field name. Use "chamilo_user_id" as the field name if you want to use the internal user_id
+	 * @param string User id value. Leave blank if you are using the internal user_id
+	 * @param int Visibility. Set by default to 1
+	 * @param string User email. Set by default to an empty string
+	 * @param string Language. Set by default to english
+	 * @param string Phone. Set by default to an empty string
+	 * @param string Expiration date. Set to null by default
+	 * @param array Extra fields. An array with elements of the form ('field_name' => 'name_of_the_field', 'field_value' => 'value_of_the_field'). Set to an empty array by default
+	 * @return int New user id generated by the system
+	 */
+	public function CreateUser($secret_key, $firstname, $lastname, $status, $login, $password, $encrypt_method, $user_id_field_name, $user_id_value, $visibility = 1, $email = '', $language = 'english', $phone = '', $expiration_date = '0000-00-00 00:00:00', $extras = array()) {
+		// First, verify the secret key
+		$verifKey = $this->verifyKey($secret_key);
+		if($verifKey instanceof WSError) {
+			$this->handleError($verifKey);
+		} else {
+			$result = $this->createUserHelper($firstname, $lastname, $status, $login, $password, $encrypt_method, $user_id_field_name, $user_id_value, $visibility, $email, $language, $phone, $expiration_date, $extras);
+			if($result instanceof WSError) {
+				$this->handleError($result);
+			} else {
+				return $result;
+			}
+		}
+	}
+
+	/**
+	 * Creates multiple users
+	 *
+	 * @param string API secret key
+	 * @param array Users array. Each member of this array must follow the structure imposed by the CreateUser method
+	 * @return array Array with elements of the form array('user_id_value' => 'original value sent', 'user_id_generated' => 'value_generated', 'result' => array('code' => 0, 'message' => 'Operation was successful'))
+	 */
+	public function CreateUsers($secret_key, $users) {
+		$verifKey = $this->verifyKey($secret_key);
+		if($verifKey instanceof WSError) {
+			$this->handleError($verifKey);
+		} else {
+			$results = array();
+			foreach($users as $user) {
+				$result_tmp = array();
+				extract($user);
+				$result = $this->createUserHelper($firstname, $lastname, $status, $login, $password, $encrypt_method, $user_id_field_name, $user_id_value, $visibility, $email, $language, $phone, $expiration_date, $extras);
+				if($result instanceof WSError) {
+					$result_tmp['result'] = $result->toArray();
+					$result_tmp['user_id_value'] = $user_id_value;
+					$result_tmp['user_id_generated'] = 0;
+				} else {
+					$result_tmp['result'] = $this->getSuccessfulResult();
+					$result_tmp['user_id_value'] = $user_id_value;
+					$result_tmp['user_id_generated'] = $result;
+				}
+				$results[] = $result_tmp;
+			}
+			return $results;
+		}
+	}
+
+	/**
+	 * Edits user info (helper method)
+	 *
+	 * @param string User id field name. Use "chamilo_user_id" in order to use internal system id
+	 * @param string User id value
+	 * @param string First name
+	 * @param string Last name
+	 * @param int User status
+	 * @param string Login name
+	 * @param string Password. Leave blank if you don't want to update it
+	 * @param string Encrypt method
+	 * @param string User email
+	 * @param string Language. Set by default to english
+	 * @param string Phone. Set by default to an empty string
+	 * @param string Expiration date. Set to null by default
+	 * @param array Extra fields. An array with elements of the form ('field_name' => 'name_of_the_field', 'field_value' => 'value_of_the_field'). Leave empty if you don't want to update
+	 * @return mixed True if user was successfully updated, WSError otherwise
+	 */
+	protected function editUserHelper($user_id_field_name, $user_id_value, $firstname, $lastname, $status, $loginname, $password, $encrypt_method, $email, $language, $phone, $expiration_date, $extras) {
+		$user_id = $this->getUserId($user_id_field_name, $user_id_value);
+		if($user_id instanceof WSError) {
+			return $user_id;
+		} else {
+			if($password == '') {
+				$password = null;
+			}
+			$user_info = UserManager::get_user_info_by_id($user_id);
+			if(count($extras) == 0) {
+				$extras = null;
+			}
+			$result = UserManager::update_user($user_id, $firstname, $lastname, $loginname, $password, PLATFORM_AUTH_SOURCE, $email, $status, '', $phone, $user_info['picture_uri'], $expiration_date, $user_info['active'], null, $user_info['hr_dept_id'], $extras, $encrypt_method);
+			if (!$result) {
+				$failure = $api_failureList[0];
+				if($failure == 'encrypt_method invalid') {
+					return new WSError(103, 'The encryption of the password is invalid');
+				} else {
+					return new WSError(105, 'There was an error updating the user');
+				}
+			} else {
+				return $result;
+			}
+		}
+	}
+
+	/**
+	 * Edits user info
+	 *
+	 * @param string API secret key
+	 * @param string User id field name. Use "chamilo_user_id" in order to use internal system id
+	 * @param string User id value
+	 * @param string First name
+	 * @param string Last name
+	 * @param int User status
+	 * @param string Login name
+	 * @param string Password. Leave blank if you don't want to update it
+	 * @param string Encrypt method
+	 * @param string User email
+	 * @param string Language. Set by default to english
+	 * @param string Phone. Set by default to an empty string
+	 * @param string Expiration date. Set to null by default
+	 * @param array Extra fields. An array with elements of the form ('field_name' => 'name_of_the_field', 'field_value' => 'value_of_the_field'). Leave empty if you don't want to update
+	 */
+	public function EditUser($secret_key, $user_id_field_name, $user_id_value, $firstname, $lastname, $status, $loginname, $password, $encrypt_method, $email, $language, $phone, $expiration_date, $extras) {
+		// First, verify the secret key
+		$verifKey = $this->verifyKey($secret_key);
+		if($verifKey instanceof WSError) {
+			$this->handleError($verifKey);
+		} else {
+			$result = $this->editUserHelper($user_id_field_name, $user_id_value, $firstname, $lastname, $status, $loginname, $password, $encrypt_method, $user_id_field_name, $email, $language, $phone, $expiration_date, $extras);
+			if($result instanceof WSError) {
+				$this->handleError($result);
+			}
+		}
+	}
+
+	/**
+	 * Edits multiple users
+	 *
+	 * @param string API secret key
+	 * @param array Users array. Each member of this array must follow the structure imposed by the EditUser method
+	 * @return array Array with elements like array('user_id_value' => 'value', 'result' => array('code' => 0, 'message' => 'Operation was successful')). Note that if the result array contains a code different
+	 * than 0, an error occured
+	 */
+	public function EditUsers($secret_key, $users) {
+		$verifKey = $this->verifyKey($secret_key);
+		if($verifKey instanceof WSError) {
+			$this->handleError($verifKey);
+		} else {
+			$results = array();
+			foreach($users as $user) {
+				$result_tmp = array();
+				extract($user);
+				$result_op = $this->editUserHelper($user_id_field_name, $user_id_value, $firstname, $lastname, $status, $loginname, $password, $encrypt_method, $email, $language, $phone, $expiration_date, $extras);
+				$result_tmp['user_id_value'] = $user['user_id_value'];
+				if($result_op instanceof WSError) {
+					// Return the error in the results
+					$result_tmp['result'] = $result_op->toArray();
+				} else {
+					$result_tmp['result'] = $this->getSuccessfulResult();
+				}
+				$results[] = $result_tmp;
+			}
+			return $results;
+		}
+	}
+}

+ 4 - 1
main/webservices/webservice_session.php

@@ -1,5 +1,8 @@
 <?php
-
+/* For licensing terms, see /license.txt */
+/**
+ * @package chamilo.webservices
+ */
 require_once(dirname(__FILE__).'/../inc/global.inc.php');
 $libpath = api_get_path(LIBRARY_PATH);
 require_once($libpath.'sessionmanager.lib.php');

+ 4 - 1
main/webservices/webservice_user.php

@@ -1,5 +1,8 @@
 <?php
-
+/* For licensing terms, see /license.txt */
+/**
+ * @package chamilo.webservices
+ */
 require_once(dirname(__FILE__).'/../inc/global.inc.php');
 $libpath = api_get_path(LIBRARY_PATH);
 require_once $libpath.'usermanager.lib.php';