Skip to content

Commit

Permalink
MDL-82124 mod_assign: recalculate penalty
Browse files Browse the repository at this point in the history
  • Loading branch information
Nathan Nguyen committed Sep 10, 2024
1 parent 61c7308 commit a8bf331
Show file tree
Hide file tree
Showing 19 changed files with 618 additions and 28 deletions.
2 changes: 1 addition & 1 deletion grade/penalty/duedate/lang/en/gradepenalty_duedate.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@
$string['privacy:metadata:gradepenalty_duedate_rule'] = 'Grade penalty due date table';
$string['privacy:metadata:gradepenalty_duedate_rule:usermodified'] = 'User who modified the rule';
$string['recalculatepenalty'] = 'Penalty recalculation';
$string['resetconfirm'] = 'This will remove all rules set up for this context. Are you sure you want to continue?';
$string['recalculatepenalty_help'] = 'Recalculate and apply penalties for all submissions in this context.';
$string['recalculatepenaltybutton'] = 'Update grades';
$string['recalculatepenaltyconfirm'] = 'This will recalculate and apply penalties for all submissions in this context. Are you sure you want to continue?';
$string['recalculatepenaltysuccess'] = 'Successfully initiated penalty recalculation. There may be a delay before grades are updated.';
$string['resetconfirm'] = 'This will remove all rules set up for this context. Are you sure you want to continue?';
2 changes: 2 additions & 0 deletions lang/en/grades.php
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,8 @@
$string['modgradeerrorbadpoint'] = 'Invalid grade value. This must be an integer between 1 and {$a}';
$string['modgradeerrorbadscale'] = 'Invalid scale selected. Please make sure you select a scale from the selections below.';
$string['modgrademaxgrade'] = 'Maximum grade';
$string['modgraderecalculatepenalty'] = 'Recalculate penalty';
$string['modgraderecalculatepenalty_help'] = 'The penalty will be recalculated for all users.';
$string['modgraderescalegrades'] = 'Rescale existing grades';
$string['modgraderescalegrades_help'] = 'When changing the maximum grades on a gradebook item you need to specify whether or not this will cause existing percentage grades to change as well.
Expand Down
3 changes: 3 additions & 0 deletions mod/assign/amd/build/override_delete_modal.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions mod/assign/amd/build/override_delete_modal.min.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

165 changes: 165 additions & 0 deletions mod/assign/amd/src/override_delete_modal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
import * as CustomEvents from 'core/custom_interaction_events';
import Modal from 'core/modal';

// Custom modal.
let modal = null;

const SELECTORS = {
DELETE_BUTTONS: '.delete-override',
RECACULATION_CHECKBOX: '#recalculatepenalties',
};

/**
* Custom Modal
*/
export default class OverrideDeleteModal extends Modal {
static TYPE = "mod_assign/override_delete_modal";
static TEMPLATE = "mod_assign/override_delete_modal";

/**
* Register the modal type.
* @param {string} confirmMessage The message to display in the modal.
* @param {boolean} showRecalculationCheckBox Whether to show the recalculation checkbox.
* @returns {Promise<void>}
*/
static async init(confirmMessage, showRecalculationCheckBox) {
// Create the modal.
modal = await OverrideDeleteModal.create({
templateContext: {
confirmmessage: confirmMessage,
showpenaltyrecalculation: showRecalculationCheckBox,
},
});

// Add event listeners.
document.querySelectorAll(SELECTORS.DELETE_BUTTONS).forEach(button => {
button.addEventListener('click', async(event) => {
event.preventDefault();
modal.setOverrideId(button.getAttribute('data-overrideid'));
modal.setSessionKey(button.getAttribute('data-sesskey'));
modal.show();
});
});
}

/**
* Configure the modal.
*
* @param {Object} modalConfig
*/
configure(modalConfig) {
// Add question modals are always large.
modalConfig.large = true;

// Always show on creation.
modalConfig.show = false;
modalConfig.removeOnClose = false;

// Apply standard configuration.
super.configure(modalConfig);
}

/**
* Constructor.
* Set required data to null.
*
* @param {HTMLElement} root
*/
constructor(root) {
super(root);

// Recalculate penalties checkbox.
this.recalculationCheckbox = this.getModal().find(SELECTORS.RECACULATION_CHECKBOX);

// Data.
this.setOverrideId(null);
this.setSessionKey(null);
}

/**
* Set the override id.
*
* @param {number} id The override id.
*/
setOverrideId(id) {
this.overrideId = id;
}

/**
* Get the override id.
*
* @returns {*}
*/
getOverrideId() {
return this.overrideId;
}

/**
* Set the session key.
*
* @param {string} key
*/
setSessionKey(key) {
this.sessionKey = key;
}

/**
* Get the session key.
*
* @returns {*}
*/
getSessionKey() {
return this.sessionKey;
}

/**
* Register events.
*
*/
registerEventListeners() {
// Apply parent event listeners.
super.registerEventListeners(this);

// Register to close on cancel.
this.registerCloseOnCancel();

// Register the delete action.
this.getModal().on(CustomEvents.events.activate, this.getActionSelector('delete'), () => {
this.deleteOverride();
});
}

/**
* Delete a override.
*
*/
deleteOverride() {
// Check if the recalculation checkbox is checked.
const recalculate = this.recalculationCheckbox.prop('checked');

// Redirect to the delete URL.
window.location.href = M.cfg.wwwroot + '/mod/assign/overridedelete.php?id=' + this.getOverrideId() +
'&sesskey=' + this.getSessionKey() + '&confirm=1'
+ (recalculate ? '&recalculate=1' : '');

// Hide the modal.
this.hide();
}

/**
* Reset the modal data when hiding.
*
*/
hide() {
// Reset the data.
this.setOverrideId(null);
this.setSessionKey(null);

// Reset the recalculation checkbox.
this.recalculationCheckbox.prop('checked', false);

super.hide();
}
}

