2026-02-09 21:25:42 +05:30
|
|
|
'use server';
|
|
|
|
|
|
|
|
|
|
import { z } from 'zod';
|
|
|
|
|
import { logAdminAction } from '@/lib/audit-logger';
|
|
|
|
|
|
|
|
|
|
// --- Validation Schemas ---
|
|
|
|
|
|
|
|
|
|
const suspendSchema = z.object({
|
|
|
|
|
userId: z.string(),
|
|
|
|
|
reason: z.string().min(10, "Reason must be at least 10 characters"),
|
|
|
|
|
duration: z.enum(['24h', '7d', '30d', 'indefinite']),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const banSchema = z.object({
|
|
|
|
|
userId: z.string(),
|
|
|
|
|
reason: z.string().min(10),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const ticketSchema = z.object({
|
|
|
|
|
userId: z.string(),
|
|
|
|
|
summary: z.string().min(5),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// --- Authorization Helper ---
|
|
|
|
|
|
|
|
|
|
async function verifyAdmin() {
|
|
|
|
|
// TODO: Integrate with Auth.js session check
|
|
|
|
|
// const session = await auth();
|
|
|
|
|
// if (session?.user?.role !== 'admin') throw new Error("Unauthorized");
|
|
|
|
|
|
|
|
|
|
// Mock successful admin check
|
|
|
|
|
return { id: 'admin-1', role: 'admin' };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Server Actions ---
|
|
|
|
|
|
|
|
|
|
export async function resetPassword(userId: string) {
|
|
|
|
|
try {
|
|
|
|
|
const admin = await verifyAdmin();
|
|
|
|
|
|
|
|
|
|
// Simulate DB call
|
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 800));
|
|
|
|
|
|
|
|
|
|
await logAdminAction({
|
|
|
|
|
actorId: admin.id,
|
|
|
|
|
action: 'RESET_PASSWORD',
|
|
|
|
|
targetId: userId,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return { success: true, message: "Recovery email sent to user." };
|
|
|
|
|
} catch (error) {
|
|
|
|
|
return { success: false, message: "Failed to reset password." };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function impersonateUser(userId: string) {
|
|
|
|
|
try {
|
|
|
|
|
const admin = await verifyAdmin();
|
|
|
|
|
|
|
|
|
|
await logAdminAction({
|
|
|
|
|
actorId: admin.id,
|
|
|
|
|
action: 'IMPERSONATE_USER',
|
|
|
|
|
targetId: userId,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// In a real app, you'd set a cookie here
|
|
|
|
|
// cookies().set('impersonate_id', userId);
|
|
|
|
|
|
|
|
|
|
return { success: true, redirectUrl: '/dashboard' };
|
|
|
|
|
} catch (error) {
|
|
|
|
|
return { success: false, message: "Failed to start impersonation session." };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function terminateSessions(userId: string) {
|
|
|
|
|
try {
|
|
|
|
|
const admin = await verifyAdmin();
|
|
|
|
|
|
|
|
|
|
// Simulate DB call to delete sessions
|
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
|
|
|
|
|
|
|
|
await logAdminAction({
|
|
|
|
|
actorId: admin.id,
|
|
|
|
|
action: 'TERMINATE_SESSIONS',
|
|
|
|
|
targetId: userId,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return { success: true, message: "All active sessions terminated." };
|
|
|
|
|
} catch (error) {
|
|
|
|
|
return { success: false, message: "Failed to terminate sessions." };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function toggleSuspension(formData: FormData) {
|
|
|
|
|
try {
|
|
|
|
|
const admin = await verifyAdmin();
|
|
|
|
|
|
|
|
|
|
const rawData = {
|
|
|
|
|
userId: formData.get('userId'),
|
|
|
|
|
reason: formData.get('reason'),
|
|
|
|
|
duration: formData.get('duration'),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const validated = suspendSchema.safeParse(rawData);
|
|
|
|
|
if (!validated.success) {
|
|
|
|
|
return { success: false, message: validated.error.errors[0].message };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Simulate DB update
|
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
|
|
|
|
|
|
|
|
await logAdminAction({
|
|
|
|
|
actorId: admin.id,
|
|
|
|
|
action: 'SUSPEND_USER',
|
|
|
|
|
targetId: validated.data.userId,
|
|
|
|
|
details: { reason: validated.data.reason, duration: validated.data.duration },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return { success: true, message: `User suspended for ${validated.data.duration}.` };
|
|
|
|
|
} catch (error) {
|
|
|
|
|
return { success: false, message: "Failed to suspend user." };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function createSupportTicket(userId: string, summary: string) {
|
|
|
|
|
try {
|
|
|
|
|
const admin = await verifyAdmin();
|
|
|
|
|
|
|
|
|
|
const validated = ticketSchema.safeParse({ userId, summary });
|
|
|
|
|
if (!validated.success) return { success: false, message: "Invalid input" };
|
|
|
|
|
|
|
|
|
|
// Simulate DB insert
|
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 600));
|
|
|
|
|
|
|
|
|
|
await logAdminAction({
|
|
|
|
|
actorId: admin.id,
|
|
|
|
|
action: 'CREATE_TICKET',
|
|
|
|
|
targetId: userId,
|
|
|
|
|
details: { summary },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return { success: true, message: "Support ticket #T-1234 created." };
|
|
|
|
|
} catch (error) {
|
|
|
|
|
return { success: false, message: "Failed to create ticket." };
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-02-09 21:40:09 +05:30
|
|
|
|
|
|
|
|
// --- Bulk Actions ---
|
|
|
|
|
|
|
|
|
|
export async function bulkSuspendUsers(userIds: string[]) {
|
|
|
|
|
try {
|
|
|
|
|
const admin = await verifyAdmin();
|
|
|
|
|
|
|
|
|
|
// Simulate DB update
|
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
|
|
|
|
|
|
|
|
// Log for each user or a single bulk log
|
|
|
|
|
await logAdminAction({
|
|
|
|
|
actorId: admin.id,
|
|
|
|
|
action: 'BULK_SUSPEND',
|
|
|
|
|
targetId: 'multiple',
|
|
|
|
|
details: { count: userIds.length, userIds },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return { success: true, message: `Successfully suspended ${userIds.length} users.` };
|
|
|
|
|
} catch (error) {
|
|
|
|
|
return { success: false, message: "Failed to perform bulk suspension." };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function bulkBanUsers(userIds: string[]) {
|
|
|
|
|
try {
|
|
|
|
|
const admin = await verifyAdmin();
|
|
|
|
|
|
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
|
|
|
|
|
|
|
|
await logAdminAction({
|
|
|
|
|
actorId: admin.id,
|
|
|
|
|
action: 'BULK_BAN',
|
|
|
|
|
targetId: 'multiple',
|
|
|
|
|
details: { count: userIds.length, userIds },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return { success: true, message: `Successfully banned ${userIds.length} users.` };
|
|
|
|
|
} catch (error) {
|
|
|
|
|
return { success: false, message: "Failed to perform bulk ban." };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function bulkDeleteUsers(userIds: string[]) {
|
|
|
|
|
try {
|
|
|
|
|
const admin = await verifyAdmin();
|
|
|
|
|
|
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
|
|
|
|
|
|
|
|
await logAdminAction({
|
|
|
|
|
actorId: admin.id,
|
|
|
|
|
action: 'BULK_DELETE',
|
|
|
|
|
targetId: 'multiple',
|
|
|
|
|
details: { count: userIds.length, userIds },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return { success: true, message: `Successfully deleted ${userIds.length} users.` };
|
|
|
|
|
} catch (error) {
|
|
|
|
|
return { success: false, message: "Failed to perform bulk delete." };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function bulkVerifyUsers(userIds: string[]) {
|
|
|
|
|
try {
|
|
|
|
|
const admin = await verifyAdmin();
|
|
|
|
|
|
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
|
|
|
|
|
|
|
|
await logAdminAction({
|
|
|
|
|
actorId: admin.id,
|
|
|
|
|
action: 'BULK_VERIFY',
|
|
|
|
|
targetId: 'multiple',
|
|
|
|
|
details: { count: userIds.length, userIds },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return { success: true, message: `Successfully verified ${userIds.length} users.` };
|
|
|
|
|
} catch (error) {
|
|
|
|
|
return { success: false, message: "Failed to verify users." };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function bulkTagUsers(userIds: string[], tagId: string) {
|
|
|
|
|
try {
|
|
|
|
|
const admin = await verifyAdmin();
|
|
|
|
|
|
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
|
|
|
|
|
|
|
|
await logAdminAction({
|
|
|
|
|
actorId: admin.id,
|
|
|
|
|
action: 'BULK_TAG_ADD',
|
|
|
|
|
targetId: 'multiple',
|
|
|
|
|
details: { count: userIds.length, userIds, tagId },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return { success: true, message: `Added tag to ${userIds.length} users.` };
|
|
|
|
|
} catch (error) {
|
|
|
|
|
return { success: false, message: "Failed to tag users." };
|
|
|
|
|
}
|
|
|
|
|
}
|