diff --git a/lbplanner/classes/enums/CAPABILITY.php b/lbplanner/classes/enums/CAPABILITY.php index ef195f00..cf37d86c 100644 --- a/lbplanner/classes/enums/CAPABILITY.php +++ b/lbplanner/classes/enums/CAPABILITY.php @@ -54,6 +54,11 @@ class CAPABILITY extends Enum { */ const STUDENT = 'local/lb_planner:student'; + /** + * Shortname of the slotmaster CAPABILITY. + */ + const SLOTMASTER = 'local/lb_planner:slotmaster'; + /** * Matches a capability string to its bitmappable flag * @param string $str the capability string diff --git a/lbplanner/classes/enums/CAPABILITY_FLAG.php b/lbplanner/classes/enums/CAPABILITY_FLAG.php index 88d06fe6..5728405d 100644 --- a/lbplanner/classes/enums/CAPABILITY_FLAG.php +++ b/lbplanner/classes/enums/CAPABILITY_FLAG.php @@ -54,6 +54,11 @@ class CAPABILITY_FLAG extends Enum { */ const STUDENT = 8; + /** + * Flag of the slotmaster CAPABILITY. + */ + const SLOTMASTER = 16; + /** * matches a flag to its capability string * @param int $num the bitmappable flag diff --git a/lbplanner/classes/helpers/slot_helper.php b/lbplanner/classes/helpers/slot_helper.php index f642ad53..980da3e5 100644 --- a/lbplanner/classes/helpers/slot_helper.php +++ b/lbplanner/classes/helpers/slot_helper.php @@ -25,10 +25,13 @@ namespace local_lbplanner\helpers; +use core\context\system as context_system; + use DateInterval; use DateTime; use DateTimeImmutable; use DateTimeInterface; +use local_lbplanner\enums\CAPABILITY; use local_lbplanner\enums\WEEKDAY; use local_lbplanner\model\{slot, reservation, slot_filter}; @@ -372,15 +375,37 @@ public static function amend_date_with_unit_time(int $unit, DateTimeInterface $d } /** - * Checks whether a user is supervisor for a specific slot. + * Checks whether a user has supervisor-level permissions for a specific slot. + * NOTE: The user in question does not necessarily literally be the slot's supervisor, just have sufficient permissions! * @param int $supervisorid userid of the supervisor in question * @param int $slotid the slot to check * - * @return bool Whether this user is supervisor for this slot + * @return bool Whether this user has perms for this slot */ public static function check_slot_supervisor(int $supervisorid, int $slotid): bool { global $DB; + $context = context_system::instance(); + if ( + has_capability(CAPABILITY::ADMIN, $context, $supervisorid) + || has_capability(CAPABILITY::SLOTMASTER, $context, $supervisorid) + ) { + return true; + } + return $DB->record_exists(self::TABLE_SUPERVISORS, ['userid' => $supervisorid, 'slotid' => $slotid]); } + + /** + * Same as {@see check_slot_supervisor()}, except it throws an error if permissions are insufficient. + * @param int $supervisorid userid of the supervisor in question + * @param int $slotid the slot to check + * + * @throws \moodle_exception if the user has insufficient permissions + */ + public static function assert_slot_supervisor(int $supervisorid, int $slotid): void { + if (!self::check_slot_supervisor($supervisorid, $slotid)) { + throw new \moodle_exception('Insufficient Permission: you\'re not supervisor of this slot'); + } + } } diff --git a/lbplanner/db/access.php b/lbplanner/db/access.php index 921734bc..c0fa9e87 100644 --- a/lbplanner/db/access.php +++ b/lbplanner/db/access.php @@ -46,4 +46,9 @@ 'captype' => 'write', 'contextlevel' => CONTEXT_SYSTEM, ], + 'local/lb_planner:slotmaster' => [ + 'riskbitmask' => RISK_SPAM || RISK_PERSONAL, + 'captype' => 'write', + 'contextlevel' => CONTEXT_SYSTEM, + ], ]; diff --git a/lbplanner/services/slots/add_slot_filter.php b/lbplanner/services/slots/add_slot_filter.php index 2b87a5c3..fdc7b29b 100644 --- a/lbplanner/services/slots/add_slot_filter.php +++ b/lbplanner/services/slots/add_slot_filter.php @@ -84,9 +84,7 @@ public static function add_slot_filter(int $slotid, ?int $courseid, ?string $vin ); // Check if user is supervisor for this slot, throw error if not. - if (!slot_helper::check_slot_supervisor($USER->id, $slotid)) { - throw new \moodle_exception('Insufficient Permission: you\'re not supervisor of this slot'); - } + slot_helper::assert_slot_supervisor($USER->id, $slotid); // Ensure that either $courseid or $vintage are non-null. if (is_null($courseid) && is_null($vintage)) { throw new \moodle_exception('courseid and vintage can\'t both be null'); diff --git a/lbplanner/services/slots/add_slot_supervisor.php b/lbplanner/services/slots/add_slot_supervisor.php index beafa729..ff106a8d 100644 --- a/lbplanner/services/slots/add_slot_supervisor.php +++ b/lbplanner/services/slots/add_slot_supervisor.php @@ -71,9 +71,7 @@ public static function add_slot_supervisor(int $userid, int $slotid): void { ); // Check if current user is supervisor for this slot, throw error if not. - if (!slot_helper::check_slot_supervisor($USER->id, $slotid)) { - throw new \moodle_exception('Insufficient Permission: you\'re not supervisor of this slot'); - } + slot_helper::assert_slot_supervisor($USER->id, $slotid); // Add supervisor. $DB->insert_record( diff --git a/lbplanner/services/slots/book_reservation.php b/lbplanner/services/slots/book_reservation.php index de049625..8b118905 100644 --- a/lbplanner/services/slots/book_reservation.php +++ b/lbplanner/services/slots/book_reservation.php @@ -103,10 +103,7 @@ public static function book_reservation(int $slotid, string $date, int $userid): $student = $USER; } else { // Supervisor reserving slot for student. - - if (!slot_helper::check_slot_supervisor($USER->id, $slotid)) { - throw new \moodle_exception('Forbidden: you\'re not a supervisor of this slot'); - } + slot_helper::assert_slot_supervisor($USER->id, $slotid); $maxdays = slot_helper::RESERVATION_RANGE_USER; $student = core_user::get_user($userid, '*', MUST_EXIST); diff --git a/lbplanner/services/slots/delete_slot.php b/lbplanner/services/slots/delete_slot.php index 17caf4d7..9412abd4 100644 --- a/lbplanner/services/slots/delete_slot.php +++ b/lbplanner/services/slots/delete_slot.php @@ -63,9 +63,7 @@ public static function delete_slot(int $slotid): void { ); // Check if user is supervisor for this slot, throw error if not. - if (!slot_helper::check_slot_supervisor($USER->id, $slotid)) { - throw new \moodle_exception('Insufficient Permission: you\'re not supervisor of this slot'); - } + slot_helper::assert_slot_supervisor($USER->id, $slotid); // Notify affected users. $reservations = slot_helper::get_reservations_for_slot($slotid); diff --git a/lbplanner/services/slots/get_slot_filters.php b/lbplanner/services/slots/get_slot_filters.php index bcd91046..26e0cbde 100644 --- a/lbplanner/services/slots/get_slot_filters.php +++ b/lbplanner/services/slots/get_slot_filters.php @@ -63,9 +63,7 @@ public static function get_slot_filters(int $slotid): array { ); // Check if user is supervisor for this slot, throw error if not. - if (!slot_helper::check_slot_supervisor($USER->id, $slotid)) { - throw new \moodle_exception('Insufficient Permission: you\'re not supervisor of this slot'); - } + slot_helper::assert_slot_supervisor($USER->id, $slotid); // Get all filters for this slot, and return their API representations. $filters = slot_helper::get_filters_for_slot($slotid); $filterdicts = []; diff --git a/lbplanner/services/slots/get_slot_reservations.php b/lbplanner/services/slots/get_slot_reservations.php index 0b390ba9..36f69462 100644 --- a/lbplanner/services/slots/get_slot_reservations.php +++ b/lbplanner/services/slots/get_slot_reservations.php @@ -53,9 +53,7 @@ public static function get_slot_reservations(int $slotid): array { ['slotid' => $slotid] ); - if (!slot_helper::check_slot_supervisor($USER->id, $slotid)) { - throw new \moodle_exception('Insufficient Permissions: not a supervisor of this slot'); - } + slot_helper::assert_slot_supervisor($USER->id, $slotid); $reservations = slot_helper::get_reservations_for_slot($slotid); diff --git a/lbplanner/services/slots/update_slot.php b/lbplanner/services/slots/update_slot.php index 7139da66..c5b0bb78 100644 --- a/lbplanner/services/slots/update_slot.php +++ b/lbplanner/services/slots/update_slot.php @@ -109,9 +109,7 @@ public static function update_slot(int $slotid, int $startunit, int $duration, i ); // Check if user is supervisor for this slot, throw error if not. - if (!slot_helper::check_slot_supervisor($USER->id, $slotid)) { - throw new \moodle_exception('Insufficient Permission: you\'re not supervisor of this slot'); - } + slot_helper::assert_slot_supervisor($USER->id, $slotid); // Replace slot's values with new values if not null. $slot = slot_helper::get_slot($slotid);