orderBy('created_at', 'desc')->get(); // Fetch all apps $apps = App::orderBy('name', 'asc')->get(); // Fetch all roles $roles = Role::with('apps')->orderBy('name', 'asc')->get(); // Fetch all overrides $overrides = UserAppOverride::with(['user', 'app'])->orderBy('created_at', 'desc')->get(); // Calculate statistics $stats = [ 'total_users' => User::count(), 'admins_count' => User::where('role', 'admin')->count(), 'blocked_count' => User::where('is_blocked', true)->count(), 'apps_count' => App::count(), 'roles_count' => Role::count(), ]; $defaultRoleName = \App\Models\Setting::get('default_role', 'Developer'); return view('admin.dashboard', compact('admin', 'users', 'apps', 'roles', 'overrides', 'stats', 'defaultRoleName')); } /** * Store a new app / service. */ public function storeApp(Request $request) { $request->validate([ 'name' => 'required|string|max:255', 'url' => 'required|url|max:255', 'icon_svg' => 'nullable|string', 'logo' => 'nullable|file|mimes:jpg,jpeg,png,webp,svg,avif,gif,bmp,ico|max:5120', 'color' => 'nullable|string|max:20', 'desc' => 'nullable|string', 'tag' => 'nullable|string|max:255', ], [ 'logo.mimes' => 'Invalid file format. Only image formats (PNG, JPG, WEBP, SVG, AVIF, GIF, BMP) are allowed.', 'logo.max' => 'File size exceeds maximum limit of 5MB. Please upload an image under 5MB.', ]); $logoPath = null; if ($request->hasFile('logo')) { $file = $request->file('logo'); $filename = time() . '_' . uniqid() . '.' . $file->getClientOriginalExtension(); $file->move(public_path('uploads/logos'), $filename); $logoPath = 'uploads/logos/' . $filename; } App::create([ 'name' => $request->name, 'url' => $request->url, 'icon_svg' => $request->icon_svg, 'logo' => $logoPath, 'color' => $request->color ?? '#4f46e5', 'desc' => $request->desc, 'tag' => $request->tag ?? 'General', ]); return redirect()->route('admin.dashboard')->with('success', 'Service app registered successfully.'); } /** * Delete an app / service. */ public function destroyApp($id) { $app = App::findOrFail($id); if ($app->logo && file_exists(public_path($app->logo))) { @unlink(public_path($app->logo)); } $app->delete(); return redirect()->route('admin.dashboard')->with('success', 'Service app deleted successfully.'); } /** * Update an app / service. */ public function updateApp(Request $request, $id) { $app = App::findOrFail($id); $request->validate([ 'name' => 'required|string|max:255', 'url' => 'required|url|max:255', 'icon_svg' => 'nullable|string', 'logo' => 'nullable|file|mimes:jpg,jpeg,png,webp,svg,avif,gif,bmp,ico|max:5120', 'color' => 'nullable|string|max:20', 'desc' => 'nullable|string', 'tag' => 'nullable|string|max:255', ], [ 'logo.mimes' => 'Invalid file format. Only image formats (PNG, JPG, WEBP, SVG, AVIF, GIF, BMP) are allowed.', 'logo.max' => 'File size exceeds maximum limit of 5MB. Please upload an image under 5MB.', ]); $logoPath = $app->logo; if ($request->hasFile('logo')) { if ($app->logo && file_exists(public_path($app->logo))) { @unlink(public_path($app->logo)); } $file = $request->file('logo'); $filename = time() . '_' . uniqid() . '.' . $file->getClientOriginalExtension(); $file->move(public_path('uploads/logos'), $filename); $logoPath = 'uploads/logos/' . $filename; } $app->update([ 'name' => $request->name, 'url' => $request->url, 'icon_svg' => $request->icon_svg, 'logo' => $logoPath, 'color' => $request->color ?? '#4f46e5', 'desc' => $request->desc, 'tag' => $request->tag ?? 'General', ]); return redirect()->route('admin.dashboard')->with('success', 'Service app updated successfully.'); } /** * Store a new role. */ public function storeRole(Request $request) { $request->validate([ 'name' => 'required|string|max:255|unique:roles,name', 'description' => 'nullable|string', 'apps' => 'nullable|array', 'apps.*' => 'exists:apps,id', ]); $role = Role::create([ 'name' => $request->name, 'description' => $request->description, 'can_manage_onboarding' => $request->boolean('can_manage_onboarding'), ]); if ($request->has('apps')) { $role->apps()->sync($request->apps); } return redirect()->route('admin.dashboard')->with('success', 'Role created successfully.'); } /** * Update an existing role. */ public function updateRole(Request $request, $id) { $role = Role::findOrFail($id); $request->validate([ 'name' => 'required|string|max:255|unique:roles,name,' . $role->id, 'description' => 'nullable|string', 'apps' => 'nullable|array', 'apps.*' => 'exists:apps,id', ]); $role->update([ 'name' => $request->name, 'description' => $request->description, 'can_manage_onboarding' => $request->boolean('can_manage_onboarding'), ]); $role->apps()->sync($request->apps ?? []); return redirect()->route('admin.dashboard')->with('success', 'Role updated successfully.'); } /** * Delete a role. */ public function destroyRole($id) { $role = Role::findOrFail($id); $role->delete(); return redirect()->route('admin.dashboard')->with('success', 'Role deleted successfully.'); } /** * Update user roles. */ public function updateUserRoles(Request $request, $id) { $user = User::findOrFail($id); $request->validate([ 'roles' => 'nullable|array', 'roles.*' => 'exists:roles,id', ]); $user->roles()->sync($request->roles ?? []); return redirect()->route('admin.dashboard')->with('success', 'User roles updated successfully.'); } /** * Add a user-specific app override. */ public function storeUserOverride(Request $request) { $request->validate([ 'user_id' => 'required|exists:users,id', 'app_id' => 'required|exists:apps,id', 'type' => 'required|in:allow,deny', ]); $user = User::findOrFail($request->user_id); // Prevent duplicate overrides $exists = UserAppOverride::where('user_id', $user->id) ->where('app_id', $request->app_id) ->exists(); if ($exists) { return redirect()->route('admin.dashboard')->with('error', 'An override for this service and user already exists.'); } UserAppOverride::create([ 'user_id' => $user->id, 'app_id' => $request->app_id, 'type' => $request->type, ]); return redirect()->route('admin.dashboard')->with('success', 'User service override registered successfully.'); } /** * Remove a user-specific override. */ public function destroyUserOverride($id) { $override = UserAppOverride::findOrFail($id); $override->delete(); return redirect()->route('admin.dashboard')->with('success', 'User service override removed successfully.'); } /** * Toggle the blocked status of a user. */ public function toggleBlockUser(Request $request, $id) { $user = User::findOrFail($id); // Security: Prevent blocking oneself if ($user->id === Auth::id()) { return redirect()->route('admin.dashboard')->with('error', 'Security violation: You cannot block your own administrator account.'); } $user->is_blocked = !$user->is_blocked; $user->save(); $status = $user->is_blocked ? 'blocked' : 'unblocked'; return redirect()->route('admin.dashboard')->with('success', "User account has been {$status} successfully."); } /** * Update the default role for new users. */ public function updateDefaultRole(Request $request) { $request->validate([ 'default_role' => 'required|string|exists:roles,name', ]); \App\Models\Setting::set('default_role', $request->default_role); return redirect()->route('admin.dashboard')->with('success', 'Default role for new users updated successfully.'); } /** * Toggle the Onboarding & Offboarding module status globally. */ public function updateOnboardingToggle(Request $request) { $enabled = $request->boolean('onboarding_enabled') ? '1' : '0'; \App\Models\Setting::set('onboarding_enabled', $enabled); $msg = $enabled === '1' ? 'Onboarding & Offboarding module enabled.' : 'Onboarding & Offboarding module disabled.'; return redirect()->route('admin.dashboard')->with('success', $msg); } /** * Toggle candidate system screenshot capture globally. */ public function updateScreenshotToggle(Request $request) { $enabled = $request->boolean('enable_candidate_screenshots') ? '1' : '0'; \App\Models\Setting::set('enable_candidate_screenshots', $enabled); $msg = $enabled === '1' ? 'Candidate System Screenshot Capture ENABLED globally.' : 'Candidate System Screenshot Capture DISABLED globally by Admin.'; return redirect()->route('admin.dashboard')->with('success', $msg); } /** * Toggle the admin privilege of a user. */ public function toggleAdminPrivilege(Request $request, $id) { $user = User::findOrFail($id); // Security: Prevent modifying own admin privileges if ($user->id === Auth::id()) { return redirect()->route('admin.dashboard')->with('error', 'Security violation: You cannot modify your own administrator privilege.'); } if ($user->role === 'admin') { $user->role = 'user'; // Detach Admin role from pivot if it exists $adminRole = Role::where('name', 'Admin')->first(); if ($adminRole) { $user->roles()->detach($adminRole->id); } $user->save(); $status = 'revoked'; } else { $user->role = 'admin'; // Attach Admin role to pivot (create if missing) $adminRole = Role::firstOrCreate( ['name' => 'Admin'], ['description' => 'Administrator access role.'] ); $user->roles()->syncWithoutDetaching([$adminRole->id]); $user->save(); $status = 'granted'; } return redirect()->route('admin.dashboard')->with('success', "Admin privilege has been {$status} for {$user->name} successfully."); } }