Fix: Correct ban migration logic

This commit is contained in:
gpt-engineer-app[bot]
2025-10-30 12:03:55 +00:00
parent e5de404e59
commit db101bc5f2
8 changed files with 509 additions and 52 deletions

View File

@@ -1,16 +1,16 @@
import { useState, useEffect } from 'react';
import { Search, Ban, Shield, UserCheck, UserX, AlertTriangle, Trash2 } from 'lucide-react';
import { Search, Shield, Trash2, Ban, AlertTriangle } 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 { BanUserDialog } from '@/components/admin/BanUserDialog';
import { Card, CardContent } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from '@/components/ui/alert-dialog';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { handleError, handleSuccess, getErrorMessage } from '@/lib/errorHandler';
import { logger } from '@/lib/logger';
@@ -83,15 +83,32 @@ export function ProfileManager() {
}
};
const handleBanUser = async (targetUserId: string, ban: boolean) => {
const handleBanUser = async (
targetUserId: string,
ban: boolean,
banReason?: string,
banExpiresAt?: Date | null
) => {
if (!user || !permissions) return;
setActionLoading(targetUserId);
try {
// Prepare update data
const updateData: any = { banned: ban };
if (ban && banReason) {
updateData.ban_reason = banReason;
updateData.ban_expires_at = banExpiresAt;
} else if (!ban) {
// Clear ban data when unbanning
updateData.ban_reason = null;
updateData.ban_expires_at = null;
}
// Update banned status
const { error: updateError } = await supabase
.from('profiles')
.update({ banned: ban })
.update(updateData)
.eq('user_id', targetUserId);
if (updateError) throw updateError;
@@ -102,7 +119,11 @@ export function ProfileManager() {
_admin_user_id: user.id,
_target_user_id: targetUserId,
_action: ban ? 'ban_user' : 'unban_user',
_details: { banned: ban }
_details: {
banned: ban,
ban_reason: banReason,
ban_expires_at: banExpiresAt?.toISOString()
}
});
if (logError) logger.error('Failed to log admin action', { error: getErrorMessage(logError) });
@@ -120,7 +141,7 @@ export function ProfileManager() {
handleError(error, {
action: `${ban ? 'Ban' : 'Unban'} User`,
userId: user?.id,
metadata: { targetUserId, ban }
metadata: { targetUserId, ban, banReason, banExpiresAt }
});
} finally {
setActionLoading(null);
@@ -363,47 +384,12 @@ export function ProfileManager() {
<div className="flex items-center gap-2">
{/* Ban/Unban Button */}
{canManageUser(profile) && permissions.can_ban_any_user && (
<AlertDialog>
<AlertDialogTrigger asChild>
<Button
variant={profile.banned ? "outline" : "destructive"}
size="sm"
disabled={actionLoading === profile.user_id}
>
{profile.banned ? (
<>
<UserCheck className="w-4 h-4 mr-2" />
Unban
</>
) : (
<>
<UserX className="w-4 h-4 mr-2" />
Ban
</>
)}
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>
{profile.banned ? 'Unban' : 'Ban'} User
</AlertDialogTitle>
<AlertDialogDescription>
Are you sure you want to {profile.banned ? 'unban' : 'ban'} {profile.username}?
{!profile.banned && ' This will prevent them from accessing the application.'}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
onClick={() => handleBanUser(profile.user_id, !profile.banned)}
className={profile.banned ? "" : "bg-destructive hover:bg-destructive/90"}
>
{profile.banned ? 'Unban' : 'Ban'} User
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
<BanUserDialog
profile={profile}
onBanComplete={fetchProfiles}
onBanUser={handleBanUser}
disabled={actionLoading === profile.user_id}
/>
)}
{/* Delete User Button - Superusers Only */}