216 lines
7.4 KiB
Markdown
216 lines
7.4 KiB
Markdown
# Agent 2: Telegram Bot Fixes (Tasks B, C, E)
|
|
|
|
## Summary
|
|
Fixed three issues in `crates/cgcx-bot/src/main.rs`:
|
|
- **Task B**: Enabled admin commands (including `/get_id`) in channels.
|
|
- **Task C**: Escaped angle-bracket placeholders in `/help` text to prevent Telegram HTML parse errors.
|
|
- **Task E**: Restricted `/blacklist_uid` and `/whitelist_uid` to admin groups at the outer dispatch level and removed redundant inner checks.
|
|
|
|
---
|
|
|
|
## Task B — /get_id in channels
|
|
|
|
**Problem:** Admin command dispatch was gated behind `msg.chat.is_group() || msg.chat.is_supergroup()`, so channels were excluded.
|
|
|
|
**Change:** Added `|| msg.chat.is_channel()` to the dispatch guard.
|
|
|
|
**oldText:**
|
|
```rust
|
|
// Admin commands in groups
|
|
if msg.chat.is_group() || msg.chat.is_supergroup() {
|
|
```
|
|
|
|
**newText:**
|
|
```rust
|
|
// Admin commands in groups
|
|
if msg.chat.is_group() || msg.chat.is_supergroup() || msg.chat.is_channel() {
|
|
```
|
|
|
|
---
|
|
|
|
## Task C — /help HTML parse errors
|
|
|
|
**Problem:** The `help_text` raw string contained unescaped placeholders like `<ID>`, `<@username>`, `<displayname>`, `<user_id>`, `<dur>`, `<unit>`. Telegram HTML parse mode rejects unsupported tags.
|
|
|
|
**Change:** Replaced every `<arg>` placeholder with `[arg]` (e.g., `<ID>` → `[ID]`). Existing `<dest>` / `<review>` were left untouched because they were already properly escaped.
|
|
|
|
**oldText:**
|
|
```rust
|
|
let help_text = r#"<b>Admin Commands</b>
|
|
|
|
/reload — Reload moderation lists.
|
|
/blacklist_uid <ID> — Blacklist a user ID.
|
|
/whitelist_uid <ID> — Remove a user from blacklist.
|
|
/help — Show this message.
|
|
/get_id — Get current chat ID.
|
|
/get_id <@username> — Search administrators by username.
|
|
/get_id <displayname> — Search members in this chat by display name.
|
|
/create_submit_forward <dest> <review> [msg] — Create a submission forward.
|
|
/show_c_forward [page] — List forward links.
|
|
/add_blacklist <user_id> — Blacklist a user in all active forwards.
|
|
/rm_blacklist <user_id> — Remove a user from blacklist in all active forwards.
|
|
/sban @user <dur> <unit> [reason] — Ban for duration
|
|
/smute @user <dur> <unit> [reason] — Mute for duration
|
|
/mute @user [reason] — Mute indefinitely
|
|
/pban @user [reason] — Permanent ban
|
|
/kick @user [reason] — Kick from group
|
|
/rmute @user — Revoke mute
|
|
/rban @user — Revoke ban"#;
|
|
```
|
|
|
|
**newText:**
|
|
```rust
|
|
let help_text = r#"<b>Admin Commands</b>
|
|
|
|
/reload — Reload moderation lists.
|
|
/blacklist_uid [ID] — Blacklist a user ID.
|
|
/whitelist_uid [ID] — Remove a user from blacklist.
|
|
/help — Show this message.
|
|
/get_id — Get current chat ID.
|
|
/get_id [@username] — Search administrators by username.
|
|
/get_id [displayname] — Search members in this chat by display name.
|
|
/create_submit_forward <dest> <review> [msg] — Create a submission forward.
|
|
/show_c_forward [page] — List forward links.
|
|
/add_blacklist [user_id] — Blacklist a user in all active forwards.
|
|
/rm_blacklist [user_id] — Remove a user from blacklist in all active forwards.
|
|
/sban @user [dur] [unit] [reason] — Ban for duration
|
|
/smute @user [dur] [unit] [reason] — Mute for duration
|
|
/mute @user [reason] — Mute indefinitely
|
|
/pban @user [reason] — Permanent ban
|
|
/kick @user [reason] — Kick from group
|
|
/rmute @user — Revoke mute
|
|
/rban @user — Revoke ban"#;
|
|
```
|
|
|
|
---
|
|
|
|
## Task E — /blacklist_uid and /whitelist_uid behavior
|
|
|
|
**Problem:** The outer dispatch only checked `is_admin()`, then the inner handler checked `admin_group_ids`. This leaked the command's existence to non-admin groups.
|
|
|
|
**Changes:**
|
|
1. At the outer command dispatch, both commands now require:
|
|
- `ctx.config.groups.admin_group_ids.contains(&chat_id.0)`
|
|
- `is_admin(&bot, msg.chat.id, user.id).await`
|
|
2. Removed the redundant `admin_group_ids` checks from inside `handle_admin_blacklist_uid` and `handle_admin_whitelist_uid`.
|
|
3. Missing-parameter usage replies remain intact in the handlers.
|
|
|
|
### Outer dispatch
|
|
|
|
**oldText:**
|
|
```rust
|
|
"/blacklist_uid" => {
|
|
tracing::info!("admin command /blacklist_uid chat={} user={}", chat_id, user_id);
|
|
if is_admin(&bot, msg.chat.id, user.id).await {
|
|
handle_admin_blacklist_uid(&bot, chat_id, text, &ctx).await?;
|
|
}
|
|
return Ok(());
|
|
}
|
|
"/whitelist_uid" => {
|
|
tracing::info!("admin command /whitelist_uid chat={} user={}", chat_id, user_id);
|
|
if is_admin(&bot, msg.chat.id, user.id).await {
|
|
handle_admin_whitelist_uid(&bot, chat_id, text, &ctx).await?;
|
|
}
|
|
return Ok(());
|
|
}
|
|
```
|
|
|
|
**newText:**
|
|
```rust
|
|
"/blacklist_uid" => {
|
|
tracing::info!("admin command /blacklist_uid chat={} user={}", chat_id, user_id);
|
|
if ctx.config.groups.admin_group_ids.contains(&chat_id.0) && is_admin(&bot, msg.chat.id, user.id).await {
|
|
handle_admin_blacklist_uid(&bot, chat_id, text, &ctx).await?;
|
|
}
|
|
return Ok(());
|
|
}
|
|
"/whitelist_uid" => {
|
|
tracing::info!("admin command /whitelist_uid chat={} user={}", chat_id, user_id);
|
|
if ctx.config.groups.admin_group_ids.contains(&chat_id.0) && is_admin(&bot, msg.chat.id, user.id).await {
|
|
handle_admin_whitelist_uid(&bot, chat_id, text, &ctx).await?;
|
|
}
|
|
return Ok(());
|
|
}
|
|
```
|
|
|
|
### Inner handler `handle_admin_blacklist_uid`
|
|
|
|
**oldText:**
|
|
```rust
|
|
async fn handle_admin_blacklist_uid(
|
|
bot: &Bot,
|
|
chat_id: ChatId,
|
|
text: &str,
|
|
ctx: &BotContext,
|
|
) -> HandlerResult {
|
|
if !ctx.config.groups.admin_group_ids.contains(&chat_id.0) {
|
|
bot.send_message(chat_id, "This command is only available in the admin group.")
|
|
.await?;
|
|
return Ok(());
|
|
}
|
|
let uid = text.split_whitespace().nth(1).and_then(|s| s.parse::<i64>().ok());
|
|
```
|
|
|
|
**newText:**
|
|
```rust
|
|
async fn handle_admin_blacklist_uid(
|
|
bot: &Bot,
|
|
chat_id: ChatId,
|
|
text: &str,
|
|
ctx: &BotContext,
|
|
) -> HandlerResult {
|
|
let uid = text.split_whitespace().nth(1).and_then(|s| s.parse::<i64>().ok());
|
|
```
|
|
|
|
### Inner handler `handle_admin_whitelist_uid`
|
|
|
|
**oldText:**
|
|
```rust
|
|
async fn handle_admin_whitelist_uid(
|
|
bot: &Bot,
|
|
chat_id: ChatId,
|
|
text: &str,
|
|
ctx: &BotContext,
|
|
) -> HandlerResult {
|
|
if !ctx.config.groups.admin_group_ids.contains(&chat_id.0) {
|
|
bot.send_message(chat_id, "This command is only available in the admin group.")
|
|
.await?;
|
|
return Ok(());
|
|
}
|
|
let uid = text.split_whitespace().nth(1).and_then(|s| s.parse::<i64>().ok());
|
|
```
|
|
|
|
**newText:**
|
|
```rust
|
|
async fn handle_admin_whitelist_uid(
|
|
bot: &Bot,
|
|
chat_id: ChatId,
|
|
text: &str,
|
|
ctx: &BotContext,
|
|
) -> HandlerResult {
|
|
let uid = text.split_whitespace().nth(1).and_then(|s| s.parse::<i64>().ok());
|
|
```
|
|
|
|
---
|
|
|
|
## Validation
|
|
|
|
```
|
|
$ cargo check -p cgcx-bot
|
|
Finished `dev` profile [unoptimized + debuginfo] target(s) in 45.10s
|
|
```
|
|
|
|
**Result:** `cargo check -p cgcx-bot` passed with no errors or warnings introduced by these changes.
|
|
|
|
---
|
|
|
|
## Files Changed
|
|
- `crates/cgcx-bot/src/main.rs`
|
|
- `progress.md` (updated task list)
|
|
|
|
## Open risks/questions
|
|
- None identified for these three tasks.
|
|
|
|
## Recommended next step
|
|
- Continue with remaining plan tasks (if any) or run `cargo test -p cgcx-bot` if tests exist.
|