diff --git a/apps/chat/src/index.ts b/apps/chat/src/index.ts index b91c3af..a4b6ed2 100644 --- a/apps/chat/src/index.ts +++ b/apps/chat/src/index.ts @@ -280,23 +280,32 @@ async function logModerationEvent(payload: { }); } -async function deleteMessageFromHistory(targetUsername: string, msgId: string): Promise { +async function deleteMessageFromHistory( + targetUsername: string, + msgId: string +): Promise<{ deleted: boolean; messageContent?: string }> { const channelKey = `chat:history:${targetUsername}`; const history = await redis.zrange(channelKey, 0, -1); for (const entry of history) { try { - const parsed = JSON.parse(entry) as { msgId?: string }; + const parsed = JSON.parse(entry) as { msgId?: string; message?: string }; if (parsed.msgId === msgId) { await redis.zrem(channelKey, entry); - return true; + return { + deleted: true, + messageContent: + typeof parsed.message === 'string' && parsed.message.length > 0 + ? parsed.message + : undefined, + }; } } catch { continue; } } - return false; + return { deleted: false }; } const app = new Hono(); diff --git a/apps/chat/src/utils/moderation.ts b/apps/chat/src/utils/moderation.ts index 9b848ce..cfe0479 100644 --- a/apps/chat/src/utils/moderation.ts +++ b/apps/chat/src/utils/moderation.ts @@ -26,7 +26,10 @@ type ModerationContext = { }; type DeleteMessageDeps = { - deleteMessageFromHistory: (targetUsername: string, msgId: string) => Promise; + deleteMessageFromHistory: ( + targetUsername: string, + msgId: string + ) => Promise<{ deleted: boolean; messageContent?: string }>; logModerationEvent: (payload: { action: ChatModerationAction; channelId: string; @@ -258,8 +261,8 @@ export async function handleDeleteMessageCommand( return; } - const deleted = await deps.deleteMessageFromHistory(context.targetUsername, msgId); - if (!deleted) { + const deletedMessage = await deps.deleteMessageFromHistory(context.targetUsername, msgId); + if (!deletedMessage.deleted) { sendModerationError(socket, 'NOT_FOUND', 'Message not found.'); return; } @@ -269,7 +272,10 @@ export async function handleDeleteMessageCommand( channelId: context.channelId, moderatorId: context.chatUser.moderatorUserId, reason: 'Message deleted by moderator', - details: { msgId }, + details: { + msgId, + messageContent: deletedMessage.messageContent, + }, }); recordChatModerationAction('message_deleted'); diff --git a/apps/web/src/app/(ui)/(protected)/admin/page.client.tsx b/apps/web/src/app/(ui)/(protected)/admin/page.client.tsx index bcc5a53..a772884 100644 --- a/apps/web/src/app/(ui)/(protected)/admin/page.client.tsx +++ b/apps/web/src/app/(ui)/(protected)/admin/page.client.tsx @@ -1019,6 +1019,20 @@ export default function AdminPanelClient({ currentUser }: AdminPanelClientProps) {log.reason}

)} + + {log.deletedMessageContent && ( +
+ +
+

+ Deleted message +

+

+ {log.deletedMessageContent} +

+
+
+ )} ); @@ -1184,10 +1198,10 @@ export default function AdminPanelClient({ currentUser }: AdminPanelClientProps) )} - )} - - {activeTab === 'settings' && ( -
+ )} + + {activeTab === 'settings' && ( +
} title="Platform Settings" @@ -1205,7 +1219,8 @@ export default function AdminPanelClient({ currentUser }: AdminPanelClientProps) ID Verification Bypass

- Allow existing users to bypass HCA verification and let them access the platform. + Allow existing users to bypass HCA verification and let them access the + platform.

@@ -1231,16 +1246,15 @@ export default function AdminPanelClient({ currentUser }: AdminPanelClientProps) Start searching to manage users

- Type an email or username above to find users and toggle their verification bypass + Type an email or username above to find users and toggle their + verification bypass

) : users.length === 0 ? (

No users found

-

- Try a different search term -

+

Try a different search term

) : ( <> @@ -1292,7 +1306,8 @@ export default function AdminPanelClient({ currentUser }: AdminPanelClientProps) onClick={() => handleToggleBypassVerification(user.id)} className={cn( 'h-7 text-xs gap-1 shrink-0 font-semibold transition-all duration-200', - user.bypassVerification && 'border-primary/30 hover:bg-primary/10 hover:border-primary/50' + user.bypassVerification && + 'border-primary/30 hover:bg-primary/10 hover:border-primary/50' )} > {user.bypassVerification ? ( @@ -1327,7 +1342,8 @@ export default function AdminPanelClient({ currentUser }: AdminPanelClientProps)

Session Management

- Force logout all other sessions except your current one. Useful for security maintenance. + Force logout all other sessions except your current one. Useful for + security maintenance.