-
Notifications
You must be signed in to change notification settings - Fork 0
feat: ban and mute command args overloading
#87
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -1,17 +1,30 @@ | ||||||||
| import type { User } from "grammy/types" | ||||||||
| import { CommandsCollection } from "@/lib/managed-commands" | ||||||||
| import { logger } from "@/logger" | ||||||||
| import { Moderation } from "@/modules/moderation" | ||||||||
| import { duration } from "@/utils/duration" | ||||||||
| import { fmt } from "@/utils/format" | ||||||||
| import { ephemeral } from "@/utils/messages" | ||||||||
| import { getTelegramId } from "@/utils/telegram-id" | ||||||||
| import { numberOrString, type Role } from "@/utils/types" | ||||||||
| import { getUser } from "@/utils/users" | ||||||||
| import { getUserFromIdOrUsername } from "@/utils/users" | ||||||||
|
|
||||||||
| export const ban = new CommandsCollection<Role>("Banning") | ||||||||
| .createCommand({ | ||||||||
| trigger: "ban", | ||||||||
| args: [{ key: "reason", optional: true, description: "Optional reason to ban the user" }], | ||||||||
| args: [ | ||||||||
| { | ||||||||
| key: "reasonOrUser", | ||||||||
| optional: true, | ||||||||
| type: numberOrString, | ||||||||
| description: | ||||||||
| "If the message is a reply, this argument is the reason. Otherwise, it's the username or user id of the user to mute", | ||||||||
| }, | ||||||||
| { | ||||||||
| key: "reason", | ||||||||
| optional: true, | ||||||||
| description: "Reason to mute the user (only if the first argument is the username or user id)", | ||||||||
| }, | ||||||||
| ], | ||||||||
| description: "Permanently ban a user from a group", | ||||||||
| scope: "group", | ||||||||
| reply: "required", | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make non-reply Line 30 still has Suggested patch- reply: "required",
+ reply: "optional",📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||
|
|
@@ -21,12 +34,34 @@ export const ban = new CommandsCollection<Role>("Banning") | |||||||
| allowGroupAdmins: true, | ||||||||
| }, | ||||||||
| handler: async ({ args, context, repliedTo }) => { | ||||||||
| if (!repliedTo.from) { | ||||||||
| logger.error("ban: no repliedTo.from field (the msg was sent in a channel)") | ||||||||
| return | ||||||||
| } | ||||||||
| let user: User | null = null | ||||||||
| let reason: string | undefined | ||||||||
|
|
||||||||
| const res = await Moderation.ban(repliedTo.from, context.chat, context.from, null, [repliedTo], args.reason) | ||||||||
| if (repliedTo) { | ||||||||
| if (!repliedTo.from) { | ||||||||
| logger.error("BAN: no repliedTo.from field (the msg was sent in a channel)") | ||||||||
| return | ||||||||
| } | ||||||||
| user = repliedTo.from | ||||||||
| reason = [args.reasonOrUser, args.reason].filter(Boolean).join(" ") ?? undefined | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Normalize empty reason to Line 46 uses Suggested patch- reason = [args.reasonOrUser, args.reason].filter(Boolean).join(" ") ?? undefined
+ const mergedReason = [args.reasonOrUser, args.reason].filter(Boolean).join(" ").trim()
+ reason = mergedReason || undefined📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||
| } else { | ||||||||
| if (!args.reasonOrUser) { | ||||||||
| const msg = await context.reply( | ||||||||
| fmt(({ b }) => b`You must specify a user to ban or reply to one of their messages`) | ||||||||
| ) | ||||||||
| await ephemeral(msg) | ||||||||
| return | ||||||||
| } | ||||||||
| user = await getUserFromIdOrUsername(args.reasonOrUser, context) | ||||||||
| if (!user) { | ||||||||
| const msg = await context.reply(fmt(({ n }) => n`Error: cannot find this user`)) | ||||||||
| logger.error({ user: args.reasonOrUser }, "BAN: cannot retrieve the user") | ||||||||
| await ephemeral(msg) | ||||||||
| return | ||||||||
| } | ||||||||
| reason = args.reason | ||||||||
| } | ||||||||
| const res = await Moderation.ban(user, context.chat, context.from, null, repliedTo ? [repliedTo] : [], reason) | ||||||||
| if (res.isErr()) await ephemeral(context.reply(res.error.fmtError)) | ||||||||
| }, | ||||||||
| }) | ||||||||
|
|
@@ -51,7 +86,7 @@ export const ban = new CommandsCollection<Role>("Banning") | |||||||
| }, | ||||||||
| handler: async ({ args, context, repliedTo }) => { | ||||||||
| if (!repliedTo.from) { | ||||||||
| logger.error("ban: no repliedTo.from field (the msg was sent in a channel)") | ||||||||
| logger.error("TBAN: no repliedTo.from field (the msg was sent in a channel)") | ||||||||
| return | ||||||||
| } | ||||||||
|
|
||||||||
|
|
@@ -77,18 +112,9 @@ export const ban = new CommandsCollection<Role>("Banning") | |||||||
| allowGroupAdmins: true, | ||||||||
| }, | ||||||||
| handler: async ({ args, context }) => { | ||||||||
| const userId: number | null = | ||||||||
| typeof args.username === "string" ? await getTelegramId(args.username.replaceAll("@", "")) : args.username | ||||||||
|
|
||||||||
| if (!userId) { | ||||||||
| logger.debug(`unban: no userId for username ${args.username}`) | ||||||||
| await ephemeral(context.reply(fmt(({ b }) => b`@${context.from.username} user not found`))) | ||||||||
| return | ||||||||
| } | ||||||||
|
|
||||||||
| const user = await getUser(userId, context) | ||||||||
| const user = await getUserFromIdOrUsername(args.username, context) | ||||||||
| if (!user) { | ||||||||
| logger.error({ userId }, "UNBAN: cannot retrieve the user") | ||||||||
| logger.error({ user: args.username }, "UNBAN: cannot retrieve the user") | ||||||||
| await ephemeral(context.reply(fmt(({ n }) => [n`Error: cannot find this user`]))) | ||||||||
| return | ||||||||
| } | ||||||||
|
|
||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,12 @@ | ||
| import type { User } from "grammy/types" | ||
| import { CommandsCollection } from "@/lib/managed-commands" | ||
| import { logger } from "@/logger" | ||
| import { Moderation } from "@/modules/moderation" | ||
| import { duration } from "@/utils/duration" | ||
| import { fmt } from "@/utils/format" | ||
| import { ephemeral } from "@/utils/messages" | ||
| import { getTelegramId } from "@/utils/telegram-id" | ||
| import { numberOrString, type Role } from "@/utils/types" | ||
| import { getUser } from "@/utils/users" | ||
| import { getUserFromIdOrUsername } from "@/utils/users" | ||
|
|
||
| export const mute = new CommandsCollection<Role>("Muting") | ||
| .createCommand({ | ||
|
|
@@ -30,7 +30,7 @@ export const mute = new CommandsCollection<Role>("Muting") | |
| }, | ||
| handler: async ({ args, context, repliedTo }) => { | ||
| if (!repliedTo.from) { | ||
| logger.error("tmute: no repliedTo.from field (the msg was sent in a channel)") | ||
| logger.error("TMUTE: no repliedTo.from field (the msg was sent in a channel)") | ||
| return | ||
| } | ||
|
|
||
|
|
@@ -47,22 +47,58 @@ export const mute = new CommandsCollection<Role>("Muting") | |
| }) | ||
| .createCommand({ | ||
| trigger: "mute", | ||
| args: [{ key: "reason", optional: true, description: "Optional reason to mute the user" }], | ||
| args: [ | ||
| { | ||
| key: "reasonOrUser", | ||
| optional: true, | ||
| type: numberOrString, | ||
| description: | ||
| "If the message is a reply, this argument is the reason. Otherwise, it's the username or user id of the user to mute", | ||
| }, | ||
| { | ||
| key: "reason", | ||
| optional: true, | ||
| description: "Reason to mute the user (only if the first argument is the username or user id)", | ||
| }, | ||
| ], | ||
| description: "Permanently mute a user from a group", | ||
| scope: "group", | ||
| reply: "required", | ||
| reply: "optional", | ||
| permissions: { | ||
| allowedRoles: ["owner", "direttivo"], | ||
| excludedRoles: ["creator"], | ||
| allowGroupAdmins: true, | ||
| }, | ||
| handler: async ({ args, context, repliedTo }) => { | ||
| if (!repliedTo.from) { | ||
| logger.error("mute: no repliedTo.from field (the msg was sent in a channel)") | ||
| return | ||
| let user: User | null = null | ||
| let reason: string | undefined | ||
|
|
||
| if (repliedTo) { | ||
| if (!repliedTo.from) { | ||
| logger.error("MUTE: no repliedTo.from field (the msg was sent in a channel)") | ||
| return | ||
| } | ||
| user = repliedTo.from | ||
| reason = [args.reasonOrUser, args.reason].filter(Boolean).join(" ") ?? undefined | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid sending empty-string reasons. Line 82 can produce Suggested patch- reason = [args.reasonOrUser, args.reason].filter(Boolean).join(" ") ?? undefined
+ const mergedReason = [args.reasonOrUser, args.reason].filter(Boolean).join(" ").trim()
+ reason = mergedReason || undefined🤖 Prompt for AI Agents |
||
| } else { | ||
| if (!args.reasonOrUser) { | ||
| const msg = await context.reply( | ||
| fmt(({ b }) => b`You must specify a user to mute or reply to one of their messages`) | ||
| ) | ||
| await ephemeral(msg) | ||
| return | ||
| } | ||
| user = await getUserFromIdOrUsername(args.reasonOrUser, context) | ||
| if (!user) { | ||
| const msg = await context.reply(fmt(({ n }) => n`Error: cannot find this user`)) | ||
| logger.error({ user: args.reasonOrUser }, "MUTE: cannot retrieve the user") | ||
| await ephemeral(msg) | ||
| return | ||
| } | ||
| reason = args.reason | ||
| } | ||
|
|
||
| const res = await Moderation.mute(repliedTo.from, context.chat, context.from, null, [repliedTo], args.reason) | ||
| const res = await Moderation.mute(user, context.chat, context.from, null, repliedTo ? [repliedTo] : [], reason) | ||
| if (res.isErr()) await ephemeral(context.reply(res.error.fmtError)) | ||
| }, | ||
| }) | ||
|
|
@@ -77,19 +113,10 @@ export const mute = new CommandsCollection<Role>("Muting") | |
| allowGroupAdmins: true, | ||
| }, | ||
| handler: async ({ args, context }) => { | ||
| const userId: number | null = | ||
| typeof args.username === "string" ? await getTelegramId(args.username.replaceAll("@", "")) : args.username | ||
| if (!userId) { | ||
| logger.debug(`unmute: no userId for username ${args.username}`) | ||
| const msg = await context.reply(fmt(({ b }) => b`@${context.from.username} user not found`)) | ||
| await ephemeral(msg) | ||
| return | ||
| } | ||
|
|
||
| const user = await getUser(userId, context) | ||
| const user = await getUserFromIdOrUsername(args.username, context) | ||
| if (!user) { | ||
| const msg = await context.reply(fmt(({ n }) => n`Error: cannot find this user`)) | ||
| logger.error({ userId }, "UNMUTE: cannot retrieve the user") | ||
| logger.error({ user: args.username }, "UNMUTE: cannot retrieve the user") | ||
| await ephemeral(msg) | ||
| return | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix copy text in
banargument descriptions.Lines 20 and 25 say "mute" in the
bancommand help text, which is confusing for users.Suggested patch
📝 Committable suggestion
🤖 Prompt for AI Agents