Actualización

This commit is contained in:
Xes
2025-04-10 12:49:05 +02:00
parent 4aff98e77b
commit 1cdd00920f
9151 changed files with 1800913 additions and 0 deletions

1120
main/tracking/courseLog.php Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,155 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/../inc/global.inc.php';
$this_section = SECTION_COURSES;
$course_id = api_get_course_int_id();
$course_code = api_get_course_id();
$sessionId = api_get_session_id();
// Access restrictions.
$is_allowedToTrack = Tracking::isAllowToTrack($sessionId);
if (!$is_allowedToTrack) {
api_not_allowed(true);
}
// Starting the output buffering when we are exporting the information.
$export_csv = isset($_GET['export']) && 'csv' == $_GET['export'] ? true : false;
$exportXls = isset($_GET['export']) && 'xls' == $_GET['export'] ? true : false;
$keyword = isset($_GET['keyword']) ? Security::remove_XSS($_GET['keyword']) : '';
// jqgrid will use this URL to do the selects
$url = api_get_path(WEB_AJAX_PATH).'model.ajax.php?a=course_log_events&'.api_get_cidreq().'&keyword='.$keyword;
// The order is important you need to check the the $column variable in the model.ajax.php file
$columns = [
get_lang('EventType'),
get_lang('DataType'),
get_lang('Value'),
get_lang('Course'),
get_lang('Session'),
get_lang('UserName'),
get_lang('IPAddress'),
get_lang('Date'),
];
// Column config
$column_model = [
[
'name' => 'col0',
'index' => 'col0',
'width' => '70',
'align' => 'left',
'sortable' => 'false',
],
[
'name' => 'col1',
'index' => 'col1',
'width' => '50',
'align' => 'left',
'sortable' => 'false',
],
[
'name' => 'col2',
'index' => 'col2',
'width' => '200',
'align' => 'left',
'sortable' => 'false',
],
[
'name' => 'col3',
'index' => 'col3',
'width' => '50',
'align' => 'left',
'sortable' => 'false',
'hidden' => 'true',
],
[
'name' => 'col4',
'index' => 'col4',
'width' => '50',
'align' => 'left',
'sortable' => 'false',
'hidden' => 'true',
],
[
'name' => 'col5',
'index' => 'col5',
'width' => '50',
'align' => 'left',
'sortable' => 'false',
],
[
'name' => 'col6',
'index' => '6',
'width' => '50',
'align' => 'left',
'sortable' => 'false',
],
[
'name' => 'col7',
'index' => '7',
'width' => '50',
'align' => 'left',
],
];
// Autowidth
$extra_params['autowidth'] = 'true';
// height auto
$extra_params['height'] = 'auto';
// Order by date
$extra_params['sortorder'] = 'desc';
$extra_params['sortname'] = 'col7';
$actionLinks = '';
// Add the JS needed to use the jqgrid
$htmlHeadXtra[] = api_get_jqgrid_js();
$htmlHeadXtra[] = '
<script>
$(function() {
'.Display::grid_js(
'course_log_events',
$url,
$columns,
$column_model,
$extra_params,
[],
$actionLinks,
true
).'
});
</script>';
Display::display_header();
echo '<div class="actions">';
echo TrackingCourseLog::actionsLeft('logs', api_get_session_id());
echo '</div>';
$form = new FormValidator(
'search_simple',
'get',
api_get_self().'?'.api_get_cidreq(),
'',
[],
FormValidator::LAYOUT_INLINE
);
$renderer = $form->defaultRenderer();
$renderer->setCustomElementTemplate('<span>{element}</span>');
$form->addHidden('report', 'activities');
$form->addHidden('activities_direction', 'DESC');
$form->addElement('text', 'keyword', get_lang('Keyword'));
$form->addButtonSearch(get_lang('Search'), 'submit');
echo '<div class="actions">';
$form->display();
echo '</div>';
echo Display::grid_html('course_log_events');
Display::display_footer();

View File

@@ -0,0 +1,131 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/../inc/global.inc.php';
$from_myspace = false;
$from = isset($_GET['from']) ? $_GET['from'] : null;
$course_id = api_get_course_int_id();
$course_code = api_get_course_id();
$sessionId = api_get_session_id();
$this_section = SECTION_COURSES;
if ('myspace' == $from) {
$from_myspace = true;
$this_section = "session_my_space";
}
// Access restrictions.
$is_allowedToTrack = Tracking::isAllowToTrack($sessionId);
if (!$is_allowedToTrack) {
api_not_allowed(true);
exit;
}
// jqgrid will use this URL to do the selects
$url = api_get_path(WEB_AJAX_PATH).'model.ajax.php?a=get_group_reporting&course_id='.$course_id.'&session_id='.$sessionId;
// The order is important you need to check the the $column variable in the model.ajax.php file
$columns = [
get_lang('Name'),
get_lang('Time'),
get_lang('Progress'),
get_lang('Score'),
get_lang('Works'),
get_lang('Messages'),
get_lang('Actions'),
];
// Column config
$column_model = [
[
'name' => 'name',
'index' => 'name',
'width' => '200',
'align' => 'left',
],
[
'name' => 'time',
'index' => 'time',
'width' => '50',
'align' => 'left',
'sortable' => 'false',
],
[
'name' => 'progress',
'index' => 'progress',
'width' => '50',
'align' => 'left',
'sortable' => 'false',
],
[
'name' => 'score',
'index' => 'score',
'width' => '50',
'align' => 'left',
'sortable' => 'false',
],
[
'name' => 'works',
'index' => 'works',
'width' => '50',
'align' => 'left',
'sortable' => 'false',
],
[
'name' => 'messages',
'index' => 'messages',
'width' => '50',
'align' => 'left',
'sortable' => 'false',
],
[
'name' => 'actions',
'index' => 'actions',
'width' => '50',
'align' => 'left',
'formatter' => 'action_formatter',
'sortable' => 'false',
],
];
// Autowidth
$extra_params['autowidth'] = 'true';
// height auto
$extra_params['height'] = 'auto';
$action_links = '
function action_formatter(cellvalue, options, rowObject) {
return \'<a href="course_log_tools.php?id_session=0&cidReq='.$course_code.'&gidReq=\'+options.rowId+\'">'.Display::return_icon('2rightarrow.png', get_lang('Edit'), '', ICON_SIZE_SMALL).'</a>'.
'\';
}';
// Add the JS needed to use the jqgrid
$htmlHeadXtra[] = api_get_jqgrid_js();
$htmlHeadXtra[] = '
<script>
$(function() {
'.Display::grid_js(
'group_users',
$url,
$columns,
$column_model,
$extra_params,
[],
$action_links,
true
).'
});
</script>';
Display::display_header();
echo '<div class="actions">';
echo TrackingCourseLog::actionsLeft('groups', $sessionId);
echo '</div>';
echo Display::grid_html('group_users');
Display::display_footer();

View File

@@ -0,0 +1,162 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/../inc/global.inc.php';
$current_course_tool = TOOL_TRACKING;
$from_myspace = false;
$from = isset($_GET['from']) ? $_GET['from'] : null;
// Starting the output buffering when we are exporting the information.
$export_csv = isset($_GET['export']) && $_GET['export'] == 'csv' ? true : false;
$exportXls = isset($_GET['export']) && $_GET['export'] == 'xls' ? true : false;
$session_id = intval($_REQUEST['id_session']);
$this_section = SECTION_COURSES;
if ('myspace' === $from) {
$from_myspace = true;
$this_section = 'session_my_space';
}
// Access restrictions.
$is_allowedToTrack = Tracking::isAllowToTrack($session_id);
if (!$is_allowedToTrack) {
api_not_allowed(true);
}
if ($export_csv || $exportXls) {
$csvData = TrackingCourseLog::getItemResourcesData(0, 0, '', '');
array_walk(
$csvData,
function (&$item) {
$item[0] = strip_tags($item[0]);
$item[2] = strip_tags(preg_replace('/\<br(\s*)?\/?\>/i', PHP_EOL, $item[2]));
$item[3] = strip_tags($item[3]);
$item[4] = strip_tags($item[4]);
unset(
$item['col0'],
$item['col1'],
$item['ref'],
$item['col3'],
$item['col6'],
$item['user_id'],
$item['col7']
);
}
);
array_unshift(
$csvData,
[
get_lang('Tool'),
get_lang('EventType'),
get_lang('Session'),
get_lang('UserName'),
get_lang('IPAddress'),
get_lang('Document'),
get_lang('Date'),
]
);
if ($export_csv) {
Export::arrayToCsv($csvData);
}
if ($exportXls) {
Export::arrayToXls($csvData);
}
exit;
}
if (empty($session_id)) {
$session_id = api_get_session_id();
}
// Breadcrumbs.
if (isset($_GET['origin']) && $_GET['origin'] == 'resume_session') {
$interbreadcrumb[] = [
'url' => api_get_path(WEB_CODE_PATH).'admin/index.php',
'name' => get_lang('PlatformAdmin'),
];
$interbreadcrumb[] = [
'url' => api_get_path(WEB_CODE_PATH).'session/session_list.php',
'name' => get_lang('SessionList'),
];
$interbreadcrumb[] = [
'url' => api_get_path(WEB_CODE_PATH).'session/resume_session.php?id_session='.api_get_session_id(),
'name' => get_lang('SessionOverview'),
];
}
$nameTools = get_lang('Tracking');
Display::display_header($nameTools, 'Tracking');
echo '<div class="actions">';
echo TrackingCourseLog::actionsLeft('resources', api_get_session_id());
echo '<span style="float:right; padding-top:0px;">';
echo '<a href="javascript: void(0);" onclick="javascript: window.print();">'.
Display::return_icon('printer.png', get_lang('Print'), '', ICON_SIZE_MEDIUM).
'</a>';
$addional_param = '';
if (isset($_GET['additional_profile_field'])) {
$addional_param = 'additional_profile_field='.intval($_GET['additional_profile_field']);
}
$users_tracking_per_page = '';
if (isset($_GET['users_tracking_per_page'])) {
$users_tracking_per_page = '&users_tracking_per_page='.intval($_GET['users_tracking_per_page']);
}
echo '<a href="'.api_get_self().'?'.api_get_cidreq().'&export=csv&'.$addional_param.$users_tracking_per_page.'">
'.Display::return_icon('export_csv.png', get_lang('ExportAsCSV'), '', ICON_SIZE_MEDIUM).'</a>';
echo '<a href="'.api_get_self().'?'.api_get_cidreq().'&export=xls&'.$addional_param.$users_tracking_per_page.'">
'.Display::return_icon('export_excel.png', get_lang('ExportAsXLS'), '', ICON_SIZE_MEDIUM).'</a>';
echo '</span>';
echo '</div>';
// Create a search-box.
$form = new FormValidator(
'search_simple',
'GET',
api_get_path(WEB_CODE_PATH).'tracking/course_log_resources.php?'.api_get_cidreq().'&id_session'.$session_id,
'',
['class' => 'form-search'],
false
);
$renderer = $form->defaultRenderer();
$renderer->setCustomElementTemplate('<span>{element}</span>');
$form->addElement('text', 'keyword', get_lang('Keyword'));
$form->addElement('hidden', 'cidReq', api_get_course_id());
$form->addElement('hidden', 'id_session', $session_id);
$form->addButtonSearch(get_lang('SearchUsers'), 'submit');
echo '<div class="actions">';
$form->display();
echo '</div>';
$table = new SortableTable(
'resources',
['TrackingCourseLog', 'countItemResources'],
['TrackingCourseLog', 'getItemResourcesData'],
6,
20,
'DESC'
);
$parameters = [
'id_session' => $session_id,
'cidReq' => api_get_course_id(),
];
$table->set_additional_parameters($parameters);
$table->set_header(0, get_lang('Tool'));
$table->set_header(1, get_lang('EventType'));
$table->set_header(2, get_lang('Session'), false);
$table->set_header(3, get_lang('UserName'), true, 'width=65px');
$table->set_header(4, get_lang('IPAddress'), true, 'width=100px');
$table->set_header(5, get_lang('Document'), false);
$table->set_header(6, get_lang('Date'), true, 'width=190px');
$table->display();
Display::display_footer();

