User::count(), 'new_users_today' => User::whereDate('created_at', today())->count(), 'staff_count' => User::whereIn('role', ['admin', 'manager', 'editorial'])->count(), 'moderator_count' => User::where('role', 'moderator')->count(), ]; return Inertia::render('Admin/Dashboard', [ 'stats' => $stats, ]); } // ── Users ───────────────────────────────────────────────────────────────── public function users(Request $request): Response { $search = $request->string('search')->trim()->toString(); $roleFilter = $request->string('role')->trim()->toString(); $query = User::select('id', 'name', 'username', 'email', 'role', 'created_at', 'is_active') ->orderByDesc('created_at'); if ($search !== '') { $query->where(function ($q) use ($search): void { $q->where('name', 'like', "%{$search}%") ->orWhere('username', 'like', "%{$search}%") ->orWhere('email', 'like', "%{$search}%"); }); } if ($roleFilter !== '' && $roleFilter !== 'all') { $query->where('role', $roleFilter); } $users = $query->paginate(50)->withQueryString(); return Inertia::render('Admin/Users/Index', [ 'users' => $users, 'filters' => ['search' => $search, 'role' => $roleFilter], 'roles' => collect(UserRole::cases())->map(fn ($r) => [ 'value' => $r->value, 'label' => $r->label(), 'badge' => $r->badgeClass(), ]), ]); } // ── Promote / Demote ────────────────────────────────────────────────────── public function updateRole(Request $request, User $user): RedirectResponse { $request->validate([ 'role' => ['required', 'string', 'in:' . implode(',', array_column(UserRole::cases(), 'value'))], ]); /** @var \App\Models\User $actor */ $actor = $request->user(); // Only admins can set the 'admin' role. if ($request->input('role') === UserRole::Admin->value && ! $actor->isAdmin()) { abort(403, 'Only admins can grant the Admin role.'); } // Prevent self-demotion. if ($actor->id === $user->id) { return back()->with('error', 'You cannot change your own role.'); } $user->update(['role' => $request->input('role')]); return back()->with('success', "Role updated to \"{$request->input('role')}\" for {$user->name}."); } // ── Stories ─────────────────────────────────────────────────────────────── public function stories(Request $request): Response { $stories = Story::with('creator:id,name,username') ->select('id', 'title', 'status', 'published_at', 'creator_id') ->orderByDesc('created_at') ->paginate(50) ->withQueryString(); return Inertia::render('Admin/Stories', [ 'stories' => $stories, ]); } // ── Artworks ────────────────────────────────────────────────────────────── public function artworks(Request $request): Response { $artworks = Artwork::with('user:id,name,username') ->select('id', 'title', 'artwork_status', 'created_at', 'user_id', 'hash', 'thumb_ext') ->orderByDesc('created_at') ->paginate(50) ->withQueryString(); // Normalise status field and add thumb URL $artworks->getCollection()->transform(function ($artwork) { return [ 'id' => $artwork->id, 'title' => $artwork->title, 'status' => $artwork->artwork_status, 'thumb' => $artwork->thumbUrl('sm') ?? null, 'created_at' => $artwork->created_at, 'user' => $artwork->user, ]; }); return Inertia::render('Admin/Artworks', [ 'artworks' => $artworks, ]); } // ── Username Queue ──────────────────────────────────────────────────────── public function usernameQueue(): Response { return Inertia::render('Admin/UsernameQueue'); } // ── Upload Queue ────────────────────────────────────────────────────────── public function uploadQueue(): Response { return Inertia::render('Admin/UploadQueue'); } // ── Settings ────────────────────────────────────────────────────────────── public function settings(): Response { return Inertia::render('Admin/Settings', [ 'settings' => [], ]); } public function authAudit(Request $request): Response { abort_unless($request->user()?->isAdmin(), 403, 'Only admins can access this area.'); $search = $request->string('search')->trim()->toString(); $eventType = $request->string('event')->trim()->toString(); $status = $request->string('status')->trim()->toString(); $query = AuthAuditLog::query() ->with('user:id,name,username,email,role') ->latest('created_at') ->latest('id'); if ($search !== '') { $query->where(function ($builder) use ($search): void { $builder ->where('identifier', 'like', "%{$search}%") ->orWhere('ip', 'like', "%{$search}%") ->orWhere('reason', 'like', "%{$search}%") ->orWhereHas('user', function ($userQuery) use ($search): void { $userQuery ->where('name', 'like', "%{$search}%") ->orWhere('username', 'like', "%{$search}%") ->orWhere('email', 'like', "%{$search}%"); }); }); } if ($eventType !== '' && $eventType !== 'all') { $query->where('event_type', $eventType); } if ($status !== '' && $status !== 'all') { $query->where('status', $status); } $logs = $query->paginate(50)->withQueryString()->through(function (AuthAuditLog $log): array { return [ 'id' => $log->id, 'event_type' => $log->event_type, 'identifier' => $log->identifier, 'status' => $log->status, 'reason' => $log->reason, 'ip' => $log->ip, 'user_agent' => $log->user_agent, 'metadata' => $log->metadata ?? [], 'created_at' => $log->created_at, 'user' => $log->user ? [ 'id' => $log->user->id, 'name' => $log->user->name, 'username' => $log->user->username, 'email' => $log->user->email, 'role' => $log->user->role, ] : null, ]; }); return Inertia::render('Admin/AuthAudit', [ 'logs' => $logs, 'filters' => [ 'search' => $search, 'event' => $eventType, 'status' => $status, ], 'eventOptions' => [ ['value' => 'all', 'label' => 'All events'], ['value' => 'login', 'label' => 'Login'], ['value' => 'register', 'label' => 'Register'], ['value' => 'forgot_password', 'label' => 'Forgot password'], ['value' => 'reset_password', 'label' => 'Reset password'], ], 'statusOptions' => [ ['value' => 'all', 'label' => 'All statuses'], ['value' => 'success', 'label' => 'Success'], ['value' => 'failed', 'label' => 'Failed'], ], ]); } }