From e89e0ed2d80d87728ff81cd38950955e061729ea Mon Sep 17 00:00:00 2001 From: Riedler Date: Tue, 28 Jan 2025 18:27:50 +0100 Subject: [PATCH 01/25] fix: slot instantiation --- lbplanner/classes/helpers/slot_helper.php | 12 ++++++------ lbplanner/classes/model/slot.php | 16 ++++++++++++++++ lbplanner/classes/model/slot_filter.php | 14 ++++++++++++++ 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/lbplanner/classes/helpers/slot_helper.php b/lbplanner/classes/helpers/slot_helper.php index 24b4f2fd..c4e78dfe 100644 --- a/lbplanner/classes/helpers/slot_helper.php +++ b/lbplanner/classes/helpers/slot_helper.php @@ -109,7 +109,7 @@ public static function get_all_slots(): array { $slotsobj = []; foreach ($slots as $slot) { - array_push($slotsobj, new slot(...$slot)); + array_push($slotsobj, slot::from_db($slot)); } return $slotsobj; @@ -133,7 +133,7 @@ public static function get_supervisor_slots(int $supervisorid): array { $slotsobj = []; foreach ($slots as $slot) { - array_push($slotsobj, new slot(...$slot)); + array_push($slotsobj, slot::from_db($slot)); } return $slotsobj; @@ -151,7 +151,7 @@ public static function get_slots_by_room(string $room): array { $slotsobj = []; foreach ($slots as $slot) { - array_push($slotsobj, new slot(...$slot)); + array_push($slotsobj, slot::from_db($slot)); } return $slotsobj; @@ -167,7 +167,7 @@ public static function get_slot(int $slotid): slot { global $DB; $slot = $DB->get_record(self::TABLE_SLOTS, ['id' => $slotid]); - return new slot(...$slot); + return slot::from_db($slot); } /** @@ -197,7 +197,7 @@ public static function get_slot_filter(int $filterid): slot_filter { global $DB; $filter = $DB->get_record(self::TABLE_SLOT_FILTERS, ['id' => $filterid]); - return new slot_filter(...$filter); + return slot_filter::from_db($filter); } /** @@ -265,7 +265,7 @@ public static function get_filters_for_slot(int $slotid): array { $filtersobj = []; foreach ($filters as $filter) { - array_push($filtersobj, new slot_filter(...$filter)); + array_push($filtersobj, slot_filter::from_db($filter)); } return $filtersobj; diff --git a/lbplanner/classes/model/slot.php b/lbplanner/classes/model/slot.php index 17e22c70..6b35389a 100644 --- a/lbplanner/classes/model/slot.php +++ b/lbplanner/classes/model/slot.php @@ -105,6 +105,22 @@ public function __construct(int $id, int $startunit, int $duration, int $weekday $this->filters = null; } + /** + * Creates a slot object from a DB result + * @param \stdClass $obj the DB object + * @return slot the resulting slot object + */ + public static function from_db(\stdClass $obj): self { + return new slot( + $obj->id, + $obj->startunit, + $obj->duration, + $obj->weekday, + $obj->room, + $obj->size, + ); + } + /** * Mark the object as freshly created and sets the new ID * @param int $id the new ID after inserting into the DB diff --git a/lbplanner/classes/model/slot_filter.php b/lbplanner/classes/model/slot_filter.php index 68f9361a..e368cab8 100644 --- a/lbplanner/classes/model/slot_filter.php +++ b/lbplanner/classes/model/slot_filter.php @@ -67,6 +67,20 @@ public function __construct(int $id, int $slotid, ?int $courseid, ?string $vinta $this->vintage = $vintage; } + /** + * Creates a slot_filter object from a DB result + * @param \stdClass $obj the DB object + * @return slot_filter the resulting slot_filter object + */ + public static function from_db(\stdClass $obj): self { + return new slot_filter( + $obj->id, + $obj->slotid, + $obj->courseid, + $obj->vintage, + ); + } + /** * Mark the object as freshly created and sets the new ID * @param int $id the new ID after inserting into the DB From d4d3b00a8b9a2332df47a902e1716aa74efd3b9f Mon Sep 17 00:00:00 2001 From: Riedler Date: Tue, 28 Jan 2025 18:34:27 +0100 Subject: [PATCH 02/25] fix: slot->get_supervisors() --- lbplanner/classes/model/slot.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lbplanner/classes/model/slot.php b/lbplanner/classes/model/slot.php index 6b35389a..dbb4610d 100644 --- a/lbplanner/classes/model/slot.php +++ b/lbplanner/classes/model/slot.php @@ -200,11 +200,10 @@ public function get_forcuruser(): bool { public function get_supervisors(): array { global $DB; if (is_null($this->supervisors)) { - $this->supervisors = $DB->get_records( + $this->supervisors = $DB->get_fieldset( slot_helper::TABLE_SUPERVISORS, + 'userid', ['slotid' => $this->id], - '', - ['userid'] ); } From d6ad09e22f90244e1c653abefa5f4b1e5372e1d1 Mon Sep 17 00:00:00 2001 From: Riedler Date: Tue, 28 Jan 2025 18:42:00 +0100 Subject: [PATCH 03/25] fix: don't set current user as slot supervisor if slotmaster --- lbplanner/services/slots/create_slot.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lbplanner/services/slots/create_slot.php b/lbplanner/services/slots/create_slot.php index 0dbff4a0..734fc5b3 100644 --- a/lbplanner/services/slots/create_slot.php +++ b/lbplanner/services/slots/create_slot.php @@ -17,6 +17,7 @@ namespace local_lbplanner_services; use core_external\{external_api, external_function_parameters, external_single_structure, external_value}; +use local_lbplanner\enums\CAPABILITY; use local_lbplanner\enums\WEEKDAY; use local_lbplanner\helpers\slot_helper; use local_lbplanner\model\slot; @@ -104,11 +105,13 @@ public static function create_slot(int $startunit, int $duration, int $weekday, $id = $DB->insert_record(slot_helper::TABLE_SLOTS, $slot->prepare_for_db()); $slot->set_fresh($id); - // Set current user as supervisor for this new slot. - $DB->insert_record( - slot_helper::TABLE_SUPERVISORS, - (new supervisor(0, $slot->id, $USER->id))->prepare_for_db() - ); + // Set current user as supervisor for this new slot if not supervisor. + if (!has_capability(CAPABILITY::SLOTMASTER, $USER->id)) { + $DB->insert_record( + slot_helper::TABLE_SUPERVISORS, + (new supervisor(0, $slot->id, $USER->id))->prepare_for_db() + ); + } return $slot->prepare_for_api(); } From 15fd52438e32cc67f953bf08549fcce0490799a6 Mon Sep 17 00:00:00 2001 From: Riedler Date: Tue, 28 Jan 2025 18:55:06 +0100 Subject: [PATCH 04/25] fix: create_slot --- lbplanner/services/slots/create_slot.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lbplanner/services/slots/create_slot.php b/lbplanner/services/slots/create_slot.php index 734fc5b3..5800ff8f 100644 --- a/lbplanner/services/slots/create_slot.php +++ b/lbplanner/services/slots/create_slot.php @@ -17,11 +17,11 @@ namespace local_lbplanner_services; use core_external\{external_api, external_function_parameters, external_single_structure, external_value}; -use local_lbplanner\enums\CAPABILITY; -use local_lbplanner\enums\WEEKDAY; +use core\context\system as context_system; + +use local_lbplanner\enums\{CAPABILITY, WEEKDAY}; use local_lbplanner\helpers\slot_helper; -use local_lbplanner\model\slot; -use local_lbplanner\model\supervisor; +use local_lbplanner\model\{slot, supervisor}; /** * Create a slot @@ -97,6 +97,7 @@ public static function create_slot(int $startunit, int $duration, int $weekday, 'size' => $size, ] ); + $syscontext = context_system::instance(); $slot = new slot(0, $startunit, $duration, $weekday, $room, $size); $slot->validate(); @@ -106,7 +107,7 @@ public static function create_slot(int $startunit, int $duration, int $weekday, $slot->set_fresh($id); // Set current user as supervisor for this new slot if not supervisor. - if (!has_capability(CAPABILITY::SLOTMASTER, $USER->id)) { + if (!has_capability(CAPABILITY::SLOTMASTER, $syscontext, $USER->id)) { $DB->insert_record( slot_helper::TABLE_SUPERVISORS, (new supervisor(0, $slot->id, $USER->id))->prepare_for_db() From 2538bd8ed3356b3c4f331d5f09958db0b6650a43 Mon Sep 17 00:00:00 2001 From: Riedler Date: Tue, 28 Jan 2025 18:59:13 +0100 Subject: [PATCH 05/25] fix: typo in services.php --- lbplanner/db/services.php | 2 +- lbplanner/version.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lbplanner/db/services.php b/lbplanner/db/services.php index 4021f5d5..79f8f380 100644 --- a/lbplanner/db/services.php +++ b/lbplanner/db/services.php @@ -333,7 +333,7 @@ 'ajax' => true, ], 'local_lbplanner_slots_update_slot' => [ - 'classname' => 'update_slot\slots_update_slot', + 'classname' => 'local_lbplanner_services\slots_update_slot', 'methodname' => 'create_slot', 'classpath' => 'local/lbplanner/services/slots/update_slot.php', 'description' => 'Update a slot\'s values', diff --git a/lbplanner/version.php b/lbplanner/version.php index 5061d7ed..6e330ac2 100644 --- a/lbplanner/version.php +++ b/lbplanner/version.php @@ -28,7 +28,7 @@ $plugin->component = 'local_lbplanner'; $plugin->release = 'Alpha v.'.$release; -$plugin->version = 2025012800; +$plugin->version = 2025012801; $plugin->dependencies = [ // Depend upon version 2023110600 of local_modcustomfields. 'local_modcustomfields' => 2023110600, From ffedecdb98685a0fafc7ac2dee798d9c66d84bf9 Mon Sep 17 00:00:00 2001 From: Riedler Date: Tue, 28 Jan 2025 19:01:44 +0100 Subject: [PATCH 06/25] fix: slot_filter API structure --- lbplanner/classes/model/slot_filter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lbplanner/classes/model/slot_filter.php b/lbplanner/classes/model/slot_filter.php index e368cab8..56ac4a35 100644 --- a/lbplanner/classes/model/slot_filter.php +++ b/lbplanner/classes/model/slot_filter.php @@ -142,7 +142,7 @@ public static function api_structure(): external_single_structure { NULL_ALLOWED ), 'vintage' => new external_value( - PARAM_INT, + PARAM_TEXT, 'class name to filter for (or null if "any")', VALUE_REQUIRED, null, From bd1e572527a79657577559bd93aff12b13a4e2c1 Mon Sep 17 00:00:00 2001 From: Riedler Date: Tue, 28 Jan 2025 19:11:24 +0100 Subject: [PATCH 07/25] feat: disallow null on slot_filter's courseid and vintage (fixes lpp-57) --- lbplanner/classes/model/slot_filter.php | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/lbplanner/classes/model/slot_filter.php b/lbplanner/classes/model/slot_filter.php index 56ac4a35..41f35755 100644 --- a/lbplanner/classes/model/slot_filter.php +++ b/lbplanner/classes/model/slot_filter.php @@ -42,11 +42,11 @@ class slot_filter { /** * @var ?int $id ID of linked course or null if any */ - public ?int $courseid; + public int $courseid; /** * @var ?string $vintage linked class or null if any */ - public ?string $vintage; + public string $vintage; /** * Constructs new slot_filter @@ -55,11 +55,8 @@ class slot_filter { * @param ?int $courseid ID of linked course or null if any * @param ?string $vintage linked class or null if any */ - public function __construct(int $id, int $slotid, ?int $courseid, ?string $vintage) { - assert(!(is_null($courseid) && is_null($vintage))); - if (!is_null($vintage)) { - assert(strlen($vintage) <= 7); - } + public function __construct(int $id, int $slotid, int $courseid, string $vintage) { + assert(strlen($vintage) <= 7); $this->id = $id; $this->slotid = $slotid; @@ -137,16 +134,12 @@ public static function api_structure(): external_single_structure { 'courseid' => new external_value( PARAM_INT, 'ID of course to filter for (or null if "any")', - VALUE_REQUIRED, - null, - NULL_ALLOWED + VALUE_REQUIRED ), 'vintage' => new external_value( PARAM_TEXT, 'class name to filter for (or null if "any")', - VALUE_REQUIRED, - null, - NULL_ALLOWED + VALUE_REQUIRED ), ] ); From 39ad69fab163130dc6f4e3f9de553e8afe760f37 Mon Sep 17 00:00:00 2001 From: Riedler Date: Tue, 28 Jan 2025 19:21:27 +0100 Subject: [PATCH 08/25] fix: parsing imports --- document_services.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document_services.py b/document_services.py index e622cc5e..fe9df311 100644 --- a/document_services.py +++ b/document_services.py @@ -703,7 +703,7 @@ def makepath(p: str, symbol: str): im_symbol = use.split('\\')[-1].replace(';', '') found = False if im_symbol.startswith('{'): - for subsymbol in im_symbol.split(','): + for subsymbol in im_symbol[1:-1].split(','): if subsymbol.strip() == symbol: found = True break From 423a1d82dbf03fa097aaa600d7b8da8e1a48440b Mon Sep 17 00:00:00 2001 From: Riedler Date: Tue, 28 Jan 2025 19:23:41 +0100 Subject: [PATCH 09/25] feat: allow writing docs to devnull --- document_services.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/document_services.py b/document_services.py index fe9df311..de073ad4 100644 --- a/document_services.py +++ b/document_services.py @@ -800,6 +800,8 @@ def main(): if sys.argv[1] == "-": print(data) + elif sys.argv[1] == "/dev/null": + pass else: declaration = f"const funcs = {data}" From 89d0d910abfafb4087762024756c07078d93bbef Mon Sep 17 00:00:00 2001 From: Riedler Date: Tue, 28 Jan 2025 20:10:13 +0100 Subject: [PATCH 10/25] =?UTF-8?q?fix:=20services.php=E2=80=A6=20yet=20agai?= =?UTF-8?q?n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lbplanner/db/services.php | 2 +- lbplanner/version.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lbplanner/db/services.php b/lbplanner/db/services.php index 79f8f380..3f40a0fa 100644 --- a/lbplanner/db/services.php +++ b/lbplanner/db/services.php @@ -334,7 +334,7 @@ ], 'local_lbplanner_slots_update_slot' => [ 'classname' => 'local_lbplanner_services\slots_update_slot', - 'methodname' => 'create_slot', + 'methodname' => 'update_slot', 'classpath' => 'local/lbplanner/services/slots/update_slot.php', 'description' => 'Update a slot\'s values', 'type' => 'write', diff --git a/lbplanner/version.php b/lbplanner/version.php index 6e330ac2..5652919a 100644 --- a/lbplanner/version.php +++ b/lbplanner/version.php @@ -28,7 +28,7 @@ $plugin->component = 'local_lbplanner'; $plugin->release = 'Alpha v.'.$release; -$plugin->version = 2025012801; +$plugin->version = 2025012802; $plugin->dependencies = [ // Depend upon version 2023110600 of local_modcustomfields. 'local_modcustomfields' => 2023110600, From b232854c2f7878c5d027ba434d92da004561b104 Mon Sep 17 00:00:00 2001 From: Riedler Date: Tue, 28 Jan 2025 20:16:59 +0100 Subject: [PATCH 11/25] fix: add update_slot to service list --- lbplanner/db/services.php | 1 + lbplanner/version.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lbplanner/db/services.php b/lbplanner/db/services.php index 3f40a0fa..6b9941a1 100644 --- a/lbplanner/db/services.php +++ b/lbplanner/db/services.php @@ -438,6 +438,7 @@ 'local_lbplanner_slots_get_student_slots', 'local_lbplanner_slots_get_supervisor_slots', 'local_lbplanner_slots_remove_slot_supervisor', + 'local_lbplanner_slots_update_slot', ], 'restrictedusers' => 0, 'enabled' => 1, diff --git a/lbplanner/version.php b/lbplanner/version.php index 5652919a..cef47ea5 100644 --- a/lbplanner/version.php +++ b/lbplanner/version.php @@ -28,7 +28,7 @@ $plugin->component = 'local_lbplanner'; $plugin->release = 'Alpha v.'.$release; -$plugin->version = 2025012802; +$plugin->version = 2025012803; $plugin->dependencies = [ // Depend upon version 2023110600 of local_modcustomfields. 'local_modcustomfields' => 2023110600, From 6487a09595235e836f52f1dcb11449187a3efb68 Mon Sep 17 00:00:00 2001 From: Riedler Date: Tue, 28 Jan 2025 20:23:14 +0100 Subject: [PATCH 12/25] fix: renamed slotid to id when appropriate --- lbplanner/services/slots/delete_slot.php | 20 ++++++++++---------- lbplanner/services/slots/update_slot.php | 12 ++++++------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lbplanner/services/slots/delete_slot.php b/lbplanner/services/slots/delete_slot.php index 6fc01f36..b7587f2e 100644 --- a/lbplanner/services/slots/delete_slot.php +++ b/lbplanner/services/slots/delete_slot.php @@ -37,7 +37,7 @@ class slots_delete_slot extends external_api { */ public static function delete_slot_parameters(): external_function_parameters { return new external_function_parameters([ - 'slotid' => new external_value( + 'id' => new external_value( PARAM_INT, 'ID of the slot to be deleted', VALUE_REQUIRED, @@ -49,44 +49,44 @@ public static function delete_slot_parameters(): external_function_parameters { /** * Tries to request unbooking - * @param int $slotid which slot to delete + * @param int $id which slot to delete */ - public static function delete_slot(int $slotid): void { + public static function delete_slot(int $id): void { global $USER, $DB; self::validate_parameters( self::delete_slot_parameters(), [ - 'slotid' => $slotid, + 'slotid' => $id, ] ); // Check if user is supervisor for this slot, throw error if not. - slot_helper::assert_slot_supervisor($USER->id, $slotid); + slot_helper::assert_slot_supervisor($USER->id, $id); // Notify affected users. - $reservations = slot_helper::get_reservations_for_slot($slotid); + $reservations = slot_helper::get_reservations_for_slot($id); foreach ($reservations as $res) { notifications_helper::notify_user($res->userid, $res->id, NOTIF_TRIGGER::UNBOOK_FORCED); } // Delete all reservations for this slot. $DB->delete_records( slot_helper::TABLE_RESERVATIONS, - ['slotid' => $slotid] + ['slotid' => $id] ); // Delete Supervisors for this slot. $DB->delete_records( slot_helper::TABLE_SUPERVISORS, - ['slotid' => $slotid] + ['slotid' => $id] ); // Delete Filters for this slot. $DB->delete_records( slot_helper::TABLE_SLOT_FILTERS, - ['slotid' => $slotid] + ['slotid' => $id] ); // Finally, delete slot. $DB->delete_records( slot_helper::TABLE_SLOTS, - ['id' => $slotid] + ['id' => $id] ); } diff --git a/lbplanner/services/slots/update_slot.php b/lbplanner/services/slots/update_slot.php index 235f2b7f..212109d5 100644 --- a/lbplanner/services/slots/update_slot.php +++ b/lbplanner/services/slots/update_slot.php @@ -37,7 +37,7 @@ class slots_update_slot extends external_api { public static function update_slot_parameters(): external_function_parameters { // TODO: set hardcoded doc values with constants instead of hardcoded values. return new external_function_parameters([ - 'slotid' => new external_value( + 'id' => new external_value( PARAM_INT, 'ID of the slot to update', VALUE_REQUIRED, @@ -85,19 +85,19 @@ public static function update_slot_parameters(): external_function_parameters { /** * Update a slot's values - * @param int $slotid ID of the slot to update + * @param int $id ID of the slot to update * @param int $startunit the unit this slot starts in * @param int $duration how long the unit lasts for * @param int $weekday which day of the week this slot is on * @param string $room which room this slot is for * @param int $size how many pupils this slot can fit */ - public static function update_slot(int $slotid, int $startunit, int $duration, int $weekday, string $room, int $size): void { + public static function update_slot(int $id, int $startunit, int $duration, int $weekday, string $room, int $size): void { global $USER, $DB; self::validate_parameters( self::update_slot_parameters(), [ - 'slotid' => $slotid, + 'id' => $id, 'startunit' => $startunit, 'duration' => $duration, 'weekday' => $weekday, @@ -107,10 +107,10 @@ public static function update_slot(int $slotid, int $startunit, int $duration, i ); // Check if user is supervisor for this slot, throw error if not. - slot_helper::assert_slot_supervisor($USER->id, $slotid); + slot_helper::assert_slot_supervisor($USER->id, $id); // Replace slot's values with new values if not null. - $slot = slot_helper::get_slot($slotid); + $slot = slot_helper::get_slot($id); $varnames = ['startunit', 'duration', 'weekday', 'room', 'size']; foreach ($varnames as $varname) { if (!is_null($$varname)) { From df99442b0ebb77a336440aea673569f4ae349544 Mon Sep 17 00:00:00 2001 From: Riedler Date: Tue, 28 Jan 2025 20:38:41 +0100 Subject: [PATCH 13/25] fix: fucked in previous commit --- lbplanner/services/slots/delete_slot.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lbplanner/services/slots/delete_slot.php b/lbplanner/services/slots/delete_slot.php index b7587f2e..6c0a4873 100644 --- a/lbplanner/services/slots/delete_slot.php +++ b/lbplanner/services/slots/delete_slot.php @@ -56,7 +56,7 @@ public static function delete_slot(int $id): void { self::validate_parameters( self::delete_slot_parameters(), [ - 'slotid' => $id, + 'id' => $id, ] ); From 2af17588876604192c5d58f82f144ea9b125b629 Mon Sep 17 00:00:00 2001 From: Riedler Date: Wed, 29 Jan 2025 18:42:44 +0100 Subject: [PATCH 14/25] fix: various minor fixes for the concept of time --- lbplanner/classes/helpers/slot_helper.php | 20 ++++++++++---------- lbplanner/classes/model/slot.php | 19 ++++++++++++++----- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/lbplanner/classes/helpers/slot_helper.php b/lbplanner/classes/helpers/slot_helper.php index c4e78dfe..a847b946 100644 --- a/lbplanner/classes/helpers/slot_helper.php +++ b/lbplanner/classes/helpers/slot_helper.php @@ -291,12 +291,12 @@ public static function filter_slots_for_user(array $allslots, \stdClass $user): $filters = $slot->get_filters(); foreach ($filters as $filter) { // Checking for course ID. - if (!is_null($filter->courseid) && !in_array($filter->courseid, $mycourseids)) { + if (!in_array($filter->courseid, $mycourseids)) { continue; } // TODO: replace address with cohorts. // Checking for vintage. - if (!is_null($filter->vintage) && $user->address !== $filter->vintage) { + if ($user->address !== $filter->vintage) { continue; } // If all filters passed, add slot to my slots and break. @@ -331,23 +331,23 @@ public static function filter_slots_for_time(array $allslots, int $range): array /** * calculates when a slot is to happen next * @param slot $slot the slot - * @param DateTimeInterface $now the point in time representing now + * @param DateTimeImmutable $now the point in time representing now * @return DateTimeImmutable the next time this slot will occur */ - public static function calculate_slot_datetime(slot $slot, DateTimeInterface $now): DateTimeImmutable { - $utctz = new DateTimeZone('UTC'); + public static function calculate_slot_datetime(slot $slot, DateTimeImmutable $now): DateTimeImmutable { $slotdaytime = self::SCHOOL_UNITS[$slot->startunit]; - // NOTE: format and fromFormat use different date formatting conventions. - $slotdatetime = DateTime::createFromFormat('YY-MM-DD tHH:MM', $now->format('Y-m-d ').$slotdaytime, $utctz); // Move to next day this weekday occurs (doesn't move if it's the same as today). - $slotdatetime->modify('this '.WEEKDAY::name_from($slot->weekday)); + $slotdatetime = $now->modify('this '.WEEKDAY::name_from($slot->weekday)." {$slotdaytime}"); + if ($slotdatetime === false) { + throw new \coding_exception('error while calculating slot datetime'); + } // Check if slot is before now (because time of day and such) and move it a week into the future if so. if ($now->diff($slotdatetime)->invert === 1) { - $slotdatetime->add(new DateInterval('P1W')); + $slotdatetime = $slotdatetime->modify('+1 week'); } - return new DateTimeImmutable($slotdatetime, $utctz); + return DateTimeImmutable::createFromInterface($slotdatetime); } /** diff --git a/lbplanner/classes/model/slot.php b/lbplanner/classes/model/slot.php index dbb4610d..182503b6 100644 --- a/lbplanner/classes/model/slot.php +++ b/lbplanner/classes/model/slot.php @@ -89,15 +89,24 @@ class slot { */ public function __construct(int $id, int $startunit, int $duration, int $weekday, string $room, int $size) { $this->id = $id; - assert($startunit > 0); + if ($startunit <= 0 || $startunit > slot_helper::SCHOOL_UNIT_MAX) { + throw new \moodle_exception("slot's startunit must be >0 and <=".slot_helper::SCHOOL_UNIT_MAX.", but is {$startunit}"); + } + if ($duration <= 0 || ($startunit + $duration - 1) > slot_helper::SCHOOL_UNIT_MAX) { + throw new \moodle_exception( + "slot's duration must be >0 and can't exceed ".slot_helper::SCHOOL_UNIT_MAX." with startunit, but is {$duration}" + ); + } $this->startunit = $startunit; - assert($duration > 0); - assert($duration + $startunit < count(slot_helper::SCHOOL_UNITS)); $this->duration = $duration; $this->weekday = WEEKDAY::from($weekday); - assert(strlen($room) > 0 && strlen($room) <= slot_helper::ROOM_MAXLENGTH); + if (strlen($room) <= 0 && strlen($room) > slot_helper::ROOM_MAXLENGTH) { + throw new \moodle_exception("room name's length must be >0 and <=".slot_helper::ROOM_MAXLENGTH.", but is ".strlen($room)); + } $this->room = $room; - assert($size >= 0); // Make it technically possible to not allow any students in a room to temporarily disable the slot. + if ($size < 0) { + throw new \moodle_exception('room size must be >0'); + } $this->size = $size; $this->fullness = null; $this->forcuruser = null; From 42b62c1b9efa3d0f9da40cf4234cb0ec037a3864 Mon Sep 17 00:00:00 2001 From: Riedler Date: Wed, 29 Jan 2025 19:07:11 +0100 Subject: [PATCH 15/25] fix: appease code checker --- lbplanner/classes/model/slot.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lbplanner/classes/model/slot.php b/lbplanner/classes/model/slot.php index 182503b6..8a9eb56e 100644 --- a/lbplanner/classes/model/slot.php +++ b/lbplanner/classes/model/slot.php @@ -101,7 +101,9 @@ public function __construct(int $id, int $startunit, int $duration, int $weekday $this->duration = $duration; $this->weekday = WEEKDAY::from($weekday); if (strlen($room) <= 0 && strlen($room) > slot_helper::ROOM_MAXLENGTH) { - throw new \moodle_exception("room name's length must be >0 and <=".slot_helper::ROOM_MAXLENGTH.", but is ".strlen($room)); + throw new \moodle_exception( + "room name's length must be >0 and <=".slot_helper::ROOM_MAXLENGTH.", but is ".strlen($room) + ); } $this->room = $room; if ($size < 0) { From dc6ff2eb151dbc85eb90ef51b45a8980a9b12298 Mon Sep 17 00:00:00 2001 From: Riedler Date: Wed, 29 Jan 2025 19:26:32 +0100 Subject: [PATCH 16/25] fix: fucked date format parsing --- lbplanner/services/slots/book_reservation.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lbplanner/services/slots/book_reservation.php b/lbplanner/services/slots/book_reservation.php index 93675fa4..edecb3d0 100644 --- a/lbplanner/services/slots/book_reservation.php +++ b/lbplanner/services/slots/book_reservation.php @@ -83,7 +83,10 @@ public static function book_reservation(int $slotid, string $date, int $userid): ); $now = new DateTimeImmutable(); - $dateobj = DateTimeImmutable::createFromFormat("YY-MM-DD", $date); + $dateobj = DateTimeImmutable::createFromFormat("Y-m-d", $date); + if ($dateobj === false) { + throw new \moodle_exception("invalid date formatting: got '{$date}', must be YYYY-MM-DD"); + } $td = $dateobj->diff($now); if ($td->invert) { From 61d0f1325d0642ec9b980e23384dc3eeebcb5332 Mon Sep 17 00:00:00 2001 From: Riedler Date: Wed, 29 Jan 2025 19:49:34 +0100 Subject: [PATCH 17/25] fix: corrected dt direction in book_reservation --- lbplanner/services/slots/book_reservation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lbplanner/services/slots/book_reservation.php b/lbplanner/services/slots/book_reservation.php index edecb3d0..a601c993 100644 --- a/lbplanner/services/slots/book_reservation.php +++ b/lbplanner/services/slots/book_reservation.php @@ -87,7 +87,7 @@ public static function book_reservation(int $slotid, string $date, int $userid): if ($dateobj === false) { throw new \moodle_exception("invalid date formatting: got '{$date}', must be YYYY-MM-DD"); } - $td = $dateobj->diff($now); + $td = $now->diff($dateobj); if ($td->invert) { throw new \moodle_exception('Can\'t reserve date in the past'); From 46e275bca06218c04b2a1bb487b2e3862d752f28 Mon Sep 17 00:00:00 2001 From: Riedler Date: Wed, 29 Jan 2025 19:50:01 +0100 Subject: [PATCH 18/25] fix: minor formatting weirdness --- lbplanner/classes/helpers/slot_helper.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lbplanner/classes/helpers/slot_helper.php b/lbplanner/classes/helpers/slot_helper.php index a847b946..2b9ff6cf 100644 --- a/lbplanner/classes/helpers/slot_helper.php +++ b/lbplanner/classes/helpers/slot_helper.php @@ -377,9 +377,7 @@ public static function check_slot_supervisor(int $supervisorid, int $slotid): bo global $DB; $context = context_system::instance(); - if ( - has_capability(CAPABILITY::SLOTMASTER, $context, $supervisorid) - ) { + if (has_capability(CAPABILITY::SLOTMASTER, $context, $supervisorid)) { return true; } From a83b9a6043e6dc56c73a4bc249049a7de91cd729 Mon Sep 17 00:00:00 2001 From: Riedler Date: Wed, 29 Jan 2025 19:50:09 +0100 Subject: [PATCH 19/25] fix: userid comparison --- lbplanner/services/slots/book_reservation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lbplanner/services/slots/book_reservation.php b/lbplanner/services/slots/book_reservation.php index a601c993..0f012baa 100644 --- a/lbplanner/services/slots/book_reservation.php +++ b/lbplanner/services/slots/book_reservation.php @@ -96,7 +96,7 @@ public static function book_reservation(int $slotid, string $date, int $userid): $maxdays = null; $student = null; - if ($userid === $USER->id) { + if ($userid === intval($USER->id)) { // Student reserving slot for themself. $maxdays = slot_helper::RESERVATION_RANGE_USER; From 9a053c26ca8e0887ebfdad9f35a30727511faa1c Mon Sep 17 00:00:00 2001 From: Riedler Date: Wed, 29 Jan 2025 19:50:50 +0100 Subject: [PATCH 20/25] fix: reservation object instantiation from db object --- lbplanner/classes/model/reservation.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lbplanner/classes/model/reservation.php b/lbplanner/classes/model/reservation.php index 9ccf3976..8ae0f9b3 100644 --- a/lbplanner/classes/model/reservation.php +++ b/lbplanner/classes/model/reservation.php @@ -91,13 +91,13 @@ public function __construct(int $id, int $slotid, DateTimeImmutable $date, int $ /** * Initializes reservation object from a DB object - * @param array $obj the DB obj + * @param \stdClass $obj the DB obj * @return reservation the reservation obj */ - public static function from_obj(array $obj): self { + public static function from_obj(\stdClass $obj): self { $utctz = new DateTimeZone('UTC'); - $obj['date'] = new DateTimeImmutable($obj['date'], $utctz); - return new self(...$obj); + $date = new DateTimeImmutable($obj->date, $utctz); + return new self($obj->id, $obj->slotid, $date, $obj->userid, $obj->reserverid); } /** From f1018c9f3cd0a2be713d37c9b12659e2224659ab Mon Sep 17 00:00:00 2001 From: Riedler Date: Wed, 29 Jan 2025 19:51:02 +0100 Subject: [PATCH 21/25] fix: db object instantiation from reservation object --- lbplanner/classes/model/reservation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lbplanner/classes/model/reservation.php b/lbplanner/classes/model/reservation.php index 8ae0f9b3..5019efb6 100644 --- a/lbplanner/classes/model/reservation.php +++ b/lbplanner/classes/model/reservation.php @@ -203,7 +203,7 @@ public function prepare_for_db(): object { $obj = new \stdClass(); $obj->slotid = $this->slotid; - $obj->date = $this->date; + $obj->date = $this->date->format('Y-m-d'); $obj->userid = $this->userid; $obj->reserverid = $this->reserverid; From 7331a9dc16833c8b583a35924ea05060cc4654f0 Mon Sep 17 00:00:00 2001 From: Riedler Date: Wed, 29 Jan 2025 20:44:16 +0100 Subject: [PATCH 22/25] =?UTF-8?q?fix:=20time=20formatting=20(again?= =?UTF-8?q?=E2=80=A6=20ugh)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lbplanner/classes/helpers/slot_helper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lbplanner/classes/helpers/slot_helper.php b/lbplanner/classes/helpers/slot_helper.php index 2b9ff6cf..18973aed 100644 --- a/lbplanner/classes/helpers/slot_helper.php +++ b/lbplanner/classes/helpers/slot_helper.php @@ -362,7 +362,7 @@ public static function amend_date_with_unit_time(int $unit, DateTimeInterface $d $utctz = new DateTimeZone('UTC'); $daytime = self::SCHOOL_UNITS[$unit]; - return DateTimeImmutable::createFromFormat('YY-MM-DD tHH:MM', $date->format('Y-m-d ').$daytime, $utctz); + return DateTimeImmutable::createFromFormat('Y-m-d G:i', $date->format('Y-m-d ').$daytime, $utctz); } /** From 00c5e35592b3ebc526c11ad54b5b44d09bcde840 Mon Sep 17 00:00:00 2001 From: Riedler Date: Wed, 29 Jan 2025 20:44:43 +0100 Subject: [PATCH 23/25] fix: silly typo --- lbplanner/classes/model/slot.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lbplanner/classes/model/slot.php b/lbplanner/classes/model/slot.php index 8a9eb56e..a09370ae 100644 --- a/lbplanner/classes/model/slot.php +++ b/lbplanner/classes/model/slot.php @@ -254,7 +254,7 @@ public function check_overlaps(slot $other, bool $checkroom): bool { // Now only three variants are left: one entirely inside the other, or both intersecting partially. // In either case, if one of the startunits is inside the other's range, then we know the time ranges overlap. // Logically, only the one that starts later can be inside the other's range. - $thisbeforeother = $this->startunit < $other; + $thisbeforeother = $this->startunit < $other->startunit; $a = $thisbeforeother ? $this : $other; $b = $thisbeforeother ? $other : $this; From 0298ddbf2aaa8e50cd0a755cdcbf978a4279cdba Mon Sep 17 00:00:00 2001 From: Riedler Date: Wed, 29 Jan 2025 22:04:17 +0100 Subject: [PATCH 24/25] fix: complex SQL statement in get_supervisor_slots --- lbplanner/classes/helpers/slot_helper.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lbplanner/classes/helpers/slot_helper.php b/lbplanner/classes/helpers/slot_helper.php index 18973aed..3335db04 100644 --- a/lbplanner/classes/helpers/slot_helper.php +++ b/lbplanner/classes/helpers/slot_helper.php @@ -125,8 +125,8 @@ public static function get_supervisor_slots(int $supervisorid): array { global $DB; $slots = $DB->get_records_sql( - 'SELECT slot.* FROM {'.self::TABLE_SLOTS.'} as slot'. - 'INNER JOIN '.self::TABLE_SUPERVISORS.' as supervisor ON supervisor.slotid=slot.id'. + 'SELECT slot.* FROM {'.self::TABLE_SLOTS.'} as slot '. + 'INNER JOIN {'.self::TABLE_SUPERVISORS.'} as supervisor ON supervisor.slotid=slot.id '. 'WHERE supervisor.userid=?', [$supervisorid] ); From 867aa8821b8b29b0a9bea2b5ec34a143c86caeeb Mon Sep 17 00:00:00 2001 From: Riedler Date: Wed, 29 Jan 2025 22:09:07 +0100 Subject: [PATCH 25/25] fix: allow get_all_courses for teachers as well --- lbplanner/services/courses/get_all_courses.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lbplanner/services/courses/get_all_courses.php b/lbplanner/services/courses/get_all_courses.php index a899b6c9..45a638b9 100644 --- a/lbplanner/services/courses/get_all_courses.php +++ b/lbplanner/services/courses/get_all_courses.php @@ -46,7 +46,7 @@ public static function get_all_courses_parameters(): external_function_parameter public static function get_all_courses(): array { global $USER; $user = user::from_mdlobj($USER); - if (!($user->get_capabilitybitmask() & CAPABILITY_FLAG::SLOTMASTER)) { + if (!($user->get_capabilitybitmask() & (CAPABILITY_FLAG::SLOTMASTER | CAPABILITY_FLAG::TEACHER))) { throw new \moodle_exception('access denied: must be slotmaster'); }