mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 08:31:12 -05:00
feat: Implement comprehensive audit logging
This commit is contained in:
@@ -333,16 +333,40 @@ export const ReportsQueue = forwardRef<ReportsQueueRef>((props, ref) => {
|
||||
const handleReportAction = async (reportId: string, action: 'reviewed' | 'dismissed') => {
|
||||
setActionLoading(reportId);
|
||||
try {
|
||||
// Fetch report details for audit log
|
||||
const report = reports.find(r => r.id === reportId);
|
||||
|
||||
const { error } = await supabase
|
||||
.from('reports')
|
||||
.update({
|
||||
status: action,
|
||||
reviewed_by: user?.id,
|
||||
reviewed_at: new Date().toISOString(),
|
||||
})
|
||||
.eq('id', reportId);
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
// Log audit trail for report resolution
|
||||
if (user && report) {
|
||||
try {
|
||||
await supabase.rpc('log_admin_action', {
|
||||
_admin_user_id: user.id,
|
||||
_target_user_id: report.reported_by,
|
||||
_action: action === 'reviewed' ? 'report_resolved' : 'report_dismissed',
|
||||
_details: {
|
||||
report_id: reportId,
|
||||
reported_entity_type: report.reported_entity_type,
|
||||
reported_entity_id: report.reported_entity_id,
|
||||
report_reason: report.reason,
|
||||
action: action
|
||||
}
|
||||
});
|
||||
} catch (auditError) {
|
||||
console.error('Failed to log report action audit:', auditError);
|
||||
}
|
||||
}
|
||||
|
||||
handleSuccess(`Report ${action}`, `The report has been marked as ${action}`);
|
||||
|
||||
// Remove report from queue
|
||||
|
||||
@@ -235,6 +235,25 @@ export function useModerationActions(config: ModerationActionsConfig): Moderatio
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
// Log audit trail for review moderation
|
||||
if (table === 'reviews' && user) {
|
||||
try {
|
||||
await supabase.rpc('log_admin_action', {
|
||||
_admin_user_id: user.id,
|
||||
_target_user_id: item.user_id,
|
||||
_action: `review_${action}`,
|
||||
_details: {
|
||||
review_id: item.id,
|
||||
entity_type: item.entity_type,
|
||||
entity_id: item.entity_id,
|
||||
moderator_notes: moderatorNotes
|
||||
}
|
||||
});
|
||||
} catch (auditError) {
|
||||
logger.error('Failed to log review moderation audit', { error: auditError });
|
||||
}
|
||||
}
|
||||
|
||||
toast({
|
||||
title: `Content ${action}`,
|
||||
description: `The ${item.type} has been ${action}`,
|
||||
@@ -266,10 +285,35 @@ export function useModerationActions(config: ModerationActionsConfig): Moderatio
|
||||
onActionStart(item.id);
|
||||
|
||||
try {
|
||||
// Fetch submission details for audit log
|
||||
const { data: submission } = await supabase
|
||||
.from('content_submissions')
|
||||
.select('user_id, submission_type, status')
|
||||
.eq('id', item.id)
|
||||
.single();
|
||||
|
||||
const { error } = await supabase.from('content_submissions').delete().eq('id', item.id);
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
// Log audit trail for deletion
|
||||
if (user && submission) {
|
||||
try {
|
||||
await supabase.rpc('log_admin_action', {
|
||||
_admin_user_id: user.id,
|
||||
_target_user_id: submission.user_id,
|
||||
_action: 'submission_deleted',
|
||||
_details: {
|
||||
submission_id: item.id,
|
||||
submission_type: submission.submission_type,
|
||||
status_when_deleted: submission.status
|
||||
}
|
||||
});
|
||||
} catch (auditError) {
|
||||
logger.error('Failed to log submission deletion audit', { error: auditError });
|
||||
}
|
||||
}
|
||||
|
||||
toast({
|
||||
title: 'Submission deleted',
|
||||
description: 'The submission has been permanently deleted',
|
||||
@@ -302,6 +346,23 @@ export function useModerationActions(config: ModerationActionsConfig): Moderatio
|
||||
const { resetRejectedItemsToPending } = await import('@/lib/submissionItemsService');
|
||||
await resetRejectedItemsToPending(item.id);
|
||||
|
||||
// Log audit trail for reset
|
||||
if (user) {
|
||||
try {
|
||||
await supabase.rpc('log_admin_action', {
|
||||
_admin_user_id: user.id,
|
||||
_target_user_id: item.user_id,
|
||||
_action: 'submission_reset',
|
||||
_details: {
|
||||
submission_id: item.id,
|
||||
submission_type: item.submission_type
|
||||
}
|
||||
});
|
||||
} catch (auditError) {
|
||||
logger.error('Failed to log submission reset audit', { error: auditError });
|
||||
}
|
||||
}
|
||||
|
||||
toast({
|
||||
title: 'Reset Complete',
|
||||
description: 'Submission and all items have been reset to pending status',
|
||||
@@ -355,6 +416,25 @@ export function useModerationActions(config: ModerationActionsConfig): Moderatio
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
// Log audit trail for retry
|
||||
if (user) {
|
||||
try {
|
||||
await supabase.rpc('log_admin_action', {
|
||||
_admin_user_id: user.id,
|
||||
_target_user_id: item.user_id,
|
||||
_action: 'submission_retried',
|
||||
_details: {
|
||||
submission_id: item.id,
|
||||
submission_type: item.submission_type,
|
||||
items_retried: failedItems.length,
|
||||
request_id: requestId
|
||||
}
|
||||
});
|
||||
} catch (auditError) {
|
||||
logger.error('Failed to log submission retry audit', { error: auditError });
|
||||
}
|
||||
}
|
||||
|
||||
toast({
|
||||
title: 'Items Retried',
|
||||
description: `Successfully retried ${failedItems.length} failed item(s)${requestId ? ` (Request: ${requestId.substring(0, 8)})` : ''}`,
|
||||
|
||||
@@ -1155,6 +1155,13 @@ export async function escalateSubmission(
|
||||
throw new Error('User authentication required to escalate submission');
|
||||
}
|
||||
|
||||
// Fetch submission details for audit log
|
||||
const { data: submission } = await supabase
|
||||
.from('content_submissions')
|
||||
.select('user_id, submission_type')
|
||||
.eq('id', submissionId)
|
||||
.single();
|
||||
|
||||
const { error } = await supabase
|
||||
.from('content_submissions')
|
||||
.update({
|
||||
@@ -1166,4 +1173,22 @@ export async function escalateSubmission(
|
||||
.eq('id', submissionId);
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
// Log audit trail for escalation
|
||||
if (submission) {
|
||||
try {
|
||||
await supabase.rpc('log_admin_action', {
|
||||
_admin_user_id: userId,
|
||||
_target_user_id: submission.user_id,
|
||||
_action: 'submission_escalated',
|
||||
_details: {
|
||||
submission_id: submissionId,
|
||||
submission_type: submission.submission_type,
|
||||
escalation_reason: reason
|
||||
}
|
||||
});
|
||||
} catch (auditError) {
|
||||
logger.error('Failed to log escalation audit', { error: auditError });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -602,6 +602,35 @@ serve(async (req) => {
|
||||
console.error('[APPROVAL] Failed to update submission status:', { error: updateError.message });
|
||||
}
|
||||
|
||||
// Log audit trail for submission action
|
||||
try {
|
||||
const approvedCount = approvalResults.filter(r => r.success).length;
|
||||
const rejectedCount = approvalResults.filter(r => !r.success).length;
|
||||
|
||||
await supabaseClient.rpc('log_admin_action', {
|
||||
_admin_user_id: authenticatedUserId,
|
||||
_target_user_id: submission.user_id,
|
||||
_action: finalStatus === 'approved'
|
||||
? 'submission_approved'
|
||||
: finalStatus === 'partially_approved'
|
||||
? 'submission_partially_approved'
|
||||
: 'submission_rejected',
|
||||
_details: {
|
||||
submission_id: submissionId,
|
||||
submission_type: submission.submission_type,
|
||||
items_approved: approvedCount,
|
||||
items_rejected: rejectedCount,
|
||||
total_items: approvalResults.length,
|
||||
final_status: finalStatus,
|
||||
has_dependency_failure: hasDependencyFailure,
|
||||
reviewer_notes: reviewerNotes
|
||||
}
|
||||
});
|
||||
} catch (auditError) {
|
||||
// Log but don't fail the operation
|
||||
console.error('[AUDIT] Failed to log admin action:', auditError);
|
||||
}
|
||||
|
||||
const duration = endRequest(tracking);
|
||||
|
||||
return new Response(
|
||||
|
||||
Reference in New Issue
Block a user