+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since 3.1
+ */
+define(['jquery', 'core/ajax', 'core/str', 'core/notification'],
+ function($, ajax, str, notification) {
+ return /** @alias module:report_progress/completion_override */ {
+
+ /**
+ * Change the activity completion state.
+ *
+ * @method change
+ */
+ update: function() {
+
+ $('#completion-progress a.changecompl').on('click', function(e) {
+ e.preventDefault();
+
+ var el = $(this);
+ var changecompl = el.data('changecompl');
+ var changecomplfields = changecompl.split('-');
+ var userid = changecomplfields[0];
+ var cmid = changecomplfields[1];
+ var newstate = changecomplfields[2];
+ var newstatestr = (newstate == 1) ? 'completion-y' : 'completion-n';
+
+ str.get_strings([
+ {key: newstatestr, component: 'completion'}
+ ]).done(function(strings) {
+ str.get_strings([
+ {key: 'confirm', component: 'moodle'},
+ {key: 'areyousureoverridecompletion', component: 'completion', param: strings[0]},
+ {key: 'yes', component: 'moodle'},
+ {key: 'cancel', component: 'moodle'}
+ ]).done(function(strings) {
+ notification.confirm(
+ strings[0], // Confirm.
+ strings[1], // Message.
+ strings[2], // Yes.
+ strings[3], // Cancel.
+ function() {
+ el.append('');
+
+ var promise = ajax.call([{
+ methodname: 'core_completion_override_activity_completion_status',
+ args: {
+ userid: userid, cmid: cmid, newstate: newstate
+ }
+ }]);
+
+ promise[0].then(function(results) {
+ el.data('changecompl', results.changecompl);
+ el.attr('data-changecompl', results.changecompl);
+ el.children("img").replaceWith(results.img);
+ $('.ajaxworking').remove();
+ }).fail(notification.exception);
+ }
+ );
+ }).fail(notification.exception);
+ }).fail(notification.exception);
+
+ });
+ }
+ };
+});
diff --git a/report/progress/index.php b/report/progress/index.php
index 2895e1343f1..064461cacc0 100644
--- a/report/progress/index.php
+++ b/report/progress/index.php
@@ -51,6 +51,9 @@ $sifirst = optional_param('sifirst', 'all', PARAM_NOTAGS);
$silast = optional_param('silast', 'all', PARAM_NOTAGS);
$start = optional_param('start', 0, PARAM_INT);
+// Action.
+$changecompl = optional_param('changecompl', '', PARAM_ALPHANUMEXT);
+
// Whether to show extra user identity information
$extrafields = get_extra_user_fields($context);
$leftcols = 1 + count($extrafields);
@@ -74,6 +77,12 @@ if ($format !== '') {
if ($start !== 0) {
$url->param('start', $start);
}
+if ($sifirst !== 'all') {
+ $url->param('sifirst', $sifirst);
+}
+if ($silast !== 'all') {
+ $url->param('silast', $silast);
+}
$PAGE->set_url($url);
$PAGE->set_pagelayout('report');
@@ -94,6 +103,20 @@ $reportsurl = $CFG->wwwroot.'/course/report.php?id='.$course->id;
$completion = new completion_info($course);
$activities = $completion->get_activities();
+if ($changecompl) {
+ if ($changecompl) {
+ require_capability('moodle/course:overridecompletion', $context);
+ require_sesskey();
+ list($userid, $cmid, $newstate) = preg_split('/-/', $changecompl, 3);
+ // Make sure the activity and user are tracked.
+ if (isset($activities[$cmid]) &&
+ $completion->get_num_tracked_users('u.id = :userid', array('userid' => (int)$userid), $group)) {
+ $completion->update_state($activities[$cmid], $newstate, $userid, true);
+ }
+ redirect($PAGE->url);
+ }
+}
+
if ($sifirst !== 'all') {
set_user_preference('ifirst', $sifirst);
}
@@ -173,6 +196,7 @@ if ($csv && $grandtotal && count($activities)>0) { // Only show CSV if there are
$PAGE->set_title($strcompletion);
$PAGE->set_heading($course->fullname);
echo $OUTPUT->header();
+ $PAGE->requires->js_call_amd('report_progress/completion_override', 'update');
// Handle groups (if enabled)
groups_print_course_menu($course,$CFG->wwwroot.'/report/progress/?course='.$course->id);
@@ -363,25 +387,40 @@ foreach($progress as $user) {
if (array_key_exists($activity->id,$user->progress)) {
$thisprogress=$user->progress[$activity->id];
$state=$thisprogress->completionstate;
+ $overrideby = $thisprogress->overrideby;
$date=userdate($thisprogress->timemodified);
} else {
$state=COMPLETION_INCOMPLETE;
+ $overrideby = 0;
$date='';
}
// Work out how it corresponds to an icon
switch($state) {
- case COMPLETION_INCOMPLETE : $completiontype='n'; break;
- case COMPLETION_COMPLETE : $completiontype='y'; break;
- case COMPLETION_COMPLETE_PASS : $completiontype='pass'; break;
- case COMPLETION_COMPLETE_FAIL : $completiontype='fail'; break;
+ case COMPLETION_INCOMPLETE :
+ $completiontype = 'n'.($overrideby ? '-override' : '');
+ break;
+ case COMPLETION_COMPLETE :
+ $completiontype = 'y'.($overrideby ? '-override' : '');
+ break;
+ case COMPLETION_COMPLETE_PASS :
+ $completiontype = 'pass';
+ break;
+ case COMPLETION_COMPLETE_FAIL :
+ $completiontype = 'fail';
+ break;
}
$completionicon='completion-'.
($activity->completion==COMPLETION_TRACKING_AUTOMATIC ? 'auto' : 'manual').
'-'.$completiontype;
- $describe = get_string('completion-' . $completiontype, 'completion');
+ if ($overrideby) {
+ $overridebyuser = $DB->get_record('user', array('id' => $overrideby), '*', MUST_EXIST);
+ $describe = get_string('completion-' . $completiontype, 'completion', fullname($overridebyuser));
+ } else {
+ $describe = get_string('completion-' . $completiontype, 'completion');
+ }
$a=new StdClass;
$a->state=$describe;
$a->date=$date;
@@ -392,8 +431,19 @@ foreach($progress as $user) {
if ($csv) {
print $sep.csv_quote($describe).$sep.csv_quote($date);
} else {
+ $celltext = '
';
+ if (has_capability('moodle/course:overridecompletion', $context) &&
+ $state != COMPLETION_COMPLETE_PASS && $state != COMPLETION_COMPLETE_FAIL) {
+ $newstate = ($state == COMPLETION_COMPLETE) ? COMPLETION_INCOMPLETE : COMPLETION_COMPLETE;
+ $changecompl = $user->id . '-' . $activity->id . '-' . $newstate;
+ $url = new moodle_url($PAGE->url, array('sesskey' => sesskey(),
+ 'changecompl' => $changecompl));
+ $celltext = html_writer::link($url, $celltext, array('class' => 'changecompl',
+ 'data-changecompl' => $changecompl));
+ }
print ''.
- $OUTPUT->pix_icon('i/' . $completionicon, $fulldescribe) . ' | ';
+ $celltext . '';
}
}
diff --git a/report/progress/styles.css b/report/progress/styles.css
index ede47d068dc..425d0674ef8 100644
--- a/report/progress/styles.css
+++ b/report/progress/styles.css
@@ -59,4 +59,9 @@
#page-report-progress-index .modicon {
padding-top: 5px;
}
+
+#page-report-progress-index #completion-progress td a .ajaxworking {
+ height: 16px;
+ background: url([[pix:i/ajaxloader]]) no-repeat;
+}
/*rtl:end:ignore*/
diff --git a/version.php b/version.php
index a8c58ddd6fb..0a6f2d6f3f8 100644
--- a/version.php
+++ b/version.php
@@ -29,7 +29,7 @@
defined('MOODLE_INTERNAL') || die();
-$version = 2017100600.00; // YYYYMMDD = weekly release date of this DEV branch.
+$version = 2017100600.01; // YYYYMMDD = weekly release date of this DEV branch.
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.