diff --git a/modules/Admin/Controllers/UserController.php b/modules/Admin/Controllers/UserController.php index 85aa24cf9cf3c42d64a7dbe3199a56c181f5fe87..99441dc5903a541989e954f02d68c41e269f7c9b 100644 --- a/modules/Admin/Controllers/UserController.php +++ b/modules/Admin/Controllers/UserController.php @@ -143,6 +143,17 @@ class UserController extends BaseController $authorize = Services::authorization(); $roles = $this->request->getPost('roles'); + + if ($this->user->isOwner) { + return redirect() + ->back() + ->with('errors', [ + lang('User.messages.editOwnerError', [ + 'username' => $this->user->username, + ]), + ]); + } + $authorize->setUserGroups($this->user->id, $roles ?? []); // Success! diff --git a/modules/Admin/Language/en/User.php b/modules/Admin/Language/en/User.php index 8b2e478bf7b6c5d97364e6888e9724b8fa24188f..585d6799fc98d3f7c485c26b9ed1439b28813a3b 100644 --- a/modules/Admin/Language/en/User.php +++ b/modules/Admin/Language/en/User.php @@ -45,6 +45,8 @@ return [ '{username} will be prompted with a password reset upon next visit.', 'banSuccess' => '{username} has been banned.', 'unbanSuccess' => '{username} has been unbanned.', + 'editOwnerError' => + '{username} is the instance owner, you cannot edit its roles.', 'banSuperAdminError' => '{username} is a superadmin, one does not simply ban a superadmin…', 'deleteSuperAdminError' => diff --git a/modules/Auth/Entities/User.php b/modules/Auth/Entities/User.php index c94e23f603cc07c428245476667c988e435495de..5a7d9a6ca488d5631751d697391512c58b9beeec 100644 --- a/modules/Auth/Entities/User.php +++ b/modules/Auth/Entities/User.php @@ -13,6 +13,7 @@ namespace Modules\Auth\Entities; use App\Entities\Podcast; use App\Models\NotificationModel; use App\Models\PodcastModel; +use App\Models\UserModel; use Myth\Auth\Entities\User as MythAuthUser; use RuntimeException; @@ -31,6 +32,8 @@ use RuntimeException; */ class User extends MythAuthUser { + public bool $is_owner; + /** * @var Podcast[]|null */ @@ -54,6 +57,17 @@ class User extends MythAuthUser 'podcast_role' => '?string', ]; + public function getIsOwner(): bool + { + $firstUser = (new UserModel())->first(); + + if (! $firstUser instanceof self) { + return false; + } + + return $this->username === $firstUser->username; + } + /** * Returns the podcasts the user is contributing to * diff --git a/themes/cp_admin/user/edit.php b/themes/cp_admin/user/edit.php index 88c641d866b8ef8c4ef9795915ef5e524eea6726..2981b9f38f8e3fe06c68fce18930f7807c24ec03 100644 --- a/themes/cp_admin/user/edit.php +++ b/themes/cp_admin/user/edit.php @@ -23,7 +23,6 @@ id="roles" name="roles[]" label="<?= lang('User.form.roles') ?>" - required="true" options="<?= esc(json_encode($roleOptions)) ?>" selected="<?= esc(json_encode($user->roles)) ?>" /> diff --git a/themes/cp_admin/user/list.php b/themes/cp_admin/user/list.php index 54c7bdb65455b83b7566b51258fe766cb48f172e..ce9777924c29c5c2765133514ac0460ca78df127 100644 --- a/themes/cp_admin/user/list.php +++ b/themes/cp_admin/user/list.php @@ -30,10 +30,13 @@ [ 'header' => lang('User.list.roles'), 'cell' => function ($user) { - return implode(',', $user->roles) . - '<IconButton uri="' . route_to('user-edit', $user->id) . '" glyph="edit" variant="info">' . lang('User.edit_roles', [ - 'username' => esc($user->username), - ]) . '</IconButton>'; + if ($user->isOwner) { + return 'owner, ' . implode(',', $user->roles); + } + + return implode(',', $user->roles) . '<IconButton uri="' . route_to('user-edit', $user->id) . '" glyph="edit" variant="info">' . lang('User.edit_roles', [ + 'username' => esc($user->username), + ]) . '</IconButton>'; }, ], [