courseLog.php 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970
  1. <?php //$id: $
  2. /* For licensing terms, see /dokeos_license.txt */
  3. /**
  4. ==============================================================================
  5. * @author Thomas Depraetere
  6. * @author Hugues Peeters
  7. * @author Christophe Gesche
  8. * @author Sebastien Piraux
  9. * @author Toon Keppens (Vi-Host.net)
  10. *
  11. * @package dokeos.tracking
  12. ==============================================================================
  13. */
  14. /**
  15. * INIT SECTION
  16. */
  17. $pathopen = isset($_REQUEST['pathopen']) ? $_REQUEST['pathopen'] : null;
  18. // name of the language file that needs to be included
  19. $language_file[] = 'admin';
  20. $language_file[] = 'tracking';
  21. $language_file[] = 'scorm';
  22. $cidReset = true;
  23. // including the global Dokeos file
  24. require '../inc/global.inc.php';
  25. // the section (for the tabs)
  26. //$this_section = "session_my_space";
  27. $from_myspace = false;
  28. if (isset($_GET['from']) && $_GET['from'] == 'myspace') {
  29. $from_myspace = true;
  30. $this_section = "session_my_space";
  31. } else {
  32. $this_section = SECTION_COURSES;
  33. }
  34. // access restrictions
  35. $is_allowedToTrack = $is_courseAdmin || $is_platformAdmin || $is_courseCoach || $is_sessionAdmin;
  36. if (!$is_allowedToTrack) {
  37. Display :: display_header(null);
  38. api_not_allowed();
  39. Display :: display_footer();
  40. exit;
  41. }
  42. // including additional libraries
  43. require_once api_get_path(SYS_CODE_PATH).'newscorm/learnpath.class.php';
  44. require_once api_get_path(SYS_CODE_PATH).'newscorm/learnpathItem.class.php';
  45. require_once api_get_path(SYS_CODE_PATH).'newscorm/learnpathList.class.php';
  46. require_once api_get_path(SYS_CODE_PATH).'newscorm/scorm.class.php';
  47. require_once api_get_path(SYS_CODE_PATH).'newscorm/scormItem.class.php';
  48. require_once api_get_path(LIBRARY_PATH).'tracking.lib.php';
  49. require_once api_get_path(LIBRARY_PATH).'course.lib.php';
  50. require_once api_get_path(LIBRARY_PATH).'usermanager.lib.php';
  51. require_once api_get_path(LIBRARY_PATH).'export.lib.inc.php';
  52. require_once api_get_path(LIBRARY_PATH).'formvalidator/FormValidator.class.php';
  53. require api_get_path(LIBRARY_PATH).'statsUtils.lib.inc.php';
  54. require api_get_path(SYS_CODE_PATH).'resourcelinker/resourcelinker.inc.php';
  55. // starting the output buffering when we are exporting the information
  56. $export_csv = isset($_GET['export']) && $_GET['export'] == 'csv' ? true : false;
  57. if ($export_csv) {
  58. ob_start();
  59. }
  60. $csv_content = array();
  61. // charset determination
  62. if (!empty($_GET['scormcontopen'])) {
  63. $tbl_lp = Database::get_course_table(TABLE_LP_MAIN);
  64. $contopen = (int) $_GET['scormcontopen'];
  65. $sql = "SELECT default_encoding FROM $tbl_lp WHERE id = ".$contopen;
  66. $res = Database::query($sql,__FILE__,__LINE__);
  67. $row = Database::fetch_array($res);
  68. $lp_charset = $row['default_encoding'];
  69. }
  70. $htmlHeadXtra[] = "<style type='text/css'>
  71. /*<![CDATA[*/
  72. .secLine {background-color : #E6E6E6;}
  73. .content {padding-left : 15px;padding-right : 15px; }
  74. .specialLink{color : #0000FF;}
  75. /*]]>*/
  76. </style>
  77. <style media='print' type='text/css'>
  78. </style>";
  79. // Database table definitions
  80. $TABLETRACK_ACCESS = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
  81. $TABLETRACK_LINKS = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_LINKS);
  82. $TABLETRACK_DOWNLOADS = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
  83. $TABLETRACK_ACCESS_2 = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_ACCESS);
  84. $TABLETRACK_EXERCISES = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
  85. $TABLECOURSUSER = Database::get_main_table(TABLE_MAIN_COURSE_USER);
  86. $TABLECOURSE = Database::get_main_table(TABLE_MAIN_COURSE);
  87. $TABLECOURSE_LINKS = Database::get_course_table(TABLE_LINK);
  88. $table_user = Database::get_main_table(TABLE_MAIN_USER);
  89. $TABLEQUIZ = Database :: get_course_table(TABLE_QUIZ_TEST);
  90. $tbl_learnpath_main = Database::get_course_table(TABLE_LP_MAIN);
  91. $tbl_learnpath_item = Database::get_course_table(TABLE_LP_ITEM);
  92. $tbl_learnpath_view = Database::get_course_table(TABLE_LP_VIEW);
  93. $tbl_learnpath_item_view = Database::get_course_table(TABLE_LP_ITEM_VIEW);
  94. // breadcrumbs
  95. if (isset($_GET['origin']) && $_GET['origin'] == 'resume_session') {
  96. $interbreadcrumb[] = array('url' => '../admin/index.php','name' => get_lang('PlatformAdmin'));
  97. $interbreadcrumb[] = array('url' => '../admin/session_list.php','name' => get_lang('SessionList'));
  98. $interbreadcrumb[] = array('url' => '../admin/resume_session.php?id_session='.$_SESSION['id_session'], 'name' => get_lang('SessionOverview'));
  99. }
  100. $view = (isset($_REQUEST['view']) ? $_REQUEST['view'] : '');
  101. $nameTools = get_lang('Tracking');
  102. // display the header
  103. Display::display_header($nameTools, 'Tracking');
  104. // getting all the students of the course
  105. $a_students = CourseManager :: get_student_list_from_course_code($_course['id'], true, (empty($_SESSION['id_session']) ? null : $_SESSION['id_session']));
  106. $nbStudents = count($a_students);
  107. // gettting all the additional information of an additional profile field
  108. if (isset($_GET['additional_profile_field']) && is_numeric($_GET['additional_profile_field'])) {
  109. //$additional_user_profile_info = get_addtional_profile_information_of_field($_GET['additional_profile_field']);
  110. $user_array = array();
  111. foreach ($a_students as $key=>$item) {
  112. $user_array[] = $key;
  113. }
  114. //fetching only the user that are loaded NOT ALL user in the portal
  115. $additional_user_profile_info = get_addtional_profile_information_of_field_by_user($_GET['additional_profile_field'],$user_array);
  116. }
  117. function count_item_resources() {
  118. $table_item_property = Database :: get_course_table(TABLE_ITEM_PROPERTY);
  119. $table_user = Database :: get_main_table(TABLE_MAIN_USER);
  120. $sql = "SELECT count(tool) AS total_number_of_items FROM $table_item_property track_resource, $table_user user" .
  121. " WHERE track_resource.insert_user_id = user.user_id";
  122. if (isset($_GET['keyword'])) {
  123. $keyword = Database::escape_string($_GET['keyword']);
  124. $sql .= " AND (user.username LIKE '%".$keyword."%' OR lastedit_type LIKE '%".$keyword."%' OR tool LIKE '%".$keyword."%')";
  125. }
  126. $sql .= " AND tool IN ('document', 'learnpath', 'quiz', 'glossary', 'link', 'course_description')";
  127. $res = Database::query($sql, __FILE__, __LINE__);
  128. $obj = Database::fetch_object($res);
  129. return $obj->total_number_of_items;
  130. }
  131. function get_item_resources_data($from, $number_of_items, $column, $direction) {
  132. global $dateTimeFormatLong;
  133. $table_item_property = Database :: get_course_table(TABLE_ITEM_PROPERTY);
  134. $table_user = Database :: get_main_table(TABLE_MAIN_USER);
  135. $table_session = Database :: get_main_table(TABLE_MAIN_SESSION);
  136. $sql = "SELECT
  137. tool as col0,
  138. lastedit_type as col1,
  139. ref as ref,
  140. user.username as col3,
  141. insert_date as col5,
  142. visibility as col6
  143. FROM $table_item_property track_resource, $table_user user
  144. WHERE track_resource.insert_user_id = user.user_id ";
  145. if (isset($_GET['keyword'])) {
  146. $keyword = Database::escape_string($_GET['keyword']);
  147. $sql .= " AND (user.username LIKE '%".$keyword."%' OR lastedit_type LIKE '%".$keyword."%' OR tool LIKE '%".$keyword."%') ";
  148. }
  149. $sql .= " AND tool IN ('document', 'learnpath', 'quiz', 'glossary', 'link', 'course_description')";
  150. if ($column == 0) { $column = '0'; }
  151. if ($column != '' && $direction != '') {
  152. if ($column != 2 && $column != 4) {
  153. $sql .= " ORDER BY col$column $direction";
  154. }
  155. } else {
  156. $sql .= " ORDER BY col5 DESC ";
  157. }
  158. $sql .= " LIMIT $from, $number_of_items ";
  159. $res = Database::query($sql, __FILE__, __LINE__) or die(mysql_error());
  160. $resources = array ();
  161. while ($row = Database::fetch_array($res)) {
  162. $ref = $row['ref'];
  163. $table_name = get_tool_name_table($row['col0']);
  164. $table_tool = Database :: get_course_table($table_name['table_name']);
  165. $id = $table_name['id_tool'];
  166. $query = "SELECT session.id, session.name, user.username FROM $table_tool tool, $table_session session, $table_user user" .
  167. " WHERE tool.session_id = session.id AND session.id_coach = user.user_id AND tool.$id = $ref";
  168. $recorset = Database::query($query, __FILE__, __LINE__);
  169. if (!empty($recorset)) {
  170. $obj = Database::fetch_object($recorset);
  171. $name_session = '';
  172. $coach_name = '';
  173. if (!empty($obj)) {
  174. $name_session = $obj->name;
  175. $coach_name = $obj->username;
  176. }
  177. $url_tool = api_get_path(WEB_CODE_PATH).$table_name['link_tool'];
  178. $row[0] = '';
  179. if ($row['col6'] != 2) {
  180. $row[0] = '<a href="'.$url_tool.'?'.api_get_cidreq().'&'.$obj->id.'">'.api_ucfirst($row['col0']).'</a>';
  181. } else {
  182. $row[0] = api_ucfirst($row['col0']);
  183. }
  184. $row[1] = get_lang($row[1]);
  185. $row[5] = api_ucfirst(format_locale_date($dateTimeFormatLong, strtotime($row['col5'])));
  186. $row[4] = '';
  187. if ($table_name['table_name'] == 'document') {
  188. $condition = 'tool.title as title';
  189. $query_document = "SELECT $condition FROM $table_tool tool" .
  190. " WHERE id = $ref";
  191. $rs_document = Database::query($query_document, __FILE__, __LINE__) or die(mysql_error());
  192. $obj_document = Database::fetch_object($rs_document);
  193. $row[4] = $obj_document->title;
  194. }
  195. $row2 = $name_session;
  196. if (!empty($coach_name)) {
  197. $row2 .= '<br />'.get_lang('Coach').': '.$coach_name;
  198. }
  199. $row[2] = $row2;
  200. $resources[] = $row;
  201. }
  202. }
  203. return $resources;
  204. }
  205. function get_tool_name_table($tool) {
  206. switch ($tool) {
  207. case 'document':
  208. $table_name = TABLE_DOCUMENT;
  209. $link_tool = 'document/document.php';
  210. $id_tool = 'id';
  211. break;
  212. case 'learnpath':
  213. $table_name = TABLE_LP_MAIN;
  214. $link_tool = 'newscorm/lp_controller.php';
  215. $id_tool = 'id';
  216. break;
  217. case 'quiz':
  218. $table_name = TABLE_QUIZ_TEST;
  219. $link_tool = 'exercice/exercice.php';
  220. $id_tool = 'id';
  221. break;
  222. case 'glossary':
  223. $table_name = TABLE_GLOSSARY;
  224. $link_tool = 'glossary/index.php';
  225. $id_tool = 'glossary_id';
  226. break;
  227. case 'link':
  228. $table_name = TABLE_LINK;
  229. $link_tool = 'link/link.php';
  230. $id_tool = 'id';
  231. break;
  232. case 'course_description':
  233. $table_name = TABLE_COURSE_DESCRIPTION;
  234. $link_tool = 'course_description/';
  235. $id_tool = 'id';
  236. break;
  237. default:
  238. $table_name = $tool;
  239. break;
  240. }
  241. return array('table_name' => $table_name,
  242. 'link_tool' => $link_tool,
  243. 'id_tool' => $id_tool);
  244. }
  245. /*
  246. ==============================================================================
  247. MAIN CODE
  248. ==============================================================================
  249. */
  250. echo '<div class="actions">';
  251. if ($_GET['studentlist'] == 'false') {
  252. 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');
  253. } elseif($_GET['studentlist'] == 'resources') {
  254. 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');
  255. } elseif($_GET['studentlist'] == '' || $_GET['studentlist'] == 'true') {
  256. 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>';
  257. }
  258. echo '&nbsp;<a href="javascript: void(0);" onclick="javascript: window.print();">'.Display::return_icon('printmgr.gif',get_lang('Print')).get_lang('Print').'</a>';
  259. if($_GET['studentlist'] == 'false') {
  260. 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>';
  261. } elseif ($_GET['studentlist'] == '' || $_GET['studentlist'] == 'true') {
  262. $addional_param = '';
  263. if (isset($_GET['additional_profile_field'])) {
  264. $addional_param ='additional_profile_field='.intval($_GET['additional_profile_field']);
  265. }
  266. echo '<a href="'.api_get_self().'?'.api_get_cidreq().'&export=csv&'.$addional_param.'">'.Display::return_icon('csv.gif',get_lang('ExportAsCSV')).get_lang('ExportAsCSV').'</a>';
  267. }
  268. if($_GET['studentlist'] == 'true' || empty($_GET['studentlist'])) {
  269. echo display_additional_profile_fields();
  270. }
  271. echo '</div>';
  272. if ($_GET['studentlist'] == 'false') {
  273. echo'<br /><br />';
  274. // learning path tracking
  275. echo '<div class="report_section">
  276. <h4>'.Display::return_icon('scormbuilder.gif',get_lang('AverageProgressInLearnpath')).get_lang('AverageProgressInLearnpath').'</h4>
  277. <table class="data_table">';
  278. $list = new LearnpathList($student);
  279. $flat_list = $list->get_flat_list();
  280. if ($export_csv) {
  281. $temp = array(get_lang('AverageProgressInLearnpath', ''), '');
  282. $csv_content[] = array('', '');
  283. $csv_content[] = $temp;
  284. }
  285. if (count($flat_list) > 0) {
  286. foreach ($flat_list as $lp_id => $lp) {
  287. $lp_avg_progress = 0;
  288. foreach ($a_students as $student_id => $student) {
  289. // get the progress in learning pathes
  290. $lp_avg_progress += learnpath::get_db_progress($lp_id, $student_id);
  291. }
  292. if ($nbStudents > 0) {
  293. $lp_avg_progress = $lp_avg_progress / $nbStudents;
  294. } else {
  295. $lp_avg_progress = null;
  296. }
  297. // Separated presentation logic.
  298. if (is_null($lp_avg_progress)) {
  299. $lp_avg_progress = '0%';
  300. } else {
  301. $lp_avg_progress = round($lp_avg_progress, 1).'%';
  302. }
  303. echo '<tr><td>'.$lp['lp_name'].'</td><td align="right">'.$lp_avg_progress.'</td></tr>';
  304. if ($export_csv) {
  305. $temp = array($lp['lp_name'], $lp_avg_progress);
  306. $csv_content[] = $temp;
  307. }
  308. }
  309. } else {
  310. echo '<tr><td>'.get_lang('NoLearningPath').'</td></tr>';
  311. if ($export_csv) {
  312. $temp = array(get_lang('NoLearningPath', ''), '');
  313. $csv_content[] = $temp;
  314. }
  315. }
  316. echo '</table></div>';
  317. echo '<div class="clear"></div>';
  318. // Exercices tracking
  319. echo '<div class="report_section">
  320. <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>
  321. <table class="data_table">';
  322. $sql = "SELECT id, title
  323. FROM $TABLEQUIZ WHERE active <> -1";
  324. $rs = Database::query($sql, __FILE__, __LINE__);
  325. if ($export_csv) {
  326. $temp = array(get_lang('AverageProgressInLearnpath'), '');
  327. $csv_content[] = array('', '');
  328. $csv_content[] = $temp;
  329. }
  330. if (Database::num_rows($rs) > 0) {
  331. // gets course actual administrators
  332. $sql = "SELECT user.user_id FROM $table_user user, $TABLECOURSUSER course_user
  333. WHERE course_user.user_id=user.user_id AND course_user.course_code='".api_get_course_id()."' AND course_user.status <> '1' ";
  334. $res = Database::query($sql, __FILE__, __LINE__);
  335. $student_ids = array();
  336. while($row = Database::fetch_row($res)) {
  337. $student_ids[] = $row[0];
  338. }
  339. $count_students = count($student_ids);
  340. while ($quiz = Database::fetch_array($rs)) {
  341. $quiz_avg_score = 0;
  342. if ($count_students > 0) {
  343. foreach ($student_ids as $student_id) {
  344. // get the scorn in exercises
  345. $sql = 'SELECT exe_result , exe_weighting
  346. FROM '.$TABLETRACK_EXERCISES.'
  347. WHERE exe_exo_id = '.$quiz['id'].'
  348. AND exe_user_id = '.(int)$student_id.'
  349. AND exe_cours_id = "'.api_get_course_id().'"
  350. AND orig_lp_id = 0
  351. AND orig_lp_item_id = 0
  352. ORDER BY exe_date DESC';
  353. $rsAttempt = Database::query($sql, __FILE__, __LINE__);
  354. $nb_attempts = 0;
  355. $avg_student_score = 0;
  356. while ($attempt = Database::fetch_array($rsAttempt)) {
  357. $nb_attempts++;
  358. $exe_weight = $attempt['exe_weighting'];
  359. if ($exe_weight > 0) {
  360. $avg_student_score += round(($attempt['exe_result'] / $exe_weight * 100), 2);
  361. }
  362. }
  363. if ($nb_attempts > 0) {
  364. $avg_student_score = $avg_student_score / $nb_attempts;
  365. }
  366. $quiz_avg_score += $avg_student_score;
  367. }
  368. }
  369. $count_students = ($count_students == 0 || is_null($count_students) || $count_students == '') ? 1 : $count_students;
  370. echo '<tr><td>'.$quiz['title'].'</td><td align="right">'.round(($quiz_avg_score / $count_students), 2).'%'.'</td></tr>';
  371. if ($export_csv) {
  372. $temp = array($quiz['title'], $quiz_avg_score);
  373. $csv_content[] = $temp;
  374. }
  375. }
  376. } else {
  377. echo '<tr><td>'.get_lang('NoExercises').'</td></tr>';
  378. if ($export_csv) {
  379. $temp = array(get_lang('NoExercises', ''), '');
  380. $csv_content[] = $temp;
  381. }
  382. }
  383. echo '</table></div>';
  384. echo '<div class="clear"></div>';
  385. // forums tracking
  386. echo '<div class="report_section">
  387. <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>
  388. <table class="data_table">';
  389. $count_number_of_posts_by_course = Tracking :: count_number_of_posts_by_course($_course['id']);
  390. $count_number_of_forums_by_course = Tracking :: count_number_of_forums_by_course($_course['id']);
  391. $count_number_of_threads_by_course = Tracking :: count_number_of_threads_by_course($_course['id']);
  392. if ($export_csv) {
  393. $csv_content[] = array(get_lang('Forum'), '');
  394. $csv_content[] = array(get_lang('ForumForumsNumber', ''), $count_number_of_forums_by_course);
  395. $csv_content[] = array(get_lang('ForumThreadsNumber', ''), $count_number_of_threads_by_course);
  396. $csv_content[] = array(get_lang('ForumPostsNumber', ''), $count_number_of_posts_by_course);
  397. }
  398. echo '<tr><td>'.get_lang('ForumForumsNumber').'</td><td align="right">'.$count_number_of_forums_by_course.'</td></tr>';
  399. echo '<tr><td>'.get_lang('ForumThreadsNumber').'</td><td align="right">'.$count_number_of_threads_by_course.'</td></tr>';
  400. echo '<tr><td>'.get_lang('ForumPostsNumber').'</td><td align="right">'.$count_number_of_posts_by_course.'</td></tr>';
  401. echo '</table></div>';
  402. echo '<div class="clear"></div>';
  403. // chat tracking
  404. echo '<div class="report_section">
  405. <h4>'.Display::return_icon('chat.gif',get_lang('Chat')).get_lang('Chat').'</h4>
  406. <table class="data_table">';
  407. $chat_connections_during_last_x_days_by_course = Tracking :: chat_connections_during_last_x_days_by_course($_course['id'], 7);
  408. if ($export_csv) {
  409. $csv_content[] = array(get_lang('Chat', ''), '');
  410. $csv_content[] = array(sprintf(get_lang('ChatConnectionsDuringLastXDays', ''), '7'), $chat_connections_during_last_x_days_by_course);
  411. }
  412. echo '<tr><td>'.sprintf(get_lang('ChatConnectionsDuringLastXDays'), '7').'</td><td align="right">'.$chat_connections_during_last_x_days_by_course.'</td></tr>';
  413. echo '</table></div>';
  414. echo '<div class="clear"></div>';
  415. // tools tracking
  416. echo '<div class="report_section">
  417. <h4>'.Display::return_icon('acces_tool.gif', get_lang('ToolsMostUsed')).get_lang('ToolsMostUsed').'</h4>
  418. <table class="data_table">';
  419. $sql = "SELECT access_tool, COUNT(DISTINCT access_user_id),count( access_tool ) as count_access_tool
  420. FROM $TABLETRACK_ACCESS
  421. WHERE access_tool IS NOT NULL
  422. AND access_cours_code = '$_cid'
  423. GROUP BY access_tool
  424. ORDER BY count_access_tool DESC
  425. LIMIT 0, 3";
  426. $rs = Database::query($sql, __FILE__, __LINE__);
  427. if ($export_csv) {
  428. $temp = array(get_lang('ToolsMostUsed'), '');
  429. $csv_content[] = $temp;
  430. }
  431. while ($row = Database::fetch_array($rs)) {
  432. echo ' <tr>
  433. <td>'.get_lang(ucfirst($row['access_tool'])).'</td>
  434. <td align="right">'.$row['count_access_tool'].' '.get_lang('Clicks').'</td>
  435. </tr>';
  436. if ($export_csv) {
  437. $temp = array(get_lang(ucfirst($row['access_tool']), ''), $row['count_access_tool'].' '.get_lang('Clicks', ''));
  438. $csv_content[] = $temp;
  439. }
  440. }
  441. echo '</table></div>';
  442. echo '<div class="clear"></div>';
  443. // Documents tracking
  444. if ($_GET['num'] == 0 or empty($_GET['num'])) {
  445. $num = 3;
  446. $link='&nbsp;-&nbsp;<a href="'.api_get_self().'?'.api_get_cidreq().'&studentlist=false&num=1#documents_tracking">'.get_lang('SeeDetail').'</a>';
  447. } else {
  448. $num = 1000;
  449. $link='&nbsp;-&nbsp;<a href="'.api_get_self().'?'.api_get_cidreq().'&studentlist=false&num=0#documents_tracking">'.get_lang('ViewMinus').'</a>';
  450. }
  451. echo '<a name="documents_tracking" id="a"></a><div class="report_section">
  452. <h4>'.Display::return_icon('documents.gif',get_lang('DocumentsMostDownloaded')).'&nbsp;'.get_lang('DocumentsMostDownloaded').$link.'</h4>
  453. <table class="data_table">';
  454. $sql = "SELECT down_doc_path, COUNT(DISTINCT down_user_id), COUNT(down_doc_path) as count_down
  455. FROM $TABLETRACK_DOWNLOADS
  456. WHERE down_cours_id = '$_cid'
  457. GROUP BY down_doc_path
  458. ORDER BY count_down DESC
  459. LIMIT 0, $num";
  460. $rs = Database::query($sql, __FILE__, __LINE__);
  461. if ($export_csv) {
  462. $temp = array(get_lang('DocumentsMostDownloaded', ''), '');
  463. $csv_content[] = array('', '');
  464. $csv_content[] = $temp;
  465. }
  466. if (Database::num_rows($rs) > 0) {
  467. while($row = Database::fetch_array($rs)) {
  468. echo ' <tr>
  469. <td>'.$row['down_doc_path'].'</td>
  470. <td align="right">'.$row['count_down'].' '.get_lang('Clicks').'</td>
  471. </tr>';
  472. if ($export_csv) {
  473. $temp = array($row['down_doc_path'], $row['count_down'].' '.get_lang('Clicks', ''));
  474. $csv_content[] = $temp;
  475. }
  476. }
  477. } else {
  478. echo '<tr><td>'.get_lang('NoDocumentDownloaded').'</td></tr>';
  479. if ($export_csv) {
  480. $temp = array(get_lang('NoDocumentDownloaded', ''),'');
  481. $csv_content[] = $temp;
  482. }
  483. }
  484. echo '</table></div>';
  485. echo '<div class="clear"></div>';
  486. // links tracking
  487. echo '<div class="report_section">
  488. <h4>'.Display::return_icon('link.gif',get_lang('LinksMostClicked')).'&nbsp;'.get_lang('LinksMostClicked').'</h4>
  489. <table class="data_table">';
  490. $sql = "SELECT cl.title, cl.url,count(DISTINCT sl.links_user_id), count(cl.title) as count_visits
  491. FROM $TABLETRACK_LINKS AS sl, $TABLECOURSE_LINKS AS cl
  492. WHERE sl.links_link_id = cl.id
  493. AND sl.links_cours_id = '$_cid'
  494. GROUP BY cl.title, cl.url
  495. ORDER BY count_visits DESC
  496. LIMIT 0, 3";
  497. $rs = Database::query($sql, __FILE__, __LINE__);
  498. if ($export_csv) {
  499. $temp = array(get_lang('LinksMostClicked'),'');
  500. $csv_content[] = array('','');
  501. $csv_content[] = $temp;
  502. }
  503. if (Database::num_rows($rs) > 0) {
  504. while ($row = Database::fetch_array($rs)) {
  505. echo ' <tr>
  506. <td>'.$row['title'].'</td>
  507. <td align="right">'.$row['count_visits'].' '.get_lang('Clicks').'</td>
  508. </tr>';
  509. if ($export_csv){
  510. $temp = array($row['title'],$row['count_visits'].' '.get_lang('Clicks', ''));
  511. $csv_content[] = $temp;
  512. }
  513. }
  514. } else {
  515. echo '<tr><td>'.get_lang('NoLinkVisited').'</td></tr>';
  516. if ($export_csv) {
  517. $temp = array(get_lang('NoLinkVisited'), '');
  518. $csv_content[] = $temp;
  519. }
  520. }
  521. echo '</table></div>';
  522. echo '<div class="clear"></div>';
  523. // send the csv file if asked
  524. if ($export_csv) {
  525. ob_end_clean();
  526. Export :: export_table_csv($csv_content, 'reporting_course_tracking');
  527. }
  528. } elseif ($_GET['studentlist'] == 'true' or $_GET['studentlist'] == '') {
  529. // else display student list with all the informations
  530. // BEGIN : form to remind inactives susers
  531. $form = new FormValidator('reminder_form', 'get', api_get_path(REL_CODE_PATH).'announcements/announcements.php');
  532. $renderer = $form->defaultRenderer();
  533. $renderer->setElementTemplate('<span>{label} {element}</span>&nbsp;<button class="save" type="submit">'.get_lang('SendNotification').'</button>','since');
  534. $options = array (
  535. 2 => '2 '.get_lang('Days'),
  536. 3 => '3 '.get_lang('Days'),
  537. 4 => '4 '.get_lang('Days'),
  538. 5 => '5 '.get_lang('Days'),
  539. 6 => '6 '.get_lang('Days'),
  540. 7 => '7 '.get_lang('Days'),
  541. 15 => '15 '.get_lang('Days'),
  542. 30 => '30 '.get_lang('Days'),
  543. 'never' => get_lang('Never')
  544. );
  545. $el = $form -> addElement('select', 'since', '<img width="22" align="middle" src="'.api_get_path(WEB_IMG_PATH).'messagebox_warning.gif" border="0" />'.get_lang('RemindInactivesLearnersSince'), $options);
  546. $el -> setSelected(7);
  547. $form -> addElement('hidden', 'action', 'add');
  548. $form -> addElement('hidden', 'remindallinactives', 'true');
  549. $form -> display();
  550. // END : form to remind inactives susers
  551. if ($export_csv) {
  552. $is_western_name_order = api_is_western_name_order(PERSON_NAME_DATA_EXPORT);
  553. } else {
  554. $is_western_name_order = api_is_western_name_order();
  555. }
  556. $sort_by_first_name = api_sort_by_first_name();
  557. $tracking_column = isset($_GET['tracking_column']) ? $_GET['tracking_column'] : 0;
  558. $tracking_direction = isset($_GET['tracking_direction']) ? $_GET['tracking_direction'] : 'DESC';
  559. if (count($a_students) > 0) {
  560. $table = new SortableTable('tracking', 'count_student_in_course', null, ($is_western_name_order xor $sort_by_first_name) ? 2 : 1);
  561. $table -> set_header(0, get_lang('OfficialCode'), false, 'align="center"');
  562. if ($is_western_name_order) {
  563. $table -> set_header(1, get_lang('FirstName'), false, 'align="center"');
  564. $table -> set_header(2, get_lang('LastName'), true, 'align="center"');
  565. } else {
  566. $table -> set_header(1, get_lang('LastName'), true, 'align="center"');
  567. $table -> set_header(2, get_lang('FirstName'), false, 'align="center"');
  568. }
  569. $table -> set_header(3, get_lang('TrainingTime'),false);
  570. $table -> set_header(4, get_lang('CourseProgress'),false);
  571. $table -> set_header(5, get_lang('Score'),false);
  572. $table -> set_header(6, get_lang('Student_publication'),false);
  573. $table -> set_header(7, get_lang('Messages'),false);
  574. $table -> set_header(8, get_lang('FirstLogin'), false, 'align="center"');
  575. $table -> set_header(9, get_lang('LatestLogin'), false, 'align="center"');
  576. if (isset($_GET['additional_profile_field']) AND is_numeric($_GET['additional_profile_field'])) {
  577. $table -> set_header(10, get_lang('AdditionalProfileField'),false);
  578. $table -> set_header(11, get_lang('Details'),false);
  579. } else {
  580. $table -> set_header(10, get_lang('Details'),false);
  581. }
  582. if ($export_csv) {
  583. $csv_content[] = array ();
  584. }
  585. $all_datas = array();
  586. $course_code = $_course['id'];
  587. foreach ($a_students as $student_id => $student) {
  588. $student_datas = UserManager :: get_user_info_by_id($student_id);
  589. $avg_time_spent = $avg_student_score = $avg_student_progress = $total_assignments = $total_messages = 0;
  590. $nb_courses_student = 0;
  591. $avg_time_spent = Tracking :: get_time_spent_on_the_course($student_id, $course_code);
  592. $avg_student_score = Tracking :: get_average_test_scorm_and_lp($student_id, $course_code);
  593. $avg_student_progress = Tracking :: get_avg_student_progress($student_id, $course_code);
  594. $total_assignments = Tracking :: count_student_assignments($student_id, $course_code);
  595. $total_messages = Tracking :: count_student_messages($student_id, $course_code);
  596. $row = array();
  597. $row[] = $student_datas['official_code'];
  598. if ($is_western_name_order) {
  599. $row[] = $student_datas['firstname'];
  600. $row[] = $student_datas['lastname'];
  601. } else {
  602. $row[] = $student_datas['lastname'];
  603. $row[] = $student_datas['firstname'];
  604. }
  605. $row[] = api_time_to_hms($avg_time_spent);
  606. if (is_null($avg_student_score)) {$avg_student_score=0;}
  607. if (is_null($avg_student_progress)) {$avg_student_progress=0;}
  608. $row[] = $avg_student_progress.'%';
  609. $row[] = $avg_student_score.'%';
  610. $row[] = $total_assignments;
  611. $row[] = $total_messages;
  612. $row[] = Tracking :: get_first_connection_date_on_the_course($student_id, $course_code);
  613. $row[] = Tracking :: get_last_connection_date_on_the_course($student_id, $course_code);
  614. // we need to display an additional profile field
  615. if (isset($_GET['additional_profile_field']) AND is_numeric($_GET['additional_profile_field'])) {
  616. if (is_array($additional_user_profile_info[$student_id])) {
  617. $row[]=implode(', ', $additional_user_profile_info[$student_id]);
  618. } else {
  619. $row[]='&nbsp;';
  620. }
  621. }
  622. $row[] = '<center><a href="../mySpace/myStudents.php?student='.$student_id.'&details=true&course='.$course_code.'&origin=tracking_course"><img src="'.api_get_path(WEB_IMG_PATH).'2rightarrow.gif" border="0" /></a></center>';
  623. if ($export_csv) {
  624. $row[8] = strip_tags($row[8]);
  625. $row[9] = strip_tags($row[9]);
  626. unset($row[10]);
  627. $csv_content[] = $row;
  628. }
  629. $all_datas[] = $row;
  630. }
  631. $clean_order = array('ASC','DESC');
  632. if(in_array($_GET['tracking_direction'],$clean_order) && $_GET['tracking_direction'] == 'ASC'){
  633. usort($all_datas, 'sort_users');
  634. } else if (in_array($_GET['tracking_direction'],$clean_order) && $_GET['tracking_direction'] == 'DESC') {
  635. usort($all_datas, 'sort_users_desc');
  636. }
  637. $page = $table->get_pager()->getCurrentPageID();
  638. $all_datas = array_slice($all_datas, ($page-1)*$table -> per_page, $table -> per_page);
  639. // if ($export_csv) { usort($csv_content, 'sort_users'); }
  640. foreach ($all_datas as $row) {
  641. $table -> addRow($row,'align="right"');
  642. }
  643. $table -> setColAttributes(0, array('align' => 'left'));
  644. $table -> setColAttributes(1, array('align' => 'left'));
  645. $table -> setColAttributes(2, array('align' => 'left'));
  646. $table -> setColAttributes(7, array('align' => 'right'));
  647. $table -> setColAttributes(8, array('align' => 'center'));
  648. $table -> setColAttributes(9, array('align' => 'center'));
  649. $table -> display();
  650. } else {
  651. echo get_lang('NoUsersInCourseTracking');
  652. }
  653. // send the csv file if asked
  654. if ($export_csv) {
  655. if ($is_western_name_order) {
  656. $csv_headers = array (
  657. get_lang('OfficialCode', ''),
  658. get_lang('FirstName', ''),
  659. get_lang('LastName', ''),
  660. get_lang('TrainingTime', ''),
  661. get_lang('CourseProgress', ''),
  662. get_lang('Score', ''),
  663. get_lang('Student_publication', ''),
  664. get_lang('Messages', ''),
  665. get_lang('FirstLogin', ''),
  666. get_lang('LatestLogin', '')
  667. );
  668. } else {
  669. $csv_headers = array (
  670. get_lang('OfficialCode', ''),
  671. get_lang('LastName', ''),
  672. get_lang('FirstName', ''),
  673. get_lang('TrainingTime', ''),
  674. get_lang('CourseProgress', ''),
  675. get_lang('Score', ''),
  676. get_lang('Student_publication', ''),
  677. get_lang('Messages', ''),
  678. get_lang('FirstLogin', ''),
  679. get_lang('LatestLogin', '')
  680. );
  681. }
  682. if (isset($_GET['additional_profile_field']) AND is_numeric($_GET['additional_profile_field'])) {
  683. $csv_headers[]=get_lang('AdditionalProfileField');
  684. }
  685. ob_end_clean();
  686. array_unshift($csv_content, $csv_headers); // adding headers before the content
  687. Export :: export_table_csv($csv_content, 'reporting_student_list');
  688. }
  689. } elseif($_GET['studentlist'] == 'resources') {
  690. // Create a search-box
  691. $form = new FormValidator('search_simple','get',api_get_path(WEB_CODE_PATH).'tracking/courseLog.php?'.api_get_cidreq().'&studentlist=resources','','width=200px',false);
  692. $renderer =& $form->defaultRenderer();
  693. $renderer->setElementTemplate('<span>{element}</span>');
  694. $form->addElement('hidden','studentlist','resources');
  695. $form->addElement('text','keyword',get_lang('keyword'));
  696. $form->addElement('style_submit_button', 'submit', get_lang('Search'),'class="search"');
  697. echo '<div class="actions">';
  698. $form->display();
  699. echo '</div>';
  700. $table = new SortableTable('resources', 'count_item_resources', 'get_item_resources_data', 5, 20, 'DESC');
  701. $parameters = array();
  702. if (isset($_GET['keyword'])) {
  703. $parameters['keyword'] = Security::remove_XSS($_GET['keyword']);
  704. }
  705. $parameters['studentlist'] = 'resources';
  706. $table->set_additional_parameters($parameters);
  707. $table->set_header(0, get_lang('Tool'));
  708. $table->set_header(1, get_lang('EventType'));
  709. $table->set_header(2, get_lang('Session'), false);
  710. $table->set_header(3, get_lang('UserName'));
  711. $table->set_header(4, get_lang('Document'), false);
  712. $table->set_header(5, get_lang('Date'));
  713. $table->display();
  714. }
  715. ?>
  716. </table>
  717. <?php
  718. Display::display_footer();
  719. /**
  720. * Display all the additionally defined user profile fields
  721. * This function will only display the fields, not the values of the field because it does not act as a filter
  722. * but it adds an additional column instead.
  723. *
  724. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, Belgium
  725. * @since October 2009
  726. * @version 1.8.7
  727. */
  728. function display_additional_profile_fields() {
  729. // getting all the extra profile fields that are defined by the platform administrator
  730. $extra_fields = UserManager :: get_extra_fields(0,50,5,'ASC');
  731. // creating the form
  732. $return = '<form action="courseLog.php" method="get" name="additional_profile_field_form" id="additional_profile_field_form">';
  733. // the select field with the additional user profile fields (= this is where we select the field of which we want to see
  734. // the information the users have entered or selected.
  735. $return .= '<select name="additional_profile_field">';
  736. $return .= '<option value="-">'.get_lang('SelectFieldToAdd').'</option>';
  737. foreach ($extra_fields as $key=>$field) {
  738. // show only extra fields that are visible, added by J.Montoya
  739. if ($field[6]==1) {
  740. if ($field[0] == $_GET['additional_profile_field'] ) {
  741. $selected = 'selected="selected"';
  742. } else {
  743. $selected = '';
  744. }
  745. $return .= '<option value="'.$field[0].'" '.$selected.'>'.$field[3].'</option>';
  746. }
  747. }
  748. $return .= '</select>';
  749. // the form elements for the $_GET parameters (because the form is passed through GET
  750. foreach ($_GET as $key=>$value){
  751. if ($key <> 'additional_profile_field') {
  752. $return .= '<input type="hidden" name="'.$key.'" value="'.Security::Remove_XSS($value).'" />';
  753. }
  754. }
  755. // the submit button
  756. $return .= '<button class="save" type="submit">'.get_lang('AddAdditionalProfileField').'</button>';
  757. $return .= '</form>';
  758. return $return;
  759. }
  760. /**
  761. * This function gets all the information of a certrain ($field_id) additional profile field.
  762. * 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
  763. *
  764. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, Belgium
  765. * @since October 2009
  766. * @version 1.8.7
  767. */
  768. function get_addtional_profile_information_of_field($field_id){
  769. // Database table definition
  770. $table_user = Database::get_main_table(TABLE_MAIN_USER);
  771. $table_user_field_values = Database::get_main_table(TABLE_MAIN_USER_FIELD_VALUES);
  772. $sql = "SELECT user.user_id, field.field_value FROM $table_user user, $table_user_field_values field
  773. WHERE user.user_id = field.user_id
  774. AND field.field_id='".intval($field_id)."'";
  775. $result = api_sql_query($sql,__FILE__,__LINE__);
  776. while($row = Database::fetch_array($result))
  777. {
  778. $return[$row['user_id']][] = $row['field_value'];
  779. }
  780. return $return;
  781. }
  782. /**
  783. * This function gets all the information of a certrain ($field_id) additional profile field for a specific list of users is more efficent than get_addtional_profile_information_of_field() function
  784. * 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
  785. *
  786. * @author Julio Montoya <gugli100@gmail.com>
  787. * @param int field id
  788. * @param array list of user ids
  789. * @return array
  790. * @since Nov 2009
  791. * @version 1.8.6.2
  792. */
  793. function get_addtional_profile_information_of_field_by_user($field_id, $users){
  794. // Database table definition
  795. $table_user = Database::get_main_table(TABLE_MAIN_USER);
  796. $table_user_field_values = Database::get_main_table(TABLE_MAIN_USER_FIELD_VALUES);
  797. $result_extra_field = UserManager::get_extra_field_information($field_id);
  798. if (!empty($users)) {
  799. if ($result_extra_field['field_type'] == USER_FIELD_TYPE_TAG ) {
  800. foreach($users as $user_id) {
  801. $user_result = UserManager::get_user_tags($user_id, $field_id);
  802. $tag_list = array();
  803. foreach($user_result as $item) {
  804. $tag_list[] = $item['tag'];
  805. }
  806. $return[$user_id][] = implode(', ',$tag_list);
  807. }
  808. } else {
  809. $new_user_array = array();
  810. foreach($users as $user_id) {
  811. $new_user_array[]= "'".$user_id."'";
  812. }
  813. $users = implode(',',$new_user_array);
  814. //selecting only the necessary information NOT ALL the user list
  815. $sql = "SELECT user.user_id, field.field_value FROM $table_user user INNER JOIN $table_user_field_values field
  816. ON (user.user_id = field.user_id)
  817. WHERE field.field_id=".intval($field_id)." AND user.user_id IN ($users)";
  818. $result = api_sql_query($sql,__FILE__,__LINE__);
  819. while($row = Database::fetch_array($result)) {
  820. // get option value for field type double select by id
  821. if (!empty($row['field_value'])) {
  822. if ($result_extra_field['field_type'] == USER_FIELD_TYPE_DOUBLE_SELECT) {
  823. $id_double_select = explode(';',$row['field_value']);
  824. if (is_array($id_double_select)) {
  825. $value1 = $result_extra_field['options'][$id_double_select[0]]['option_value'];
  826. $value2 = $result_extra_field['options'][$id_double_select[1]]['option_value'];
  827. $row['field_value'] = ($value1.';'.$value2);
  828. }
  829. }
  830. }
  831. // get other value from extra field
  832. $return[$row['user_id']][] = $row['field_value'];
  833. }
  834. }
  835. }
  836. return $return;
  837. }
  838. /**
  839. * count the number of students in this course (used for SortableTable)
  840. */
  841. function count_student_in_course() {
  842. global $nbStudents;
  843. return $nbStudents;
  844. }
  845. function sort_users($a, $b) {
  846. return strcmp(trim(api_strtolower($a[$_SESSION['tracking_column']])), trim(api_strtolower($b[$_SESSION['tracking_column']])));
  847. }
  848. function sort_users_desc($a, $b) {
  849. return strcmp( trim(api_strtolower($b[$_SESSION['tracking_column']])), trim(api_strtolower($a[$_SESSION['tracking_column']])));
  850. }