Merge remote-tracking branch 'chamilo/1.11.x' into 18214

* chamilo/1.11.x:
  Minor - format code
  Tracking: Remove config use_new_tracking_in_lp_item BT#18443
  Admin: Add config my_courses_show_pending_exercise_attempts BT#18351
  Exercises: Fix back to attempt list URL when an exercise is inside a LP
  Minor - fix typo
  Plugin: Azure AD: Improve README documentation
  Documentation: Remove PHP 5.6 from allowed PHP versions in dependencies guide
  Documentation: add ffmpeg as suitable replacement for libav-tools in dependencies list
  Minor - Update GH action name
  Minor - Add int casting
pull/3743/head
Carlos Alvarado 5 years ago
commit 2aa9a326cf
No known key found for this signature in database
GPG Key ID: B612DB1EE6658FBB
  1. 2
      .github/workflows/php.yml
  2. 5
      documentation/dependencies.html
  3. 4
      main/admin/extra_field_workflow.php
  4. 513
      main/exercise/pending.php
  5. 7
      main/exercise/result.php
  6. 88
      main/inc/ajax/model.ajax.php
  7. 285
      main/inc/lib/exercise.lib.php
  8. 33
      main/inc/lib/tracking.lib.php
  9. 22
      main/inc/lib/userportal.lib.php
  10. 7
      main/install/configuration.dist.php
  11. 21
      plugin/azure_active_directory/README.md

@ -1,4 +1,4 @@
name: PHP Composer
name: Behat tests 1.11.x 🐞
on: [push, pull_request]

@ -71,7 +71,7 @@ We recommend using HTML5-compatible technology.
<h2>Dependencies - server-side</h2>
<ul>
<li>Apache 2+</li>
<li>PHP 5.6 (not recommended) with MySQL bindings or PHP 7.2 (recommended) or 7.3. PHP 7.0 is not supported by this version of Chamilo. PHP 7.1 should be supported but we lack elements of infrastructure to check it fully and thoroughly.</li>
<li>PHP 7.2, 7.3 or 7.4 (recommended). PHP 5.6 and 7.0 are not supported by this version of Chamilo. PHP 7.1 should be supported but we lack elements of infrastructure to check it fully and thoroughly.</li>
<li>MySQL 5.6+ or any version of MariaDB database server</li>
<li>php-curl</li>
<li>php-dom (usually available by default)</li>
@ -131,8 +131,7 @@ ensure all components are installed by an expert in the field.<br />
</li>
<li>Audio recording (generate mp3 from wav)
<ul>
<li>libav-tools</li>
<li>libavcodec-extra-53</li>
<li>libav-tools libavcodec-extra-53 *or* ffmpeg on more recent distributions</li>
<li>libmp3lame0</li>
</ul>
</li>

@ -17,7 +17,7 @@ $interbreadcrumb[] = ['url' => 'index.php', 'name' => get_lang('PlatformAdmin')]
$tool_name = null;
$action = isset($_GET['action']) ? $_GET['action'] : null;
$field_id = isset($_GET['field_id']) ? $_GET['field_id'] : null;
$field_id = isset($_GET['field_id']) ? (int) $_GET['field_id'] : null;
if (empty($field_id)) {
api_not_allowed();
@ -73,7 +73,7 @@ if ($action == 'add') {
];
}
$roleId = isset($_REQUEST['roleId']) ? $_REQUEST['roleId'] : null;
$roleId = isset($_REQUEST['roleId']) ? (int) $_REQUEST['roleId'] : null;
//jqgrid will use this URL to do the selects
$params = 'field_id='.$field_id.'&type='.$extraField->type.'&roleId='.$roleId;