OverrideDeleteModal.registerModalType();
59 changes: 59 additions & 0 deletions mod/assign/classes/hook/hook_callbacks.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

namespace mod_assign\hook;

use core_grades\hook\before_penalty_recalculation;
use mod_assign\task\recalculate_penalties;

defined('MOODLE_INTERNAL') || die();

require_once($CFG->dirroot . '/mod/assign/locallib.php');

/**
* Hook callbacks.
*
* @package mod_assign
* @copyright 2024 Catalyst IT Australia
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class hook_callbacks {

/**
* Callback for before_penalty_recalculation.
*
* @param before_penalty_recalculation $hook
* @return void
*/
public static function extend_penalty_recalculation(before_penalty_recalculation $hook): void {
global $DB;

switch ($hook->context->contextlevel) {
case CONTEXT_MODULE:
$cmid = $hook->context->instanceid;
$cm = get_coursemodule_from_id('assign', $cmid, 0, false, MUST_EXIST);
recalculate_penalties::queue($cm->instance, $hook->usermodified);
break;
case CONTEXT_COURSE:
$courseid = $hook->context->instanceid;
$assigns = $DB->get_records('assign', ['course' => $courseid]);
foreach ($assigns as $assign) {
recalculate_penalties::queue($assign->id, $hook->usermodified);
}
break;
}
}
}
66 changes: 66 additions & 0 deletions mod/assign/classes/task/recalculate_penalties.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

namespace mod_assign\task;

defined('MOODLE_INTERNAL') || die();

require_once($CFG->dirroot . '/mod/assign/lib.php');
require_once($CFG->dirroot.'/course/lib.php');

use core\exception\moodle_exception;
use core\task\adhoc_task;

/**
* Ad-hoc task to recalculate penalties for users in an assignment.
*
* @package mod_assign
* @copyright 2024 David Woloszyn <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class recalculate_penalties extends adhoc_task {

/**
* Execute the task.
*/
public function execute(): void {
global $DB;
try {
$assignid = $this->get_custom_data()->assignid;
$assign = $DB->get_record('assign', ['id' => $assignid], '*', MUST_EXIST);
$cm = get_coursemodule_from_instance('assign', $assignid, 0, false, MUST_EXIST);
$assign->cmidnumber = $cm->idnumber;
assign_update_grades($assign);
} catch (moodle_exception $e) {
debugging($e->getMessage(), DEBUG_DEVELOPER);
}
}

/**
* Queue the task.
*
* @param int $assignid assignment id
* @param int $usermodified user who triggered the recalculation
*/
public static function queue(int $assignid, int $usermodified): void {
$task = new self();
$task->set_custom_data((object)[
'assignid' => $assignid,
'usermodified' => $usermodified,
]);
\core\task\manager::queue_adhoc_task($task);
}
}
Loading

0 comments on commit a8bf331

Please sign in to comment.