Files
Nexumi/apps/bot/src/modules/gdpr/service.ts
smueller 08af99ed52 Implement premium features and GDPR compliance in bot and WebUI
- Added new models for premium tier configurations and assignments, enabling feature limits for free and premium users.
- Introduced GDPR deletion logging and commands for user data management.
- Enhanced logging configuration with retention days for audit logs.
- Updated bot commands and job processing to include new premium and GDPR functionalities.
- Improved localization with new keys for premium features and GDPR commands in both English and German.
- Added UI components for managing premium settings and logging retention in the WebUI.
2026-07-22 16:59:23 +02:00

97 lines
2.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { PrismaClient } from '@prisma/client';
export type GdprDeletionSummary = {
warnings: number;
modNotes: number;
memberLevels: number;
memberEconomies: number;
inventoryItems: number;
birthdays: number;
afkStatuses: number;
reminders: number;
inviteStats: number;
casesAnonymized: number;
userPremium: number;
userRecord: number;
};
/**
* Deletes or anonymizes personal data for a Discord user across guilds.
* Moderation case history is anonymized (targetUserId cleared to a placeholder)
* so server audit integrity is preserved.
*/
export async function deleteUserPersonalData(
prisma: PrismaClient,
userId: string,
guildId: string | null
): Promise<GdprDeletionSummary> {
const scope = guildId ? { guildId, userId } : { userId };
const caseScope = guildId
? { guildId, targetUserId: userId }
: { targetUserId: userId };
const [
warnings,
modNotes,
memberLevels,
memberEconomies,
inventoryItems,
birthdays,
afkStatuses,
reminders,
inviteStats,
inviteJoins,
casesAnonymized,
userPremium
] = await prisma.$transaction([
prisma.warning.deleteMany({ where: scope }),
prisma.modNote.deleteMany({ where: scope }),
prisma.memberLevel.deleteMany({ where: scope }),
prisma.memberEconomy.deleteMany({ where: scope }),
prisma.inventoryItem.deleteMany({ where: scope }),
prisma.birthday.deleteMany({ where: scope }),
prisma.afkStatus.deleteMany({ where: scope }),
prisma.reminder.deleteMany({ where: { userId, ...(guildId ? { guildId } : {}) } }),
prisma.inviteStat.deleteMany({
where: guildId ? { guildId, inviterId: userId } : { inviterId: userId }
}),
prisma.inviteJoin.deleteMany({ where: scope }),
prisma.case.updateMany({
where: caseScope,
data: { targetUserId: '0', reason: '[redacted GDPR deletion]' }
}),
prisma.userPremiumAssignment.deleteMany({ where: { userId } })
]);
let userRecord = 0;
if (!guildId) {
const deleted = await prisma.user.deleteMany({ where: { id: userId } });
userRecord = deleted.count;
}
const summary: GdprDeletionSummary = {
warnings: warnings.count,
modNotes: modNotes.count,
memberLevels: memberLevels.count,
memberEconomies: memberEconomies.count,
inventoryItems: inventoryItems.count,
birthdays: birthdays.count,
afkStatuses: afkStatuses.count,
reminders: reminders.count,
inviteStats: inviteStats.count + inviteJoins.count,
casesAnonymized: casesAnonymized.count,
userPremium: userPremium.count,
userRecord
};
await prisma.gdprDeletionLog.create({
data: {
userId,
guildId,
summary
}
});
return summary;
}