diff --git a/app/Http/Controllers/Admin/Controller.php b/app/Http/Controllers/Admin/Controller.php index d96487f9a4a..bf27ceb1981 100644 --- a/app/Http/Controllers/Admin/Controller.php +++ b/app/Http/Controllers/Admin/Controller.php @@ -15,7 +15,7 @@ public function __construct() $this->middleware('auth'); $this->middleware(function ($request, $next) { - if (Auth::check() && !Auth::user()->isAdmin()) { + if (Auth::check() && !Auth::user()->isGroup('admin')) { abort(403); } diff --git a/app/Http/Controllers/ArtistsController.php b/app/Http/Controllers/ArtistsController.php index 1a63b4680f3..a5d66e60692 100644 --- a/app/Http/Controllers/ArtistsController.php +++ b/app/Http/Controllers/ArtistsController.php @@ -18,7 +18,7 @@ public function index() $artists = Artist::with('label')->withMax('tracks', 'created_at')->withCount('tracks')->orderBy('name', 'asc'); $user = Auth::user(); - if ($user === null || !$user->isAdmin()) { + if ($user === null || !$user->isGroup('admin')) { $artists->where('visible', true); } @@ -32,7 +32,7 @@ public function show($id) $artist = Artist::with('label')->findOrFail($id); $user = Auth::user(); - if (!$artist->visible && ($user === null || !$user->isAdmin())) { + if (!$artist->visible && ($user === null || !$user->isGroup('admin'))) { abort(404); } diff --git a/app/Http/Controllers/ContestsController.php b/app/Http/Controllers/ContestsController.php index 3ed5d131fd4..d04074d7655 100644 --- a/app/Http/Controllers/ContestsController.php +++ b/app/Http/Controllers/ContestsController.php @@ -15,7 +15,7 @@ public function index() { $contests = Contest::orderBy('id', 'desc'); - if (!Auth::check() || !Auth::user()->isAdmin()) { + if (!Auth::check() || !Auth::user()->isGroup('admin')) { $contests->where('visible', true); } @@ -29,7 +29,7 @@ public function show($id) $contest = Contest::findOrFail($id); $user = Auth::user(); - if (!$contest->visible && (!$user || !$user->isAdmin())) { + if (!$contest->visible && (!$user || !$user->isGroup('admin'))) { abort(404); } diff --git a/app/Http/Controllers/Forum/ForumCoversController.php b/app/Http/Controllers/Forum/ForumCoversController.php index e94cb7b995e..a9fb6c07127 100644 --- a/app/Http/Controllers/Forum/ForumCoversController.php +++ b/app/Http/Controllers/Forum/ForumCoversController.php @@ -25,7 +25,7 @@ public function __construct() ]]); $this->middleware(function ($request, $next) { - if (Auth::check() && !Auth::user()->isAdmin()) { + if (Auth::check() && !Auth::user()->isGroup('admin')) { abort(403); } diff --git a/app/Http/Controllers/StoreController.php b/app/Http/Controllers/StoreController.php index 4248f8bd226..df12089c3a8 100644 --- a/app/Http/Controllers/StoreController.php +++ b/app/Http/Controllers/StoreController.php @@ -47,7 +47,7 @@ public function getInvoice($id = null) ->with('items.product') ->findOrFail($id); - if (Auth::user()->user_id !== $order->user_id && !Auth::user()->isAdmin()) { + if (Auth::user()->user_id !== $order->user_id && !Auth::user()->isGroup('admin')) { abort(403); } diff --git a/app/Libraries/ClientCheck.php b/app/Libraries/ClientCheck.php index fd75549f7ad..41f4a11d132 100644 --- a/app/Libraries/ClientCheck.php +++ b/app/Libraries/ClientCheck.php @@ -11,7 +11,7 @@ class ClientCheck { public static function findBuild($user, $params): ?Build { - $assertValid = config('osu.client.check_version') && $user->findUserGroup(app('groups')->byIdentifier('admin'), true) === null; + $assertValid = config('osu.client.check_version') && !$user->isGroup('admin', allowOAuth: true); $clientHash = presence(get_string($params['version_hash'] ?? null)); if ($clientHash === null) { diff --git a/app/Libraries/OsuAuthorize.php b/app/Libraries/OsuAuthorize.php index 2ed38bad822..eff25247c9c 100644 --- a/app/Libraries/OsuAuthorize.php +++ b/app/Libraries/OsuAuthorize.php @@ -82,7 +82,7 @@ public function doCheckUser(?User $user, string $ability, object $object = null) $auth = $authMap->get($cacheKey, null); if ($auth === null) { - if ($user !== null && $user->isAdmin() && !static::alwaysCheck($ability)) { + if ($user !== null && $user->isGroup('admin') && !static::alwaysCheck($ability)) { $message = 'ok'; } else { $function = "check{$ability}"; @@ -141,7 +141,7 @@ public function checkBeatmapUpdateOwner(?User $user, ?Beatmapset $beatmapset): s Beatmapset::STATES['graveyard'], Beatmapset::STATES['loved'], ]; - if ($user->isProjectLoved() && in_array($status, $lovedModifiable, true)) { + if ($user->isGroup('loved') && in_array($status, $lovedModifiable, true)) { return 'ok'; } @@ -628,7 +628,7 @@ public function checkBeatmapsetLove(?User $user): string { $this->ensureLoggedIn($user); - if (!$user->isProjectLoved()) { + if (!$user->isGroup('loved')) { return 'unauthorized'; } @@ -648,7 +648,7 @@ public function checkBeatmapsetNominate(?User $user, Beatmapset $beatmapset): st static $prefix = 'beatmap_discussion.nominate.'; - if (!$user->isBNG() && !$user->isNAT()) { + if (!$user->isBNG() && !$user->isGroup('nat')) { return 'unauthorized'; } @@ -770,7 +770,7 @@ public function checkBeatmapsetDisqualify(?User $user, Beatmapset $beatmapset): { $this->ensureLoggedIn($user); - if (!$user->isFullBN() && !$user->isModerator()) { + if (!$user->isGroup('bng') && !$user->isModerator()) { return 'unauthorized'; } @@ -841,7 +841,7 @@ public function checkBeatmapsetMetadataEdit(?User $user, Beatmapset $beatmapset) Beatmapset::STATES['graveyard'], Beatmapset::STATES['loved'], ]; - if ($user->isProjectLoved() && in_array($beatmapset->approved, $lovedEditable, true)) { + if ($user->isGroup('loved') && in_array($beatmapset->approved, $lovedEditable, true)) { return 'ok'; } @@ -912,7 +912,7 @@ public function checkChatAnnounce(?User $user): string $this->ensureLoggedIn($user); $this->ensureCleanRecord($user, $prefix); - if ($user->isModerator() || $user->isChatAnnouncer()) { + if ($user->isModerator() || $user->isGroup('announce', allowOAuth: true)) { return 'ok'; } @@ -1363,7 +1363,14 @@ public function checkForumModerate(?User $user, Forum $forum): string return 'ok'; } - if ($forum->moderator_groups !== null && !empty(array_intersect($user->groupIds()['active'], $forum->moderator_groups))) { + // TODO: If `$user` is the resource owner, authorizing with a + // third-party OAuth client, `$user->groupIds()` should be empty + // here to match the restrictions in `User::isGroup()`. + // + // Some third-party clients currently rely on this mistake, so an + // alternative method to request usage of group permissions needs + // to be provided before fixing this. + if ($forum->moderator_groups !== null && !empty(array_intersect($user->groupIds(), $forum->moderator_groups))) { return 'ok'; } @@ -1808,8 +1815,7 @@ public function checkLegacyIrcKeyStore(?User $user): string $this->ensureLoggedIn($user); $this->ensureCleanRecord($user); - // isBot checks user primary group - if (!$user->isGroup(app('groups')->byIdentifier('bot')) && $user->playCount() < 100) { + if (!$user->isGroup('bot') && $user->playCount() < 100) { return 'play_more'; } diff --git a/app/Models/Beatmapset.php b/app/Models/Beatmapset.php index 3bd7f67f44f..b38e8f87fa4 100644 --- a/app/Models/Beatmapset.php +++ b/app/Models/Beatmapset.php @@ -724,10 +724,10 @@ public function nominate(User $user, array $playmodes = []) $canNominate = false; $canFullNominate = false; foreach ($this->playmodesStr() as $mode) { - if ($user->isFullBN($mode) || $user->isNAT($mode)) { + if ($user->isGroup('bng', $mode) || $user->isGroup('nat', $mode)) { $canNominate = true; $canFullNominate = true; - } else if ($user->isLimitedBN($mode)) { + } else if ($user->isGroup('bng_limited', $mode)) { $canNominate = true; } } @@ -747,8 +747,8 @@ public function nominate(User $user, array $playmodes = []) } foreach ($playmodes as $mode) { - if (!$user->isFullBN($mode) && !$user->isNAT($mode)) { - if (!$user->isLimitedBN($mode)) { + if (!$user->isGroup('bng', $mode) && !$user->isGroup('nat', $mode)) { + if (!$user->isGroup('bng_limited', $mode)) { throw new InvariantException(osu_trans('beatmapsets.nominate.incorrect_mode', ['mode' => $mode])); } @@ -1270,7 +1270,7 @@ public function hasFullBNNomination($mode = null) ->get() ->pluck('user') ->contains(function ($user) use ($mode) { - return $user->isNAT($mode) || $user->isFullBN($mode); + return $user->isGroup('nat', $mode) || $user->isGroup('bng', $mode); }); } diff --git a/app/Models/Chat/Channel.php b/app/Models/Chat/Channel.php index adab21408ee..580c5999e33 100644 --- a/app/Models/Chat/Channel.php +++ b/app/Models/Chat/Channel.php @@ -241,7 +241,7 @@ public function isVisibleFor(User $user): bool return !( $targetUser === null || $user->hasBlocked($targetUser) - && !($targetUser->isBot() || $targetUser->isModerator() || $targetUser->isAdmin()) + && !($targetUser->isBot() || $targetUser->isModerator() || $targetUser->isGroup('admin')) ); } diff --git a/app/Models/Forum/Authorize.php b/app/Models/Forum/Authorize.php index 316aa011957..f4dea498b71 100644 --- a/app/Models/Forum/Authorize.php +++ b/app/Models/Forum/Authorize.php @@ -25,7 +25,7 @@ class Authorize extends Model public static function aclCheck($user, $authOption, $forum) { - $groupIds = $user->groupIds()['active']; + $groupIds = $user->groupIds(); $authOptionId = AuthOption::where('auth_option', $authOption)->value('auth_option_id'); // the group may contain direct acl entry @@ -48,7 +48,7 @@ public static function aclCheck($user, $authOption, $forum) public static function aclGetAllowedForums($user, $authOption) { - $groupIds = $user->groupIds()['active']; + $groupIds = $user->groupIds(); $authOptionId = AuthOption::where('auth_option', $authOption)->value('auth_option_id'); $directAclForumIds = model_pluck(static::directAcl($groupIds, $authOptionId), 'forum_id'); diff --git a/app/Models/Forum/TopicCover.php b/app/Models/Forum/TopicCover.php index 199a70ce311..27e41195c10 100644 --- a/app/Models/Forum/TopicCover.php +++ b/app/Models/Forum/TopicCover.php @@ -52,7 +52,7 @@ public static function findForUse($id, $user) $covers = static::select(); - if ($user->isAdmin() === false) { + if ($user->isGroup('admin') === false) { $covers->where('user_id', $user->user_id); } diff --git a/app/Models/User.php b/app/Models/User.php index 3c81fc5e2e8..6b455789b7e 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -445,7 +445,7 @@ public function getUsernameAvailableAt(): Carbon { $playCount = $this->playCount(); - $allGroupIds = array_merge([$this->group_id], $this->groupIds()['active']); + $allGroupIds = array_merge([$this->group_id], $this->groupIds()); $allowedGroupIds = array_map(function ($groupIdentifier) { return app('groups')->byIdentifier($groupIdentifier)->getKey(); }, config('osu.user.allowed_rename_groups')); @@ -567,7 +567,7 @@ public function addToGroup(Group $group, ?array $playmodes = null, ?self $actor throw new InvariantException('Invalid playmodes: '.implode(', ', $invalidPlaymodes)); } - $activeUserGroup = $this->findUserGroup($group, true); + $activeUserGroup = $this->findUserGroup($group); if ($activeUserGroup === null) { $userGroup = $this @@ -612,7 +612,7 @@ public function addToGroup(Group $group, ?array $playmodes = null, ?self $actor public function removeFromGroup(Group $group, ?self $actor = null): void { - $userGroup = $this->findUserGroup($group, false); + $userGroup = $this->findUserGroup($group, includePending: true); if ($userGroup === null) { return; @@ -637,7 +637,7 @@ public function removeFromGroup(Group $group, ?self $actor = null): void public function setDefaultGroup(Group $group, ?self $actor = null): void { $this->getConnection()->transaction(function () use ($actor, $group) { - if ($this->findUserGroup($group, true) === null) { + if (!$this->isGroup($group, allowOAuth: true)) { $this->addToGroup($group, null, $actor); } @@ -947,83 +947,51 @@ public function getAttribute($key) | */ - public function inGroupWithPlaymode($groupIdentifier, $playmode = null) - { - $group = app('groups')->byIdentifier($groupIdentifier); - $isGroup = $this->isGroup($group); - - if ($isGroup === false || $playmode === null) { - return $isGroup; - } - - $groupModes = $this->findUserGroup($group, true)->actualRulesets(); - - return in_array($playmode, $groupModes ?? [], true); - } - - public function isNAT($mode = null) - { - return $this->inGroupWithPlaymode('nat', $mode); - } - - public function isAdmin() - { - return $this->isGroup(app('groups')->byIdentifier('admin')); - } - - public function isChatAnnouncer() - { - return $this->findUserGroup(app('groups')->byIdentifier('announce'), true) !== null; - } - - public function isGMT() - { - return $this->isGroup(app('groups')->byIdentifier('gmt')); - } - - public function isBNG($mode = null) - { - return $this->isFullBN($mode) || $this->isLimitedBN($mode); - } - - public function isFullBN($mode = null) - { - return $this->inGroupWithPlaymode('bng', $mode); - } - - public function isLimitedBN($mode = null) - { - return $this->inGroupWithPlaymode('bng_limited', $mode); - } - - public function isDev() + /** + * Check if the user is in the "bng" or "bng_limited" groups. + */ + public function isBNG(): bool { - return $this->isGroup(app('groups')->byIdentifier('dev')); + return $this->isGroup('bng') || $this->isGroup('bng_limited'); } - public function isModerator() + /** + * Check if the user is a bot. + * + * Note that this checks the user's default group, so it is different from + * calling `isGroup('bot')`: + * + * - Use `isBot()` to check if the user does not represent a real person. + * - Use `isGroup('bot')` to check if the user has been given approval to + * run a chat bot on their account. + */ + public function isBot(): bool { - return $this->isGMT() || $this->isNAT(); + return $this->group_id === app('groups')->byIdentifier('bot')->getKey(); } - public function isAlumni() + /** + * Check if the user is in the "gmt" or "nat" groups. + */ + public function isModerator(): bool { - return $this->isGroup(app('groups')->byIdentifier('alumni')); + return $this->isGroup('gmt') || $this->isGroup('nat'); } - public function isRegistered() + /** + * Check if the user is in any groups that give extra permissions. + */ + public function isPrivileged(): bool { - return $this->isGroup(app('groups')->byIdentifier('default')); - } + static $groups = ['admin', 'bng', 'bng_limited', 'dev', 'gmt', 'loved', 'nat']; - public function isProjectLoved() - { - return $this->isGroup(app('groups')->byIdentifier('loved')); - } + foreach ($groups as $group) { + if ($this->isGroup($group)) { + return true; + } + } - public function isBot() - { - return $this->group_id === app('groups')->byIdentifier('bot')->getKey(); + return false; } public function hasSupported() @@ -1059,16 +1027,6 @@ public function isOnline() && time() - $this->getRawAttribute('user_lastvisit') < config('osu.user.online_window'); } - public function isPrivileged() - { - return $this->isAdmin() - || $this->isDev() - || $this->isGMT() - || $this->isBNG() - || $this->isNAT() - || $this->isProjectLoved(); - } - public function isBanned() { return $this->user_type === 1; @@ -1118,31 +1076,36 @@ public function defaultGroup(): Group return $groups->byId($this->group_id) ?? $groups->byIdentifier('default'); } - public function groupIds() + /** + * Get the group IDs of the user's active usergroups. + * + * @return array + */ + public function groupIds(): array { return $this->memoize(__FUNCTION__, function () { - $ret = [ - 'active' => [], - 'pending' => [], - ]; - - foreach ($this->userGroups as $userGroup) { - $key = $userGroup->user_pending ? 'pending' : 'active'; - $ret[$key][] = $userGroup->group_id; - } - - return $ret; + return $this + ->userGroups + ->where('user_pending', false) + ->pluck('group_id') + ->all(); }); } - - public function findUserGroup($group, bool $activeOnly): ?UserGroup + /** + * Get the user's usergroup corresponding to a specified group. + */ + public function findUserGroup(Group|string $group, bool $includePending = false): ?UserGroup { $byGroupId = $this->memoize(__FUNCTION__.':byGroupId', fn () => $this->userGroups->keyBy('group_id')); + if (is_string($group)) { + $group = app('groups')->byIdentifier($group); + } + $userGroup = $byGroupId->get($group->getKey()); - if ($userGroup === null || ($activeOnly && $userGroup->user_pending)) { + if ($userGroup === null || (!$includePending && $userGroup->user_pending)) { return null; } @@ -1150,17 +1113,25 @@ public function findUserGroup($group, bool $activeOnly): ?UserGroup } /** - * Check if a user is in a specific group. - * - * This will always return false when called on user authenticated using OAuth. + * Check if the user is in a specified group. * - * @param Group $group - * - * @return bool + * @param \App\Models\Group|string $group + * @param string|null $ruleset Additionally check if the usergroup has a specified ruleset. + * @param bool $allowOAuth Whether to perform the check if the user was authenticated using OAuth. */ - public function isGroup($group) + public function isGroup(Group|string $group, ?string $ruleset = null, bool $allowOAuth = false): bool { - return $this->findUserGroup($group, true) !== null && $this->token() === null; + if (!$allowOAuth && $this->token() !== null) { + return false; + } + + $userGroup = $this->findUserGroup($group); + + if ($userGroup === null) { + return false; + } + + return $ruleset === null || in_array($ruleset, $userGroup->actualRulesets(), true); } public function badges() @@ -1687,8 +1658,8 @@ public function userGroupsForBadges() } return $this->userGroups - ->filter(function ($userGroup) { - return optional($userGroup->group)->hasBadge(); + ->filter(function (UserGroup $userGroup) { + return !$userGroup->user_pending && $userGroup->group->hasBadge(); }) ->sort(function ($a, $b) { // If the user has a default group, always show it first @@ -1709,28 +1680,28 @@ public function userGroupsForBadges() public function nominationModes() { return $this->memoize(__FUNCTION__, function () { - if (!$this->isNAT() && !$this->isBNG()) { + if (!$this->isGroup('nat') && !$this->isBNG()) { return; } $modes = []; - if ($this->isLimitedBN()) { - $playmodes = $this->findUserGroup(app('groups')->byIdentifier('bng_limited'), true)->actualRulesets(); + if ($this->isGroup('bng_limited')) { + $playmodes = $this->findUserGroup('bng_limited')->actualRulesets(); foreach ($playmodes as $playmode) { $modes[$playmode] = 'limited'; } } - if ($this->isFullBN()) { - $playmodes = $this->findUserGroup(app('groups')->byIdentifier('bng'), true)->actualRulesets(); + if ($this->isGroup('bng')) { + $playmodes = $this->findUserGroup('bng')->actualRulesets(); foreach ($playmodes as $playmode) { $modes[$playmode] = 'full'; } } - if ($this->isNAT()) { - $playmodes = $this->findUserGroup(app('groups')->byIdentifier('nat'), true)->actualRulesets(); + if ($this->isGroup('nat')) { + $playmodes = $this->findUserGroup('nat')->actualRulesets(); foreach ($playmodes as $playmode) { $modes[$playmode] = 'full'; } diff --git a/app/Models/UserGroup.php b/app/Models/UserGroup.php index 0cc18fdfc68..ffef8973edb 100644 --- a/app/Models/UserGroup.php +++ b/app/Models/UserGroup.php @@ -8,10 +8,10 @@ /** * @property Group $group * @property int $group_id - * @property int $group_leader + * @property bool $group_leader * @property User $user * @property int $user_id - * @property int $user_pending + * @property bool $user_pending * @property array|null $playmodes */ class UserGroup extends Model @@ -20,6 +20,7 @@ class UserGroup extends Model public $incrementing = false; protected $casts = [ + 'group_leader' => 'boolean', 'user_pending' => 'boolean', ]; protected $primaryKey = ':composite'; diff --git a/app/Models/UserGroupEvent.php b/app/Models/UserGroupEvent.php index 90ee7aebc68..61a2bc793b1 100644 --- a/app/Models/UserGroupEvent.php +++ b/app/Models/UserGroupEvent.php @@ -171,7 +171,7 @@ public function scopeVisibleForUser(Builder $query, ?User $user): void $query->where('hidden', false); $userGroupIds = priv_check_user($user, 'IsSpecialScope')->can() - ? $user->groupIds()['active'] + ? $user->groupIds() : []; if (!empty($userGroupIds)) { diff --git a/app/Transformers/UserCompactTransformer.php b/app/Transformers/UserCompactTransformer.php index fbbbf529141..1edcb93aa46 100644 --- a/app/Transformers/UserCompactTransformer.php +++ b/app/Transformers/UserCompactTransformer.php @@ -243,7 +243,7 @@ public function includeGuestBeatmapsetCount(User $user) public function includeIsAdmin(User $user) { - return $this->primitive($user->isAdmin()); + return $this->primitive($user->isGroup('admin')); } public function includeIsBng(User $user) @@ -253,17 +253,17 @@ public function includeIsBng(User $user) public function includeIsFullBn(User $user) { - return $this->primitive($user->isFullBN()); + return $this->primitive($user->isGroup('bng')); } public function includeIsGmt(User $user) { - return $this->primitive($user->isGMT()); + return $this->primitive($user->isGroup('gmt')); } public function includeIsLimitedBn(User $user) { - return $this->primitive($user->isLimitedBN()); + return $this->primitive($user->isGroup('bng_limited')); } public function includeIsModerator(User $user) @@ -273,7 +273,7 @@ public function includeIsModerator(User $user) public function includeIsNat(User $user) { - return $this->primitive($user->isNAT()); + return $this->primitive($user->isGroup('nat')); } public function includeIsRestricted(User $user) diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index ce517ee827f..49591bde133 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -129,7 +129,7 @@ public function withGroup(?string $groupIdentifier, ?array $playmodes = null) app('groups')->resetMemoized(); } - $user->findUserGroup($group, true)->update(['playmodes' => $playmodes]); + $user->findUserGroup($group)->update(['playmodes' => $playmodes]); } }); } diff --git a/database/factories/UserGroupFactory.php b/database/factories/UserGroupFactory.php deleted file mode 100644 index 3ccd2c541e9..00000000000 --- a/database/factories/UserGroupFactory.php +++ /dev/null @@ -1,23 +0,0 @@ -. Licensed under the GNU Affero General Public License v3.0. -// See the LICENCE file in the repository root for full licence text. - -declare(strict_types=1); - -namespace Database\Factories; - -use App\Models\UserGroup; - -class UserGroupFactory extends Factory -{ - protected $model = UserGroup::class; - - public function definition(): array - { - return [ - 'group_leader' => 0, - 'user_pending' => 0, - ]; - } -} diff --git a/resources/views/beatmapsets/show.blade.php b/resources/views/beatmapsets/show.blade.php index 14e3036f4b0..d46beb26ea1 100644 --- a/resources/views/beatmapsets/show.blade.php +++ b/resources/views/beatmapsets/show.blade.php @@ -2,7 +2,7 @@ Copyright (c) ppy Pty Ltd . Licensed under the GNU Affero General Public License v3.0. See the LICENCE file in the repository root for full licence text. --}} -@if (optional(Auth::user())->isAdmin()) +@if (optional(Auth::user())->isGroup('admin')) @php $extraFooterLinks = [ osu_trans('common.buttons.admin') => route('admin.beatmapsets.show', $beatmapset->getKey()), diff --git a/resources/views/forum/forums/show.blade.php b/resources/views/forum/forums/show.blade.php index 0c621e36a0f..523b7300bab 100644 --- a/resources/views/forum/forums/show.blade.php +++ b/resources/views/forum/forums/show.blade.php @@ -132,7 +132,7 @@ class="simple-menu simple-menu--forum-list js-click-menu" @endif - @if (auth()->check() && auth()->user()->isAdmin()) + @if (auth()->check() && auth()->user()->isGroup('admin'))