mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-24 08:51:16 -05:00
feat: Implement mandatory AAL2 for superuser actions
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Search, Ban, Shield, UserCheck, UserX, AlertTriangle } from 'lucide-react';
|
||||
import { Search, Ban, Shield, UserCheck, UserX, AlertTriangle, Trash2 } from 'lucide-react';
|
||||
import { supabase } from '@/integrations/supabase/client';
|
||||
import { useAuth } from '@/hooks/useAuth';
|
||||
import { useUserRole, UserRole } from '@/hooks/useUserRole';
|
||||
import { useSuperuserGuard } from '@/hooks/useSuperuserGuard';
|
||||
import { AdminUserDeletionDialog } from '@/components/admin/AdminUserDeletionDialog';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -34,6 +36,8 @@ export function ProfileManager() {
|
||||
const [statusFilter, setStatusFilter] = useState<'all' | 'active' | 'banned'>('all');
|
||||
const [roleFilter, setRoleFilter] = useState<'all' | UserRole>('all');
|
||||
const [actionLoading, setActionLoading] = useState<string | null>(null);
|
||||
const [deletionTarget, setDeletionTarget] = useState<UserProfile | null>(null);
|
||||
const superuserGuard = useSuperuserGuard();
|
||||
|
||||
useEffect(() => {
|
||||
if (!roleLoading && permissions?.can_view_all_profiles) {
|
||||
@@ -193,6 +197,20 @@ export function ProfileManager() {
|
||||
}
|
||||
};
|
||||
|
||||
// Check if current superuser can delete a specific user
|
||||
const canDeleteUser = (targetProfile: UserProfile) => {
|
||||
if (!superuserGuard.isSuperuser) return false;
|
||||
if (!superuserGuard.canPerformAction) return false;
|
||||
|
||||
// Cannot delete other superusers
|
||||
if (targetProfile.roles.includes('superuser')) return false;
|
||||
|
||||
// Cannot delete self
|
||||
if (targetProfile.user_id === user?.id) return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const canManageUser = (targetProfile: UserProfile) => {
|
||||
if (!permissions) return false;
|
||||
|
||||
@@ -336,10 +354,10 @@ export function ProfileManager() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{canManageUser(profile) && (
|
||||
{(canManageUser(profile) || canDeleteUser(profile)) && (
|
||||
<div className="flex items-center gap-2">
|
||||
{/* Ban/Unban Button */}
|
||||
{permissions.can_ban_any_user && (
|
||||
{canManageUser(profile) && permissions.can_ban_any_user && (
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<Button
|
||||
@@ -383,8 +401,21 @@ export function ProfileManager() {
|
||||
</AlertDialog>
|
||||
)}
|
||||
|
||||
{/* Delete User Button - Superusers Only */}
|
||||
{canDeleteUser(profile) && (
|
||||
<Button
|
||||
variant="destructive"
|
||||
size="sm"
|
||||
onClick={() => setDeletionTarget(profile)}
|
||||
disabled={actionLoading === profile.user_id}
|
||||
>
|
||||
<Trash2 className="w-4 h-4 mr-2" />
|
||||
Delete User
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{/* Role Management */}
|
||||
{(permissions.can_manage_moderator_roles || permissions.can_manage_admin_roles) && (
|
||||
{canManageUser(profile) && (permissions.can_manage_moderator_roles || permissions.can_manage_admin_roles) && (
|
||||
<Select
|
||||
onValueChange={(value) => handleRoleChange(profile.user_id, value as UserRole | 'remove', profile.roles)}
|
||||
disabled={actionLoading === profile.user_id}
|
||||
@@ -422,6 +453,25 @@ export function ProfileManager() {
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* User Deletion Dialog */}
|
||||
{deletionTarget && (
|
||||
<AdminUserDeletionDialog
|
||||
open={!!deletionTarget}
|
||||
onOpenChange={(open) => !open && setDeletionTarget(null)}
|
||||
targetUser={{
|
||||
userId: deletionTarget.user_id,
|
||||
username: deletionTarget.username,
|
||||
email: '', // Email not available in profile data
|
||||
displayName: deletionTarget.display_name || undefined,
|
||||
roles: deletionTarget.roles
|
||||
}}
|
||||
onDeletionComplete={() => {
|
||||
setDeletionTarget(null);
|
||||
fetchProfiles();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user