Implement warning system enhancements with unique identifiers

- Added a `warningNumber` field to the `Warning` model for sequential identification of warnings.
- Updated the `createWarning` function to handle the new `warningNumber` logic and notify users via DM upon receiving a warning.
- Refactored moderation commands to utilize the new warning system, including changes to the warning creation and removal processes.
- Enhanced the WebUI to display warning numbers in the warnings table and updated localization for related messages.
- Documented changes in phase tracking to reflect the new warning system features.
This commit is contained in:
TheOnlyMace
2026-07-25 17:31:28 +02:00
parent 061e287390
commit 2058713e03
14 changed files with 218 additions and 52 deletions

View File

@@ -8,7 +8,7 @@ import { t, tf } from '@nexumi/shared';
import type { SlashCommand } from '../../types.js';
import { requirePermission } from '../../permissions.js';
import { assertModerableMember } from '../../hierarchy.js';
import { applyWarnEscalation, createCase } from './service.js';
import { applyWarnEscalation, createCase, createWarning } from './service.js';
import { parseDuration, parseTimeoutDuration, tryParseDuration } from './duration.js';
import { getGuildLocale } from '../../i18n.js';
import { promptDestructiveConfirmation } from './confirmations.js';
@@ -307,19 +307,15 @@ const warnCommand: SlashCommand = {
action: 'WARN_ADD',
reason
});
await context.prisma.user.upsert({
where: { id: user.id },
update: {},
create: { id: user.id }
});
const warning = await context.prisma.warning.create({
data: {
guildId: interaction.guildId!,
userId: user.id,
moderatorId: interaction.user.id,
reason,
caseId: modCase.id
}
const { warning } = await createWarning(context, {
guildId: interaction.guildId!,
userId: user.id,
moderatorId: interaction.user.id,
reason,
caseId: modCase.id,
guildName: interaction.guild!.name,
locale,
notifyUser: user
});
const escalationResult = await applyWarnEscalation(
interaction,
@@ -330,8 +326,8 @@ const warnCommand: SlashCommand = {
);
await interaction.reply({
content: escalationResult
? `${tf(locale, 'moderation.warning.created', { warningId: warning.id })}\n${escalationResult}`
: tf(locale, 'moderation.warning.created', { warningId: warning.id }),
? `${tf(locale, 'moderation.warning.created', { warningNumber: warning.warningNumber })}\n${escalationResult}`
: tf(locale, 'moderation.warning.created', { warningNumber: warning.warningNumber }),
ephemeral: true
});
return;
@@ -349,8 +345,8 @@ const warnCommand: SlashCommand = {
? t(locale, 'moderation.warning.none')
: warnings
.map(
(w: { id: string; reason: string | null }) =>
`- ${w.id}: ${w.reason ?? t(locale, 'moderation.warning.defaultReason')}`
(w: { warningNumber: number; reason: string | null }) =>
`- #${w.warningNumber}: ${w.reason ?? t(locale, 'moderation.warning.defaultReason')}`
)
.join('\n');
await interaction.reply({ content, ephemeral: true });
@@ -358,9 +354,9 @@ const warnCommand: SlashCommand = {
}
if (sub === 'remove') {
const warningId = interaction.options.getString('warning_id', true);
const warningNumber = interaction.options.getInteger('id', true);
const warning = await context.prisma.warning.findFirst({
where: { id: warningId, guildId: interaction.guildId! }
where: { warningNumber, guildId: interaction.guildId! }
});
if (!warning) {
await interaction.reply({
@@ -376,7 +372,7 @@ const warnCommand: SlashCommand = {
moderatorId: interaction.user.id,
...auditFrom(interaction),
action: 'WARN_REMOVE',
reason: `Warning ${warningId} removed`
reason: `Warning #${warningNumber} removed`
});
await replySuccessCase(interaction, locale, modCase.caseNumber);
return;