View File

@@ -0,0 +1,471 @@
<?php
/* For licensing terms, see /license.txt */
use ChamiloSession as Session;
require_once __DIR__.'/../inc/global.inc.php';
$current_course_tool = TOOL_TRACKING;
$course_info = api_get_course_info();
$groupId = api_get_group_id();
$session_id = api_get_session_id();
$course_code = api_get_course_id();
$course_id = api_get_course_int_id();
$from_myspace = false;
$from = isset($_GET['from']) ? $_GET['from'] : null;
$this_section = SECTION_COURSES;
if ('myspace' === $from) {
$from_myspace = true;
$this_section = 'session_my_space';
}
// Access restrictions.
$is_allowedToTrack = Tracking::isAllowToTrack($session_id);
if (!$is_allowedToTrack) {
api_not_allowed(true);
exit;
}
$showChatReporting = true;
$showTrackingReporting = true;
$documentReporting = true;
$linkReporting = true;
$exerciseReporting = true;
$lpReporting = true;
if (!empty($groupId)) {
$showChatReporting = false;
$showTrackingReporting = false;
$documentReporting = false;
$linkReporting = false;
$exerciseReporting = false;
$lpReporting = false;
}
$TABLEQUIZ = Database::get_course_table(TABLE_QUIZ_TEST);
// Starting the output buffering when we are exporting the information.
$export_csv = isset($_GET['export']) && $_GET['export'] === 'csv' ? true : false;
$session_id = intval($_REQUEST['id_session']);
if ($export_csv) {
if (!empty($session_id)) {
Session::write('id_session', $session_id);
}
ob_start();
}
$csv_content = [];
// Breadcrumbs.
if (isset($_GET['origin']) && $_GET['origin'] === 'resume_session') {
$interbreadcrumb[] = ['url' => '../admin/index.php', 'name' => get_lang('PlatformAdmin')];
$interbreadcrumb[] = ['url' => '../session/session_list.php', 'name' => get_lang('SessionList')];
$interbreadcrumb[] = [
'url' => '../session/resume_session.php?id_session='.api_get_session_id(),
'name' => get_lang('SessionOverview'),
];
}
$view = isset($_REQUEST['view']) ? $_REQUEST['view'] : '';
$nameTools = get_lang('Tracking');
Display::display_header($nameTools, 'Tracking');
// getting all the students of the course
if (empty($session_id)) {
// Registered students in a course outside session.
$students = CourseManager::get_student_list_from_course_code(
api_get_course_id(),
false,
0,
null,
null,
true,
api_get_group_id()
);
} else {
// Registered students in session.
$students = CourseManager::get_student_list_from_course_code(
api_get_course_id(),
true,
api_get_session_id()
);
}
$nbStudents = count($students);
$student_ids = array_keys($students);
$studentCount = count($student_ids);
echo '<div class="actions">';
echo TrackingCourseLog::actionsLeft('courses', api_get_session_id());
echo '<span style="float:right; padding-top:0px;">';
echo '<a href="javascript: void(0);" onclick="javascript: window.print();">'.
Display::return_icon('printer.png', get_lang('Print'), '', ICON_SIZE_MEDIUM).'</a>';
echo '<a href="'.api_get_self().'?'.api_get_cidreq().'&id_session='.api_get_session_id().'&export=csv">
'.Display::return_icon('export_csv.png', get_lang('ExportAsCSV'), '', ICON_SIZE_MEDIUM).'</a>';
echo '</span>';
echo '</div>';
if ($lpReporting) {
$list = new LearnpathList(null, $course_info, $session_id);
$flat_list = $list->get_flat_list();
if (count($flat_list) > 0) {
// learning path tracking
echo '<div class="report_section">';
echo Display::page_subheader(
Display::return_icon(
'scorms.gif',
get_lang('AverageProgressInLearnpath')
).' '.get_lang('AverageProgressInLearnpath')
);
echo '<table class="table table-hover table-striped data_table">';
if ($export_csv) {
$temp = [get_lang('AverageProgressInLearnpath', ''), ''];
$csv_content[] = ['', ''];
$csv_content[] = $temp;
}
foreach ($flat_list as $lp_id => $lp) {
$lp_avg_progress = 0;
foreach ($students as $student_id => $student) {
// get the progress in learning paths.
$lp_avg_progress += Tracking::get_avg_student_progress(
$student_id,
$course_code,
[$lp_id],
$session_id
);
}
if ($studentCount > 0) {
$lp_avg_progress = $lp_avg_progress / $studentCount;
}
// Separated presentation logic.
if (is_null($lp_avg_progress)) {
$lp_avg_progress = '0%';
} else {
$lp_avg_progress = round($lp_avg_progress, 1).'%';
}
echo '<tr><td>'.$lp['lp_name'].'</td><td align="right">'.$lp_avg_progress.'</td></tr>';
if ($export_csv) {
$temp = [$lp['lp_name'], $lp_avg_progress];
$csv_content[] = $temp;
}
}
echo '</table></div>';
} else {
if ($export_csv) {
$temp = [get_lang('NoLearningPath', ''), ''];
$csv_content[] = $temp;
}
}
}
if ($exerciseReporting) {
// Exercises tracking.
echo '<div class="report_section">';
echo Display::page_subheader(
Display::return_icon(
'quiz.png',
get_lang('AverageResultsToTheExercices')
).' '.get_lang('AverageResultsToTheExercices')
);
echo '<table class="table table-hover table-striped data_table">';
$course_id = api_get_course_int_id();
$sql = "SELECT iid, title FROM $TABLEQUIZ
WHERE c_id = $course_id AND active <> -1 AND session_id = $session_id";
$rs = Database::query($sql);
if ($export_csv) {
$temp = [get_lang('AverageProgressInLearnpath'), ''];
$csv_content[] = ['', ''];
$csv_content[] = $temp;
}
$course_path_params = '&cidReq='.$course_code.'&id_session='.$session_id;
if (Database::num_rows($rs) > 0) {
while ($quiz = Database::fetch_array($rs)) {
$quiz_avg_score = 0;
if ($studentCount > 0) {
foreach ($student_ids as $student_id) {
$avg_student_score = Tracking::get_avg_student_exercise_score(
$student_id,
$course_code,
$quiz['iid'],
$session_id
);
$quiz_avg_score += $avg_student_score;
}
}
$studentCount = ($studentCount == 0 || is_null($studentCount) || $studentCount == '') ? 1 : $studentCount;
$quiz_avg_score = round(($quiz_avg_score / $studentCount), 2).'%';
$url = api_get_path(WEB_CODE_PATH).'exercise/overview.php?exerciseId='.$quiz['iid'].$course_path_params;
echo '<tr><td>';
echo Display::url(
$quiz['title'],
$url
);
echo '</td><td align="right">'.$quiz_avg_score.'</td></tr>';
if ($export_csv) {
$temp = [$quiz['title'], $quiz_avg_score];
$csv_content[] = $temp;
}
}
} else {
echo '<tr><td>'.get_lang('NoExercises').'</td></tr>';
if ($export_csv) {
$temp = [get_lang('NoExercises', ''), ''];
$csv_content[] = $temp;
}
}
echo '</table></div>';
echo '<div class="clear"></div>';
}
$filterByUsers = [];
if (!empty($groupId)) {
$filterByUsers = $student_ids;
}
$count_number_of_forums_by_course = Tracking::count_number_of_forums_by_course(
$course_code,
$session_id,
$groupId
);
$count_number_of_threads_by_course = Tracking::count_number_of_threads_by_course(
$course_code,
$session_id,
$groupId
);
$count_number_of_posts_by_course = Tracking::count_number_of_posts_by_course(
$course_code,
$session_id,
$groupId
);
if ($export_csv) {
$csv_content[] = [get_lang('Forum')];
$csv_content[] = [get_lang('ForumForumsNumber'), $count_number_of_forums_by_course];
$csv_content[] = [get_lang('ForumThreadsNumber'), $count_number_of_threads_by_course];
$csv_content[] = [get_lang('ForumPostsNumber'), $count_number_of_posts_by_course];
}
// Forums tracking.
echo '<div class="report_section">';
echo Display::page_subheader(
Display::return_icon('forum.gif', get_lang('Forum')).' '.
get_lang('Forum').'&nbsp;-&nbsp;<a href="../forum/index.php?'.api_get_cidreq().'">'.
get_lang('SeeDetail').'</a>'
);
echo '<table class="table table-hover table-striped data_table">';
echo '<tr><td>'.get_lang('ForumForumsNumber').'</td><td align="right">'.$count_number_of_forums_by_course.'</td></tr>';
echo '<tr><td>'.get_lang('ForumThreadsNumber').'</td><td align="right">'.$count_number_of_threads_by_course.'</td></tr>';
echo '<tr><td>'.get_lang('ForumPostsNumber').'</td><td align="right">'.$count_number_of_posts_by_course.'</td></tr>';
echo '</table></div>';
echo '<div class="clear"></div>';
// Chat tracking.
if ($showChatReporting) {
echo '<div class="report_section">';
echo Display::page_subheader(
Display::return_icon('chat.gif', get_lang('Chat')).' '.get_lang('Chat')
);
echo '<table class="table table-hover table-striped data_table">';
$chat_connections_during_last_x_days_by_course = Tracking::chat_connections_during_last_x_days_by_course(
$course_code,
7,
$session_id
);
if ($export_csv) {
$csv_content[] = [get_lang('Chat', ''), ''];
$csv_content[] = [
sprintf(
get_lang('ChatConnectionsDuringLastXDays', ''),
'7'
),
$chat_connections_during_last_x_days_by_course,
];
}
echo '<tr><td>';
echo sprintf(
get_lang('ChatConnectionsDuringLastXDays'),
'7'
);
echo '</td><td align="right">'.$chat_connections_during_last_x_days_by_course.'</td></tr>';
echo '</table></div>';
echo '<div class="clear"></div>';
}
// Tools tracking.
if ($showTrackingReporting) {
echo '<div class="report_section">';
echo Display::page_subheader(
Display::return_icon(
'acces_tool.gif',
get_lang('ToolsMostUsed')
).' '.get_lang('ToolsMostUsed')
);
echo '<table class="table table-hover table-striped data_table">';
$tools_most_used = Tracking::get_tools_most_used_by_course(
$course_id,
$session_id
);
if ($export_csv) {
$temp = [get_lang('ToolsMostUsed'), ''];
$csv_content[] = $temp;
}
if (!empty($tools_most_used)) {
foreach ($tools_most_used as $row) {
echo '<tr>
<td>'.get_lang(ucfirst($row['access_tool'])).'</td>
<td align="right">'.$row['count_access_tool'].' '.get_lang('Clicks').'</td>
</tr>';
if ($export_csv) {
$temp = [
get_lang(ucfirst($row['access_tool']), ''),
$row['count_access_tool'].' '.get_lang('Clicks', ''),
];
$csv_content[] = $temp;
}
}
}
echo '</table></div>';
echo '<div class="clear"></div>';
}
if ($documentReporting) {
// Documents tracking.
if (!isset($_GET['num']) || empty($_GET['num'])) {
$num = 3;
$link = '&nbsp;-&nbsp;<a href="'.api_get_self().'?'.api_get_cidreq().'&num=1#documents_tracking">'.get_lang('SeeDetail').'</a>';
} else {
$num = 1000;
$link = '&nbsp;-&nbsp;<a href="'.api_get_self().'?'.api_get_cidreq().'&num=0#documents_tracking">'.get_lang('ViewMinus').'</a>';
}
echo '<a name="documents_tracking" id="a"></a><div class="report_section">';
echo Display::page_subheader(
Display::return_icon(
'documents.gif',
get_lang('DocumentsMostDownloaded')
).'&nbsp;'.get_lang('DocumentsMostDownloaded').$link
);
echo '<table class="table table-hover table-striped data_table">';
$documents_most_downloaded = Tracking::get_documents_most_downloaded_by_course(
$course_code,
$session_id,
$num
);
if ($export_csv) {
$temp = [get_lang('DocumentsMostDownloaded', ''), ''];
$csv_content[] = ['', ''];
$csv_content[] = $temp;
}
if (!empty($documents_most_downloaded)) {
foreach ($documents_most_downloaded as $row) {
echo '<tr>
<td>';
echo Display::url(
$row['down_doc_path'],
api_get_path(
WEB_CODE_PATH
).'document/show_content.php?file='.$row['down_doc_path'].$course_path_params
);
echo '</td>
<td align="right">'.$row['count_down'].' '.get_lang('Clicks').'</td>
</tr>';
if ($export_csv) {
$temp = [
$row['down_doc_path'],
$row['count_down'].' '.get_lang('Clicks', ''),
];
$csv_content[] = $temp;
}
}
} else {
echo '<tr><td>'.get_lang('NoDocumentDownloaded').'</td></tr>';
if ($export_csv) {
$temp = [get_lang('NoDocumentDownloaded', ''), ''];
$csv_content[] = $temp;
}
}
echo '</table></div>';
echo '<div class="clear"></div>';
}
if ($linkReporting) {
// links tracking
echo '<div class="report_section">';
echo Display::page_subheader(
Display::return_icon(
'link.gif',
get_lang('LinksMostClicked')
).'&nbsp;'.get_lang('LinksMostClicked')
);
echo '<table class="table table-hover table-striped data_table">';
$links_most_visited = Tracking::get_links_most_visited_by_course(
$course_code,
$session_id
);
if ($export_csv) {
$temp = [get_lang('LinksMostClicked'), ''];
$csv_content[] = ['', ''];
$csv_content[] = $temp;
}
if (!empty($links_most_visited)) {
foreach ($links_most_visited as $row) {
echo '<tr><td>';
echo Display::url(
$row['title'].' ('.$row['url'].')',
$row['url']
);
echo '</td><td align="right">'.$row['count_visits'].' '.get_lang('Clicks').'</td></tr>';
if ($export_csv) {
$temp = [
$row['title'],
$row['count_visits'].' '.get_lang('Clicks', ''),
];
$csv_content[] = $temp;
}
}
} else {
echo '<tr><td>'.get_lang('NoLinkVisited').'</td></tr>';
if ($export_csv) {
$temp = [get_lang('NoLinkVisited'), ''];
$csv_content[] = $temp;
}
}
echo '</table></div>';
echo '<div class="clear"></div>';
}
// send the csv file if asked
if ($export_csv) {
ob_end_clean();
Export::arrayToCsv($csv_content, 'reporting_course_tools');
exit;
}
Display::display_footer();

View File

@@ -0,0 +1,216 @@
<?php
/* For licensing terms, see /license.txt */
$cidReset = true;
require_once __DIR__.'/../inc/global.inc.php';
$session_id = isset($_GET['session_id']) ? intval($_GET['session_id']) : null;
$this_section = 'session_my_space';
$is_allowedToTrack = Tracking::isAllowToTrack($session_id);
if (!$is_allowedToTrack) {
api_not_allowed(true);
}
$export_to_xls = false;
if (isset($_GET['export'])) {
$export_to_xls = true;
}
if (api_is_platform_admin()) {
$global = true;
} else {
$global = false;
}
$global = true;
if (empty($session_id)) {
$session_id = 1;
}
$form = new FormValidator('search_simple', 'POST', '', '', null, false);
//Get session list
$session_list = SessionManager::get_sessions_list([], ['name']);
$my_session_list = [];
foreach ($session_list as $sesion_item) {
$my_session_list[$sesion_item['id']] = $sesion_item['name'];
}
if (count($session_list) == 0) {
$my_session_list[0] = get_lang('None');
}
$form->addElement('select', 'session_id', get_lang('Sessions'), $my_session_list);
$form->addButtonFilter(get_lang('Filter'));
if (!empty($_REQUEST['score'])) {
$filter_score = intval($_REQUEST['score']);
} else {
$filter_score = 70;
}
if (!empty($_REQUEST['session_id'])) {
$session_id = intval($_REQUEST['session_id']);
} else {
$session_id = 0;
}
if (empty($session_id)) {
$session_id = key($my_session_list);
}
$form->setDefaults(['session_id' => $session_id]);
$course_list = SessionManager::get_course_list_by_session_id($session_id);
if (!$export_to_xls) {
Display::display_header(get_lang("MySpace"));
echo '<div class="actions">';
if ($global) {
echo MySpace::getTopMenu();
} else {
echo '<div style="float:left; clear:left">
<a href="courseLog.php?'.api_get_cidreq().'&studentlist=true">'.get_lang('StudentsTracking').'</a>&nbsp;|
<a href="courseLog.php?'.api_get_cidreq().'&studentlist=false">'.get_lang('CourseTracking').'</a>&nbsp;';
echo '</div>';
}
echo '</div>';
if (api_is_platform_admin()) {
echo MySpace::getAdminActions();
}
echo '<h2>'.get_lang('LPExerciseResultsBySession').'</h2>';
$form->display();
echo Display::return_message(get_lang('StudentScoreAverageIsCalculatedBaseInAllLPsAndAllAttempts'));
}
$users = SessionManager::get_users_by_session($session_id);
$course_average = $course_average_counter = [];
$counter = 0;
$main_result = [];
// Getting course list
foreach ($course_list as $current_course) {
$course_info = api_get_course_info($current_course['code']);
$_course = $course_info;
$attempt_result = [];
// Getting LP list
$list = new LearnpathList('', $course_info, $session_id);
$lp_list = $list->get_flat_list();
// Looping LPs
foreach ($lp_list as $lp_id => $lp) {
$exercise_list = Event::get_all_exercises_from_lp($lp_id, $course_info['real_id']);
// Looping Chamilo Exercises in LP
foreach ($exercise_list as $exercise) {
$exercise_stats = Event::get_all_exercise_event_from_lp(
$exercise['path'],
$course_info['real_id'],
$session_id
);
// Looping Exercise Attempts
foreach ($exercise_stats as $stats) {
$attempt_result[$stats['exe_user_id']]['result'] += $stats['exe_result'] / $stats['exe_weighting'];
$attempt_result[$stats['exe_user_id']]['attempts']++;
}
}
}
$main_result[$current_course['code']] = $attempt_result;
}
$total_average_score = 0;
$total_average_score_count = 0;
$html_result = '';
if (!empty($users) && is_array($users)) {
$html_result .= '<table class="table table-hover table-striped data_table">';
$html_result .= '<tr><th>'.get_lang('User').'</th>';
foreach ($course_list as $item) {
$html_result .= '<th>'.$item['title'].'<br /> '.get_lang('AverageScore').' %</th>';
}
$html_result .= '<th>'.get_lang('AverageScore').' %</th>';
$html_result .= '<th>'.get_lang('LastConnexionDate').'</th></tr>';
foreach ($users as $user) {
$total_student = 0;
$counter++;
$s_css_class = 'row_even';
if ($counter % 2 == 0) {
$s_css_class = 'row_odd';
}
$html_result .= "<tr class='$s_css_class'>
<td >";
$html_result .= $user['firstname'].' '.$user['lastname'];
$html_result .= "</td>";
// Getting course list
$counter = 0;
$total_result_by_user = 0;
foreach ($course_list as $current_course) {
$total_course = 0;
$html_result .= "<td>";
$result = '-';
if (isset($main_result[$current_course['code']][$user['user_id']])) {
$user_info_stat = $main_result[$current_course['code']][$user['user_id']];
if (!empty($user_info_stat['result']) && !empty($user_info_stat['attempts'])) {
$result = round(
$user_info_stat['result'] / $user_info_stat['attempts'] * 100,
2
);
$total_course += $result;
$total_result_by_user += $result;
$course_average[$current_course['code']] += $total_course;
$course_average_counter[$current_course['code']]++;
$result = $result.' ('.$user_info_stat['attempts'].' '.get_lang('Attempts').')';
$counter++;
}
}
$html_result .= $result;
$html_result .= "</td>";
}
if (empty($counter)) {
$total_student = '-';
} else {
$total_student = $total_result_by_user / $counter;
$total_average_score += $total_student;
$total_average_score_count++;
}
$string_date = Tracking::get_last_connection_date($user['user_id'], true);
$html_result .= "<td>$total_student</td><td>$string_date</td></tr>";
}
$html_result .= "<tr><th>".get_lang('AverageScore')."</th>";
$total_average = 0;
$counter = 0;
foreach ($course_list as $course_item) {
if (!empty($course_average_counter[$course_item['code']])) {
$average_per_course = round(
$course_average[$course_item['code']] / ($course_average_counter[$course_item['code']] * 100) * 100,
2
);
} else {
$average_per_course = 0;
}
if (!empty($average_per_course)) {
$counter++;
}
$total_average = $total_average + $average_per_course;
$html_result .= "<td>$average_per_course</td>";
}
if (!empty($total_average_score_count)) {
$total_average = round($total_average_score / ($total_average_score_count * 100) * 100, 2);
} else {
$total_average = '-';
}
$html_result .= '<td>'.$total_average.'</td>';
$html_result .= "<td>-</td>";
$html_result .= "</tr>";
$html_result .= '</table>';
} else {
echo Display::return_message(get_lang('NoResults'), 'warning');
}
if (!$export_to_xls) {
echo $html_result;
}
Display::display_footer();

730
main/tracking/exams.php Normal file
View File

@@ -0,0 +1,730 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Exams script.
*/
require_once __DIR__.'/../inc/global.inc.php';
$toolTable = Database::get_course_table(TABLE_TOOL_LIST);
$quizTable = Database::get_course_table(TABLE_QUIZ_TEST);
$this_section = SECTION_TRACKING;
$is_allowedToTrack = api_is_course_admin() || api_is_platform_admin(true) || $is_session_general_coach;
if (!$is_allowedToTrack) {
api_not_allowed(true);
}
$exportToXLS = false;
if (isset($_GET['export'])) {
$exportToXLS = true;
}
if (api_is_platform_admin() && empty($_GET['cidReq'])) {
$global = true;
} else {
$global = false;
}
$courseList = [];
if ($global) {
$temp = CourseManager::get_courses_list();
foreach ($temp as $tempCourse) {
$courseInfo = api_get_course_info($tempCourse['code']);
$courseList[] = $courseInfo;
}
} else {
$courseList = [api_get_course_info()];
}
$sessionId = api_get_session_id();
if (empty($sessionId)) {
$sessionCondition = ' AND (session_id = 0 OR session_id IS NULL)';
} else {
$sessionCondition = api_get_session_condition($sessionId, true, true);
}
$form = new FormValidator(
'search_simple',
'POST',
api_get_self().'?'.api_get_cidreq(),
'',
null,
false
);
$form->addElement('number', 'score', get_lang('Percentage'));
if ($global) {
$form->addElement('hidden', 'view', 'admin');
} else {
// Get exam lists
$courseId = api_get_course_int_id();
$sql = "SELECT quiz.title, iid FROM $quizTable AS quiz
WHERE
c_id = $courseId AND
active = 1
$sessionCondition
ORDER BY quiz.title ASC";
$result = Database::query($sql);
// Only show select bar if there is more than one test
if (Database::num_rows($result) > 0) {
$exerciseList = [get_lang('All')];
while ($row = Database::fetch_array($result)) {
$exerciseList[$row['iid']] = $row['title'];
}
$form->addElement('select', 'exercise_id', get_lang('Exercise'), $exerciseList);
}
}
$form->addButton('filter', get_lang('Filter'), 'filter', 'primary', null, null, ['style' => 'margin-top: 5px; margin-left: 15px;']);
$filter_score = isset($_REQUEST['score']) ? intval($_REQUEST['score']) : 70;
$exerciseId = isset($_REQUEST['exercise_id']) ? intval($_REQUEST['exercise_id']) : 0;
$form->setDefaults(['score' => $filter_score]);
if (!$exportToXLS) {
Display::display_header(get_lang('Reporting'));
$actionsLeft = $actionsRight = '';
if ($global) {
$actionsLeft .= '<a href="'.api_get_path(WEB_CODE_PATH).'auth/my_progress.php">'.
Display::return_icon('statistics.png', get_lang('MyStats'), '', ICON_SIZE_MEDIUM);
$actionsLeft .= '</a>';
$courseInfo = api_get_course_info();
$actionsRight .= '<a href="'.api_get_self().'?export=1&score='.$filter_score.'&exercise_id='.$exerciseId.'">'.
Display::return_icon('export_excel.png', get_lang('ExportAsXLS'), '', ICON_SIZE_MEDIUM).'</a>';
$actionsRight .= '<a href="javascript: void(0);" onclick="javascript: window.print()">'.
Display::return_icon('printer.png', get_lang('Print'), '', ICON_SIZE_MEDIUM).'</a>';
$menuItems[] = Display::url(
Display::return_icon('teacher.png', get_lang('TeacherInterface'), [], 32),
api_get_path(WEB_CODE_PATH).'mySpace/?view=teacher'
);
if (api_is_platform_admin()) {
$menuItems[] = Display::url(
Display::return_icon('star.png', get_lang('AdminInterface'), [], 32),
api_get_path(WEB_CODE_PATH).'mySpace/admin_view.php'
);
} else {
$menuItems[] = Display::url(
Display::return_icon('star.png', get_lang('CoachInterface'), [], 32),
api_get_path(WEB_CODE_PATH).'mySpace/index.php?view=coach'
);
}
$menuItems[] = '<a href="#">'.Display::return_icon('quiz_na.png', get_lang('ExamTracking'), [], 32).'</a>';
$nb_menu_items = count($menuItems);
if ($nb_menu_items > 1) {
foreach ($menuItems as $key => $item) {
$actionsLeft .= $item;
}
}
} else {
$actionsLeft = TrackingCourseLog::actionsLeft('exams', api_get_session_id());
$actionsRight .= Display::url(
Display::return_icon('export_excel.png', get_lang('ExportAsXLS'), [], 32),
api_get_self().'?'.api_get_cidreq().'&export=1&score='.$filter_score.'&exercise_id='.$exerciseId
);
}
$toolbar = Display::toolbarAction('toolbar-exams', [$actionsLeft, $actionsRight]);
echo $toolbar;
$form->display();
echo '<h3>'.sprintf(get_lang('FilteringWithScoreX'), $filter_score).'%</h3>';
}
$html = '<div class="table-responsive">';
$html .= '<table class="table table-hover table-striped data_table">';
if ($global) {
$html .= '<tr>';
$html .= '<th>'.get_lang('Courses').'</th>';
$html .= '<th>'.get_lang('Quiz').'</th>';
$html .= '<th>'.get_lang('ExamTaken').'</th>';
$html .= '<th>'.get_lang('ExamNotTaken').'</th>';
$html .= '<th>'.sprintf(get_lang('ExamPassX'), $filter_score).'%</th>';
$html .= '<th>'.get_lang('ExamFail').'</th>';
$html .= '<th>'.get_lang('TotalStudents').'</th>';
$html .= '</tr>';
} else {
$html .= '<tr>';
$html .= '<th>'.get_lang('Quiz').'</th>';
$html .= '<th>'.get_lang('User').'</th>';
$html .= '<th>'.get_lang('Username').'</th>';
//$html .= '<th>'.sprintf(get_lang('ExamPassX'), $filter_score).'</th>';
$html .= '<th>'.get_lang('Percentage').' %</th>';
$html .= '<th>'.get_lang('Status').'</th>';
$html .= '<th>'.get_lang('Attempts').'</th>';
$html .= '</tr>';
}
$export_array_global = $export_array = [];
$s_css_class = null;
if (!empty($courseList) && is_array($courseList)) {
foreach ($courseList as $courseInfo) {
$sessionList = SessionManager::get_session_by_course($courseInfo['real_id']);
$newSessionList = [];
if (!empty($sessionList)) {
foreach ($sessionList as $session) {
$newSessionList[$session['id']] = $session['name'];
}
}
$courseId = $courseInfo['real_id'];
if ($global) {
$sql = "SELECT count(iid) as count
FROM $quizTable AS quiz
WHERE c_id = $courseId AND active = 1 AND (session_id = 0 OR session_id IS NULL)";
$result = Database::query($sql);
$countExercises = Database::store_result($result);
$exerciseCount = $countExercises[0]['count'];
$sql = "SELECT count(iid) as count
FROM $quizTable AS quiz
WHERE c_id = $courseId AND active = 1 AND session_id <> 0";
$result = Database::query($sql);
$countExercises = Database::store_result($result);
$exerciseSessionCount = $countExercises[0]['count'];
$exerciseCount = $exerciseCount + $exerciseCount * count($newSessionList) + $exerciseSessionCount;
// Add course and session list.
if (0 == $exerciseCount) {
$exerciseCount = 2;
}
$html .= "<tr>
<td rowspan=$exerciseCount>";
$html .= $courseInfo['title'];
$html .= "</td>";
}
$sql = "SELECT visibility FROM $toolTable
WHERE c_id = $courseId AND name = 'quiz'";
$result = Database::query($sql);
// If main tool is visible.
if (1 == Database::result($result, 0, 'visibility')) {
// Getting the exam list.
if ($global) {
$sql = "SELECT quiz.title, iid, session_id
FROM $quizTable AS quiz
WHERE c_id = $courseId AND active = 1
ORDER BY session_id, quiz.title ASC";
} else {
//$sessionCondition = api_get_session_condition($sessionId, true, false);
if (!empty($exerciseId)) {
$sql = "SELECT quiz.title, iid, session_id
FROM $quizTable AS quiz
WHERE
c_id = $courseId AND
active = 1 AND
id = $exerciseId
$sessionCondition
ORDER BY session_id, quiz.title ASC";
} else {
$sql = "SELECT quiz.title, iid, session_id
FROM $quizTable AS quiz
WHERE
c_id = $courseId AND
active = 1
$sessionCondition
ORDER BY session_id, quiz.title ASC";
}
}
$resultExercises = Database::query($sql);
if (Database::num_rows($resultExercises) > 0) {
while ($exercise = Database::fetch_array($resultExercises, 'ASSOC')) {
$exerciseSessionId = $exercise['session_id'];
if (empty($exerciseSessionId)) {
if ($global) {
// If the exercise was created in the base course.
// Load all sessions.
foreach ($newSessionList as $currentSessionId => $sessionName) {
$result = processStudentList(
$filter_score,
$global,
$exercise,
$courseInfo,
$currentSessionId,
$newSessionList
);
$html .= $result['html'];
$export_array_global = array_merge($export_array_global, $result['export_array_global']);
}
// Load base course.
$result = processStudentList(
$filter_score,
$global,
$exercise,
$courseInfo,
0,
$newSessionList
);
$html .= $result['html'];
$export_array_global = array_merge($export_array_global, $result['export_array_global']);
} else {
if (empty($sessionId)) {
// Load base course.
$result = processStudentList(
$filter_score,
$global,
$exercise,
$courseInfo,
0,
$newSessionList
);
$html .= $result['html'];
if (is_array($result['export_array_global'])) {
$export_array_global = array_merge(
$export_array_global,
$result['export_array_global']
);
}
} else {
$result = processStudentList(
$filter_score,
$global,
$exercise,
$courseInfo,
$sessionId,
$newSessionList
);
$html .= $result['html'];
$export_array_global = array_merge(
$export_array_global,
$result['export_array_global']
);
}
}
} else {
// If the exercise only exists in this session.
$result = processStudentList(
$filter_score,
$global,
$exercise,
$courseInfo,
$exerciseSessionId,
$newSessionList
);
$html .= $result['html'];
$export_array_global = array_merge(
$export_array_global,
$result['export_array_global']
);
}
}
} else {
$html .= "<tr>
<td colspan='6'>
".get_lang('NoExercise')."
</td>
</tr>
";
}
} else {
$html .= "<tr>
<td colspan='6'>
".get_lang('NoExercise')."
</td>
</tr>
";
}
}
}
$html .= '</table>';
$html .= '</div>';
if (!$exportToXLS) {
echo $html;
}
$filename = 'exam-reporting-'.api_get_local_time().'.xlsx';
if ($exportToXLS) {
export_complete_report_xls($filename, $export_array_global);
exit;
}
/**
* @param $a
* @param $b
*
* @return int
*/
function sort_user($a, $b)
{
if (is_numeric($a['score']) && is_numeric($b['score'])) {
if ($a['score'] < $b['score']) {
return 1;
}
return 0;
}
return 1;
}
/**
* @param string $filename
* @param array $array
*/
function export_complete_report_xls($filename, $array)
{
global $global, $filter_score;
$spreadsheet = new PHPExcel();
$spreadsheet->setActiveSheetIndex(0);
$worksheet = $spreadsheet->getActiveSheet();
$line = 1;
$column = 0; //skip the first column (row titles)
if ($global) {
$worksheet->setCellValueByColumnAndRow($column, $line, get_lang('Courses'));
$column++;
$worksheet->setCellValueByColumnAndRow($column, $line, get_lang('Exercises'));
$column++;
$worksheet->setCellValueByColumnAndRow($column, $line, get_lang('ExamTaken'));
$column++;
$worksheet->setCellValueByColumnAndRow($column, $line, get_lang('ExamNotTaken'));
$column++;
$worksheet->setCellValueByColumnAndRow($column, $line, sprintf(get_lang('ExamPassX'), $filter_score).'%');
$column++;
$worksheet->setCellValueByColumnAndRow($column, $line, get_lang('ExamFail'));
$column++;
$worksheet->setCellValueByColumnAndRow($column, $line, get_lang('TotalStudents'));
$column++;
$line++;
foreach ($array as $row) {
$column = 0;
foreach ($row as $item) {
$worksheet->setCellValueByColumnAndRow($column, $line, html_entity_decode(strip_tags($item)));
$column++;
}
$line++;
}
$line++;
} else {
$worksheet->setCellValueByColumnAndRow(0, $line, get_lang('Exercises'));
$worksheet->setCellValueByColumnAndRow(1, $line, get_lang('User'));
$worksheet->setCellValueByColumnAndRow(2, $line, get_lang('Username'));
$worksheet->setCellValueByColumnAndRow(3, $line, get_lang('Percentage'));
$worksheet->setCellValueByColumnAndRow(4, $line, get_lang('Status'));
$worksheet->setCellValueByColumnAndRow(5, $line, get_lang('Attempts'));
$line++;
foreach ($array as $row) {
$worksheet->setCellValueByColumnAndRow(
0,
$line,
html_entity_decode(strip_tags($row['exercise']))
);
foreach ($row['users'] as $key => $user) {
$worksheet->setCellValueByColumnAndRow(
1,
$line,
html_entity_decode(strip_tags($user))
);
$worksheet->setCellValueByColumnAndRow(
2,
$line,
$row['usernames'][$key]
);
$column = 3;
foreach ($row['results'][$key] as $result_item) {
$worksheet->setCellValueByColumnAndRow(
$column,
$line,
html_entity_decode(strip_tags($result_item))
);
$column++;
}
$line++;
}
}
}
$file = api_get_path(SYS_ARCHIVE_PATH).api_replace_dangerous_char($filename);
$writer = new PHPExcel_Writer_Excel2007($spreadsheet);
$writer->save($file);
DocumentManager::file_send_for_download($file, true, $filename);
exit;
}
/**
* @param $filter_score
* @param $global
* @param $exercise
* @param $courseInfo
* @param $sessionId
* @param $newSessionList
*
* @return array
*/
function processStudentList($filter_score, $global, $exercise, $courseInfo, $sessionId, $newSessionList)
{
if ((isset($exercise['iid']) && empty($exercise['iid'])) ||
!isset($exercise['iid'])
) {
return [
'html' => '',
'export_array_global' => [],
'total_students' => 0,
];
}
$exerciseStatsTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
$courseId = api_get_course_int_id($courseInfo['code']);
if (empty($sessionId)) {
$students = CourseManager::get_student_list_from_course_code(
$courseInfo['code'],
false,
0,
null,
null,
false
);
} else {
$students = CourseManager::get_student_list_from_course_code(
$courseInfo['code'],
true,
$sessionId,
null,
null,
false
);
}
$html = null;
$totalStudents = count($students);
if (!$global) {
$html .= "<tr>";
}
if (!$global) {
$html .= '<td rowspan="'.$totalStudents.'">';
} else {
$html .= '<td>';
}
$html .= $exercise['title'];
if ($global && !empty($sessionId)) {
$sessionName = isset($newSessionList[$sessionId]) ? $newSessionList[$sessionId] : null;
$html .= Display::return_icon('star.png', get_lang('Session')).' ('.$sessionName.')';
}
$html .= '</td>';
$globalRow = [
$courseInfo['title'],
$exercise['title'],
];
$total_with_parameter_score = 0;
$taken = 0;
$export_array_global = [];
$studentResult = [];
$export_array = [];
foreach ($students as $student) {
$studentId = isset($student['user_id']) ? $student['user_id'] : $student['id_user'];
$sql = "SELECT COUNT(ex.exe_id) as count
FROM $exerciseStatsTable AS ex
WHERE
ex.c_id = $courseId AND
ex.exe_exo_id = ".$exercise['iid']." AND
exe_user_id= $studentId AND
session_id = $sessionId
";
$result = Database::query($sql);
$attempts = Database::fetch_array($result);
$sql = "SELECT exe_id, exe_result, exe_weighting
FROM $exerciseStatsTable
WHERE
exe_user_id = $studentId AND
c_id = $courseId AND
exe_exo_id = ".$exercise['iid']." AND
session_id = $sessionId
ORDER BY exe_result DESC
LIMIT 1";
$result = Database::query($sql);
$score = 0;
$weighting = 0;
while ($scoreInfo = Database::fetch_array($result)) {
$score = $score + $scoreInfo['exe_result'];
$weighting = $weighting + $scoreInfo['exe_weighting'];
}
$percentageScore = 0;
if ($weighting != 0) {
$percentageScore = round(($score * 100) / $weighting);
}
if ($attempts['count'] > 0) {
$taken++;
}
if ($percentageScore >= $filter_score) {
$total_with_parameter_score++;
}
$tempArray = [];
if (!$global) {
$userInfo = api_get_user_info($studentId);
// User
$userRow = '<td>';
$userRow .= $userInfo['complete_name'];
$userRow .= '</td>';
$userRow .= '<td>'.$userInfo['username'].'</td>';
// Best result
if (!empty($attempts['count'])) {
$userRow .= '<td>';
$userRow .= $percentageScore;
$tempArray[] = $percentageScore;
$userRow .= '</td>';
if ($percentageScore >= $filter_score) {
$userRow .= '<td style="background-color:#DFFFA8">';
$userRow .= get_lang('PassExam').'</td>';
$tempArray[] = get_lang('PassExam');
} else {
$userRow .= '<td style="background-color:#FC9A9E" >';
$userRow .= get_lang('ExamFail').'</td>';
$tempArray[] = get_lang('ExamFail');
}
$userRow .= '<td>';
$userRow .= $attempts['count'];
$tempArray[] = $attempts['count'];
$userRow .= '</td>';
} else {
$score = '-';
$userRow .= '<td>';
$userRow .= '-';
$tempArray[] = '-';
$userRow .= '</td>';
$userRow .= '<td style="background-color:#FCE89A">';
$userRow .= get_lang('NoAttempt');
$tempArray[] = get_lang('NoAttempt');
$userRow .= '</td>';
$userRow .= '<td>';
$userRow .= 0;
$tempArray[] = 0;
$userRow .= '</td>';
}
$userRow .= '</tr>';
$studentResult[$studentId] = [
'html' => $userRow,
'score' => $score,
'array' => $tempArray,
'user' => $userInfo['complete_name'],
'username' => $userInfo['username'],
];
}
}
$row_not_global['exercise'] = $exercise['title'];
if (!$global) {
if (!empty($studentResult)) {
$studentResultEmpty = $studentResultContent = [];
foreach ($studentResult as $row) {
if ($row['score'] == '-') {
$studentResultEmpty[] = $row;
} else {
$studentResultContent[] = $row;
}
}
// Sort only users with content
usort($studentResultContent, 'sort_user');
$studentResult = array_merge($studentResultContent, $studentResultEmpty);
foreach ($studentResult as $row) {
$html .= $row['html'];
$row_not_global['results'][] = $row['array'];
$row_not_global['users'][] = $row['user'];
$row_not_global['usernames'][] = $row['username'];
}
$export_array[] = $row_not_global;
}
}
if ($global) {
// Exam taken
$html .= '<td>';
$html .= $taken;
$globalRow[] = $taken;
$html .= '</td>';
// Exam NOT taken
$html .= '<td>';
$html .= $not_taken = $totalStudents - $taken;
$globalRow[] = $not_taken;
$html .= '</td>';
// Exam pass
if (!empty($total_with_parameter_score)) {
$html .= '<td style="background-color:#DFFFA8" >';
} else {
$html .= '<td style="background-color:#FCE89A" >';
}
$html .= $total_with_parameter_score;
$globalRow[] = $total_with_parameter_score;
$html .= '</td>';
// Exam fail
$html .= '<td>';
$html .= $fail = $taken - $total_with_parameter_score;
$globalRow[] = $fail;
$html .= '</td>';
$html .= '<td>';
$html .= $totalStudents;
$globalRow[] = $totalStudents;
$html .= '</td>';
$html .= '</tr>';
$export_array_global[] = $globalRow;
}
return [
'html' => $html,
'export_array_global' => $global ? $export_array_global : $export_array,
'total_students' => $totalStudents,
];
}
Display::display_footer();

7
main/tracking/index.html Normal file
View File

@@ -0,0 +1,7 @@
<html>
<head>
<meta http-equiv="refresh" content="0; url=courseLog.php">
</head>
<body>
</body>
</html>

516
main/tracking/lp_report.php Normal file
View File

@@ -0,0 +1,516 @@
<?php
/* For licensing terms, see /license.txt */
use ChamiloSession as Session;
require_once __DIR__.'/../inc/global.inc.php';
api_protect_course_script();
$sessionId = api_get_session_id();
$courseId = api_get_course_int_id();
$courseInfo = api_get_course_info();
// Access restrictions.
$is_allowedToTrack = Tracking::isAllowToTrack($sessionId);
if (!$is_allowedToTrack) {
api_not_allowed(true);
exit;
}
$action = $_GET['action'] ?? null;
$additionalProfileField = $_GET['additional_profile_field'] ?? [];
$additionalExtraFieldsInfo = [];
$objExtraField = new ExtraField('user');
foreach ($additionalProfileField as $fieldId) {
$additionalExtraFieldsInfo[$fieldId] = $objExtraField->getFieldInfoByFieldId($fieldId);
}
$defaultExtraFields = [];
$defaultExtraFieldsFromSettings = api_get_configuration_value('course_log_default_extra_fields');
$defaultExtraInfo = [];
if (!empty($defaultExtraFieldsFromSettings) && isset($defaultExtraFieldsFromSettings['extra_fields'])) {
$defaultExtraFields = $defaultExtraFieldsFromSettings['extra_fields'];
foreach ($defaultExtraFields as $fieldName) {
$extraFieldInfo = UserManager::get_extra_field_information_by_name($fieldName);
if (!empty($extraFieldInfo)) {
$defaultExtraInfo[$extraFieldInfo['id']] = UserManager::get_extra_field_information_by_name($fieldName);
}
}
}
$lps = new LearnpathList(
api_get_user_id(),
$courseInfo,
$sessionId,
null,
false,
null,
true
);
$lps = $lps->get_flat_list();
Session::write('lps', $lps);
/**
* Prepares the shared SQL query for the user table.
* See get_user_data() and get_number_of_users().
*
* @param bool $getCount Whether to count, or get data
*
* @return string SQL query
*/
function prepare_user_sql_query($getCount)
{
$sql = '';
$user_table = Database::get_main_table(TABLE_MAIN_USER);
$admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
if ($getCount) {
$sql .= "SELECT COUNT(u.id) AS total_number_of_items FROM $user_table u";
} else {
$sql .= 'SELECT u.id AS col0, u.official_code AS col2, ';
if (api_is_western_name_order()) {
$sql .= 'u.firstname AS col3, u.lastname AS col4, ';
} else {
$sql .= 'u.lastname AS col3, u.firstname AS col4, ';
}
$sql .= " u.username AS col5,
u.email AS col6,
u.status AS col7,
u.active AS col8,
u.registration_date AS col9,
u.last_login as col10,
u.id AS col11,
u.expiration_date AS exp,
u.password
FROM $user_table u";
}
// adding the filter to see the user's only of the current access_url
if ((api_is_platform_admin() || api_is_session_admin()) && api_get_multiple_access_url()) {
$access_url_rel_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
$sql .= " INNER JOIN $access_url_rel_user_table url_rel_user
ON (u.id=url_rel_user.user_id)";
}
$keywordList = [
'keyword_firstname',
'keyword_lastname',
'keyword_username',
'keyword_email',
'keyword_officialcode',
'keyword_status',
'keyword_active',
'keyword_inactive',
'check_easy_passwords',
];
$keywordListValues = [];
$atLeastOne = false;
foreach ($keywordList as $keyword) {
$keywordListValues[$keyword] = null;
if (isset($_GET[$keyword]) && !empty($_GET[$keyword])) {
$keywordListValues[$keyword] = $_GET[$keyword];
$atLeastOne = true;
}
}
if ($atLeastOne == false) {
$keywordListValues = [];
}
if (isset($_GET['keyword']) && !empty($_GET['keyword'])) {
$keywordFiltered = Database::escape_string("%".$_GET['keyword']."%");
$sql .= " WHERE (
u.firstname LIKE '$keywordFiltered' OR
u.lastname LIKE '$keywordFiltered' OR
concat(u.firstname, ' ', u.lastname) LIKE '$keywordFiltered' OR
concat(u.lastname,' ',u.firstname) LIKE '$keywordFiltered' OR
u.username LIKE '$keywordFiltered' OR
u.official_code LIKE '$keywordFiltered' OR
u.email LIKE '$keywordFiltered'
)
";
} elseif (isset($keywordListValues) && !empty($keywordListValues)) {
$query_admin_table = '';
$keyword_admin = '';
if (isset($keywordListValues['keyword_status']) &&
$keywordListValues['keyword_status'] == PLATFORM_ADMIN
) {
$query_admin_table = " , $admin_table a ";
$keyword_admin = ' AND a.user_id = u.id ';
$keywordListValues['keyword_status'] = '%';
}
$keyword_extra_value = '';
$sql .= " $query_admin_table
WHERE (
u.firstname LIKE '".Database::escape_string("%".$keywordListValues['keyword_firstname']."%")."' AND
u.lastname LIKE '".Database::escape_string("%".$keywordListValues['keyword_lastname']."%")."' AND
u.username LIKE '".Database::escape_string("%".$keywordListValues['keyword_username']."%")."' AND
u.email LIKE '".Database::escape_string("%".$keywordListValues['keyword_email']."%")."' AND
u.status LIKE '".Database::escape_string($keywordListValues['keyword_status'])."' ";
if (!empty($keywordListValues['keyword_officialcode'])) {
$sql .= " AND u.official_code LIKE '".Database::escape_string("%".$keywordListValues['keyword_officialcode']."%")."' ";
}
$sql .= "
$keyword_admin
$keyword_extra_value
";
if (isset($keywordListValues['keyword_active']) &&
!isset($keywordListValues['keyword_inactive'])
) {
$sql .= ' AND u.active = 1';
} elseif (isset($keywordListValues['keyword_inactive']) &&
!isset($keywordListValues['keyword_active'])
) {
$sql .= ' AND u.active = 0';
}
$sql .= ' ) ';
}
$preventSessionAdminsToManageAllUsers = api_get_setting('prevent_session_admins_to_manage_all_users');
if (api_is_session_admin() && $preventSessionAdminsToManageAllUsers === 'true') {
$sql .= ' AND u.creator_id = '.api_get_user_id();
}
$variables = Session::read('variables_to_show', []);
if (!empty($variables)) {
$extraField = new ExtraField('user');
$extraFieldResult = [];
$extraFieldHasData = [];
foreach ($variables as $variable) {
if (isset($_GET['extra_'.$variable])) {
if (is_array($_GET['extra_'.$variable])) {
$values = $_GET['extra_'.$variable];
} else {
$values = [$_GET['extra_'.$variable]];
}
if (empty($values)) {
continue;
}
$info = $extraField->get_handler_field_info_by_field_variable(
$variable
);
if (empty($info)) {
continue;
}
foreach ($values as $value) {
if (empty($value)) {
continue;
}
if ($info['field_type'] == ExtraField::FIELD_TYPE_TAG) {
$result = $extraField->getAllUserPerTag(
$info['id'],
$value
);
$result = empty($result) ? [] : array_column(
$result,
'user_id'
);
} else {
$result = UserManager::get_extra_user_data_by_value(
$variable,
$value
);
}
$extraFieldHasData[] = true;
if (!empty($result)) {
$extraFieldResult = array_merge(
$extraFieldResult,
$result
);
}
}
}
}
if (!empty($extraFieldHasData)) {
$sql .= " AND (u.id IN ('".implode("','", $extraFieldResult)."')) ";
}
}
// adding the filter to see the user's only of the current access_url
if ((api_is_platform_admin() || api_is_session_admin()) &&
api_get_multiple_access_url()
) {
$sql .= ' AND url_rel_user.access_url_id = '.api_get_current_access_url_id();
}
return $sql;
}
function getCount()
{
$sessionId = api_get_session_id();
$courseCode = api_get_course_id();
if (empty($sessionId)) {
// Registered students in a course outside session.
$count = CourseManager::get_student_list_from_course_code(
$courseCode,
false,
null,
null,
null,
null,
null,
true
);
} else {
// Registered students in session.
$count = CourseManager::get_student_list_from_course_code(
$courseCode,
true,
$sessionId,
null,
null,
null,
null,
true
);
}
return $count;
}
/**
* Get the users to display on the current page (fill the sortable-table).
*
* @param int offset of first user to recover
* @param int Number of users to get
* @param int Column to sort on
* @param string Order (ASC,DESC)
*
* @return array Users list
*
* @see SortableTable#get_table_data($from)
*/
$getData = function ($from, $numberOfItems, $column, $direction) use ($additionalExtraFieldsInfo) {
$sessionId = api_get_session_id();
$courseCode = api_get_course_id();
$courseId = api_get_course_int_id();
$lps = Session::read('lps');
if (empty($sessionId)) {
// Registered students in a course outside session.
$students = CourseManager::get_student_list_from_course_code(
$courseCode,
false,
null,
null,
null,
null,
null,
false,
$from,
$numberOfItems
);
} else {
// Registered students in session.
$students = CourseManager::get_student_list_from_course_code(
$courseCode,
true,
$sessionId,
null,
null,
null,
null,
false,
$from,
$numberOfItems
);
}
$useNewTable = Tracking::minimumTimeAvailable($sessionId, $courseId);
$users = [];
foreach ($students as $student) {
$user = [];
$userId = $student['id'];
$user[] = $student['firstname'];
$user[] = $student['lastname'];
$user[] = $student['username'];
$objExtraValue = new ExtraFieldValue('user');
foreach ($additionalExtraFieldsInfo as $fieldInfo) {
$extraValue = $objExtraValue->get_values_by_handler_and_field_id($student['id'], $fieldInfo['id'], true);
$user[] = $extraValue['value'] ?? null;
}
$lpTimeList = [];
if ($useNewTable) {
$lpTimeList = Tracking::getCalculateTime($userId, $courseId, $sessionId);
}
foreach ($lps as $lp) {
$lpId = $lp['iid'];
$progress = Tracking::get_avg_student_progress(
$userId,
$courseCode,
[$lpId],
$sessionId
);
if ($useNewTable) {
$time = isset($lpTimeList[TOOL_LEARNPATH][$lpId]) ? $lpTimeList[TOOL_LEARNPATH][$lpId] : 0;
} else {
$time = Tracking::get_time_spent_in_lp(
$userId,
$courseCode,
[$lpId],
$sessionId
);
}
$time = api_time_to_hms($time);
$first = Tracking::getFirstConnectionTimeInLp(
$userId,
$courseCode,
$lpId,
$sessionId
);
$first = api_convert_and_format_date(
$first,
DATE_TIME_FORMAT_LONG
);
$last = Tracking::get_last_connection_time_in_lp(
$userId,
$courseCode,
$lpId,
$sessionId
);
$last = api_convert_and_format_date(
$last,
DATE_TIME_FORMAT_LONG
);
$score = Tracking::getAverageStudentScore(
$userId,
$courseCode,
[$lpId],
$sessionId
);
if (is_numeric($score)) {
$score = $score.'%';
}
$user[] = $progress;
$user[] = $first;
$user[] = $last;
$user[] = $time;
$user[] = $score;
}
$users[] = $user;
}
return $users;
};
$interbreadcrumb[] = [
'url' => api_get_path(WEB_CODE_PATH).'tracking/courseLog.php?'.api_get_cidreq(),
'name' => get_lang('Tracking'),
];
$tool_name = get_lang('CourseLearningPathsGenericStats');
$headers = [];
$headers[] = get_lang('FirstName');
$headers[] = get_lang('LastName');
$headers[] = get_lang('Username');
$parameters = [];
$parameters['sec_token'] = Security::get_token();
$parameters['cidReq'] = api_get_course_id();
$parameters['id_session'] = api_get_session_id();
foreach ($additionalExtraFieldsInfo as $fieldInfo) {
$headers[] = $fieldInfo['display_text'];
$parameters['additional_profile_field'] = $fieldInfo['id'];
}
foreach ($lps as $lp) {
$lpName = $lp['lp_name'];
$headers[] = get_lang('Progress').': '.$lpName;
$headers[] = get_lang('FirstAccess').': '.$lpName;
$headers[] = get_lang('LastAccess').': '.$lpName;
$headers[] = get_lang('Time').': '.$lpName;
$headers[] = get_lang('Score').': '.$lpName;
}
if (!empty($action)) {
switch ($action) {
case 'export':
$data = $getData(0, 100000, null, null);
$data = array_merge([$headers], $data);
$name = api_get_course_id().'_'.get_lang('Learnpath').'_'.get_lang('Export');
Export::arrayToXls($data, $name);
exit;
break;
}
}
$actionsLeft = TrackingCourseLog::actionsLeft('lp');
$actionsCenter = '';
$actionsRight = Display::url(
Display::return_icon(
'export_excel.png',
get_lang('ExportAsXLS'),
null,
ICON_SIZE_MEDIUM
),
api_get_self().'?action=export&'.api_get_cidreq().'&'
.http_build_query([
'action' => 'export',
'additional_profile_field' => $additionalProfileField,
])
);
// Create a sortable table with user-data
$table = new SortableTable(
'lps',
'getCount',
$getData
);
$table->set_additional_parameters($parameters);
$column = 0;
foreach ($headers as $header) {
$table->set_header($column++, $header, false);
}
$content = [];
$content[] = TrackingCourseLog::displayAdditionalProfileFields($defaultExtraFields, api_get_self());
$content[] = $table->return_table();
$toolbarActions = Display::toolbarAction(
'toolbarUser',
[$actionsLeft, $actionsCenter, $actionsRight],
[4, 4, 4]
);
$tpl = new Template($tool_name);
$tpl->assign('actions', $toolbarActions);
$tpl->assign('content', implode(PHP_EOL, $content));
$tpl->display_one_col_template();

View File

@@ -0,0 +1,252 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Exercise results from Learning paths.
*
* @todo implement pagination
*/
require_once __DIR__.'/../inc/global.inc.php';
$this_section = SECTION_TRACKING;
$is_allowedToTrack = Tracking::isAllowToTrack(api_get_session_id());
if (!$is_allowedToTrack) {
api_not_allowed(true);
}
$export_to_csv = false;
if (isset($_GET['export'])) {
$export_to_csv = true;
}
$global = false;
if (api_is_platform_admin()) {
$global = true;
}
if ($global) {
$temp_course_list = CourseManager::get_courses_list();
foreach ($temp_course_list as $temp_course_item) {
$course_item = api_get_course_info($temp_course_item['code']);
$course_list[] = [
'code' => $course_item['code'],
'title' => $course_item['title'],
];
}
} else {
$current_course['code'] = $_course['id'];
$course_list = [$current_course];
}
$new_course_select = [];
foreach ($course_list as $data) {
$new_course_select[$data['code']] = $data['title'];
}
$form = new FormValidator('search_simple', 'POST', '', '', null, false);
$form->addElement(
'select',
'course_code',
get_lang('Course'),
$new_course_select
);
if ($global) {
$form->addElement('hidden', 'view', 'admin');
} else {
//Get exam lists
$course_id = api_get_course_int_id();
$t_quiz = Database::get_course_table(TABLE_QUIZ_TEST);
$sqlExercices = "SELECT quiz.title,iid FROM ".$t_quiz." AS quiz
WHERE c_id = $course_id AND active='1'
ORDER BY quiz.title ASC";
$resultExercices = Database::query($sqlExercices);
$exercise_list[0] = get_lang('All');
while ($a_exercices = Database::fetch_array($resultExercices)) {
$exercise_list[$a_exercices['iid']] = $a_exercices['title'];
}
$form->addElement('select', 'exercise_id', get_lang('Exercise'), $exercise_list);
}
//$form->addElement('submit','submit',get_lang('Filter'));
$form->addButtonFilter(get_lang('Filter'));
if (!empty($_REQUEST['course_code'])) {
$selected_course = $_REQUEST['course_code'];
}
if (!empty($selected_course)) {
$selected_course = api_get_course_info($selected_course);
$course_list = [$selected_course];
}
if (!$export_to_csv) {
Display::display_header(get_lang('Reporting'));
echo '<div class="actions" style ="font-size:10pt;">';
if ($global) {
echo '<div style="float:right"> <a href="'.api_get_self().'?export=1&score='.$filter_score.'&exercise_id='.$exercise_id.'">
'.Display::return_icon('csv.gif').'
&nbsp;'.get_lang('ExportAsCSV').'</a>'.
'<a href="javascript: void(0);" onclick="javascript: window.print()">
'.Display::return_icon('printmgr.gif').'
&nbsp;'.get_lang('Print').'</a>
</div>';
$menu_items[] = '<a href="'.api_get_path(WEB_CODE_PATH).'mySpace/?view=teacher">'.get_lang('TeacherInterface').'</a>';
if (api_is_platform_admin()) {
$menu_items[] = '<a href="'.api_get_path(WEB_CODE_PATH).'mySpace/?view=admin">'.get_lang('AdminInterface').'</a>';
} else {
$menu_items[] = '<a href="'.api_get_path(WEB_CODE_PATH).'mySpace/?view=coach">'.get_lang('AdminInterface').'</a>';
}
$menu_items[] = get_lang('ExamTracking');
$nb_menu_items = count($menu_items);
if ($nb_menu_items > 1) {
foreach ($menu_items as $key => $item) {
echo $item;
if ($key != $nb_menu_items - 1) {
echo ' | ';
}
}
echo '<br />';
}
} else {
echo '<a href="courseLog.php?'.api_get_cidreq().'&studentlist=true">'.get_lang('StudentsTracking').'</a>&nbsp;|
<a href="courseLog.php?'.api_get_cidreq().'&studentlist=false">'.get_lang('CourseTracking').'</a>&nbsp;|&nbsp';
echo '<a href="courseLog.php?'.api_get_cidreq().'&studentlist=resources">'.get_lang('ResourcesTracking').'</a>';
echo ' | '.get_lang('ExamTracking').'';
echo '<a href="'.api_get_self().'?export=1&score='.$filter_score.'&exercise_id='.$exercise_id.'">
'.Display::return_icon('excel.gif').'
&nbsp;'.get_lang('ExportAsXLS').'</a><br /><br />';
}
echo '</div>';
echo '<br /><br />';
$form->display();
}
$main_result = [];
$session_id = 0;
$user_list = [];
// Getting course list
foreach ($course_list as $current_course) {
$course_info = api_get_course_info($current_course['code']);
$_course = $course_info;
// Getting LP list
$list = new LearnpathList('', $course_info, $session_id);
$lp_list = $list->get_flat_list();
// Looping LPs
$lps = [];
foreach ($lp_list as $lp_id => $lp) {
$exercise_list = Event::get_all_exercises_from_lp($lp_id, $course_info['real_id']);
$attempt_result = [];
// Looping Chamilo Exercises in LP
foreach ($exercise_list as $exercise) {
$exercise_stats = Event::get_all_exercise_event_from_lp(
$exercise['path'],
$course_info['real_id'],
$session_id
);
// Looping Exercise Attempts
foreach ($exercise_stats as $stats) {
$attempt_result[$exercise['id']]['users'][$stats['exe_user_id']][$stats['exe_id']] = $stats;
$user_list[$stats['exe_user_id']] = $stats['exe_user_id'];
}
$exercise_list_name[$exercise['id']] = $exercise['title'];
}
$lps[$lp_id] = ['lp_name' => $lp['lp_name'], 'exercises' => $attempt_result];
$lp_list_name[$lp_id] = $lp['lp_name'];
}
$main_result[$current_course['code']] = $lps;
}
if (!empty($user_list)) {
foreach ($user_list as $user_id) {
$user_data = api_get_user_info($user_id);
$user_list_name[$user_id] = api_get_person_name(
$user_data['firstname'],
$user_data['lastname']
);
}
}
$export_array = [];
if (!empty($main_result)) {
$html_result .= '<table class="table table-hover table-striped data_table">';
$html_result .= '<tr><th>'.get_lang('Course').'</th>';
$html_result .= '<th>'.get_lang('LearningPath').'</th>';
$html_result .= '<th>'.get_lang('Exercise').'</th>';
$html_result .= '<th>'.get_lang('User').'</th>';
$html_result .= '<th>'.get_lang('Attempt').'</th>';
$html_result .= '<th>'.get_lang('Date').'</th>';
$html_result .= '<th>'.get_lang('Results').'</th>';
$html_result .= '</tr>';
foreach ($main_result as $course_code => $lps) {
if (empty($lps)) {
continue;
}
foreach ($lps as $lp_id => $lp_data) {
$exercises = $lp_data['exercises'];
foreach ($exercises as $exercise_id => $exercise_data) {
$users = $exercise_data['users'];
foreach ($users as $user_id => $attempts) {
$attempt = 1;
foreach ($attempts as $exe_id => $attempt_data) {
$html_result .= '<tr colspan="">';
$html_result .= Display::tag('td', $course_code);
$html_result .= Display::tag('td', $lp_list_name[$lp_id]);
$html_result .= Display::tag('td', $exercise_list_name[$exercise_id]);
$html_result .= Display::tag('td', $user_list_name[$user_id]);
$result = $attempt_data['exe_result'].' / '.$attempt_data['exe_weighting'];
$html_result .= Display::tag('td', $attempt);
$html_result .= Display::tag('td', api_get_local_time($attempt_data['exe_date']));
$html_result .= Display::tag('td', $result);
$html_result .= '</tr>';
$export_array[] = [
$course_code,
$lp_list_name[$lp_id],
$exercise_list_name[$exercise_id],
$user_list_name[$user_id],
$attempt,
api_get_local_time($attempt_data['exe_date']),
$result,
];
$attempt++;
}
}
}
}
}
$html_result .= '</table>';
}
if (!$export_to_csv) {
echo $html_result;
}
$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_csv($filename, $array)
{
$header[] = [
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::arrayToCsv($array, $filename);
}
exit;
}
Display::display_footer();

117
main/tracking/messages.php Normal file
View File

@@ -0,0 +1,117 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/../inc/global.inc.php';
$allow = api_get_configuration_value('allow_user_message_tracking');
if (!$allow) {
api_not_allowed(true);
}
$allowUser = api_is_platform_admin() || api_is_drh();
if (!$allowUser) {
api_not_allowed(true);
}
$fromUserId = isset($_GET['from_user']) ? (int) $_GET['from_user'] : 0;
$toUserId = isset($_GET['to_user']) ? (int) $_GET['to_user'] : 0;
$coachAccessStartDate = isset($_GET['start_date']) ? $_GET['start_date'] : null;
$coachAccessEndDate = isset($_GET['end_date']) ? $_GET['end_date'] : null;
if (empty($fromUserId) || empty($toUserId)) {
api_not_allowed(true);
}
if (api_is_drh()) {
$isFollowed = UserManager::is_user_followed_by_drh($fromUserId, api_get_user_id());
if (api_drh_can_access_all_session_content()) {
$students = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
'drh_all',
api_get_user_id(),
false,
0, //$from,
null, //$limit,
null, //$column,
'desc', //$direction,
null, //$keyword,
null, //$active,
null, //$lastConnectionDate,
null,
null,
STUDENT
);
if (empty($students)) {
api_not_allowed(true);
}
$userIdList = [];
foreach ($students as $student) {
$userIdList[] = $student['user_id'];
}
if (!in_array($fromUserId, $userIdList)) {
api_not_allowed(true);
}
} else {
if (!$isFollowed) {
api_not_allowed(true);
}
}
}
$usersData[$toUserId] = api_get_user_info($toUserId);
$usersData[$fromUserId] = api_get_user_info($fromUserId);
$filterMessages = api_get_configuration_value('filter_interactivity_messages');
if ($filterMessages) {
$messages = MessageManager::getAllMessagesBetweenStudents($toUserId, $fromUserId, $coachAccessStartDate, $coachAccessEndDate);
} else {
$messages = MessageManager::getAllMessagesBetweenStudents($toUserId, $fromUserId);
}
$content = Display::page_subheader2(sprintf(
get_lang('MessagesExchangeBetweenXAndY'),
$usersData[$toUserId]['complete_name'],
$usersData[$fromUserId]['complete_name']
));
$interbreadcrumb[] = [
'url' => api_get_path(WEB_CODE_PATH).'mySpace/student.php',
'name' => get_lang('MyStudents'),
];
$interbreadcrumb[] = [
'url' => api_get_path(WEB_CODE_PATH).'mySpace/myStudents.php?student='.$fromUserId,
'name' => get_lang('StudentDetails'),
];
$uniqueMessageList = [];
foreach ($messages as $message) {
$message['title'].
$subText = get_lang('From').': '.$usersData[$message['user_sender_id']]['complete_name'];
$title = empty($message['title']) ? get_lang('Untitled') : $message['title'];
$title = $title.' - '.$subText.'<span class="pull-right">'.Display::dateToStringAgoAndLongDate($message['send_date']).'</span>';
$messageId = $message['id'];
$hash = sha1($message['title'].$message['content'].$message['send_date']);
if (in_array($hash, $uniqueMessageList)) {
continue;
}
$content .= Display::panelCollapse(
$title,
$message['content'].'<br />'.Display::dateToStringAgoAndLongDate($message['send_date']),
'message-'.$message['id'],
null,
'message-'.$message['id'],
'collapse-'.$message['id'],
false
);
$uniqueMessageList[] = $hash;
}
$template = new Template(get_lang('MessageTracking'));
$template->assign('content', $content);
$template->display_one_col_template();

View File

@@ -0,0 +1,220 @@
<?php
/* For licensing terms, see /license.txt */
$cidReset = true;
require_once __DIR__.'/../inc/global.inc.php';
$this_section = 'session_my_space';
$allow = Tracking::isAllowToTrack(api_get_session_id());
if (!$allow) {
api_not_allowed(true);
}
$export_to_xls = false;
if (isset($_GET['export'])) {
$export_to_xls = true;
}
if (api_is_platform_admin()) {
$global = true;
} else {
$global = false;
}
$global = true;
$course_list = $course_select_list = [];
$html_result = '';
$course_select_list[0] = get_lang('None');
$htmlHeadXtra[] = '
<script type="text/javascript">
function load_courses() {
document.search_simple.submit();
}
</script>';
$session_id = isset($_REQUEST['session_id']) ? intval($_REQUEST['session_id']) : null;
if (empty($session_id)) {
$temp_course_list = CourseManager::get_courses_list();
} else {
$temp_course_list = SessionManager::get_course_list_by_session_id($session_id);
}
foreach ($temp_course_list as $temp_course_item) {
$course_item = api_get_course_info($temp_course_item['code']);
$course_select_list[$temp_course_item['code']] = $course_item['title'];
}
//Get session list
$session_list = SessionManager::get_sessions_list([], ['name']);
$my_session_list = [];
$my_session_list[0] = get_lang('None');
foreach ($session_list as $sesion_item) {
$my_session_list[$sesion_item['id']] = $sesion_item['name'];
}
$form = new FormValidator('search_simple', 'POST', '', '', null);
$form->addElement(
'select',
'session_id',
get_lang('Sessions'),
$my_session_list,
['id' => 'session_id', 'onchange' => 'load_courses();']
);
$form->addElement(
'select',
'course_code',
get_lang('Courses'),
$course_select_list
);
$form->addButtonFilter(get_lang('Filter'), 'submit_form');
if (!empty($_REQUEST['course_code'])) {
$course_code = $_REQUEST['course_code'];
} else {
$course_code = '';
}
if (empty($course_code)) {
$course_code = 0;
}
$form->setDefaults(['course_code' => (string) $course_code]);
$course_info = api_get_course_info($course_code);
if (!empty($course_info)) {
$list = new LearnpathList('', $course_info);
$lp_list = $list->get_flat_list();
$main_question_list = [];
foreach ($lp_list as $lp_id => $lp) {
$exercise_list = Event::get_all_exercises_from_lp(
$lp_id,
$course_info['real_id']
);
foreach ($exercise_list as $exercise) {
$my_exercise = new Exercise($course_info['real_id']);
$my_exercise->read($exercise['path']);
$question_list = $my_exercise->selectQuestionList();
$exercise_stats = Event::get_all_exercise_event_from_lp(
$exercise['path'],
$course_info['real_id'],
$session_id
);
foreach ($question_list as $question_id) {
$question_data = Question::read($question_id, $course_info);
$main_question_list[$question_id] = $question_data;
$quantity_exercises = 0;
$question_result = 0;
foreach ($exercise_stats as $stats) {
if (!empty($stats['question_list'])) {
foreach ($stats['question_list'] as $my_question_stat) {
if ($question_id == $my_question_stat['question_id']) {
$question_result = $question_result + $my_question_stat['marks'];
$quantity_exercises++;
}
}
}
}
if (!empty($quantity_exercises)) {
// Score % average
$main_question_list[$question_id]->results = ($question_result / ($quantity_exercises));
} else {
$main_question_list[$question_id]->results = 0;
}
$main_question_list[$question_id]->quantity = $quantity_exercises;
}
}
}
}
if (!$export_to_xls) {
Display::display_header(get_lang("MySpace"));
echo '<div class="actions">';
if ($global) {
echo MySpace::getTopMenu();
} else {
echo '<div style="float:left; clear:left">
<a href="courseLog.php?'.api_get_cidreq().'&studentlist=true">'.
get_lang('StudentsTracking').'</a>&nbsp;|
<a href="courseLog.php?'.api_get_cidreq().'&studentlist=false">'.
get_lang('CourseTracking').'</a>&nbsp;';
echo '</div>';
}
echo '</div>';
if (api_is_platform_admin()) {
echo MySpace::getAdminActions();
}
echo '<br />';
echo '<h2>'.get_lang('LPQuestionListResults').'</h2>';
$form->display();
if (empty($course_code)) {
echo Display::return_message(get_lang('PleaseSelectACourse'), 'warning');
}
}
$course_average = [];
$counter = 0;
if (!empty($main_question_list) && is_array($main_question_list)) {
$html_result .= '<table class="table table-hover table-striped data_table">';
$html_result .= '<tr><th>'.get_lang('Question').
Display::return_icon('info3.gif', get_lang('QuestionsAreTakenFromLPExercises'), ['align' => 'absmiddle', 'hspace' => '3px']).'</th>';
$html_result .= '<th>'.$course_info['visual_code'].' '.get_lang('AverageScore').Display::return_icon('info3.gif', get_lang('AllStudentsAttemptsAreConsidered'), ['align' => 'absmiddle', 'hspace' => '3px']).' </th>';
$html_result .= '<th>'.get_lang('Quantity').'</th>';
foreach ($main_question_list as $question) {
$total_student = 0;
$counter++;
$s_css_class = 'row_even';
if ($counter % 2 == 0) {
$s_css_class = 'row_odd';
}
$html_result .= "<tr class='$s_css_class'>
<td >";
$question_title = trim($question->question);
if (empty($question_title)) {
$html_result .= get_lang('Untitled').' '.get_lang('Question').' #'.$question->id;
} else {
$html_result .= $question->question;
}
$html_result .= "</td>";
$html_result .= "<td>";
$html_result .= round($question->results, 2).' / '.$question->weighting;
$html_result .= "</td>";
$html_result .= "<td>";
$html_result .= $question->quantity;
$html_result .= "</td>";
}
$html_result .= "</tr>";
$html_result .= '</table>';
} else {
if (!empty($course_code)) {
echo Display::return_message(get_lang('NoResults'), 'warning');
}
}
if (!$export_to_xls) {
echo $html_result;
}
Display::display_footer();

View File

@@ -0,0 +1,316 @@
<?php
/* For licensing terms, see /license.txt */
use ChamiloSession as Session;
require_once __DIR__.'/../inc/global.inc.php';
$current_course_tool = TOOL_TRACKING;
$courseInfo = api_get_course_info(api_get_course_id());
$courseCode = $courseInfo['code'];
$from_myspace = false;
$from = isset($_GET['from']) ? $_GET['from'] : null;
// Starting the output buffering when we are exporting the information.
$export_csv = isset($_GET['export']) && $_GET['export'] == 'csv' ? true : false;
$session_id = isset($_REQUEST['id_session']) ? intval($_REQUEST['id_session']) : 0;
$this_section = SECTION_COURSES;
if ('myspace' == $from) {
$from_myspace = true;
$this_section = 'session_my_space';
}
// Access restrictions.
$is_allowedToTrack = Tracking::isAllowToTrack($session_id);
if (!$is_allowedToTrack) {
api_not_allowed(true);
exit;
}
// If the user is a HR director (drh)
if (api_is_drh()) {
// Blocking course for drh
if (api_drh_can_access_all_session_content()) {
// If the drh has been configured to be allowed to see all session content,
// give him access to the session courses
$coursesFromSession = SessionManager::getAllCoursesFollowedByUser(
api_get_user_id(),
null
);
$coursesFromSessionCodeList = [];
if (!empty($coursesFromSession)) {
foreach ($coursesFromSession as $course) {
$coursesFromSessionCodeList[$course['code']] = $course['code'];
}
}
$coursesFollowedList = CourseManager::get_courses_followed_by_drh(api_get_user_id());
if (!empty($coursesFollowedList)) {
$coursesFollowedList = array_keys($coursesFollowedList);
}
if (!in_array($courseCode, $coursesFollowedList)) {
if (!in_array($courseCode, $coursesFromSessionCodeList)) {
api_not_allowed();
}
}
} else {
// If the drh has *not* been configured to be allowed to see all session content,
// then check if he has also been given access to the corresponding courses
$coursesFollowedList = CourseManager::get_courses_followed_by_drh(api_get_user_id());
$coursesFollowedList = array_keys($coursesFollowedList);
if (!in_array(api_get_course_id(), $coursesFollowedList)) {
api_not_allowed(true);
exit;
}
}
}
if ($export_csv) {
if (!empty($session_id)) {
Session::write('id_session', $session_id);
}
ob_start();
}
$columnsToHideFromSetting = api_get_configuration_value('course_log_hide_columns');
$columnsToHide = empty($columnsToHideFromSetting) ? [0, 8, 9, 10, 11] : $columnsToHideFromSetting;
$columnsToHide = json_encode($columnsToHide);
$csv_content = [];
// Database table definitions.
//@todo remove this calls
$TABLETRACK_EXERCISES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
$TABLECOURSE = Database::get_main_table(TABLE_MAIN_COURSE);
$table_user = Database::get_main_table(TABLE_MAIN_USER);
$TABLEQUIZ = Database::get_course_table(TABLE_QUIZ_TEST);
$sessionId = api_get_session_id();
// Breadcrumbs.
if (isset($_GET['origin']) && $_GET['origin'] == 'resume_session') {
$interbreadcrumb[] = [
'url' => '../admin/index.php',
'name' => get_lang('PlatformAdmin'),
];
$interbreadcrumb[] = [
'url' => '../session/session_list.php',
'name' => get_lang('SessionList'),
];
$interbreadcrumb[] = [
'url' => '../session/resume_session.php?id_session='.$sessionId,
'name' => get_lang('SessionOverview'),
];
}
$view = isset($_REQUEST['view']) ? $_REQUEST['view'] : '';
$nameTools = get_lang('Tracking');
// getting all the students of the course
if (empty($session_id)) {
// Registered students in a course outside session.
$a_students = CourseManager::get_student_list_from_course_code(
api_get_course_id()
);
} else {
// Registered students in session.
$a_students = CourseManager::get_student_list_from_course_code(
api_get_course_id(),
true,
$sessionId
);
}
$nbStudents = count($a_students);
// Display the header.
Display::display_header($nameTools, 'Tracking');
/* MAIN CODE */
$actionsLeft = Display::return_icon(
'user_na.png',
get_lang('StudentsTracking'),
[],
ICON_SIZE_MEDIUM
);
$actionsLeft .= Display::url(
Display::return_icon('group.png', get_lang('GroupReporting'), [], ICON_SIZE_MEDIUM),
'course_log_groups.php?'.api_get_cidreq()
);
$actionsLeft .= Display::url(
Display::return_icon('course.png', get_lang('CourseTracking'), [], ICON_SIZE_MEDIUM),
'course_log_tools.php?'.api_get_cidreq()
);
$actionsLeft .= Display::url(
Display::return_icon('tools.png', get_lang('ResourcesTracking'), [], ICON_SIZE_MEDIUM),
'course_log_resources.php?'.api_get_cidreq()
);
$actionsLeft .= Display::url(
Display::return_icon('quiz.png', get_lang('ExamTracking'), [], ICON_SIZE_MEDIUM),
api_get_path(WEB_CODE_PATH).'tracking/exams.php?'.api_get_cidreq()
);
if (!empty($sessionId)) {
$actionsLeft .= Display::url(
Display::return_icon('attendance_list.png', get_lang('Logins'), '', ICON_SIZE_MEDIUM),
api_get_path(WEB_CODE_PATH).'attendance/index.php?'.api_get_cidreq().'&action=calendar_logins'
);
}
$actionsRight = '<div class="pull-right">';
$actionsRight .= '<a href="javascript: void(0);" onclick="javascript: window.print();">'.
Display::return_icon('printer.png', get_lang('Print'), '', ICON_SIZE_MEDIUM).'</a>';
$users_tracking_per_page = '';
if (isset($_GET['users_tracking_per_page'])) {
$users_tracking_per_page = '&users_tracking_per_page='.intval($_GET['users_tracking_per_page']);
}
$actionsRight .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&export=csv&'.$users_tracking_per_page.'">
'.Display::return_icon('export_csv.png', get_lang('ExportAsCSV'), '', ICON_SIZE_MEDIUM).'</a>';
$actionsRight .= '</div>';
// Create a search-box.
$form_search = new FormValidator(
'search_simple',
'GET',
api_get_path(WEB_CODE_PATH).'tracking/total_time.php?'.api_get_cidreq(),
'',
[],
FormValidator::LAYOUT_INLINE
);
$form_search->addElement('hidden', 'from', Security::remove_XSS($from));
$form_search->addElement('hidden', 'session_id', $sessionId);
$form_search->addElement('hidden', 'id_session', $sessionId);
$form_search->addElement('text', 'user_keyword');
$form_search->addButtonSearch(get_lang('SearchUsers'));
echo Display::toolbarAction(
'toolbar-courselog',
[$actionsLeft, $form_search->returnForm(), $actionsRight]
);
$course_name = get_lang('Course').' '.$courseInfo['name'];
if ($session_id) {
$titleSession = Display::return_icon(
'session.png',
get_lang('Session'),
[],
ICON_SIZE_SMALL
).' '.api_get_session_name($session_id);
$titleCourse = Display::return_icon(
'course.png',
get_lang('Course'),
[],
ICON_SIZE_SMALL
).' '.$course_name;
} else {
$titleSession = Display::return_icon(
'course.png',
get_lang('Course'),
[],
ICON_SIZE_SMALL
).' '.$courseInfo['name'];
}
$html = TrackingCourseLog::getTeachersOrCoachesHtmlHeader(
$courseInfo['code'],
$courseInfo['real_id'],
$session_id,
false
);
if (api_is_platform_admin(true) ||
api_is_session_general_coach()
) {
$sessionList = SessionManager::get_session_by_course($courseInfo['real_id']);
if (!empty($sessionList)) {
$html .= Display::page_subheader2(get_lang('SessionList'));
$icon = Display::return_icon(
'session.png',
null,
null,
ICON_SIZE_TINY
);
$html .= '<ul class="session-list">';
foreach ($sessionList as $session) {
$url = api_get_path(WEB_CODE_PATH).'mySpace/course.php?session_id='
.$session['id'].'&cidReq='.$courseInfo['code'];
$html .= Display::tag('li', $icon.' '.Display::url($session['name'], $url));
}
$html .= '</ul>';
}
}
$html .= Display::page_subheader2(get_lang('StudentList'));
// PERSON_NAME_DATA_EXPORT is buggy
$is_western_name_order = api_is_western_name_order();
if (count($a_students) > 0) {
$all_datas = [];
$course_code = $_course['id'];
$user_ids = array_keys($a_students);
$table = new SortableTable(
'users_tracking',
['TrackingCourseLog', 'getNumberOfUsers'],
['TrackingCourseLog', 'getTotalTimeReport'],
(api_is_western_name_order() xor api_sort_by_first_name()) ? 3 : 2
);
$parameters['cidReq'] = Security::remove_XSS($_GET['cidReq']);
$parameters['id_session'] = $session_id;
$parameters['from'] = isset($_GET['myspace']) ? Security::remove_XSS($_GET['myspace']) : null;
$table->set_additional_parameters($parameters);
$headers = [];
// tab of header texts
$table->set_header(0, get_lang('OfficialCode'), true);
$headers['official_code'] = get_lang('OfficialCode');
if ($is_western_name_order) {
$table->set_header(1, get_lang('FirstName'), true);
$headers['firstname'] = get_lang('FirstName');
$table->set_header(2, get_lang('LastName'), true);
$headers['lastname'] = get_lang('LastName');
} else {
$table->set_header(1, get_lang('LastName'), true);
$headers['lastname'] = get_lang('LastName');
$table->set_header(2, get_lang('FirstName'), true);
$headers['firstname'] = get_lang('FirstName');
}
$table->set_header(3, get_lang('Login'), false);
$headers['login'] = get_lang('Login');
$table->set_header(4, get_lang('TrainingTime').'&nbsp;'.
Display::return_icon('info3.gif', get_lang('CourseTimeInfo'), ['align' => 'absmiddle', 'hspace' => '3px']),
false,
['style' => 'width:110px;']
);
$headers['training_time'] = get_lang('TrainingTime');
$table->set_header(5, get_lang('TotalLPTime').'&nbsp;'.
Display::return_icon('info3.gif', get_lang('TotalLPTime'), ['align' => 'absmiddle', 'hspace' => '3px']),
false,
['style' => 'width:110px;']
);
$headers['total_time_lp'] = get_lang('TotalLPTime');
$table->set_header(6, get_lang('FirstLoginInCourse'), false);
$headers['first_login'] = get_lang('FirstLoginInCourse');
$table->set_header(7, get_lang('LatestLoginInCourse'), false);
$headers['latest_login'] = get_lang('LatestLoginInCourse');
// Display the table
$html .= "<div id='reporting_table'>";
$html .= $table->return_table();
$html .= "</div>";
} else {
$html .= Display::return_message(get_lang('NoUsersInCourse'), 'warning', true);
}
echo Display::panel($html, $titleSession);
Display::display_footer();