feat(ban): accept delete_message_seconds and app options (#2086)

This commit is contained in:
Hampus authored and GitHub committed 2026-08-29 16:22:12 +02:00
1 parent 9f099a9127
commit 805acf4e5e
48 files changed
+1358 -121

No files matched your search

@@ -133,6 +133,7 @@ export class AdminGuildMembershipService {
guildId,
targetId,
deleteMessageDays: data.delete_message_days,
deleteMessageSeconds: data.delete_message_seconds,
reason: data.reason ?? undefined,
banDurationSeconds: data.ban_duration_seconds ?? undefined,
skipGuildAuditLog: true,
@@ -225,14 +225,14 @@ export class MessageDeleteService {
async deleteUserMessagesInGuild({
userId,
guildId,
days,
seconds,
}: {
userId: UserID;
guildId: GuildID;
days: number;
seconds: number;
}): Promise<void> {
const channels = await this.deps.channelRepository.channelData.listGuildChannels(guildId);
const cutoffTimestamp = Date.now() - days * ms('1 day');
const cutoffTimestamp = Date.now() - seconds * ms('1 second');
const cutoffSnowflake = createMessageID(createSnowflakeFromTimestamp(cutoffTimestamp));
await Promise.all(
channels.map(async (channel: Channel) => {
@@ -262,7 +262,7 @@ export function GuildMemberController(app: HonoApp) {
const userId = ctx.get('user').id;
const targetId = createUserID(user_id);
const guildId = createGuildID(guild_id);
const {delete_message_days, reason, ban_duration_seconds} = ctx.req.valid('json');
const {delete_message_days, delete_message_seconds, reason, ban_duration_seconds} = ctx.req.valid('json');
const auditLogReason = ctx.get('auditLogReason') ?? null;
const effectiveReason = reason ?? auditLogReason ?? undefined;
await ctx.get('guildService').moderation.banMember(
@@ -271,6 +271,7 @@ export function GuildMemberController(app: HonoApp) {
guildId,
targetId,
deleteMessageDays: delete_message_days,
deleteMessageSeconds: delete_message_seconds,
reason: effectiveReason,
banDurationSeconds: ban_duration_seconds,
},
@@ -30,6 +30,8 @@ import type {IGuildRepositoryAggregate} from '../repositories/IGuildRepositoryAg
import {createGuildMfaEnforcer} from './GuildMfaEnforcement';
import {GuildMemberSearchIndexService} from './member/GuildMemberSearchIndexService';
const SECONDS_PER_DAY = 86_400;
export class GuildModerationService {
private readonly searchIndexService: GuildMemberSearchIndexService;
@@ -64,13 +66,23 @@ export class GuildModerationService {
targetId: UserID;
guildId: GuildID;
deleteMessageDays?: number;
deleteMessageSeconds?: number;
reason?: string | null;
banDurationSeconds?: number;
skipGuildAuditLog?: boolean;
},
auditLogReason?: string | null,
): Promise<void> {
const {userId, guildId, targetId, deleteMessageDays, reason, banDurationSeconds, skipGuildAuditLog} = params;
const {
userId,
guildId,
targetId,
deleteMessageDays,
deleteMessageSeconds,
reason,
banDurationSeconds,
skipGuildAuditLog,
} = params;
await this.checkModerationPermission({guildId, userId, permission: Permissions.BAN_MEMBERS});
if (userId === targetId) throw new UnknownGuildMemberError();
const targetUser = await this.userRepository.findUnique(targetId);
@@ -82,11 +94,13 @@ export class GuildModerationService {
const canManage = await this.gatewayService.checkTargetMember({guildId, userId, targetUserId: targetId});
if (!canManage) throw new MissingPermissionsError();
}
if (deleteMessageDays && deleteMessageDays > 0) {
const effectiveDeleteMessageSeconds =
deleteMessageSeconds ?? (deleteMessageDays !== undefined ? deleteMessageDays * SECONDS_PER_DAY : undefined);
if (effectiveDeleteMessageSeconds && effectiveDeleteMessageSeconds > 0) {
await this.workerService.addJob('deleteUserMessagesInGuildByTime', {
guildId: guildId.toString(),
userId: targetId.toString(),
days: deleteMessageDays,
seconds: effectiveDeleteMessageSeconds,
});
}
const targetIp = isIpBanExempt(targetUser.lastActiveIp) ? null : targetUser.lastActiveIp || null;
+8 -1
View File
@@ -30823,7 +30823,14 @@
"minimum": 0,
"maximum": 7,
"format": "int32",
"description": "Number of days of messages to delete from the banned user (0-7)"
"description": "Number of days of messages to delete from the banned user (0-7). Deprecated in favor of delete_message_seconds."
},
"delete_message_seconds": {
"type": "integer",
"minimum": 0,
"maximum": 604800,
"format": "int32",
"description": "Number of seconds of messages to delete for the banned user (0-604800, default 0)"
},
"reason": {
"anyOf": [{"type": "string"}, {"type": "null"}],
@@ -9,28 +9,28 @@ import {getWorkerDependencies} from '../WorkerContext';
const PayloadSchema = z.object({
guildId: z.string(),
userId: z.string(),
days: z.number().min(0).max(7),
seconds: z.number().min(0).max(604800),
});
const deleteUserMessagesInGuildByTime: WorkerTaskHandler = async (payload, helpers) => {
const validated = PayloadSchema.parse(payload);
helpers.logger.debug({payload: validated}, 'Processing deleteUserMessagesInGuildByTime task');
const guildId = createGuildID(BigInt(validated.guildId));
const userId = createUserID(BigInt(validated.userId));
const {days} = validated;
const {seconds} = validated;
Logger.debug(
{guildId: guildId.toString(), userId: userId.toString(), days},
{guildId: guildId.toString(), userId: userId.toString(), seconds},
'Starting time-based message deletion for guild ban',
);
try {
const {channelService} = getWorkerDependencies();
await channelService.messages.deletion.deleteUserMessagesInGuild({guildId, userId, days});
await channelService.messages.deletion.deleteUserMessagesInGuild({guildId, userId, seconds});
Logger.debug(
{guildId: guildId.toString(), userId: userId.toString(), days},
{guildId: guildId.toString(), userId: userId.toString(), seconds},
'Time-based message deletion completed successfully',
);
} catch (error) {
Logger.error(
{guildId: guildId.toString(), userId: userId.toString(), days, error},
{guildId: guildId.toString(), userId: userId.toString(), seconds, error},
'Failed to delete user messages in guild',
);
throw error;