Skip to content

feat: ban and mute command args overloading#87

Closed
toto04 wants to merge 1 commit intomainfrom
muteban-args
Closed

feat: ban and mute command args overloading#87
toto04 wants to merge 1 commit intomainfrom
muteban-args

Conversation

@toto04
Copy link
Copy Markdown
Contributor

@toto04 toto04 commented Apr 11, 2026

No description provided.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 11, 2026

Walkthrough

The moderation commands (ban, mute) were refactored to support both reply-based and user-argument-based execution modes. A new utility function getUserFromIdOrUsername was added to resolve users by numeric ID or username string, consolidating user lookup logic across these commands.

Changes

Cohort / File(s) Summary
Moderation Commands Refactoring
src/commands/moderation/ban.ts, src/commands/moderation/mute.ts
Commands now accept a combined first argument (reasonOrUser) representing either a user identifier or ban/mute reason, depending on whether replying. Reply constraint changed from required to optional. User resolution delegated to the new getUserFromIdOrUsername utility. Error handling updated to provide specific "must specify a user" messages. Log tag names normalized to uppercase (BAN:, MUTE:, TBAN:, TMUTE:). The corresponding unban and unmute commands also updated to use getUserFromIdOrUsername instead of manual getTelegramId lookup.
User Utility Enhancement
src/utils/users.ts
Added new exported function getUserFromIdOrUsername(idOrUsername, ctx) that accepts either a numeric Telegram user ID or a username string (with optional @ prefix). Normalizes usernames, resolves IDs via getTelegramId, logs debug messages, and delegates to getUser for user data retrieval.
🚥 Pre-merge checks | ✅ 1 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: ban and mute command args overloading' accurately describes the main change: both commands now support flexible argument parsing to accept either a user identifier/username or a ban/mute reason depending on context (reply vs non-reply), which is a form of argument overloading.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
src/utils/users.ts (1)

19-19: Use command-agnostic logging in shared resolver.

Line 19 hardcodes "unmute" inside a shared helper used by ban/mute/unban/unmute, which makes logs misleading during debugging.

Suggested patch
-    logger.debug(`unmute: no userId for username ${idOrUsername}`)
+    logger.debug({ idOrUsername }, "users: cannot resolve userId from username/id")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/users.ts` at line 19, The log message in the shared helper
currently hardcodes "unmute" which is misleading; update the logger.debug call
to be command-agnostic by removing the hardcoded verb or interpolating a
passed-in action name (e.g., use logger.debug(`${action}: no userId for username
${idOrUsername}`) or simply logger.debug(`no userId for username
${idOrUsername}`)); modify the helper signature to accept an action string if
needed and update all callers (ban/mute/unban/unmute) to pass the appropriate
action, keeping the unique identifiers idOrUsername and the logger.debug call to
locate the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/commands/moderation/ban.ts`:
- Around line 20-25: Update the help text for the ban command arguments to
replace incorrect "mute" wording with "ban": edit the first argument description
(the one that mentions reply handling) and the argument object with key "reason"
in the ban command definition so they state "ban" instead of "mute" (ensure the
phrasing matches the ban semantics and optional note about when reason applies).
- Line 30: The command definition currently forces reply-only usage by setting
reply: "required" which prevents the non-reply target branch in the /ban handler
from ever executing; update the command option/property named reply in
src/commands/moderation/ban.ts to be optional (e.g., "optional" or remove the
required flag) so the non-reply targeting logic in the branch around the handler
that checks for an explicit target (the code handling the non-reply path at the
branch around lines 47-63) can be reached; ensure the command validation still
handles both reply and explicit-target cases in the ban handler function.
- Line 46: The assignment for reason currently does reason = [args.reasonOrUser,
args.reason].filter(Boolean).join(" ") ?? undefined but join never yields
nullish so an empty string can slip through; update the logic that computes
reason (the variable named reason using args.reasonOrUser and args.reason) to
normalize empty or whitespace-only results to undefined (e.g., build the joined
string, trim it, and set reason = trimmed || undefined) so empty reasons become
undefined.

In `@src/commands/moderation/mute.ts`:
- Line 82: The current assignment to reason can end up as an empty string (""),
so update the expression that computes reason in mute.ts (the variable named
reason) to normalize empty results to undefined; for example, build the joined
string from [args.reasonOrUser, args.reason], trim it and then use a fallback
like || undefined (or explicitly set to undefined when === "") so that
empty-string reasons are not sent.

---

