diff --git a/framework/core/src/Core/Listener/SelfDemotionGuard.php b/framework/core/src/Core/Listener/SelfDemotionGuard.php index 500de5c44..1fbfe3e89 100644 --- a/framework/core/src/Core/Listener/SelfDemotionGuard.php +++ b/framework/core/src/Core/Listener/SelfDemotionGuard.php @@ -33,18 +33,35 @@ class SelfDemotionGuard */ public function whenUserWillBeSaved(UserWillBeSaved $event) { - $actor = $event->actor; - $user = $event->user; + // Non-admin users pose no problem + if (! $event->actor->isAdmin()) { + return; + } + + // Only admins can demote users, which means demoting other users is + // fine, because we still have at least one admin (the actor) left + if ($event->actor->id !== $event->user->id) { + return; + } + $groups = array_get($event->data, 'relationships.groups.data'); - if (isset($groups) && $actor->id === $user->id && $actor->isAdmin()) { - $adminGroupRemoved = empty(array_filter($groups, function ($group) { - return $group['id'] == Group::ADMINISTRATOR_ID; - })); - - if ($adminGroupRemoved) { - throw new PermissionDeniedException; - } + // If there is no group data (not even an empty array), this means + // groups were not changed (and thus not removed) - we're fine! + if (! isset($groups)) { + return; } + + $adminGroups = array_filter($groups, function ($group) { + return $group['id'] == Group::ADMINISTRATOR_ID; + }); + + // As long as the user is still part of the admin group, all is good + if ($adminGroups) { + return; + } + + // If we get to this point, we have to prohibit the edit + throw new PermissionDeniedException; } }