Skip to content

Commit

Permalink
MDL-82120 core_grades: Grade penalty setting
Browse files Browse the repository at this point in the history
  • Loading branch information
Nathan Nguyen committed Jun 23, 2024
1 parent ad7fc69 commit 79095d3
Show file tree
Hide file tree
Showing 29 changed files with 2,045 additions and 1 deletion.
2 changes: 2 additions & 0 deletions UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ The format of this change log follows the advice given at [Keep a CHANGELOG](htt

### core

- Modules using the grade penalty MUST declare their use of it with the xxx_supports() flag FEATURE_GRADE_HAS_PENALTY.

#### Removed

- The previously deprecated function `search_generate_text_SQL` has been removed and can no longer be used.
Expand Down
38 changes: 37 additions & 1 deletion admin/settings/grades.php
Original file line number Diff line number Diff line change
Expand Up @@ -221,5 +221,41 @@
}
}

} // end of speedup
// Penalty.
$ADMIN->add('grades', new admin_category('gradepenalty', new lang_string('gradepenalty', 'grades')));

// General settings for penalty.
$temp = new admin_settingpage('penaltysettings', new lang_string('gradepenalty_general_settings', 'grades'),
'moodle/grade:manage');
if ($ADMIN->fulltree) {
// Enable.
$temp->add(new admin_setting_configcheckbox('gradepenalty_enabled',
new lang_string('gradepenalty_enabled', 'grades'),
new lang_string('gradepenalty_enabled_help', 'grades'), 0));
// List of modules which support penalty.
$supported = core_grades\local\penalty\manager::get_supported_modules();
$temp->add(new admin_setting_configmultiselect('gradepenalty_supportedmodules',
new lang_string('gradepenalty_supportedmodules', 'grades'),
new lang_string('gradepenalty_supportedmodules_help', 'grades'), $supported, $supported));
}
$ADMIN->add('gradepenalty', $temp);

if (get_config('core', 'gradepenalty_enabled')) {
// External page to manage the penalty plugins.
$temp = new admin_externalpage(
'managepenaltyplugins',
get_string('managepenaltyplugins', 'grades'),
new moodle_url('/grade/penalty/manage_penalty_plugins.php'),
'moodle/grade:manage'
);
$ADMIN->add('gradepenalty', $temp);

// Settings from each penalty plugin.
foreach (core_component::get_plugin_list('gradepenalty') as $plugin => $plugindir) {
// Include all the settings commands for this plugin if there are any.
if (file_exists($plugindir.'/settings.php')) {
include($plugindir.'/settings.php');
}
}
}
} // end of speedup
74 changes: 74 additions & 0 deletions grade/classes/hook/after_penalty_applied.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?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 core_grades\hook;

use Psr\EventDispatcher\StoppableEventInterface;
/**
* Hook after penalty is applied.
*
* This hook will be dispatched after the penalty is applied to the grade.
*
* @package core_grades
* @copyright 2024 Catalyst IT Australia Pty Ltd
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
#[\core\attribute\label('Notify that the penalty has been applied to a given grade.')]
#[\core\attribute\tags('grade')]
class after_penalty_applied implements StoppableEventInterface {
/**
* Constructor for the hook.
*
* @param int $courseid The course id.
* @param string $itemtype The type of the grade item.
* @param string $itemmodule The module of the grade item.
* @param int $iteminstance The instance of the grade item.
* @param int $itemnumber The number of the grade item.
* @param int $userid the user id
*/
public function __construct(
/** @var int The course id */
public readonly int $courseid,
/** @var string The type of the grade item */
public readonly string $itemtype,
/** @var string The module of the grade item */
public readonly string $itemmodule,
/** @var int The instance of the grade item */
public readonly int $iteminstance,
/** @var int The number of the grade item */
public readonly int $itemnumber,
/** @var int The course id */
public readonly int $userid,
) {
}

/**
* Should the next listener be called?
*
* @return bool
*/
public function isPropagationStopped(): bool {
return $this->stopped;
}

/**
* Stop the propagation of the event.
*
*/
public function stop(): void {
$this->stopped = true;
}
}
117 changes: 117 additions & 0 deletions grade/classes/hook/before_penalty_applied.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?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 core_grades\hook;

use Psr\EventDispatcher\StoppableEventInterface;

