*/ public static function resolveEventPermissions(Request $request, Event $event): array { $user = $request->user(); if (! $user instanceof User) { return []; } if (self::isTenantAdmin($user)) { return ['*']; } $member = self::resolveEventMember($user, $event); if (! $member) { return []; } return self::normalizePermissions($member->permissions); } public static function ensureEventPermission(Request $request, Event $event, string $permission): void { if (self::allowsPermission(self::resolveEventPermissions($request, $event), $permission)) { return; } throw new HttpResponseException(ApiError::response( 'insufficient_permission', 'Insufficient permission', 'You are not allowed to perform this action.', Response::HTTP_FORBIDDEN, ['required_permission' => $permission] )); } public static function allowsEventPermission(Request $request, Event $event, string $permission): bool { return self::allowsPermission(self::resolveEventPermissions($request, $event), $permission); } public static function ensureTenantPermission(Request $request, string $permission): void { $user = $request->user(); if (! $user instanceof User) { throw new HttpResponseException(ApiError::response( 'unauthenticated', 'Unauthenticated', 'You must be authenticated to perform this action.', Response::HTTP_UNAUTHORIZED )); } if (self::isTenantAdmin($user)) { return; } $permissions = self::resolveTenantMemberPermissions($user); if (self::allowsPermission($permissions, $permission)) { return; } throw new HttpResponseException(ApiError::response( 'insufficient_permission', 'Insufficient permission', 'You are not allowed to perform this action.', Response::HTTP_FORBIDDEN, ['required_permission' => $permission] )); } /** * @return array */ private static function resolveTenantMemberPermissions(User $user): array { if (! $user->tenant_id) { return []; } $memberships = EventMember::query() ->where('tenant_id', $user->tenant_id) ->whereIn('status', ['active', 'invited']) ->where(function ($query) use ($user) { $query->where('user_id', $user->id) ->orWhere('email', $user->email); }) ->get(['permissions']); $permissions = []; foreach ($memberships as $member) { $permissions = array_merge($permissions, self::normalizePermissions($member->permissions)); } return array_values(array_unique($permissions)); } private static function isTenantAdmin(User $user): bool { return in_array($user->role, ['tenant_admin', 'admin', 'super_admin', 'superadmin'], true); } private static function resolveEventMember(User $user, Event $event): ?EventMember { return EventMember::query() ->where('tenant_id', $event->tenant_id) ->where('event_id', $event->id) ->whereIn('status', ['active', 'invited']) ->where(function ($query) use ($user) { $query->where('user_id', $user->id) ->orWhere('email', $user->email); }) ->first(); } /** * @param array|string|null $permissions * @return array */ private static function normalizePermissions(mixed $permissions): array { if (is_array($permissions)) { return array_values(array_filter(array_map('strval', $permissions))); } if (is_string($permissions) && $permissions !== '') { return array_values(array_filter(array_map('trim', explode(',', $permissions)))); } return []; } /** * @param array $permissions */ private static function allowsPermission(array $permissions, string $permission): bool { foreach ($permissions as $entry) { if ($entry === '*' || $entry === $permission) { return true; } if (Str::endsWith($entry, ':*')) { $prefix = Str::beforeLast($entry, '*'); if (Str::startsWith($permission, $prefix)) { return true; } } } return false; } }