@ -0,0 +1,513 @@
<?php
/* For licensing terms, see /license.txt */
$cidReset = true;
require_once __DIR__.'/../inc/global.inc.php';
// Setting the tabs
$this_section = SECTION_COURSES;
$htmlHeadXtra[] = api_get_jqgrid_js();
$filter_user = isset($_REQUEST['filter_by_user']) ? (int) $_REQUEST['filter_by_user'] : null;
$courseId = isset($_REQUEST['course_id']) ? (int) $_REQUEST['course_id'] : 0;
$exerciseId = isset($_REQUEST['exercise_id']) ? (int) $_REQUEST['exercise_id'] : 0;
$statusId = isset($_REQUEST['status']) ? (int) $_REQUEST['status'] : 0;
$action = $_REQUEST['a'] ?? null;
api_block_anonymous_users();
// Only teachers.
if (false === api_is_teacher()) {
api_not_allowed(true);
}
switch ($action) {
case 'get_exercise_by_course':
$data = [];
$results = ExerciseLib::get_all_exercises_for_course_id(
null,
0,
$courseId
);
if (!empty($results)) {
foreach ($results as $exercise) {
$data[] = ['id' => $exercise['id'], 'text' => html_entity_decode($exercise['title'])];
}
}
echo json_encode($data);
exit;
break;
}
$userId = api_get_user_id();
$origin = api_get_origin();
$TBL_TRACK_EXERCISES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
$TBL_TRACK_ATTEMPT = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
$TBL_TRACK_ATTEMPT_RECORDING = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING);
$TBL_LP_ITEM_VIEW = Database::get_course_table(TABLE_LP_ITEM_VIEW);
$allowCoachFeedbackExercises = api_get_setting('allow_coach_feedback_exercises') === 'true';
$documentPath = null;
if (!empty($_GET['path'])) {
$parameters['path'] = Security::remove_XSS($_GET['path']);
}
if (!empty($_REQUEST['export_report']) && $_REQUEST['export_report'] == '1') {
if (api_is_platform_admin() || api_is_course_admin() ||
api_is_course_tutor() || api_is_session_general_coach()
) {
$loadExtraData = false;
if (isset($_REQUEST['extra_data']) && $_REQUEST['extra_data'] == 1) {
$loadExtraData = true;
}
$includeAllUsers = false;
if (isset($_REQUEST['include_all_users']) &&
$_REQUEST['include_all_users'] == 1
) {
$includeAllUsers = true;
}
$onlyBestAttempts = false;
if (isset($_REQUEST['only_best_attempts']) &&
$_REQUEST['only_best_attempts'] == 1
) {
$onlyBestAttempts = true;
}
require_once 'exercise_result.class.php';
$export = new ExerciseResult();
$export->setIncludeAllUsers($includeAllUsers);
$export->setOnlyBestAttempts($onlyBestAttempts);
switch ($_GET['export_format']) {
case 'xls':
$export->exportCompleteReportXLS(
$documentPath,
null,
$loadExtraData,
null,
$exerciseId
);
exit;
break;
case 'csv':
default:
$export->exportCompleteReportCSV(
$documentPath,
null,
$loadExtraData,
null,
$exerciseId
);
exit;
break;
}
} else {
api_not_allowed(true);
}
}
Display::display_header(get_lang('PendingAttempts'));
$token = Security::get_token();
$extra = '<script>
$(function() {
$( "#dialog:ui-dialog" ).dialog( "destroy" );
$( "#dialog-confirm" ).dialog({
autoOpen: false,
show: "blind",
resizable: false,
height:300,
modal: true
});
$("#export_opener").click(function() {
var targetUrl = $(this).attr("href");
$( "#dialog-confirm" ).dialog({
width:400,
height:300,
buttons: {
"'.addslashes(get_lang('Download')).'": function() {
var export_format = $("input[name=export_format]:checked").val();
var extra_data = $("input[name=load_extra_data]:checked").val();
var includeAllUsers = $("input[name=include_all_users]:checked").val();
var attempts = $("input[name=only_best_attempts]:checked").val();
location.href = targetUrl+"&export_format="+export_format+"&extra_data="+extra_data+"&include_all_users="+includeAllUsers+"&only_best_attempts="+attempts;
$( this ).dialog( "close" );
}
}
});
$( "#dialog-confirm" ).dialog("open");
return false;
});
});
</script>';
$extra .= '<div id="dialog-confirm" title="'.get_lang('ConfirmYourChoice').'">';
$form = new FormValidator(
'report',
'post',
null,
null,
['class' => 'form-vertical']
);
$form->addElement(
'radio',
'export_format',
null,
get_lang('ExportAsCSV'),
'csv',
['id' => 'export_format_csv_label']
);
$form->addElement(
'radio',
'export_format',
null,
get_lang('ExportAsXLS'),
'xls',
['id' => 'export_format_xls_label']
);
$form->addElement(
'checkbox',
'load_extra_data',
null,
get_lang('LoadExtraData'),
'0',
['id' => 'export_format_xls_label']
);
$form->addElement(
'checkbox',
'include_all_users',
null,
get_lang('IncludeAllUsers'),
'0'
);
$form->addElement(
'checkbox',
'only_best_attempts',
null,
get_lang('OnlyBestAttempts'),
'0'
);
$form->setDefaults(['export_format' => 'csv']);
$extra .= $form->returnForm();
$extra .= '</div>';
echo $extra;
$courses = CourseManager::get_courses_list_by_user_id($userId, false, false, false);
$form = new FormValidator('pending', 'GET');
$courses = array_column($courses, 'title', 'real_id');
$form->addSelect('course_id', get_lang('Course'), $courses, ['placeholder' => get_lang('All'), 'id' => 'course_id']);
$form->addSelect(
'exercise_id',
get_lang('Exercise'),
[],
[
'placeholder' => get_lang('All'),
'id' => 'exercise_id',
]
);
$status = [
1 => get_lang('All'),
2 => get_lang('Validated'),
3 => get_lang('NotValidated'),
];
$form->addSelect('status', get_lang('Status'), $status);
$form->addButtonSearch(get_lang('Search'));
$content = $form->returnForm();
echo $content;
if (empty($statusId)) {
Display::display_footer();
exit;
}
$url = api_get_path(WEB_AJAX_PATH).
'model.ajax.php?a=get_exercise_pending_results&filter_by_user='.$filter_user.
'&course_id='.$courseId.'&exercise_id='.$exerciseId.'&status='.$statusId;
$action_links = '';
$officialCodeInList = api_get_setting('show_official_code_exercise_result_list');
// The order is important you need to check the the $column variable in the model.ajax.php file
$columns = [
get_lang('Course'),
get_lang('Exercise'),
get_lang('FirstName'),
get_lang('LastName'),
get_lang('LoginName'),
get_lang('Duration').' ('.get_lang('MinMinute').')',
get_lang('StartDate'),
get_lang('EndDate'),
get_lang('Score'),
get_lang('IP'),
get_lang('Status'),
//get_lang('ToolLearnpath'),
get_lang('Actions'),
];
if ($officialCodeInList === 'true') {
$columns = array_merge([get_lang('OfficialCode')], $columns);
}
// Column config
$column_model = [
['name' => 'course', 'index' => 'course', 'width' => '50', 'align' => 'left', 'search' => 'false', 'sortable' => 'false'],
['name' => 'exercise', 'index' => 'exercise', 'width' => '50', 'align' => 'left', 'search' => 'false', 'sortable' => 'false'],
['name' => 'firstname', 'index' => 'firstname', 'width' => '50', 'align' => 'left', 'search' => 'true'],
[
'name' => 'lastname',
'index' => 'lastname',
'width' => '50',
'align' => 'left',
'formatter' => 'action_formatter',
'search' => 'true',
],
[
'name' => 'login',
'index' => 'username',
'width' => '40',
'align' => 'left',
'search' => 'true',
'hidden' => api_get_configuration_value('exercise_attempts_report_show_username') ? 'false' : 'true',
],
['name' => 'duration', 'index' => 'exe_duration', 'width' => '30', 'align' => 'left', 'search' => 'true'],
['name' => 'start_date', 'index' => 'start_date', 'width' => '60', 'align' => 'left', 'search' => 'true'],
['name' => 'exe_date', 'index' => 'exe_date', 'width' => '60', 'align' => 'left', 'search' => 'true'],
['name' => 'score', 'index' => 'exe_result', 'width' => '50', 'align' => 'center', 'search' => 'true'],
['name' => 'ip', 'index' => 'user_ip', 'width' => '40', 'align' => 'center', 'search' => 'true'],
[
'name' => 'status',
'index' => 'revised',
'width' => '40',
'align' => 'left',
'search' => 'false',
'sortable' => 'false',
//'stype' => 'select',
//for the bottom bar
/*'searchoptions' => [
'defaultValue' => '',
'value' => ':'.get_lang('All').';1:'.get_lang('Validated').';0:'.get_lang('NotValidated'),
],*/
//for the top bar
/*'editoptions' => [
'value' => ':'.get_lang('All').';1:'.get_lang('Validated').';0:'.get_lang('NotValidated'),
],*/
],
//['name' => 'lp', 'index' => 'orig_lp_id', 'width' => '60', 'align' => 'left', 'search' => 'false'],
[
'name' => 'actions',
'index' => 'actions',
'width' => '60',
'align' => 'left',
'search' => 'false',
'sortable' => 'false',
],
];
if ('true' === $officialCodeInList) {
$officialCodeRow = [
'name' => 'official_code',
'index' => 'official_code',
'width' => '50',
'align' => 'left',
'search' => 'true',
];
$column_model = array_merge([$officialCodeRow], $column_model);
}
$action_links = '
// add username as title in lastname filed - ref 4226
function action_formatter(cellvalue, options, rowObject) {
// rowObject is firstname,lastname,login,... get the third word
var loginx = "'.api_htmlentities(sprintf(get_lang('LoginX'), ':::'), ENT_QUOTES).'";
var tabLoginx = loginx.split(/:::/);
// tabLoginx[0] is before and tabLoginx[1] is after :::
// may be empty string but is defined
return "<span title=\""+tabLoginx[0]+rowObject[2]+tabLoginx[1]+"\">"+cellvalue+"</span>";
}';
$extra_params['autowidth'] = 'true';
$extra_params['height'] = 'auto';
$gridJs = Display::grid_js(
'results',
$url,
$columns,
$column_model,
$extra_params,
[],
$action_links,
true
);
?>
<script>
function updateExerciseList(courseId) {
if (courseId == 0) {
return;
}
var $selectExercise = $("select#exercise_id");
$selectExercise.empty();
$.get("<?php echo api_get_self(); ?>", {
a: "get_exercise_by_course",
course_id: courseId,
}, function (exerciseList) {
$("<option>", {
value: 0,
text: "<?php echo get_lang('All'); ?>"
}).appendTo($selectExercise);
if (exerciseList.length > 0) {
$.each(exerciseList, function (index, exercise) {
$("<option>", {
value: exercise.id,
text: exercise.text
}).appendTo($selectExercise);
});
$selectExercise.find("option[value=\'<?php echo $exerciseId; ?>\']").attr("selected",true);
}
$selectExercise.selectpicker("refresh");
}, "json");
}
function exportExcel()
{
var mya = $("#results").getDataIDs(); // Get All IDs
var data = $("#results").getRowData(mya[0]); // Get First row to get the labels
var colNames = new Array();
var ii = 0;
for (var i in data) {
colNames[ii++] = i;
}
var html = "";
for (i = 0; i < mya.length; i++) {
data = $("#results").getRowData(mya[i]); // get each row
for (j = 0; j < colNames.length; j++) {
html = html + data[colNames[j]] + ","; // output each column as tab delimited
}
html = html + "\n"; // output each row with end of line
}
html = html + "\n"; // end of line at the end
var form = $("#export_report_form");
$("#csvBuffer").attr('value', html);
form.target='_blank';
form.submit();
}
$(function() {
$("#datepicker_start").datepicker({
defaultDate: "",
changeMonth: false,
numberOfMonths: 1
});
var $selectCourse = $("select#course_id");
$selectCourse.on("change", function () {
var courseId = parseInt(this.value, 10);
updateExerciseList(courseId);
});
var courseId = $selectCourse.val() ? $selectCourse.val() : 0;
updateExerciseList(courseId);
<?php
echo $gridJs;
?>
$("#results").jqGrid(
'navGrid',
'#results_pager', {
view:true, edit:false, add:false, del:false, excel:false
},
{height:280, reloadAfterSubmit:false}, // view options
{height:280, reloadAfterSubmit:false}, // edit options
{height:280, reloadAfterSubmit:false}, // add options
{reloadAfterSubmit: false}, // del options
{width:500}, // search options
);
var sgrid = $("#results")[0];
// Adding search options
var options = {
'stringResult': true,
'autosearch' : true,
'searchOnEnter': false,
}
jQuery("#results").jqGrid('filterToolbar', options);
sgrid.triggerToolbar();
$('#results').on('click', 'a.exercise-recalculate', function (e) {
e.preventDefault();
if (!$(this).data('user') || !$(this).data('exercise') || !$(this).data('id')) {
return;
}
var url = '<?php echo api_get_path(WEB_CODE_PATH); ?>exercise/recalculate.php?<?php echo api_get_cidreq(); ?>';
var recalculateXhr = $.post(url, $(this).data());
$.when(recalculateXhr).done(function (response) {
$('#results').trigger('reloadGrid');
});
});
});
// datepicker functions
var datapickerInputModified = false;
/**
* return true if the datepicker input has been modified
*/
function datepicker_input_changed() {
datapickerInputModified = true;
}
/**
* disply the datepicker calendar on mouse over the input
*/
function datepicker_input_mouseover() {
$('#datepicker_start').datepicker( "show" );
}
/**
* display or hide the datepicker input, calendar and button
*/
function display_date_picker() {
if (!$('#datepicker_span').is(":visible")) {
$('#datepicker_span').show();
$('#datepicker_start').datepicker( "show" );
} else {
$('#datepicker_start').datepicker( "hide" );
$('#datepicker_span').hide();
}
}
/**
* confirm deletion
*/
function submit_datepicker() {
if (datapickerInputModified) {
var dateTypeVar = $('#datepicker_start').datepicker('getDate');
var dateForBDD = $.datepicker.formatDate('yy-mm-dd', dateTypeVar);
// Format the date for confirm box
var dateFormat = $( "#datepicker_start" ).datepicker( "option", "dateFormat" );
var selectedDate = $.datepicker.formatDate(dateFormat, dateTypeVar);
if (confirm("<?php echo convert_double_quote_to_single(get_lang('AreYouSureDeleteTestResultBeforeDateD')).' '; ?>" + selectedDate)) {
self.location.href = "exercise_report.php?<?php echo api_get_cidreq(); ?>&exerciseId=<?php echo $exerciseId; ?>&delete_before_date="+dateForBDD+"&sec_token=<?php echo $token; ?>";
}
}
}
</script>
<form id="export_report_form" method="post" action="exercise_report.php?<?php echo api_get_cidreq(); ?>">
<input type="hidden" name="csvBuffer" id="csvBuffer" value="" />
<input type="hidden" name="export_report" id="export_report" value="1" />
<input type="hidden" name="exerciseId" id="exerciseId" value="<?php echo $exerciseId; ?>" />
</form>
<?php
echo Display::grid_html('results');
Display::display_footer();