Nitpick comments:
In `@src/utils/users.ts`:
- Line 19: The log message in the shared helper currently hardcodes "unmute"
which is misleading; update the logger.debug call to be command-agnostic by
removing the hardcoded verb or interpolating a passed-in action name (e.g., use
logger.debug(`${action}: no userId for username ${idOrUsername}`) or simply
logger.debug(`no userId for username ${idOrUsername}`)); modify the helper
signature to accept an action string if needed and update all callers
(ban/mute/unban/unmute) to pass the appropriate action, keeping the unique
identifiers idOrUsername and the logger.debug call to locate the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1afee200-9269-4b32-ab8f-b19a4eb80709

📥 Commits

Reviewing files that changed from the base of the PR and between 6f9b761 and a9a3fac.

📒 Files selected for processing (3)
  • src/commands/moderation/ban.ts
  • src/commands/moderation/mute.ts
  • src/utils/users.ts

Comment on lines +20 to +25
"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)",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix copy text in ban argument descriptions.

Lines 20 and 25 say "mute" in the ban command help text, which is confusing for users.

Suggested patch
-          "If the message is a reply, this argument is the reason. Otherwise, it's the username or user id of the user to mute",
+          "If the message is a reply, this argument is the reason. Otherwise, it's the username or user id of the user to ban",
...
-        description: "Reason to mute the user (only if the first argument is the username or user id)",
+        description: "Reason to ban the user (only if the first argument is the username or user id)",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"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)",
"If the message is a reply, this argument is the reason. Otherwise, it's the username or user id of the user to ban",
},
{
key: "reason",
optional: true,
description: "Reason to ban the user (only if the first argument is the username or user id)",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands/moderation/ban.ts` around lines 20 - 25, Update the help text
for the ban command arguments to replace incorrect "mute" wording with "ban":
edit the first argument description (the one that mentions reply handling) and
the argument object with key "reason" in the ban command definition so they
state "ban" instead of "mute" (ensure the phrasing matches the ban semantics and
optional note about when reason applies).

],
description: "Permanently ban a user from a group",
scope: "group",
reply: "required",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Make non-reply /ban path reachable.

Line 30 still has reply: "required", so the non-reply targeting branch at Lines 47-63 is effectively blocked.

Suggested patch
-    reply: "required",
+    reply: "optional",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
reply: "required",
reply: "optional",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands/moderation/ban.ts` at line 30, The command definition currently
forces reply-only usage by setting reply: "required" which prevents the
non-reply target branch in the /ban handler from ever executing; update the
command option/property named reply in src/commands/moderation/ban.ts to be
optional (e.g., "optional" or remove the required flag) so the non-reply
targeting logic in the branch around the handler that checks for an explicit
target (the code handling the non-reply path at the branch around lines 47-63)
can be reached; ensure the command validation still handles both reply and
explicit-target cases in the ban handler function.

return
}
user = repliedTo.from
reason = [args.reasonOrUser, args.reason].filter(Boolean).join(" ") ?? undefined
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Normalize empty reason to undefined.

Line 46 uses .join(" ") ?? undefined; join never returns nullish, so this can pass "" instead of undefined.

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

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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
Verify each finding against the current code and only fix it if needed.

In `@src/commands/moderation/ban.ts` at line 46, The assignment for reason
currently does reason = [args.reasonOrUser, args.reason].filter(Boolean).join("
") ?? undefined but join never yields nullish so an empty string can slip
through; update the logic that computes reason (the variable named reason using
args.reasonOrUser and args.reason) to normalize empty or whitespace-only results
to undefined (e.g., build the joined string, trim it, and set reason = trimmed
|| undefined) so empty reasons become undefined.

return
}
user = repliedTo.from
reason = [args.reasonOrUser, args.reason].filter(Boolean).join(" ") ?? undefined
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Avoid sending empty-string reasons.

Line 82 can produce "" (not undefined) because .join(" ") ?? undefined never yields nullish.

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
Verify each finding against the current code and only fix it if needed.

In `@src/commands/moderation/mute.ts` at line 82, The current assignment to reason
can end up as an empty string (""), so update the expression that computes
reason in mute.ts (the variable named reason) to normalize empty results to
undefined; for example, build the joined string from [args.reasonOrUser,
args.reason], trim it and then use a fallback like || undefined (or explicitly
set to undefined when === "") so that empty-string reasons are not sent.

@toto04
Copy link
Copy Markdown
Contributor Author

toto04 commented Apr 11, 2026

superseded by #88

@toto04 toto04 closed this Apr 11, 2026
@toto04 toto04 deleted the muteban-args branch April 11, 2026 17:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant