Procházet zdrojové kódy

Merged with Patrick - risky merge, please stay alert

Yannick Warnier před 15 roky
rodič
revize
0245d4d1d1

+ 6 - 0
documentation/changelog.html

@@ -30,11 +30,17 @@
   <li>Added an option to configure courses as "auto-registered" (every user has it in his courses list and is automatically subscribed)</li>
   <li>Allowed password to be recovered using username *or* e-mail</li>
   <li>Added editable section to the registration form</li>
+  <li>Reporting: notification of user who have never been active yet</li>
+  <li>Reporting: the additional user profiles (defined by the platform administrator through platform administration > profiling) can now be displayed also. </li>
+  <li>Subscribing users in a course: you can also filter on a certain addtional user profile field or search inside the values of the additional user profiles fields when subscribing a user in a course (through user/subscribe_user.php) </li>
 </ul>
 <h3>Debugging</h3>
 <ul>
   <li>Online editor: A upgrade from FCKEditor 2.6.4.1 to <strong>FCKEditor 2.6.5, Build 23959</strong> has been implemented. (#2867)</li>
   <li>Fixed a bug in course homepage always showing a box even when no tools were shown (r8747:3ad59f6aed1f)</li>
+  <li>Score result in reporting is expressed as a percentage</li>
+  <li>CSV export of reporting no longer contains html code in the last column</li>
+  <li>The course list is now sorted like you have defined on the course management page</li>
 </ul>
 <br />
 <h3>CSS changes</h3>

+ 15 - 3
main/announcements/announcements.php

@@ -974,7 +974,7 @@ if (!$surveyid) {
 			} else {
 				$class="";
 			}
-			//validacion when belongs to a session
+			//validation when belongs to a session
 			$session_img = api_get_session_image($myrow['session_id'], $_user['status']);
 			echo "\t\t\t\t\t\t<a style=\"text-decoration:none\" href=\"announcements.php?".api_get_cidreq()."#".$myrow['id']."\" ".$class.">" . api_trunc_str($title, $length) . "</a>\n" . $session_img;
 			echo "\t\t\t\t\t</td>\n\t\t\t\t</tr>\n";
@@ -1038,15 +1038,27 @@ if ($display_form == true) {
 			$content_to_modify = sprintf(get_lang('RemindInactiveLearnersMailContent'),api_get_setting('siteName'), 7);
 			$title_to_modify = sprintf(get_lang('RemindInactiveLearnersMailSubject'),api_get_setting('siteName'));
 		} elseif (isset($_GET['remindallinactives']) && $_GET['remindallinactives']=='true') {
+			// we want to remind inactive users. The $_GET['since'] parameter determines which users have to be warned (i.e the users who have been inactive for x days or more
 			$since = isset($_GET['since']) ? intval($_GET['since']) : 6;
+			// getting the users who have to be reminded
 			$to = Tracking :: get_inactives_students_in_course($_course['id'],$since, $_SESSION['id_session']);
+			// setting the variables for the form elements: the users who need to receive the message
 			foreach($to as &$user) {
 				$user = 'USER:'.$user;
 			}
+			// setting the variables for the form elements: the 'visible to' form element has to be expanded
 			$_SESSION['select_groupusers']="show";
+			// setting the variables for the form elements: the message has to be sent by email
 			$email_ann = '1';
-			$content_to_modify = sprintf(get_lang('RemindInactiveLearnersMailContent'),api_get_setting('siteName'),$since);
-			$title_to_modify = sprintf(get_lang('RemindInactiveLearnersMailSubject'),api_get_setting('siteName'));
+			// setting the variables for the form elements: the title of the email
+			$title_to_modify = sprintf(get_lang('RemindInactiveLearnersMailSubject'),api_get_setting('siteName'),' > ',$_course['name']);				
+			// setting the variables for the form elements: the message of the email
+			$content_to_modify = sprintf(get_lang('RemindInactiveLearnersMailContent'),api_get_setting('siteName'),' > ',$_course['name'],$since);
+			// when we want to remind the users who have never been active then we have a different subject and content for the announcement
+			if ($_GET['since'] == 'never') {
+				$title_to_modify = get_lang('NoActivityYetTitle');
+				$content_to_modify = get_lang('NoActivityYetContent');
+			}
 		} else {
 			echo get_lang("Everybody");
 		}

+ 12 - 2
main/inc/lib/tracking.lib.php

@@ -1213,6 +1213,7 @@ class Tracking {
 	{
 		$tbl_track_login = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
 		$tbl_session_course_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
+		$table_course_rel_user			= Database :: get_main_table(TABLE_MAIN_COURSE_USER);
 		$inner = '';
 		if($session_id!=0)
 		{
@@ -1226,7 +1227,16 @@ class Tracking {
 				HAVING DATE_SUB( NOW(), INTERVAL '.$since.' DAY) > max_date ';
 		//HAVING DATE_ADD(max_date, INTERVAL '.$since.' DAY) < NOW() ';
 
-		$rs = Database::query($sql,__FILE__,__LINE__);
+		if ($since == 'never') {
+			$sql = 'SELECT course_user.user_id FROM '.$table_course_rel_user.' course_user
+						LEFT JOIN '. $tbl_track_login.' stats_login 
+						ON course_user.user_id = stats_login.user_id'.
+						$inner.'
+					WHERE course_user.course_code = \''.Database::escape_string($course_code).'\' 
+					AND stats_login.login_course_date IS NULL
+					GROUP BY course_user.user_id';
+		}		
+		$rs = api_sql_query($sql,__FILE__,__LINE__);
 		$inactive_users = array();
 		while($user = Database::fetch_array($rs))
 		{
@@ -1342,7 +1352,7 @@ class Tracking {
 		}
 
 		if ((int)$count_loop > 0) {
-			$avg_student_score = round(($average_data_sum / $count_loop), 2);
+			$avg_student_score = round(($average_data_sum / $count_loop * 100), 2);
 		}
 
 		return $avg_student_score;

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

@@ -1653,9 +1653,9 @@ class UserManager
 					ON course_rel_user.user_course_cat = user_course_category.id
 				$join_access_url
 			WHERE  course_rel_user.user_id = '".$user_id."'  $where_access_url
-			ORDER BY user_course_category.sort,course.title,course_rel_user.sort ASC";
-
-		$course_list_sql_result = Database::query($personal_course_list_sql, __FILE__, __LINE__);
+										ORDER BY user_course_category.sort, course_rel_user.sort, course.title ASC";
+		
+		$course_list_sql_result = api_sql_query($personal_course_list_sql, __FILE__, __LINE__);
 		//var_dump($course_list_sql_result); exit;
 		while ($result_row = Database::fetch_array($course_list_sql_result)) {
 			$personal_course_list[] = $result_row;

+ 113 - 74
main/tracking/courseLog.php

@@ -34,6 +34,7 @@ if (isset($_GET['from']) && $_GET['from'] == 'myspace') {
 	$this_section = SECTION_COURSES;
 }
 
+// access restrictions
 $is_allowedToTrack = $is_courseAdmin || $is_platformAdmin || $is_courseCoach || $is_sessionAdmin;
 
 if (!$is_allowedToTrack) {
@@ -53,7 +54,10 @@ 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(LIBRARY_PATH).'export.lib.inc.php';
 require_once api_get_path(LIBRARY_PATH).'formvalidator/FormValidator.class.php';
+require api_get_path(LIBRARY_PATH).'statsUtils.lib.inc.php';
+require api_get_path(SYS_CODE_PATH).'resourcelinker/resourcelinker.inc.php';
 
+// starting the output buffering when we are exporting the information
 $export_csv = isset($_GET['export']) && $_GET['export'] == 'csv' ? true : false;
 if ($export_csv) {
 	ob_start();
@@ -81,12 +85,7 @@ $htmlHeadXtra[] = "<style type='text/css'>
 
 </style>";
 
-/*
------------------------------------------------------------
-	Constants and variables
------------------------------------------------------------
-*/
-// regroup table names for maintenance purpose
+// Database table definitions
 $TABLETRACK_ACCESS      = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
 $TABLETRACK_LINKS       = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_LINKS);
 $TABLETRACK_DOWNLOADS   = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
@@ -98,17 +97,12 @@ $TABLECOURSE_LINKS      = Database::get_course_table(TABLE_LINK);
 $table_user = Database::get_main_table(TABLE_MAIN_USER);
 $TABLEQUIZ = Database :: get_course_table(TABLE_QUIZ_TEST);
 
-//$table_scormdata = Database::get_scorm_table(TABLE_SCORM_SCO_DATA);
-//$table_scormmain = Database::get_scorm_table(TABLE_SCORM_MAIN);
-//$tbl_learnpath_main = Database::get_course_table(TABLE_LEARNPATH_MAIN);
-//$tbl_learnpath_item = Database::get_course_table(TABLE_LEARNPATH_ITEM);
-//$tbl_learnpath_chapter = Database::get_course_table(TABLE_LEARNPATH_CHAPTER);
-
 $tbl_learnpath_main = Database::get_course_table(TABLE_LP_MAIN);
 $tbl_learnpath_item = Database::get_course_table(TABLE_LP_ITEM);
 $tbl_learnpath_view = Database::get_course_table(TABLE_LP_VIEW);
 $tbl_learnpath_item_view = Database::get_course_table(TABLE_LP_ITEM_VIEW);
 
+// breadcrumbs 
 if (isset($_GET['origin']) && $_GET['origin'] == 'resume_session') {
     $interbreadcrumb[] = array('url' => '../admin/index.php','name' => get_lang('PlatformAdmin'));
     $interbreadcrumb[] = array('url' => '../admin/session_list.php','name' => get_lang('SessionList'));
@@ -119,11 +113,13 @@ $view = (isset($_REQUEST['view']) ? $_REQUEST['view'] : '');
 
 $nameTools = get_lang('Tracking');
 
+// display the header
 Display::display_header($nameTools, 'Tracking');
 
 require api_get_path(LIBRARY_PATH).'statsUtils.lib.inc.php';
 require api_get_path(SYS_CODE_PATH).'resourcelinker/resourcelinker.inc.php';
 
+// getting all the students of the course
 $a_students = CourseManager :: get_student_list_from_course_code($_course['id'], true, (empty($_SESSION['id_session']) ? null : $_SESSION['id_session']));
 $nbStudents = count($a_students);
 
@@ -298,31 +294,28 @@ function get_tool_name_table($tool) {
 
 echo '<div class="actions">';
 if ($_GET['studentlist'] == 'false') {
-	echo '<a href="courseLog.php?'.api_get_cidreq().'&studentlist=true">'.get_lang('StudentsTracking').'</a> | '.get_lang('CourseTracking').' | <a href="courseLog.php?'.api_get_cidreq().'&studentlist=resources">'.get_lang('ResourcesTracking');
+	echo '<a href="courseLog.php?'.api_get_cidreq().'&studentlist=true">'.get_lang('StudentsTracking').'</a> | '.get_lang('CourseTracking').'&nbsp;|&nbsp;<a href="courseLog.php?'.api_get_cidreq().'&studentlist=resources">'.get_lang('ResourcesTracking');
 } elseif($_GET['studentlist'] == 'resources') {
 	echo '<a href="courseLog.php?'.api_get_cidreq().'&studentlist=true">'.get_lang('StudentsTracking').'</a> | <a href="courseLog.php?'.api_get_cidreq().'&studentlist=false">'.get_lang('CourseTracking').'</a> | '.get_lang('ResourcesTracking');
 } elseif($_GET['studentlist'] == '' || $_GET['studentlist'] == 'true') {
 	echo get_lang('StudentsTracking').' | <a href="courseLog.php?'.api_get_cidreq().'&studentlist=false">'.get_lang('CourseTracking').'</a> | <a href="courseLog.php?'.api_get_cidreq().'&studentlist=resources">'.get_lang('ResourcesTracking').'</a>';
 }
-echo '&nbsp;<a href="javascript: void(0);" onclick="javascript: window.print();"><img align="absbottom" src="../img/printmgr.gif">&nbsp;'.get_lang('Print').'</a>';
+echo '&nbsp;<a href="javascript: void(0);" onclick="javascript: window.print();">'.Display::return_icon('printmgr.gif',get_lang('Print')).get_lang('Print').'</a>';
 if($_GET['studentlist'] == 'false') {
 	echo '<a href="'.api_get_self().'?'.api_get_cidreq().'&export=csv&studentlist=false"><img align="absbottom" src="../img/excel.gif">&nbsp;'.get_lang('ExportAsCSV').'</a>';
 } elseif ($_GET['studentlist'] == '' || $_GET['studentlist'] == 'true') {
-	echo '<a href="'.api_get_self().'?'.api_get_cidreq().'&export=csv"><img align="absbottom" src="../img/excel.gif">&nbsp;'.get_lang('ExportAsCSV').'</a>';
+	echo '<a href="'.api_get_self().'?'.api_get_cidreq().'&export=csv">'.Display::return_icon('csv.gif',get_lang('ExportAsCSV')).get_lang('ExportAsCSV').'</a>';
 }
+echo display_additional_profile_fields();
 echo '</div>';
 
 
 if ($_GET['studentlist'] == 'false') {
 	echo'<br /><br />';
 
-	/***************************
-	 * LEARNING PATHS
-	 ***************************/
+	// learning path tracking
 	 echo '<div class="report_section">
-				<h4>
-					<img src="../img/scormbuilder.gif" align="absbottom">&nbsp;'.get_lang('AverageProgressInLearnpath').'
-				</h4>
+			<h4>'.Display::return_icon('scormbuilder.gif',get_lang('AverageProgressInLearnpath')).get_lang('AverageProgressInLearnpath').'</h4>
 			<table class="data_table">';
 
 	$list = new LearnpathList($student);
@@ -368,13 +361,9 @@ if ($_GET['studentlist'] == 'false') {
 	echo '</table></div>';
 	echo '<div class="clear"></div>';
 
-	/***************************
-	 * EXERCICES
-	 ***************************/
+	 // Exercices tracking
 	 echo '<div class="report_section">
-				<h4>
-					<img src="../img/quiz.gif" align="absbottom">&nbsp;'.get_lang('AverageResultsToTheExercices').' &nbsp;-&nbsp;<a href="../exercice/exercice.php?'.api_get_cidreq().'&show=result">'.get_lang('SeeDetail').'</a>
-				</h4>
+				<h4>'.Display::return_icon('quiz.gif',get_lang('AverageResultsToTheExercices')).get_lang('AverageResultsToTheExercices').'&nbsp;-&nbsp;<a href="../exercice/exercice.php?'.api_get_cidreq().'&show=result">'.get_lang('SeeDetail').'</a></h4>
 			<table class="data_table">';
 
 	$sql = "SELECT id, title
@@ -446,14 +435,10 @@ if ($_GET['studentlist'] == 'false') {
 	echo '</table></div>';
 	echo '<div class="clear"></div>';
 
-	/**********************
-	 * FORUMS
-	 **********************/
+	 // forums tracking
 
 	echo '<div class="report_section">
-				<h4>
-					<img src="../img/forum.gif" align="absbottom">&nbsp;'.get_lang('Forum').'&nbsp;-&nbsp;<a href="../forum/index.php?cidReq='.$_course['id'].'">'.get_lang('SeeDetail').'</a>
-				</h4>
+			<h4>'.Display::return_icon('forum.gif', get_lang('Forum')).get_lang('Forum').'&nbsp;-&nbsp;<a href="../forum/index.php?cidReq='.$_course['id'].'">'.get_lang('SeeDetail').'</a></h4>
 			<table class="data_table">';
 	$count_number_of_posts_by_course = Tracking :: count_number_of_posts_by_course($_course['id']);
 	$count_number_of_forums_by_course = Tracking :: count_number_of_forums_by_course($_course['id']);
@@ -470,14 +455,10 @@ if ($_GET['studentlist'] == 'false') {
 	echo '</table></div>';
 	echo '<div class="clear"></div>';
 
-	/**********************
-	 * CHAT
-	 **********************/
+	// chat tracking
 
 	echo '<div class="report_section">
-				<h4>
-					<img src="../img/chat.gif" align="absbottom">&nbsp;'.get_lang('Chat').'</a>
-				</h4>
+			<h4>'.Display::return_icon('chat.gif',get_lang('Chat')).get_lang('Chat').'</h4>
 			<table class="data_table">';
 	$chat_connections_during_last_x_days_by_course = Tracking :: chat_connections_during_last_x_days_by_course($_course['id'], 7);
 	if ($export_csv) {
@@ -489,13 +470,9 @@ if ($_GET['studentlist'] == 'false') {
 	echo '</table></div>';
 	echo '<div class="clear"></div>';
 
-	/**********************
-	 * TOOLS
-	 **********************/
+	// tools tracking
 	echo '<div class="report_section">
-				<h4>
-					<img src="../img/acces_tool.gif" align="absbottom">&nbsp;'.get_lang('ToolsMostUsed').'
-				</h4>
+				<h4>'.Display::return_icon('acces_tool.gif', get_lang('ToolsMostUsed')).get_lang('ToolsMostUsed').'</h4>
 			<table class="data_table">';
 
 	$sql = "SELECT access_tool, COUNT(DISTINCT access_user_id),count( access_tool ) as count_access_tool
@@ -526,21 +503,17 @@ if ($_GET['studentlist'] == 'false') {
 	echo '</table></div>';
 	echo '<div class="clear"></div>';
 
-	/***************************
-	 * DOCUMENTS
-	 ***************************/
+	// Documents tracking
 	if ($_GET['num'] == 0 or empty($_GET['num'])) {
 		$num = 3;
-		$link = '&nbsp;-&nbsp;<a href="'.api_get_self().'?'.api_get_cidreq().'&studentlist=false&num=1#ancle">'.get_lang('SeeDetail').'</a>';
+		$link='&nbsp;-&nbsp;<a href="'.api_get_self().'?'.api_get_cidreq().'&studentlist=false&num=1#documents_tracking">'.get_lang('SeeDetail').'</a>';
 	} else {
 		$num = 1000;
-		$link = '&nbsp;-&nbsp;<a href="'.api_get_self().'?'.api_get_cidreq().'&studentlist=false&num=0#ancle">'.get_lang('ViewMinus').'</a>';
+		$link='&nbsp;-&nbsp;<a href="'.api_get_self().'?'.api_get_cidreq().'&studentlist=false&num=0#documents_tracking">'.get_lang('ViewMinus').'</a>';
 	}
 
-	echo '<a name="ancle" id="a"></a><div class="report_section">
-				<h4>
-					<img src="../img/documents.gif" align="absbottom">&nbsp;'.get_lang('DocumentsMostDownloaded').$link.'
-				</h4>
+	 echo '<a name="documents_tracking" id="a"></a><div class="report_section">
+				<h4>'.Display::return_icon('documents.gif',get_lang('DocumentsMostDownloaded')).'&nbsp;'.get_lang('DocumentsMostDownloaded').$link.'</h4>
 			<table class="data_table">';
 
 	$sql = "SELECT down_doc_path, COUNT(DISTINCT down_user_id), COUNT(down_doc_path) as count_down
@@ -579,13 +552,9 @@ if ($_GET['studentlist'] == 'false') {
 
 	echo '<div class="clear"></div>';
 
-	/***************************
-	 * LINKS
-	 ***************************/
+	// links tracking
 	 echo '<div class="report_section">
-				<h4>
-					<img src="../img/link.gif" align="absbottom">&nbsp;'.get_lang('LinksMostClicked').'
-				</h4>
+				<h4>'.Display::return_icon('link.gif',get_lang('LinksMostClicked')).'&nbsp;'.get_lang('LinksMostClicked').'</h4>
 			<table class="data_table">';
 
 	$sql = "SELECT cl.title, cl.url,count(DISTINCT sl.links_user_id), count(cl.title) as count_visits
@@ -629,7 +598,7 @@ if ($_GET['studentlist'] == 'false') {
 		ob_end_clean();
 		Export :: export_table_csv($csv_content, 'reporting_course_tracking');
 	}
-} elseif($_GET['studentlist'] == 'true' or $_GET['studentlist'] == '') {
+} elseif ($_GET['studentlist'] == 'true' or $_GET['studentlist'] == '') {
 // else display student list with all the informations
 
 	// BEGIN : form to remind inactives susers
@@ -665,27 +634,32 @@ if ($_GET['studentlist'] == 'false') {
 	}
 	$sort_by_first_name = api_sort_by_first_name();
 
-	$tracking_column = isset($_GET['tracking_column']) ? $_GET['tracking_column'] : ($is_western_name_order xor $sort_by_first_name) ? 2 : 1;
+	$tracking_column = isset($_GET['tracking_column']) ? $_GET['tracking_column'] : 0;
 	$tracking_direction = isset($_GET['tracking_direction']) ? $_GET['tracking_direction'] : 'DESC';
 
 	if (count($a_students) > 0) {
 		$table = new SortableTable('tracking', 'count_student_in_course', null, ($is_western_name_order xor $sort_by_first_name) ? 2 : 1);
-		$table -> set_header(0, get_lang('OfficialCode'), true, 'align="center"');
+		$table -> set_header(0, get_lang('OfficialCode'), false, 'align="center"');
 		if ($is_western_name_order) {
-			$table -> set_header(1, get_lang('FirstName'), true, 'align="center"');
+			$table -> set_header(1, get_lang('FirstName'), false, 'align="center"');
 			$table -> set_header(2, get_lang('LastName'), true, 'align="center"');
 		} else {
-			$table -> set_header(1, get_lang('LastName'), true, 'align="center"');
-			$table -> set_header(2, get_lang('FirstName'), true, 'align="center"');
+    		$table -> set_header(1, get_lang('LastName'), true, 'align="center"');
+			$table -> set_header(2, get_lang('FirstName'), false, 'align="center"');
+		}
+		$table -> set_header(3, get_lang('TrainingTime'),false);
+		$table -> set_header(4, get_lang('CourseProgress'),false);
+		$table -> set_header(5, get_lang('Score'),false);	
+		$table -> set_header(6, get_lang('Student_publication'),false);
+		$table -> set_header(7, get_lang('Messages'),false);
+		$table -> set_header(8, get_lang('FirstLogin'), false, 'align="center"');
+		$table -> set_header(9, get_lang('LatestLogin'), false, 'align="center"');		$table -> set_header(10, get_lang('Details'),false);
+		if (isset($_GET['additional_profile_field']) AND is_numeric($_GET['additional_profile_field'])) {
+			$table -> set_header(11, get_lang('AdditionalProfileField'),false);
+        }
+	    if ($export_csv) {
+			$csv_content[] = array ();
 		}
-		$table -> set_header(3, get_lang('TrainingTime'), true);
-		$table -> set_header(4, get_lang('CourseProgress'), true);
-		$table -> set_header(5, get_lang('Score'), true);
-		$table -> set_header(6, get_lang('Student_publication'), true);
-		$table -> set_header(7, get_lang('Messages'), true);
-		$table -> set_header(8, get_lang('FirstLogin'), true, 'align="center"');
-		$table -> set_header(9, get_lang('LatestLogin'), true, 'align="center"');
-		$table -> set_header(10, get_lang('Details'), false);
 
 	    $all_datas = array();
 	    $course_code = $_course['id'];
@@ -826,3 +800,68 @@ if ($_GET['studentlist'] == 'false') {
 </table>
 <?php
 Display::display_footer();
+	// creating the form
+	$return = '<form action="courseLog.php" method="get" name="additional_profile_field_form" id="additional_profile_field_form">';  
+
+	// the select field with the additional user profile fields (= this is where we select the field of which we want to see
+	// the information the users have entered or selected. 
+	$return .= '<select name="additional_profile_field">';
+	$return .= '<option value="-">'.get_lang('SelectFieldToAdd').'</option>';
+	foreach ($extra_fields as $key=>$field)
+	{
+		if ($field[0] == $_GET['additional_profile_field']) {
+			$selected = 'selected="selected"';
+		}
+		else {
+			$selected = '';
+		}
+		$return .= '<option value="'.$field[0].'" '.$selected.'>'.$field[3].'</option>';
+	}
+	$return .= '</select>';
+
+	// the form elements for the $_GET parameters (because the form is passed through GET
+	foreach ($_GET as $key=>$value){
+		$return .= '<input type="hidden" name="'.$key.'" value="'.Security::Remove_XSS($value).'" />';
+	}
+
+	// the submit button
+	$return .= '<button class="save" type="submit">'.get_lang('AddAdditionalProfileField').'</button>';
+	$return .= '</form>';
+	return $return; 
+}
+
+/**
+ * This function gets all the information of a certrain ($field_id) additional profile field.
+ * It gets the information of all the users so that it can be displayed in the sortable table or in the csv or xls export
+ * 
+ * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, Belgium
+ * @since October 2009
+ * @version 1.8.7
+ */
+function get_addtional_profile_information_of_field($field_id){
+	// Database table definition
+	$table_user 			= Database::get_main_table(TABLE_MAIN_USER);
+	$table_user_field_values 	= Database::get_main_table(TABLE_MAIN_USER_FIELD_VALUES);
+
+	$sql = "SELECT user.user_id, field.field_value FROM $table_user user, $table_user_field_values field
+		WHERE user.user_id = field.user_id
+		AND field.field_id='".Database::escape_string($field_id)."'";
+	$result = api_sql_query($sql,__FILE__,__LINE__);
+	while($row = Database::fetch_array($result))
+	{
+		$return[$row['user_id']][] = $row['field_value'];
+	}
+	return $return;
+}
+
+/**
+ * count the number of students in this course (used for SortableTable)
+ */
+function count_student_in_course() {
+	global $nbStudents;
+	return $nbStudents;
+}
+
+function sort_users($a, $b) {
+	return api_strcmp(trim(api_strtolower($a[$_SESSION['tracking_column']])), trim(api_strtolower($b[$_SESSION['tracking_column']])));
+}

+ 252 - 20
main/user/subscribe_user.php

@@ -35,14 +35,19 @@
 */
 // name of the language file that needs to be included
 $language_file = array('registration','admin');
-include ("../inc/global.inc.php");
+require '../inc/global.inc.php';
+// the section (for the tabs)
 $this_section = SECTION_COURSES;
+// access restriction
 if (!api_is_allowed_to_edit()) {
 	 api_not_allowed(true);
 }
-require_once (api_get_path(LIBRARY_PATH).'course.lib.php');
-require_once (api_get_path(LIBRARY_PATH).'sortabletable.class.php');
-require_once (api_get_path(LIBRARY_PATH).'formvalidator/FormValidator.class.php');
+// including additional libraries
+$libpath = api_get_path(LIBRARY_PATH);
+require_once $libpath.'course.lib.php';
+require_once $libpath.'sortabletable.class.php';
+require_once $libpath.'formvalidator/FormValidator.class.php';
+require_once $libpath.'usermanager.lib.php';
 
 /*
 ==============================================================================
@@ -188,8 +193,10 @@ if (!empty($_SESSION['session_user_name'])) {
  *  * Get the users to display on the current page.
  */
 function get_number_of_users() {
+	// Database table definition
 	$user_table = Database :: get_main_table(TABLE_MAIN_USER);
 	$course_user_table = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
+	$table_user_field_values 	= Database::get_main_table(TABLE_MAIN_USER_FIELD_VALUES);
 	if (isset($_REQUEST['type']) && $_REQUEST['type']=='teacher') {
 		$sql = "SELECT 	u.user_id
 						FROM $user_table u
@@ -215,8 +222,20 @@ function get_number_of_users() {
 	} else {
 		$sql = "SELECT 	u.user_id
 						FROM $user_table u
-						LEFT JOIN $course_user_table cu on u.user_id = cu.user_id and course_code='".$_SESSION['_course']['id']."'
-						WHERE cu.user_id IS NULL";
+						LEFT JOIN $course_user_table cu on u.user_id = cu.user_id and course_code='".$_SESSION['_course']['id']."'";
+						
+		// we change the SQL when we have a filter
+		if (isset($_GET['subscribe_user_filter_value'])){
+			$field_identification = explode('*',$_GET['subscribe_user_filter_value']);
+			$sql .=	"
+				LEFT JOIN $table_user_field_values field_values 
+					ON field_values.user_id = u.user_id 
+				WHERE cu.user_id IS NULL
+					AND field_values.field_id = '".Database::escape_string($field_identification[0])."' 
+					AND field_values.field_value = '".Database::escape_string($field_identification[1])."'";
+		} else	{
+			$sql .=	"WHERE cu.user_id IS NULL";
+		}		
 
 		global $_configuration;
 		if ($_configuration['multiple_access_urls']==true) {
@@ -239,23 +258,59 @@ function get_number_of_users() {
 
 	}
 
+	// when there is a keyword then we are searching and we have to change the SQL statement
 	if (isset ($_REQUEST['keyword'])) {
 		$keyword = Database::escape_string($_REQUEST['keyword']);
 		$sql .= " AND (firstname LIKE '%".$keyword."%' OR lastname LIKE '%".$keyword."%'   OR email LIKE '%".$keyword."%'  OR username LIKE '%".$keyword."%'  OR official_code LIKE '%".$keyword."%')";
+		// we also want to search for users who have something in their profile fields that matches the keyword
+		$additional_users = search_additional_profile_fields($keyword);
+					
+		// getting all the users of the course (to make sure that we do not display users that are already in the course)
+		if (!empty($_SESSION["id_session"])) {
+			$a_course_users = CourseManager :: get_user_list_from_course_code($_SESSION['_course']['id'], true, $_SESSION['id_session']);
+		} else {
+			$a_course_users = CourseManager :: get_user_list_from_course_code($_SESSION['_course']['id'], true);
 	}
-	$res = Database::query($sql, __FILE__, __LINE__);
+		foreach ($a_course_users as $user_id=>$course_user) {
+			$users_of_course[] = $course_user['user_id'];
+	    }
+		
+	}
+	
+	
+	//executing the SQL statement
+	$res = api_sql_query($sql, __FILE__, __LINE__);
+	while ($user = Database::fetch_row($res)) {
+		$users[] = $user[0];
+	}	
 	$result = Database::num_rows($res);
+	// we add 1 for every additional user (a user where the keyword matches one of the additional profile fields)
+	// that is not yet in the course and not yet in the search result
+	if (isset ($_REQUEST['keyword'])) {	
+		foreach($additional_users as $additional_user_key=>$additional_user_value){
+			if (!in_array($additional_user_key,$users) AND !in_array($additional_user_key,$users_of_course)){
+				$result++;
+			}
+		}	
+	}
 	return $result;
 }
 /**
  * Get the users to display on the current page.
  */
 function get_user_data($from, $number_of_items, $column, $direction) {
+	global $_course;
+
+	// Database table definitions
 	$user_table = Database :: get_main_table(TABLE_MAIN_USER);
 	$course_user_table = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
 	$tbl_session_rel_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
+	$table_user_field_values 	= Database::get_main_table(TABLE_MAIN_USER_FIELD_VALUES);
+	
+	// adding teachers
 	$is_western_name_order = api_is_western_name_order();
 	if (isset($_REQUEST['type']) && $_REQUEST['type']=='teacher') {
+		// adding a teacher through a session
 		if (!empty($_SESSION["id_session"])) {
 			$sql = "SELECT
 					u.user_id AS col0,
@@ -269,9 +324,19 @@ function get_user_data($from, $number_of_items, $column, $direction) {
 					u.active 	AS col5,
 					u.user_id   AS col6
 					FROM $user_table u
-					LEFT JOIN $tbl_session_rel_course_user cu on u.user_id = cu.id_user and course_code='".$_SESSION['_course']['id']."'
-					WHERE cu.id_user IS NULL";
+					LEFT JOIN $tbl_session_rel_course_user cu on u.user_id = cu.id_user and course_code='".$_SESSION['_course']['id']."'";
+
+			// applying the filter of the additional user profile fields 	
+			if (isset($_GET['subscribe_user_filter_value'])){
+				$field_identification = explode('*',$_GET['subscribe_user_filter_value']);
+				$sql .=	"
+					LEFT JOIN $table_user_field_values field_values 
+						ON field_values.user_id = u.user_id 
+					WHERE cu.user_id IS NULL
+						AND field_values.field_id = '".Database::escape_string($field_identification[0])."' 
+						AND field_values.field_value = '".Database::escape_string($field_identification[1])."'";
 		} else {
+		// adding a teacher NOT through a session
 			$sql = "SELECT
 					u.user_id AS col0,
 					u.official_code AS col1,
@@ -284,8 +349,20 @@ function get_user_data($from, $number_of_items, $column, $direction) {
 					u.active 	AS col5,
 					u.user_id   AS col6
 				FROM $user_table u
-				LEFT JOIN $course_user_table cu on u.user_id = cu.user_id and course_code='".$_SESSION['_course']['id']."'
-				WHERE cu.user_id IS NULL";
+				LEFT JOIN $course_user_table cu on u.user_id = cu.user_id and course_code='".$_SESSION['_course']['id']."'";
+				
+				// applying the filter of the additional user profile fields 	
+				if (isset($_GET['subscribe_user_filter_value'])){
+					$field_identification = explode('*',$_GET['subscribe_user_filter_value']);
+					$sql .=	"
+						LEFT JOIN $table_user_field_values field_values 
+							ON field_values.user_id = u.user_id 
+						WHERE cu.user_id IS NULL
+							AND field_values.field_id = '".Database::escape_string($field_identification[0])."' 
+							AND field_values.field_value = '".Database::escape_string($field_identification[1])."'";
+				} else	{
+					$sql .=	"WHERE cu.user_id IS NULL";
+				}
 				//showing only the courses of the current Dokeos access_url_id
 				global $_configuration;
 				if ($_configuration['multiple_access_urls']==true) {
@@ -306,10 +383,24 @@ function get_user_data($from, $number_of_items, $column, $direction) {
 						FROM $user_table u
 						LEFT JOIN $course_user_table cu on u.user_id = cu.user_id and course_code='".$_SESSION['_course']['id']."'
 						INNER JOIN  $tbl_url_rel_user as url_rel_user
-						ON (url_rel_user.user_id = u.user_id)
-						WHERE cu.user_id IS NULL AND access_url_id= $url_access_id ";
-					}
-				}
+					ON (url_rel_user.user_id = u.user_id) 
+					WHERE cu.user_id IS NULL AND access_url_id= $url_access_id ";				
+
+
+					// applying the filter of the additional user profile fields 	
+					if (isset($_GET['subscribe_user_filter_value'])){
+						$field_identification = explode('*',$_GET['subscribe_user_filter_value']);
+						$sql .=	"
+							LEFT JOIN $table_user_field_values field_values 
+								ON field_values.user_id = u.user_id 
+							WHERE cu.user_id IS NULL
+								AND field_values.field_id = '".Database::escape_string($field_identification[0])."' 
+								AND field_values.field_value = '".Database::escape_string($field_identification[1])."'";
+					} else	{
+						$sql .=	"WHERE cu.user_id IS NULL AND access_url_id= $url_access_id ";
+					}		
+				}		
+			}
 		}
 	} else {
 		if (!empty($_SESSION["id_session"])) {
@@ -365,14 +456,45 @@ function get_user_data($from, $number_of_items, $column, $direction) {
 					INNER JOIN  $tbl_url_rel_user as url_rel_user
 					ON (url_rel_user.user_id = u.user_id)
 					WHERE cu.user_id IS NULL AND access_url_id= $url_access_id ";
+
+
+					// applying the filter of the additional user profile fields 	
+					if (isset($_GET['subscribe_user_filter_value'])){
+						$field_identification = explode('*',$_GET['subscribe_user_filter_value']);
+						$sql .=	"
+							LEFT JOIN $table_user_field_values field_values 
+								ON field_values.user_id = u.user_id 
+							WHERE cu.user_id IS NULL
+								AND field_values.field_id = '".Database::escape_string($field_identification[0])."' 
+								AND field_values.field_value = '".Database::escape_string($field_identification[1])."'";
+					} else	{
+						$sql .=	"WHERE cu.user_id IS NULL AND access_url_id= $url_access_id ";
+					}		
+
 				}
 			}
 		}
 	}
+
+	// adding additional WHERE statements to the SQL for the search functionality
 	if (isset ($_REQUEST['keyword'])) {
 		$keyword = Database::escape_string($_REQUEST['keyword']);
 		$sql .= " AND (firstname LIKE '%".$keyword."%' OR lastname LIKE '%".$keyword."%'   OR email LIKE '%".$keyword."%'  OR username LIKE '%".$keyword."%'  OR official_code LIKE '%".$keyword."%')";
+		// we also want to search for users who have something in their profile fields that matches the keyword
+		$additional_users = search_additional_profile_fields($keyword);
+				
+		// getting all the users of the course (to make sure that we do not display users that are already in the course)
+		if (!empty($_SESSION["id_session"])) {
+			$a_course_users = CourseManager :: get_user_list_from_course_code($_SESSION['_course']['id'], true, $_SESSION['id_session']);
+		} else {
+			$a_course_users = CourseManager :: get_user_list_from_course_code($_SESSION['_course']['id'], true);
+	}
+		foreach ($a_course_users as $user_id=>$course_user) {
+			$users_of_course[] = $course_user['user_id'];
+		}
 	}
+	
+	// Sorting and pagination (used by the sortable table)
 	$sql .= " ORDER BY col$column $direction ";
 	$sql .= " LIMIT $from,$number_of_items";
 	$res = Database::query($sql, __FILE__, __LINE__);
@@ -386,6 +508,14 @@ function get_user_data($from, $number_of_items, $column, $direction) {
 			$_SESSION['session_user_name'][] = api_get_person_name($user[3], $user[2]);
 		}
 	}
+	// adding additional users based on the search on the additional profile fields
+	if (isset ($_REQUEST['keyword'])){
+		foreach($additional_users as $additional_user_key=>$additional_user_value){
+			if (!in_array($additional_user_key,$_SESSION['session_user_id']) AND !in_array($additional_user_key,$users_of_course)){
+				$users[]= array($additional_user_value['col0'],$additional_user_value['col1'],$additional_user_value['col2'].'*',$additional_user_value['col3'].'*',$additional_user_value['col4'],$additional_user_value['col5'], $additional_user_value['col6']);
+			}
+		}
+	}
 	return $users;
 }
 /**
@@ -447,6 +577,11 @@ if ($_POST['keyword'])
 {
 	$actions .= '<a href="subscribe_user.php?type='.Security::remove_XSS($_GET['type']).'">'.Display::return_icon('clean_group.gif').' '.get_lang('ClearSearchResults').'</a>';
 }
+if ($_GET['subscribe_user_filter_value'] AND !empty($_GET['subscribe_user_filter_value']))
+{
+	$actions .= '<a href="subscribe_user.php?type='.Security::remove_XSS($_GET['type']).'">'.Display::return_icon('clean_group.gif').' '.get_lang('ClearFilterResults').'</a>';
+}
+display_extra_profile_fields_filter();
 
 $form = new FormValidator('search_user', 'POST',api_get_self().'?type='.$_REQUEST['type'],'',null,false);
 $renderer = & $form->defaultRenderer();
@@ -488,9 +623,106 @@ if (!empty($_POST['keyword'])) {
 // Display table
 $table->display();
 
-/*
-==============================================================================
-		FOOTER
-==============================================================================
-*/
+// footer
 Display :: display_footer();
+
+/**
+ * Search the additional user profile fields defined by the platform administrator in 
+ * platform administration > profiling for a given keyword. 
+ * We not only search in the predefined options but also in the input fields wherer
+ * the user can enter some text. 
+ * 
+ * For this we get the additional profile field options that match the (search) keyword, 
+ * then we find all the users who have entered the (search)keyword in a input field of the 
+ * additional profile fields or have chosen one of the matching predefined options
+ *
+ * @param string $keyword a keyword we are looking for in the additional profile fields
+ * @return array $additional_users an array with the users who have an additional profile field that matches the keyword
+ */
+function search_additional_profile_fields($keyword)
+{
+	// database table definitions
+	$table_user_field_options 	= Database :: get_main_table(TABLE_MAIN_USER_FIELD_OPTIONS);
+	$table_user_field_values 	= Database::get_main_table(TABLE_MAIN_USER_FIELD_VALUES);
+	$table_user 				= Database::get_main_table(TABLE_MAIN_USER);
+	$table_course_user		 	= Database :: get_main_table(TABLE_MAIN_COURSE_USER);
+	$table_session_course_user 	= Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);					
+
+	// getting the field option text that match this keyword (for radio buttons and checkboxes)
+	$sql_profiling = "SELECT * FROM $table_user_field_options WHERE option_display_text LIKE '%".$keyword."%'";
+	$result_profiling = api_sql_query($sql_profiling, __FILE__, __LINE__);
+	while ($profiling_field_options = Database::fetch_array($result_profiling)) {
+		$profiling_field_options_exact_values[] = $profiling_field_options;
+	}
+	
+	foreach ($profiling_field_options_exact_values as $profilingkey=>$profilingvalue){
+		$profiling_field_options_exact_values_sql .= "OR (field_id = '".$profilingvalue['field_id']."' AND field_value='".$profilingvalue['option_value']."') ";
+	}
+	
+	// getting all the user ids of the users who have chosen on of the predefined fields that contain the keyword
+	// or all the users who have entered the keyword in a free-form field
+	$sql_profiling_values = "SELECT user.user_id as col0, user.official_code as col1, user.lastname as col2, user.firstname as col3, user.email as col4, user.active as col5, user.user_id as col6
+							FROM $table_user user, $table_user_field_values user_values 
+							WHERE user.user_id = user_values.user_id 
+							AND ( field_value LIKE '%".$keyword."%' 
+							".$profiling_field_options_exact_values_sql.")";
+	$result_profiling_values = api_sql_query($sql_profiling_values, __FILE__, __LINE__);
+	while ($profiled_users = Database::fetch_array($result_profiling_values)) {
+		$additional_users[$profiled_users['col0']] = $profiled_users;
+	}
+	
+	return $additional_users; 
+}
+/**
+ * This function displays a dropdown list with all the additional user profile fields defined by the platform administrator in 
+ * platform administration > profiling. Only the fields that have predefined fields are usefull for such a filter. 
+ *
+ */
+function display_extra_profile_fields_filter()
+{
+	// getting all the additional user profile fields
+	$extra = UserManager::get_extra_fields(0,50,5,'ASC');
+	
+	$return='<option value="">'.get_lang('SelectFilter').'</option>';
+	
+	// looping through the additional user profile fields
+	foreach($extra as $id => $field_details) {		
+		// $field_details[2] contains the type of the additional user profile field
+		switch($field_details[2]) {
+			// text fields cannot be used as a filter
+			case USER_FIELD_TYPE_TEXT:
+				break;
+			// text area fields cannot be used as a filter
+			case USER_FIELD_TYPE_TEXTAREA:				
+				break;
+			case USER_FIELD_TYPE_RADIO:
+			case USER_FIELD_TYPE_SELECT:
+			case USER_FIELD_TYPE_SELECT_MULTIPLE:		
+				$return .= '<optgroup label="'.$field_details[3].'">';
+				foreach($field_details[9] as $option_id => $option_details) {
+					if ($_GET['subscribe_user_filter_value'] == $field_details[0].'*'.$option_details[1]) {
+						$selected = 'selected="selected"';
+					} else {
+						$selected = false;
+					}
+					$return .= '<option value="'.$field_details[0].'*'.$option_details[1].'" '.$selected.'>'.$option_details[2].'</option>';
+				}				
+				$return .= '</optgroup>';
+				break;
+		}			
+	}
+	
+	echo '<form id="subscribe_user_filter" name="subscribe_user_filter" method="get" action="'.api_get_self().'?api_get_cidreq" style="float:left;">';
+	echo '	<input type="hidden" name="type" id="type" value="'.Security::Remove_XSS($_GET['type']).'" />';
+	echo   '<select name="subscribe_user_filter_value" id="subscribe_user_filter_value">'.$return.'</select>';
+	echo   '<button type="submit" name="submit_filter" id="submit_filter" value="" class="search">'.get_lang('Filter').'</button>';
+	echo '</form>';
+
+}
+
+function debug($var)
+{
+	echo '<pre>';
+	print_r($var);
+	echo '</pre>';
+}