diff --git a/lbplanner/classes/enums/CAPABILITY.php b/lbplanner/classes/enums/CAPABILITY.php index 4395de5c..ef195f00 100644 --- a/lbplanner/classes/enums/CAPABILITY.php +++ b/lbplanner/classes/enums/CAPABILITY.php @@ -60,8 +60,7 @@ class CAPABILITY extends Enum { * @return int the bitmappable flag * @link CAPABILITY_FLAG */ - public static function to_capability(string $str): int { - $name = self::name_from($str); - return constant('CAPABILITY_FLAG::'.$name); + public static function to_flag(string $str): int { + return CAPABILITY_FLAG::get(self::name_from($str)); } } diff --git a/lbplanner/classes/enums/CAPABILITY_FLAG.php b/lbplanner/classes/enums/CAPABILITY_FLAG.php index 6c3da573..88d06fe6 100644 --- a/lbplanner/classes/enums/CAPABILITY_FLAG.php +++ b/lbplanner/classes/enums/CAPABILITY_FLAG.php @@ -61,7 +61,6 @@ class CAPABILITY_FLAG extends Enum { * @link CAPABILITY */ public static function to_capability(int $num): string { - $name = self::name_from($num); - return constant('CAPABILITY::'.$name); + return CAPABILITY::get(self::name_from($num)); } } diff --git a/lbplanner/classes/helpers/user_helper.php b/lbplanner/classes/helpers/user_helper.php index 6daa68b5..c205a26f 100644 --- a/lbplanner/classes/helpers/user_helper.php +++ b/lbplanner/classes/helpers/user_helper.php @@ -16,15 +16,13 @@ namespace local_lbplanner\helpers; -use coding_exception; use context_system; use dml_exception; use moodle_exception; use stdClass; -use user_picture; use core_user; -use local_lbplanner\enums\{CAPABILITY, CAPABILITY_FLAG}; +use local_lbplanner\enums\CAPABILITY; use local_lbplanner\model\user; /** @@ -51,7 +49,13 @@ class user_helper { */ public static function check_access(int $userid): bool { global $USER; - return ((int) $USER->id) === $userid; + + if (((int) $USER->id) === $userid) { + return true; + } else { + $context = context_system::instance(); + return has_capability(CAPABILITY::ADMIN, $context, $USER->id); + } } /** @@ -69,64 +73,6 @@ public static function assert_access(int $userid): void { } } - /** - * Checks if the given user is an admin. - * - * @param int $userid The id of the user to check. - * - * @return bool True if the given user is an admin, false otherwise. - * @throws coding_exception - * @throws dml_exception - */ - public static function is_admin(int $userid): bool { - $context = context_system::instance(); - return has_capability(CAPABILITY::ADMIN, $context, $userid, false); - } - - /** - * Gives back a bitmask which represents the capabilities of the given user. - * 0 = no capabilities - * 1 = admin - * 2 = manager - * 3 = admin + manager - * 4 = teacher - * 5 = admin + teacher - * 6 = manager + teacher - * 7 = admin + manager + teacher - * 8 = student - * 9 = admin + student - * 10 = manager + student - * 11 = admin + manager + student - * 12 = teacher + student - * 13 = admin + teacher + student - * 14 = manager + teacher + student - * 15 = admin + manager + teacher + student - * - * - * @param int $userid The id of the user to check access for. - * - * @return int The capabilities of the given user. - * @throws coding_exception - * @throws dml_exception - */ - public static function get_user_capability_bitmask(int $userid): int { - $capabilities = 0; - $context = context_system::instance(); - if (has_capability(CAPABILITY::ADMIN, $context, $userid, false)) { - $capabilities += CAPABILITY_FLAG::ADMIN; - } - if (has_capability(CAPABILITY::MANAGER, $context, $userid, false)) { - $capabilities += CAPABILITY_FLAG::MANAGER; - } - if (has_capability(CAPABILITY::TEACHER, $context, $userid, false)) { - $capabilities += CAPABILITY_FLAG::TEACHER; - } - if (has_capability(CAPABILITY::STUDENT, $context, $userid, false)) { - $capabilities += CAPABILITY_FLAG::STUDENT; - } - return $capabilities; - } - /** * Checks if the given user exists in the LB_PLANNER_USER database. * diff --git a/lbplanner/classes/model/user.php b/lbplanner/classes/model/user.php index 09643eb2..aef941d6 100644 --- a/lbplanner/classes/model/user.php +++ b/lbplanner/classes/model/user.php @@ -26,8 +26,11 @@ namespace local_lbplanner\model; use coding_exception; +use context_system; use external_single_structure; use external_value; +use local_lbplanner\enums\CAPABILITY; +use local_lbplanner\enums\CAPABILITY_FLAG; use local_lbplanner\helpers\plan_helper; use local_lbplanner\helpers\user_helper; use user_picture; @@ -81,6 +84,11 @@ class user { */ private ?int $planid; + /** + * @var ?int $capabilitybitmask the cached user capability bitmask + */ + private ?int $capabilitybitmask; + /** * Constructs a new course * @param int $lbpid ID of the lb planner user @@ -107,6 +115,7 @@ public function __construct( $this->set_displaytaskcount($displaytaskcount); $this->planid = null; $this->pfp = null; + $this->capabilitybitmask = null; if ($mdlid === (int) $USER->id) { $this->mdluser = $USER; @@ -240,6 +249,24 @@ public function get_pfp(): string { return $this->pfp; } + /** + * gets the user's capability bitmask + * @return int + */ + public function get_capabilitybitmask(): int { + if ($this->capabilitybitmask === null) { + $context = context_system::instance(); + $this->capabilitybitmask = 0; + foreach (CAPABILITY::cases() as $case) { + if (has_capability($case->value, $context, $this->mdlid, false)) { + $this->capabilitybitmask |= CAPABILITY::to_flag($case->value); + } + } + } + + return $this->capabilitybitmask; + } + /** * Prepares data for the DB endpoint. * doesn't set ID if it's 0 @@ -269,14 +296,21 @@ public function prepare_for_db(): object { */ public function prepare_for_api_short(): array { $mdluser = $this->get_mdluser(); - return [ + $capabilitybm = $this->get_capabilitybitmask(); + + $data = [ 'userid' => $this->mdlid, 'username' => $mdluser->username, 'firstname' => $mdluser->firstname, 'lastname' => $mdluser->lastname, 'profileimageurl' => $this->get_pfp(), - 'vintage' => $mdluser->address, ]; + + if ($capabilitybm & CAPABILITY_FLAG::STUDENT) { + $data['vintage'] = $mdluser->address; + } + + return $data; } /** @@ -292,7 +326,7 @@ public static function api_structure_short(): external_single_structure { 'firstname' => new external_value(PARAM_TEXT, 'The firstname of the user'), 'lastname' => new external_value(PARAM_TEXT, 'The lastname of the user'), 'profileimageurl' => new external_value(PARAM_URL, 'The url of the profile image'), - 'vintage' => new external_value(PARAM_TEXT, 'The vintage of the user'), + 'vintage' => new external_value(PARAM_TEXT, 'The vintage of the user', VALUE_DEFAULT), ] ); } @@ -303,21 +337,17 @@ public static function api_structure_short(): external_single_structure { * @return array a full representation of this user and its data */ public function prepare_for_api(): array { - $mdluser = $this->get_mdluser(); - return [ - 'userid' => $mdluser->id, - 'username' => $mdluser->username, - 'firstname' => $mdluser->firstname, - 'lastname' => $mdluser->lastname, - 'theme' => $this->theme, - 'lang' => $this->lang, - 'profileimageurl' => $this->get_pfp(), - 'planid' => $this->get_planid(), - 'colorblindness' => $this->colorblindness, - 'displaytaskcount' => $this->displaytaskcount, - 'capabilities' => user_helper::get_user_capability_bitmask($this->mdlid), - 'vintage' => $mdluser->address, - ]; + return array_merge( + $this->prepare_for_api_short(), + [ + 'theme' => $this->theme, + 'lang' => $this->lang, + 'planid' => $this->get_planid(), + 'colorblindness' => $this->colorblindness, + 'displaytaskcount' => $this->displaytaskcount, + 'capabilities' => $this->get_capabilitybitmask(), + ] + ); } /** @@ -339,7 +369,7 @@ public static function api_structure(): external_single_structure { 'colorblindness' => new external_value(PARAM_TEXT, 'The colorblindness of the user'), 'displaytaskcount' => new external_value(PARAM_INT, 'If the user has the taskcount-enabled 1-yes 0-no'), 'capabilities' => new external_value(PARAM_INT, 'The capabilities of the user represented as a bitmask value'), - 'vintage' => new external_value(PARAM_TEXT, 'The vintage of the user'), + 'vintage' => new external_value(PARAM_TEXT, 'The vintage of the user', VALUE_DEFAULT), ] ); } diff --git a/lbplanner/classes/polyfill/Enum.php b/lbplanner/classes/polyfill/Enum.php index dde1b238..3a429f91 100644 --- a/lbplanner/classes/polyfill/Enum.php +++ b/lbplanner/classes/polyfill/Enum.php @@ -40,7 +40,7 @@ class Enum { * @return ?EnumCase the matching enum case or null if not found and $try==true * @throws ValueError if not found and $try==false */ - private static function find(mixed $value, bool $try): ?EnumCase { + private static function find($value, bool $try): ?EnumCase { foreach (static::cases() as $case) { if ($case->value === $value) { return $case; @@ -53,12 +53,32 @@ private static function find(mixed $value, bool $try): ?EnumCase { throw new ValueError("value {$value} cannot be represented as a value in enum ".static::class); } } + /** + * tries to match the passed value to one of the enum values + * @param string $name the value to be matched + * @param bool $try whether to return null (true) or throw an error (false) if not found + * @return ?EnumCase the matching enum case or null if not found and $try==true + * @throws ValueError if not found and $try==false + */ + private static function find_from_name(string $name, bool $try): ?EnumCase { + foreach (static::cases() as $case) { + if ($case->name === $name) { + return $case; + } + } + + if ($try) { + return null; + } else { + throw new ValueError("name {$name} doesn't exist in ".static::class); + } + } /** * tries to match the passed value to one of the enum values * @param mixed $value the value to be matched * @return mixed either the matching enum value or null if not found */ - public static function try_from(mixed $value): mixed { + public static function try_from($value) { // TODO: replace with nullsafe operator in php8. $case = static::find($value, true); if (is_null($case)) { @@ -73,16 +93,15 @@ public static function try_from(mixed $value): mixed { * @return mixed the matching enum value * @throws ValueError if not found */ - public static function from(mixed $value): mixed { + public static function from($value) { return static::find($value, false)->value; } /** * tries to match the passed value to one of the enum values * @param mixed $value the value to be matched - * @return string the matching enum case name - * @throws mixed either the matching enum case name or null if not found + * @return ?string either the matching enum case name or null if not found */ - public static function try_name_from(mixed $value): ?string { + public static function try_name_from($value): ?string { // TODO: replace with nullsafe operator in php8. $case = static::find($value, true); if (is_null($case)) { @@ -97,9 +116,26 @@ public static function try_name_from(mixed $value): ?string { * @return string the matching enum case name * @throws ValueError if not found */ - public static function name_from(mixed $value): string { + public static function name_from($value): string { return static::find($value, false)->name; } + /** + * tries to get a value based on the name + * @param string $name the name to look for + * @return mixed the matching enum case value + * @throws ValueError if not found + */ + public static function get(string $name) { + return static::find_from_name($name, false)->value; + } + /** + * tries to get a value based on the name + * @param string $name the name to look for + * @return ?mixed either the matching enum case value or null if not found + */ + public static function try_get(string $name) { + return static::find_from_name($name, false)->value; + } /** * Returns an array of all the cases that exist in this enum * diff --git a/lbplanner/services/user/delete_user.php b/lbplanner/services/user/delete_user.php index ca062be8..d89756ff 100644 --- a/lbplanner/services/user/delete_user.php +++ b/lbplanner/services/user/delete_user.php @@ -59,13 +59,11 @@ public static function delete_user_parameters(): external_function_parameters { * @throws moodle_exception */ public static function delete_user($userid) { - global $DB, $USER; + global $DB; self::validate_parameters(self::delete_user_parameters(), ['userid' => $userid]); - if (!user_helper::is_admin($USER->id)) { - user_helper::assert_access($userid); - } + user_helper::assert_access($userid); // Check if User is in user table. if (!$DB->record_exists(user_helper::LB_PLANNER_USER_TABLE, ['userid' => $userid])) {