@ -157,10 +157,15 @@ switch ($action) {
break;
}
$lpId = (int) $track_exercise_info['orig_lp_id'];
$lpItemId = (int) $track_exercise_info['orig_lp_item_id'];
$lpViewId = (int) $track_exercise_info['orig_lp_item_view_id'];
$pageBottom = '<div class="question-return">';
$pageBottom .= Display::url(
get_lang('BackToAttemptList'),
api_get_path(WEB_CODE_PATH).'exercise/overview.php?exerciseId='.$exercise_id.'&'.api_get_cidreq(),
api_get_path(WEB_CODE_PATH).'exercise/overview.php?exerciseId='.$exercise_id.'&'.api_get_cidreq().
"&learnpath_id=$lpId&learnpath_item_id=$lpItemId&learnpath_item_view_id=$lpViewId",
['class' => 'btn btn-primary']
);
$pageBottom .= '</div>';

@ -44,6 +44,7 @@ if (!in_array(
$action,
[
'get_exercise_results',
'get_exercise_pending_results',
'get_exercise_results_report',
'get_work_student_list_overview',
'get_hotpotatoes_exercise_results',
@ -630,6 +631,52 @@ switch ($action) {
null,
true
);
break;
case 'get_exercise_pending_results':
if (false === api_is_teacher()) {
exit;
}
$courseId = $_REQUEST['course_id'] ?? 0;
$exerciseId = $_REQUEST['exercise_id'] ?? 0;
$status = $_REQUEST['status'] ?? 0;
if (isset($_GET['filter_by_user']) && !empty($_GET['filter_by_user'])) {
$filter_user = (int) $_GET['filter_by_user'];
if (empty($whereCondition)) {
$whereCondition .= " te.exe_user_id = '$filter_user'";
} else {
$whereCondition .= " AND te.exe_user_id = '$filter_user'";
}
}
if (isset($_GET['group_id_in_toolbar']) && !empty($_GET['group_id_in_toolbar'])) {
$groupIdFromToolbar = (int) $_GET['group_id_in_toolbar'];
if (!empty($groupIdFromToolbar)) {
if (empty($whereCondition)) {
$whereCondition .= " te.group_id = '$groupIdFromToolbar'";
} else {
$whereCondition .= " AND group_id = '$groupIdFromToolbar'";
}
}
}
if (!empty($whereCondition)) {
$whereCondition = " AND $whereCondition";
}
if (!empty($courseId)) {
$whereCondition .= " AND te.c_id = $courseId";
}
$count = ExerciseLib::get_count_exam_results(
$exerciseId,
$whereCondition,
'',
false,
true,
$status
);
break;
case 'get_exercise_results':
$exercise_id = $_REQUEST['exerciseId'];
@ -1491,6 +1538,46 @@ switch ($action) {
$whereCondition
);
}
break;
case 'get_exercise_pending_results':
$columns = [
'course',
'exercise',
'firstname',
'lastname',
'username',
'exe_duration',
'start_date',
'exe_date',
'score',
'user_ip',
'status',
'actions',
];
$officialCodeInList = api_get_setting('show_official_code_exercise_result_list');
if ($officialCodeInList === 'true') {
$columns = array_merge(['official_code'], $columns);
}
$result = ExerciseLib::get_exam_results_data(
$start,
$limit,
$sidx,
$sord,
$exerciseId,
$whereCondition,
false,
null,
false,
false,
[],
false,
false,
false,
true,
$status
);
break;
case 'get_exercise_results':
$is_allowedToEdit = api_is_allowed_to_edit(null, true) ||
@ -2510,6 +2597,7 @@ $allowed_actions = [
'get_session_progress',
'get_exercise_progress',
'get_exercise_results',
'get_exercise_pending_results',
'get_exercise_results_report',
'get_work_student_list_overview',
'get_hotpotatoes_exercise_results',

@ -981,7 +981,7 @@ class ExerciseLib
}
}
list($answer) = explode('@@', $answer);
[$answer] = explode('@@', $answer);
// $correctAnswerList array of array with correct anwsers 0=> [0=>[\p] 1=>[plop]]
api_preg_match_all(
'/\[[^]]+\]/',
@ -1909,11 +1909,19 @@ HOTSPOT;
* @param array $conditions
* @param string $courseCode
* @param bool $showSession
* @param bool $searchAllTeacherCourses
* @param int $status
*
* @return array
*/
public static function get_count_exam_results($exerciseId, $conditions, $courseCode = '', $showSession = false)
{
public static function get_count_exam_results(
$exerciseId,
$conditions,
$courseCode = '',
$showSession = false,
$searchAllTeacherCourses = false,
$status = 0
) {
return self::get_exam_results_data(
null,
null,
@ -1923,7 +1931,14 @@ HOTSPOT;
$conditions,
true,
$courseCode,
$showSession
$showSession,
false,
[],
false,
false,
false,
$searchAllTeacherCourses,
$status
);
}
@ -2087,7 +2102,7 @@ HOTSPOT;
* @param array $userExtraFieldsToAdd
* @param bool $useCommaAsDecimalPoint
* @param bool $roundValues
* @param bool $getOnyIds
* @param bool $getOnlyIds
*
* @return array
*/
@ -2105,21 +2120,21 @@ HOTSPOT;
$userExtraFieldsToAdd = [],
$useCommaAsDecimalPoint = false,
$roundValues = false,
$getOnyIds = false
$getOnlyIds = false,
$searchAllTeacherCourses = false,
$status = 0
) {
//@todo replace all this globals
global $filter;
$courseCode = empty($courseCode) ? api_get_course_id() : $courseCode;
$courseInfo = api_get_course_info($courseCode);
if (empty($courseInfo)) {
return [];
}
$documentPath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document';
$course_id = $courseInfo['real_id'];
$documentPath = '';
$sessionId = api_get_session_id();
$exercise_id = (int) $exercise_id;
$courseId = 0;
if (!empty($courseInfo)) {
$courseId = $courseInfo['real_id'];
$documentPath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document';
}
$is_allowedToEdit =
api_is_allowed_to_edit(null, true) ||
@ -2127,6 +2142,41 @@ HOTSPOT;
api_is_drh() ||
api_is_student_boss() ||
api_is_session_admin();
$courseCondition = "c_id = $courseId";
$statusCondition = '';
if (!empty($status)) {
switch ($status) {
case 2:
// validated
$statusCondition = ' AND revised = 1 ';
break;
case 3:
// not validated
$statusCondition = ' AND revised = 0 ';
break;
}
}
if (false === $searchAllTeacherCourses) {
if (empty($courseInfo)) {
return [];
}
} else {
$courses = CourseManager::get_courses_list_by_user_id(api_get_user_id(), false, false, false);
if (empty($courses)) {
return [];
}
$courses = array_column($courses, 'real_id');
$is_allowedToEdit = true;
$courseCondition = "c_id IN ('".implode("', '", $courses)."') ";
}
$exercise_id = (int) $exercise_id;
$TBL_USER = Database::get_main_table(TABLE_MAIN_USER);
$TBL_EXERCICES = Database::get_course_table(TABLE_QUIZ_TEST);
$TBL_GROUP_REL_USER = Database::get_course_table(TABLE_GROUP_USER);
@ -2142,6 +2192,11 @@ HOTSPOT;
$sessionCondition = " AND ttte.session_id = $sessionId";
}
if ($searchAllTeacherCourses) {
$session_id_and = " AND te.session_id = 0 ";
$sessionCondition = " AND ttte.session_id = 0";
}
if (empty($sessionId) &&
api_get_configuration_value('show_exercise_session_attempts_in_base_course')
) {
@ -2150,8 +2205,10 @@ HOTSPOT;
}
$exercise_where = '';
$exerciseFilter = '';
if (!empty($exercise_id)) {
$exercise_where .= ' AND te.exe_exo_id = '.$exercise_id.' ';
$exerciseFilter = " AND exe_exo_id = $exercise_id ";
}
$hotpotatoe_where = '';
@ -2168,8 +2225,8 @@ HOTSPOT;
LEFT JOIN $TBL_TRACK_ATTEMPT_RECORDING tr
ON (ttte.exe_id = tr.exe_id)
WHERE
c_id = $course_id AND
exe_exo_id = $exercise_id
$courseCondition
$exerciseFilter
$sessionCondition
)";
@ -2191,9 +2248,9 @@ HOTSPOT;
g.id as group_id
FROM $TBL_USER u
INNER JOIN $TBL_GROUP_REL_USER gru
ON (gru.user_id = u.user_id AND gru.c_id= $course_id )
ON (gru.user_id = u.user_id AND gru.c_id= $courseId )
INNER JOIN $TBL_GROUP g
ON (gru.group_id = g.id AND g.c_id= $course_id )
ON (gru.group_id = g.id AND g.c_id= $courseId )
)";
}
@ -2254,9 +2311,9 @@ HOTSPOT;
g.id as group_id
FROM $TBL_USER u
LEFT OUTER JOIN $TBL_GROUP_REL_USER gru
ON ( gru.user_id = u.user_id AND gru.c_id= $course_id )
ON ( gru.user_id = u.user_id AND gru.c_id = $courseId )
LEFT OUTER JOIN $TBL_GROUP g
ON (gru.group_id = g.id AND g.c_id = $course_id )
ON (gru.group_id = g.id AND g.c_id = $courseId )
)";
}
@ -2272,8 +2329,13 @@ HOTSPOT;
)";
}
$sqlFromOption = " , $TBL_GROUP_REL_USER AS gru ";
$sqlWhereOption = " AND gru.c_id = $course_id AND gru.user_id = user.user_id ";
$sqlFromOption = '';
$sqlWhereOption = '';
if (false === $searchAllTeacherCourses) {
$sqlFromOption = " , $TBL_GROUP_REL_USER AS gru ";
$sqlWhereOption = " AND gru.c_id = $courseId AND gru.user_id = user.user_id ";
}
$first_and_last_name = api_is_western_name_order() ? "firstname, lastname" : "lastname, firstname";
if ($get_count) {
@ -2289,6 +2351,7 @@ HOTSPOT;
te.exe_weighting,
te.exe_date,
te.exe_id,
te.c_id,
te.session_id,
email as exemail,
te.start_date,
@ -2312,11 +2375,13 @@ HOTSPOT;
INNER JOIN $sql_inner_join_tbl_user AS user
ON (user.user_id = exe_user_id)
WHERE
te.c_id = $course_id $session_id_and AND
te.$courseCondition
$session_id_and AND
ce.active <> -1 AND
ce.c_id = $course_id
ce.$courseCondition
$exercise_where
$extra_where_conditions
$statusCondition
";
// sql for hotpotatoes tests for teacher / tutor view
@ -2339,11 +2404,11 @@ HOTSPOT;
$TBL_USER user
$sqlFromOption
WHERE
user.user_id=tth.exe_user_id
AND tth.c_id = $course_id
user.user_id=tth.exe_user_id AND
tth.$courseCondition
$hotpotatoe_where
$sqlWhereOption
AND user.status NOT IN (".api_get_users_status_ignored_in_reports('string').")
$sqlWhereOption AND
user.status NOT IN (".api_get_users_status_ignored_in_reports('string').")
ORDER BY tth.c_id ASC, tth.exe_date DESC ";
}
@ -2358,11 +2423,13 @@ HOTSPOT;
return $rowx[0];
}
$teacher_list = CourseManager::get_teacher_list_from_course_code($courseCode);
$teacher_id_list = [];
if (!empty($teacher_list)) {
foreach ($teacher_list as $teacher) {
$teacher_id_list[] = $teacher['user_id'];
if (!empty($courseCode)) {
$teacher_list = CourseManager::get_teacher_list_from_course_code($courseCode);
if (!empty($teacher_list)) {
foreach ($teacher_list as $teacher) {
$teacher_id_list[] = $teacher['user_id'];
}
}
}
@ -2386,27 +2453,32 @@ HOTSPOT;
$sql .= " ORDER BY $column $direction ";
}
if (!$getOnyIds) {
if (!$getOnlyIds) {
$sql .= " LIMIT $from, $number_of_items";
}
$results = [];
error_log($sql);
$resx = Database::query($sql);
while ($rowx = Database::fetch_array($resx, 'ASSOC')) {
$results[] = $rowx;
}
$group_list = GroupManager::get_group_list(null, $courseInfo);
$clean_group_list = [];
if (!empty($group_list)) {
foreach ($group_list as $group) {
$clean_group_list[$group['id']] = $group['name'];
$lp_list = [];
if (!empty($courseInfo)) {
$group_list = GroupManager::get_group_list(null, $courseInfo);
if (!empty($group_list)) {
foreach ($group_list as $group) {
$clean_group_list[$group['id']] = $group['name'];
}
}
}
$lp_list_obj = new LearnpathList(api_get_user_id());
$lp_list = $lp_list_obj->get_flat_list();
$oldIds = array_column($lp_list, 'lp_old_id', 'iid');
$lp_list_obj = new LearnpathList(api_get_user_id());
$lp_list = $lp_list_obj->get_flat_list();
$oldIds = array_column($lp_list, 'lp_old_id', 'iid');
}
if (is_array($results)) {
$users_array_id = [];
@ -2417,18 +2489,31 @@ HOTSPOT;
$sizeof = count($results);
$locked = api_resource_is_locked_by_gradebook($exercise_id, LINK_EXERCISE);
$timeNow = strtotime(api_get_utc_datetime());
$courseItemList = [];
// Looping results
for ($i = 0; $i < $sizeof; $i++) {
$revised = $results[$i]['revised'];
$attemptSessionId = (int) $results[$i]['session_id'];
$cidReq = api_get_cidreq(false).'&id_session='.$attemptSessionId;
$attempt = $results[$i];
$revised = $attempt['revised'];
$attemptSessionId = (int) $attempt['session_id'];
if (false === $searchAllTeacherCourses) {
$courseItemInfo = api_get_course_info();
$cidReq = api_get_cidreq(false).'&id_session='.$attemptSessionId;
} else {
if (isset($courseItemList[$attempt['c_id']])) {
$courseItemInfo = $courseItemList[$attempt['c_id']];
} else {
$courseItemInfo = api_get_course_info_by_id($attempt['c_id']);
$courseItemList[$attempt['c_id']] = $courseItemInfo;
}
$cidReq = 'cidReq='.$courseItemInfo['code'].'&id_session='.$attemptSessionId;
}
if ('incomplete' === $results[$i]['completion_status']) {
if ('incomplete' === $attempt['completion_status']) {
// If the exercise was incomplete, we need to determine
// if it is still into the time allowed, or if its
// allowed time has expired and it can be closed
// (it's "unclosed")
$minutes = $results[$i]['expired_time'];
$minutes = $attempt['expired_time'];
if ($minutes == 0) {
// There's no time limit, so obviously the attempt
// can still be "ongoing", but the teacher should
@ -2437,32 +2522,31 @@ HOTSPOT;
$revised = 2;
} else {
$allowedSeconds = $minutes * 60;
$timeAttemptStarted = strtotime($results[$i]['start_date']);
$timeAttemptStarted = strtotime($attempt['start_date']);
$secondsSinceStart = $timeNow - $timeAttemptStarted;
$revised = 3; // mark as "ongoing"
if ($secondsSinceStart > $allowedSeconds) {
$revised = 2; // mark as "unclosed"
} else {
$revised = 3; // mark as "ongoing"
}
}
}
if ($from_gradebook && ($is_allowedToEdit)) {
if (in_array(
$results[$i]['username'].$results[$i]['firstname'].$results[$i]['lastname'],
$attempt['username'].$attempt['firstname'].$attempt['lastname'],
$users_array_id
)) {
continue;
}
$users_array_id[] = $results[$i]['username'].$results[$i]['firstname'].$results[$i]['lastname'];
$users_array_id[] = $attempt['username'].$attempt['firstname'].$attempt['lastname'];
}
$lp_obj = isset($results[$i]['orig_lp_id']) &&
isset($lp_list[$results[$i]['orig_lp_id']]) ? $lp_list[$results[$i]['orig_lp_id']] : null;
$lp_obj = isset($attempt['orig_lp_id']) &&
isset($lp_list[$attempt['orig_lp_id']]) ? $lp_list[$attempt['orig_lp_id']] : null;
if (empty($lp_obj)) {
// Try to get the old id (id instead of iid)
$lpNewId = isset($results[$i]['orig_lp_id']) &&
isset($oldIds[$results[$i]['orig_lp_id']]) ? $oldIds[$results[$i]['orig_lp_id']] : null;
$lpNewId = isset($attempt['orig_lp_id']) &&
isset($oldIds[$attempt['orig_lp_id']]) ? $oldIds[$attempt['orig_lp_id']] : null;
if ($lpNewId) {
$lp_obj = isset($lp_list[$lpNewId]) ? $lp_list[$lpNewId] : null;
}
@ -2470,7 +2554,7 @@ HOTSPOT;
$lp_name = null;
if ($lp_obj) {
$url = api_get_path(WEB_CODE_PATH).
'lp/lp_controller.php?'.$cidReq.'&action=view&lp_id='.$results[$i]['orig_lp_id'];
'lp/lp_controller.php?'.$cidReq.'&action=view&lp_id='.$attempt['orig_lp_id'];
$lp_name = Display::url(
$lp_obj['lp_name'],
$url,
@ -2483,7 +2567,7 @@ HOTSPOT;
if ($is_empty_sql_inner_join_tbl_user) {
$group_list = GroupManager::get_group_ids(
api_get_course_int_id(),
$results[$i]['user_id']
$attempt['user_id']
);
foreach ($group_list as $id) {
@ -2491,25 +2575,25 @@ HOTSPOT;
$group_name_list .= $clean_group_list[$id].'<br/>';
}
}
$results[$i]['group_name'] = $group_name_list;
$attempt['group_name'] = $group_name_list;
}
$results[$i]['exe_duration'] = !empty($results[$i]['exe_duration']) ? round($results[$i]['exe_duration'] / 60) : 0;
$id = $results[$i]['exe_id'];
$dt = api_convert_and_format_date($results[$i]['exe_weighting']);
$attempt['exe_duration'] = !empty($attempt['exe_duration']) ? round($attempt['exe_duration'] / 60) : 0;
$id = $attempt['exe_id'];
$dt = api_convert_and_format_date($attempt['exe_weighting']);
// we filter the results if we have the permission to
$result_disabled = 0;
if (isset($results[$i]['results_disabled'])) {
$result_disabled = (int) $results[$i]['results_disabled'];
if (isset($attempt['results_disabled'])) {
$result_disabled = (int) $attempt['results_disabled'];
}
if ($result_disabled == 0) {
$my_res = $results[$i]['exe_result'];
$my_total = $results[$i]['exe_weighting'];
$results[$i]['start_date'] = api_get_local_time($results[$i]['start_date']);
$results[$i]['exe_date'] = api_get_local_time($results[$i]['exe_date']);
$my_res = $attempt['exe_result'];
$my_total = $attempt['exe_weighting'];
$attempt['start_date'] = api_get_local_time($attempt['start_date']);
$attempt['exe_date'] = api_get_local_time($attempt['exe_date']);
if (!$results[$i]['propagate_neg'] && $my_res < 0) {
if (!$attempt['propagate_neg'] && $my_res < 0) {
$my_res = 0;
}
@ -2529,7 +2613,7 @@ HOTSPOT;
if ($is_allowedToEdit) {
if (isset($teacher_id_list)) {
if (in_array(
$results[$i]['exe_user_id'],
$attempt['exe_user_id'],
$teacher_id_list
)) {
$actions .= Display::return_icon('teacher.png', get_lang('Teacher'));
@ -2607,7 +2691,7 @@ HOTSPOT;
// Admin can always delete the attempt
if (($locked == false || api_is_platform_admin()) && !api_is_student_boss()) {
$ip = Tracking::get_ip_from_user_event(
$results[$i]['exe_user_id'],
$attempt['exe_user_id'],
api_get_utc_datetime(),
false
);
@ -2620,14 +2704,14 @@ HOTSPOT;
http_build_query([
'id' => $id,
'exercise' => $exercise_id,
'user' => $results[$i]['exe_user_id'],
'user' => $attempt['exe_user_id'],
]);
$actions .= Display::url(
Display::return_icon('reload.png', get_lang('RecalculateResults')),
$recalculateUrl,
[
'data-exercise' => $exercise_id,
'data-user' => $results[$i]['exe_user_id'],
'data-user' => $attempt['exe_user_id'],
'data-id' => $id,
'class' => 'exercise-recalculate',
]
@ -2638,7 +2722,7 @@ HOTSPOT;
href="exercise_report.php?'.$cidReq.'&filter_by_user='.$filterByUser.'&filter='.$filter.'&exerciseId='.$exercise_id.'&delete=delete&did='.$id.'"
onclick="javascript:if(!confirm(\''.sprintf(
addslashes(get_lang('DeleteAttempt')),
$results[$i]['username'],
$attempt['username'],
$dt
).'\')) return false;">';
$delete_link .= Display::return_icon(
@ -2658,7 +2742,7 @@ HOTSPOT;
$actions .= $delete_link;
}
} else {
$attempt_url = api_get_path(WEB_CODE_PATH).'exercise/result.php?'.$cidReq.'&id='.$results[$i]['exe_id'];
$attempt_url = api_get_path(WEB_CODE_PATH).'exercise/result.php?'.$cidReq.'&id='.$attempt['exe_id'];
$attempt_link = Display::url(
get_lang('Show'),
$attempt_url,
@ -2675,17 +2759,17 @@ HOTSPOT;
foreach ($userExtraFieldsToAdd as $variable) {
$extraFieldValue = new ExtraFieldValue('user');
$values = $extraFieldValue->get_values_by_handler_and_field_variable(
$results[$i]['user_id'],
$attempt['user_id'],
$variable
);
if (isset($values['value'])) {
$results[$i][$variable] = $values['value'];
$attempt[$variable] = $values['value'];
}
}
}
$exeId = $results[$i]['exe_id'];
$results[$i]['id'] = $exeId;
$exeId = $attempt['exe_id'];
$attempt['id'] = $exeId;
$category_list = [];
if ($is_allowedToEdit) {
$sessionName = '';
@ -2698,7 +2782,14 @@ HOTSPOT;
}
}
$objExercise = new Exercise($course_id);
$courseId = $courseItemInfo['real_id'];
if ($searchAllTeacherCourses) {
$attempt['course'] = $courseItemInfo['title'];
$attempt['exercise'] = $attempt['title'];
}
$objExercise = new Exercise($courseId);
if ($showExerciseCategories) {
// Getting attempt info
$exercise_stat_info = $objExercise->get_stat_track_exercise_info_by_exe_id($exeId);
@ -2779,8 +2870,8 @@ HOTSPOT;
$thousandSeparator,
$roundValues
);
$results[$i]['category_'.$categoryId] = $scoreToDisplay;
$results[$i]['category_'.$categoryId.'_score_percentage'] = self::show_score(
$attempt['category_'.$categoryId] = $scoreToDisplay;
$attempt['category_'.$categoryId.'_score_percentage'] = self::show_score(
$result['score'],
$result['total'],
true,
@ -2791,14 +2882,14 @@ HOTSPOT;
$thousandSeparator,
$roundValues
);
$results[$i]['category_'.$categoryId.'_only_score'] = $result['score'];
$results[$i]['category_'.$categoryId.'_total'] = $result['total'];
$attempt['category_'.$categoryId.'_only_score'] = $result['score'];
$attempt['category_'.$categoryId.'_total'] = $result['total'];
}
$results[$i]['session'] = $sessionName;
$results[$i]['session_access_start_date'] = $sessionStartAccessDate;
$results[$i]['status'] = $revisedLabel;
$results[$i]['score'] = $score;
$results[$i]['score_percentage'] = self::show_score(
$attempt['session'] = $sessionName;
$attempt['session_access_start_date'] = $sessionStartAccessDate;
$attempt['status'] = $revisedLabel;
$attempt['score'] = $score;
$attempt['score_percentage'] = self::show_score(
$my_res,
$my_total,
true,
@ -2827,7 +2918,7 @@ HOTSPOT;
);
}
$results[$i]['only_score'] = $onlyScore;
$attempt['only_score'] = $onlyScore;
if ($roundValues) {
$whole = floor($my_total); // 1
@ -2845,15 +2936,15 @@ HOTSPOT;
$thousandSeparator
);
}
$results[$i]['total'] = $onlyTotal;
$results[$i]['lp'] = $lp_name;
$results[$i]['actions'] = $actions;
$listInfo[] = $results[$i];
$attempt['total'] = $onlyTotal;
$attempt['lp'] = $lp_name;
$attempt['actions'] = $actions;
$listInfo[] = $attempt;
} else {
$results[$i]['status'] = $revisedLabel;
$results[$i]['score'] = $score;
$results[$i]['actions'] = $actions;
$listInfo[] = $results[$i];
$attempt['status'] = $revisedLabel;
$attempt['score'] = $score;
$attempt['actions'] = $actions;
$listInfo[] = $attempt;
}
}
}

@ -157,21 +157,7 @@ class Tracking
}
$hideTime = api_get_configuration_value('hide_lp_time');
$allowNewTracking = api_get_configuration_value('use_new_tracking_in_lp_item');
$lp_id = (int) $lp_id;
if ($allowNewTracking) {
$extraField = new ExtraFieldValue('lp');
$result = $extraField->get_values_by_handler_and_field_variable($lp_id, 'track_lp_item');
if (empty($result)) {
$allowNewTracking = false;
} else {
if (isset($result['value']) && $result['value'] == 1) {
$allowNewTracking = true;
}
}
}
$lp_item_id = (int) $lp_item_id;
$user_id = (int) $user_id;
$session_id = (int) $session_id;
@ -383,7 +369,7 @@ class Tracking
$time_for_total = 0;
$attemptResult = 0;
if ($allowNewTracking && $timeCourse) {
if ($timeCourse) {
if (isset($timeCourse['learnpath_detailed']) &&
isset($timeCourse['learnpath_detailed'][$lp_id]) &&
isset($timeCourse['learnpath_detailed'][$lp_id][$my_item_id])
@ -476,7 +462,7 @@ class Tracking
$extend_attempt_link = '';
$extend_this_attempt = 0;
if ($allowNewTracking && $timeCourse) {
if ($timeCourse) {
//$attemptResult = 0;
if (isset($timeCourse['learnpath_detailed']) &&
isset($timeCourse['learnpath_detailed'][$lp_id]) &&
@ -534,17 +520,14 @@ class Tracking
$attemptTime = $row['mytime'];
if ($minimumAvailable) {
$lp_time = $timeCourse[TOOL_LEARNPATH];
/*$lp_time = $timeCourse[TOOL_LEARNPATH];
$lpTime = null;
if (isset($lp_time[$lp_id])) {
$lpTime = (int) $lp_time[$lp_id];
}
$time_for_total = $lpTime;
if ($allowNewTracking) {
$time_for_total = (int) $attemptResult;
$attemptTime = (int) $attemptResult;
}
$time_for_total = $lpTime;*/
$time_for_total = (int) $attemptResult;
$attemptTime = (int) $attemptResult;
}
$time = learnpathItem::getScormTimeFromParameter('js', $attemptTime);
@ -765,10 +748,6 @@ class Tracking
$subtotal_time += $tmp_row['mytime'];
}
if ($allowNewTracking) {
$subtotal_time = $attemptResult;
}
$title = $row['mytitle'];
// Selecting the exe_id from stats attempts tables in order to look the max score value.
$sql = 'SELECT * FROM '.$tbl_stats_exercices.'

@ -1129,12 +1129,22 @@ class IndexManager
];
}
if (api_get_configuration_value('my_courses_show_pending_work') && api_is_teacher()) {
$items[] = [
'icon' => Display::return_icon('work.png', get_lang('StudentPublicationToCorrect')),
'link' => api_get_path(WEB_CODE_PATH).'work/pending.php',
'title' => get_lang('StudentPublicationToCorrect'),
];
if (api_is_teacher()) {
if (api_get_configuration_value('my_courses_show_pending_work')) {
$items[] = [
'icon' => Display::return_icon('work.png', get_lang('StudentPublicationToCorrect')),
'link' => api_get_path(WEB_CODE_PATH).'work/pending.php',
'title' => get_lang('StudentPublicationToCorrect'),
];
}
if (api_get_configuration_value('my_courses_show_pending_exercise_attempts')) {
$items[] = [
'icon' => Display::return_icon('quiz.png', get_lang('PendingAttempts')),
'link' => api_get_path(WEB_CODE_PATH).'exercise/pending.php',
'title' => get_lang('PendingAttempts'),
];
}
}
return $items;

@ -1159,10 +1159,6 @@ $_configuration['profile_fields_visibility'] = [
*/
//$_configuration['lp_minimum_time'] = false;
// Track LP attempts using the new tracking system.
// Requires to add an LP extra field called "track_lp_item" (checkbox) in order to use this feature.
//$_configuration['use_new_tracking_in_lp_item'] = false;
// Add collapsable option for user course categories
// ALTER TABLE user_course_category ADD collapsed TINYINT(1) DEFAULT NULL;
// $_configuration['allow_user_course_category_collapsable'] = false;
@ -1851,6 +1847,9 @@ ALTER TABLE gradebook_comment ADD CONSTRAINT FK_C3B70763AD3ED51C FOREIGN KEY (gr
// Show a link to the work/pending.php page in my courses (user_portal)
//$_configuration['my_courses_show_pending_work'] = true;
// Show exercise report from all courses in a new page: exercise/pending.php
//$_configuration['my_courses_show_pending_exercise_attempts'] = true;
// KEEP THIS AT THE END
// -------- Custom DB changes
// Add user activation by confirmation email

@ -1,27 +1,30 @@
# The Azure Active Directory Plugin
Allow authentication (with OAuth2) with Microsoft's Azure Active Directory.
This plugin add two extra fields for users:
This plugin adds two extra fields for users:
- `organisationemail`, the email registered in Azure Active Directory for each user.
- `azure_id`, to save the internal ID for each user in Azure.
> This plugin use the [`thenetworg/oauth2-azure`](https://github.com/TheNetworg/oauth2-azure) package.
> This plugin uses the [`thenetworg/oauth2-azure`](https://github.com/TheNetworg/oauth2-azure) package.
### Prerequisites
This plugin will *not* work if you do not use HTTPS. Make sure your portal is in HTTPS before you configure this plugin.
### To configure Azure Active Directory
* Create and configure an application.
* In _Authentication_ section, set an _Reply URL_ with `https://{CHAMILO_URL}/plugin/azure_active_directory/src/callback.php`.
* In _Certificates & secrets_, create a secret string (or application password). And keep copied.
* Create and configure an application in your Azure panel (Azure Active Directory -> Applications registration -> New registration))
* In the _Authentication_ section, set an _Reply URL_ with `https://{CHAMILO_URL}/plugin/azure_active_directory/src/callback.php`.
* In _Certificates & secrets_, create a secret string (or application password). Keep the _Value_ field at hand.
### To configure this plugin
* _Enable_
* _Application ID_: Enter the Application Id assinged to your app by the Azure portal.
* _Application secret_: Enter the client secret created.
* _Application ID_: Enter the Application Id assigned to your app by the Azure portal.
* _Application secret_: Enter the client secret created in _Certificate & secrets_ above.
* _Block name_: (Optional) The name to show above the login button.
* _Force logout button_: (Optional) Add a button to force logout from Azure.
* _Management login_: (Optional) Disable the chamilo login and enable an alternative login page for users.
You will need copy the `/plugin/azure_active_directory/layout/login_form.tpl` file to `/main/template/overrides/layout/` directory.
* _Name for the management login_: A name for the management login. By default is "Management Login".
* And assign a region. Preferably `login_bottom`.
* _Name for the management login_: A name for the manager login. By default, it is set to "Management Login".
* Assign a region in which the login option will appear. Preferably `login_bottom`.
Also, you can configure the external login to work with the classic Chamilo form login.
Adding this line in `configuration.php` file.

Loading…
Cancel
Save