From d82a59c5c1f86e6efe7b35416854fd4a782cf64a Mon Sep 17 00:00:00 2001 From: Tommaso Morganti Date: Sat, 11 Apr 2026 20:32:17 +0200 Subject: [PATCH 1/2] feat: delete messages on ban --- package.json | 2 +- pnpm-lock.yaml | 10 +++++----- src/modules/moderation/index.ts | 25 ++++++++++++++++++++++++- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index ce3f971..177e5bb 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "@grammyjs/parse-mode": "^1.11.1", "@grammyjs/runner": "^2.0.3", "@influxdata/influxdb-client": "^1.35.0", - "@polinetwork/backend": "^0.15.8", + "@polinetwork/backend": "^0.15.9", "@t3-oss/env-core": "^0.13.4", "@trpc/client": "^11.5.1", "@types/ssdeep.js": "^0.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ee2edd1..46163dc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -30,8 +30,8 @@ importers: specifier: ^1.35.0 version: 1.35.0 '@polinetwork/backend': - specifier: ^0.15.8 - version: 0.15.8 + specifier: ^0.15.9 + version: 0.15.9 '@t3-oss/env-core': specifier: ^0.13.4 version: 0.13.4(arktype@2.1.20)(typescript@5.7.3)(zod@4.1.11) @@ -431,8 +431,8 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@polinetwork/backend@0.15.8': - resolution: {integrity: sha512-SneWnzHy2/x2Ku29bVpd8JGHgOWLnqm0SbdYXqMlvZJMPbKZBEUFJEK1SW50IUW+bZFmvcWl7kuKCxnZr7NzUA==} + '@polinetwork/backend@0.15.9': + resolution: {integrity: sha512-5LuAgF2qHoG47QjazwJLcGAJglmb9dJ+wTBFbwU7uKVArsp9Os1QsRJ0XeEjqBBsOZtXYuezCLVYqY8AjPkQtA==} '@redis/bloom@1.2.0': resolution: {integrity: sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==} @@ -1831,7 +1831,7 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@polinetwork/backend@0.15.8': {} + '@polinetwork/backend@0.15.9': {} '@redis/bloom@1.2.0(@redis/client@1.6.0)': dependencies: diff --git a/src/modules/moderation/index.ts b/src/modules/moderation/index.ts index 5db8fc1..249dddb 100644 --- a/src/modules/moderation/index.ts +++ b/src/modules/moderation/index.ts @@ -3,6 +3,7 @@ import type { Chat, ChatMember, Message, User } from "grammy/types" import { err, ok, type Result } from "neverthrow" import { type ApiInput, api } from "@/backend" import { logger } from "@/logger" +import { MessageUserStorage } from "@/middlewares/message-user-storage" import { groupMessagesByChat, RestrictPermissions } from "@/utils/chat" import { type Duration, duration } from "@/utils/duration" import { fmt, fmtUser } from "@/utils/format" @@ -153,13 +154,35 @@ class ModerationClass implements MiddlewareObj { revoke_messages: true, }) .catch(() => false) - case "BAN": + case "BAN": { + await MessageUserStorage.getInstance() + .sync() + .catch(() => {}) + + const messages = await api.tg.messages.getLastByUser + .query({ + userId: p.target.id, + chatId: p.chat.id, + limit: 100, // both the limit of tRPC endpoint and Telegram API hard limit: https://core.telegram.org/bots/api#deletemessages + }) + .then((res) => res.messages ?? []) + .catch(() => []) + + await modules.shared.api + .deleteMessages( + p.chat.id, + messages.map((m) => m.messageId) + ) + .catch(() => {}) + return modules.shared.api .banChatMember(p.chat.id, p.target.id, { until_date: p.duration?.timestamp_s, revoke_messages: true, }) .catch(() => false) + } + case "UNBAN": return modules.shared.api.unbanChatMember(p.chat.id, p.target.id, { only_if_banned: true }).catch(() => false) case "MUTE": From d3f1bc642c97522ef88a13ecca5350af63c938eb Mon Sep 17 00:00:00 2001 From: Tommaso Morganti Date: Sat, 11 Apr 2026 21:05:26 +0200 Subject: [PATCH 2/2] fix: ban and delete concurrently --- src/modules/moderation/index.ts | 57 ++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/src/modules/moderation/index.ts b/src/modules/moderation/index.ts index 249dddb..ca3cd9c 100644 --- a/src/modules/moderation/index.ts +++ b/src/modules/moderation/index.ts @@ -143,6 +143,30 @@ class ModerationClass implements MiddlewareObj { }) } + /** + * Mass deletes the last 100 messages of a user in a specific chat, on best effort basis. + * + * Used when banning a user to delete all their messages in the chat + */ + private async deleteLastMessages(userId: number, chatId: number): Promise { + await MessageUserStorage.getInstance() + .sync() + .catch(() => {}) + + // both the limit of tRPC endpoint and Telegram API hard limit: https://core.telegram.org/bots/api#deletemessages + const messages = await api.tg.messages.getLastByUser + .query({ userId, chatId, limit: 100 }) + .then((res) => res.messages ?? []) + .catch(() => []) + + await modules.shared.api + .deleteMessages( + chatId, + messages.map((m) => m.messageId) + ) + .catch(() => {}) + } + private async perform(p: ModerationAction) { switch (p.action) { case "SILENT": @@ -155,32 +179,13 @@ class ModerationClass implements MiddlewareObj { }) .catch(() => false) case "BAN": { - await MessageUserStorage.getInstance() - .sync() - .catch(() => {}) - - const messages = await api.tg.messages.getLastByUser - .query({ - userId: p.target.id, - chatId: p.chat.id, - limit: 100, // both the limit of tRPC endpoint and Telegram API hard limit: https://core.telegram.org/bots/api#deletemessages - }) - .then((res) => res.messages ?? []) - .catch(() => []) - - await modules.shared.api - .deleteMessages( - p.chat.id, - messages.map((m) => m.messageId) - ) - .catch(() => {}) - - return modules.shared.api - .banChatMember(p.chat.id, p.target.id, { - until_date: p.duration?.timestamp_s, - revoke_messages: true, - }) - .catch(() => false) + const [success] = await Promise.all([ + modules.shared.api + .banChatMember(p.chat.id, p.target.id, { until_date: p.duration?.timestamp_s }) + .catch(() => false), + this.deleteLastMessages(p.target.id, p.chat.id), + ]) + return success } case "UNBAN":