/**
* Hook before penalty is applied.
*
* This hook will be dispatched before the penalty is applied to the grade.
*
* @package core_grades
* @copyright 2024 Catalyst IT Australia Pty Ltd
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
#[\core\attribute\label('Allows plugins to add required data before the penalty is applied to the grade.')]
#[\core\attribute\tags('grade')]
class before_penalty_applied implements StoppableEventInterface {
/** @var int submission date*/
protected int $submissiondate = 0;

/** @var int due date */
protected int $duedate = 0;

/**
* Constructor for the hook.
*
* @param int $courseid The course id.
* @param string $itemtype The type of the grade item.
* @param string $itemmodule The module of the grade item.
* @param int $iteminstance The instance of the grade item.
* @param int $itemnumber The number of the grade item.
* @param int $userid the user id
*/
public function __construct(
/** @var int The course id */
public readonly int $courseid,
/** @var string The type of the grade item */
public readonly string $itemtype,
/** @var string The module of the grade item */
public readonly string $itemmodule,
/** @var int The instance of the grade item */
public readonly int $iteminstance,
/** @var int The number of the grade item */
public readonly int $itemnumber,
/** @var int The course id */
public readonly int $userid,
) {
}

/**
* Set the submission date.
*
* @param int $submissiondate The submission date.
*/
public function set_submission_date(int $submissiondate): void {
$this->submissiondate = $submissiondate;
}

/**
* Set the due date.
*
* @param int $duedate The due date.
*/
public function set_due_date(int $duedate): void {
$this->duedate = $duedate;
}

/**
* Get the submission date.
*
* @return int The submission date.
*/
public function get_submission_date(): int {
return $this->submissiondate;
}

/**
* Get the due date.
*
* @return int The due date.
*/
public function get_due_date(): int {
return $this->duedate;
}

/**
* Should the next listener be called?
*
* @return bool
*/
public function isPropagationStopped(): bool {
return $this->stopped;
}

/**
* Stop the propagation of the event.
*
*/
public function stop(): void {
$this->stopped = true;
}
}
112 changes: 112 additions & 0 deletions grade/classes/local/penalty/grade_penalty.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<?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/>.

/**
* Grade penalty abstract class.
*
* @package core_grades
* @copyright 2024 Catalyst IT Australia Pty Ltd
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

namespace core_grades\local\penalty;

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

use grade_item;
use stdClass;

require_once($CFG->libdir.'/gradelib.php');

/**
* Grade penalty abstract class.
*
* @package core_grades
* @copyright 2024 Catalyst IT Australia Pty Ltd
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
abstract class grade_penalty {
/** @var stdClass The course moudule object */
public readonly stdClass $cm;

/**
* Constructor for the hook.
*
* @param int $courseid The course id.
* @param string $itemtype The type of the grade item.
* @param string $itemmodule The module of the grade item.
* @param int $iteminstance The instance of the grade item.
* @param int $itemnumber The number of the grade item.
* @param int $userid the user id
*/
public function __construct(
/** @var int The course id */
public readonly int $courseid,
/** @var string The type of the grade item */
public readonly string $itemtype,
/** @var string The module of the grade item */
public readonly string $itemmodule,
/** @var int The instance of the grade item */
public readonly int $iteminstance,
/** @var int The number of the grade item */
public readonly int $itemnumber,
/** @var int The course id */
public readonly int $userid,
/** @var int The submission date */
public readonly int $submissiondate,
/** @var int The due date */
public readonly int $duedate,
) {
// Course module required to get the penalty rules.
$this->cm = get_coursemodule_from_instance($itemmodule, $iteminstance, $courseid);
}

/**
* Mark will be deducted from student grade.
*
* @return float
*/
abstract public function calculate_penalty($finalgrade): float;

/**
* Apply penalty to the grade.
*
* @return bool return true if penalty is applied successfully.
*/
final public function apply_penalty(): bool {
// Fetch the grade item.
$gradeitem = grade_item::fetch(
[
'courseid' => $this->courseid,
'itemtype' => $this->itemtype,
'itemmodule' => $this->itemmodule,
'iteminstance' => $this->iteminstance,
'itemnumber' => $this->itemnumber,
]
);

// Get the final grade. It returns a single grade object as we specify the user id.
$usergrade = $gradeitem->get_final($this->userid);
$finalgrade = $usergrade->finalgrade;

// Calculate the penalty.
$deductedgrade = $this->calculate_penalty($finalgrade);
$finalgrade -= $deductedgrade;

// Update the final grade.
return $gradeitem->update_final_grade($this->userid, $finalgrade);
}
}
Loading

0 comments on commit 79095d3

Please sign in to comment.