156 lines
5.1 KiB
Markdown
156 lines
5.1 KiB
Markdown
# Verification Report: Batches 5–9
|
||
|
||
## Batch 5 — Review Action Buttons
|
||
|
||
**Item 1: `finalize_upload` sends keyboard with [ Approve ], [ Ignore ], [ Blackl. ], [ Ban ], [ Ban/BL u. ]**
|
||
- **Status:** ✅ PASS
|
||
- **File/Line:** `crates/cgcx-bot/src/main.rs:1494–1507`
|
||
- **Evidence:**
|
||
```rust
|
||
let keyboard = InlineKeyboardMarkup::new(vec![
|
||
vec![
|
||
InlineKeyboardButton::callback("[ Approve ]", format!("v1:fwd:approve:{}", submission_id)),
|
||
InlineKeyboardButton::callback("[ Ignore ]", format!("v1:fwd:ignore:{}", submission_id)),
|
||
],
|
||
vec![
|
||
InlineKeyboardButton::callback("[ Blackl. ]", format!("v1:fwd:blk:{}", submission_id)),
|
||
InlineKeyboardButton::callback("[ Ban ]", format!("v1:fwd:ban:{}", submission_id)),
|
||
InlineKeyboardButton::callback("[ Ban/BL u. ]", format!("v1:fwd:banblk:{}", submission_id)),
|
||
],
|
||
]);
|
||
```
|
||
|
||
**Item 2: `handle_forward_callback` handles `ban`, `banblk`, `blk`, `approve`, `ignore` actions**
|
||
- **Status:** ✅ PASS
|
||
- **File/Line:** `crates/cgcx-bot/src/main.rs:1873–2121`
|
||
- **Evidence:** `match action` arm covers all five actions:
|
||
- `"approve"` → lines 1899–2053
|
||
- `"ignore"` → lines 2054–2065
|
||
- `"blk"` → lines 2066–2077
|
||
- `"ban"` → lines 2078–2094
|
||
- `"banblk"` → lines 2095–2114
|
||
|
||
**Item 3: Permission check (`is_admin_in_chat` on review group) is present**
|
||
- **Status:** ✅ PASS
|
||
- **File/Line:** `crates/cgcx-bot/src/main.rs:1901–1905`
|
||
- **Evidence:**
|
||
```rust
|
||
if !is_admin_in_chat(bot, ChatId(forward_def.review_group_id), UserId(user_id as u64)).await {
|
||
bot.send_message(chat_id, "Unauthorized.").await?;
|
||
return Ok(());
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Batch 6 — GLOBAL_BAN
|
||
|
||
**Item 1: `GroupsConfig` has `global_ban: bool`**
|
||
- **Status:** ✅ PASS
|
||
- **File/Line:** `crates/cgcx-config/src/lib.rs:66–73`
|
||
- **Evidence:**
|
||
```rust
|
||
pub struct GroupsConfig {
|
||
pub admin_group_ids: Vec<i64>,
|
||
pub review_group_ids: Vec<i64>,
|
||
#[serde(default = "default_global_ban")]
|
||
pub global_ban: bool,
|
||
}
|
||
fn default_global_ban() -> bool { false }
|
||
```
|
||
|
||
**Item 2: `propagate_punishment` checks `ctx.config.groups.global_ban`**
|
||
- **Status:** ✅ PASS
|
||
- **File/Line:** `crates/cgcx-bot/src/main.rs:2270–2272`
|
||
- **Evidence:**
|
||
```rust
|
||
async fn propagate_punishment(...) {
|
||
if !ctx.config.groups.global_ban {
|
||
return;
|
||
}
|
||
...
|
||
}
|
||
```
|
||
|
||
**Item 3: Punishment commands (`/sban`, `/smute`, `/mute`, `/pban`, `/kick`) call `propagate_punishment`**
|
||
- **Status:** ✅ PASS
|
||
- **File/Lines:**
|
||
- `/sban` → `main.rs:600`
|
||
- `/smute` → `main.rs:629`
|
||
- `/mute` → `main.rs:654`
|
||
- `/pban` → `main.rs:675`
|
||
- `/kick` → `main.rs:697`
|
||
- **Evidence:** Each command inserts a local punishment row, then immediately calls `propagate_punishment(&bot, &ctx, chat_id, target_id, "...", ...).await;`.
|
||
|
||
---
|
||
|
||
## Batch 9 — Username Tracking
|
||
|
||
**Item 1: `UserRepo::ensure_exists` logs username changes to configurable path**
|
||
- **Status:** ✅ PASS
|
||
- **File/Line:** `crates/cgcx-db/src/repos.rs:15–41`
|
||
- **Evidence:**
|
||
```rust
|
||
pub async fn ensure_exists(&self, id: i64, username: Option<&str>, first_name: &str, chat_id: i64, uname_changes_path: Option<&str>) -> Result<()> {
|
||
...
|
||
if let (Some(path), Some(ref old)) = (uname_changes_path, old_username) {
|
||
if old.as_str() != username.unwrap_or("") {
|
||
Self::log_username_change(id, chat_id, Some(old.as_str()), username, path);
|
||
}
|
||
}
|
||
Ok(())
|
||
}
|
||
```
|
||
`log_username_change` appends a JSON line with timestamp, user_id, chat_id, old, and new usernames.
|
||
|
||
**Item 2: `uname_changes_path` is in config**
|
||
- **Status:** ✅ PASS
|
||
- **File/Line:** `crates/cgcx-config/src/lib.rs:19–20, 27`
|
||
- **Evidence:**
|
||
```rust
|
||
#[serde(default = "default_uname_changes_path")]
|
||
pub uname_changes_path: String,
|
||
fn default_uname_changes_path() -> String { "data/uname_changes.json".to_string() }
|
||
```
|
||
Also used in bot at `main.rs:389`:
|
||
```rust
|
||
user_repo.ensure_exists(user_id, user.username.as_deref(), &user.first_name, chat_id.0, Some(&ctx.config.uname_changes_path)).await?;
|
||
```
|
||
|
||
---
|
||
|
||
## Batch 7 — Show/Hide Author
|
||
|
||
**Item 1: Upload options include `toggle_author` callback**
|
||
- **Status:** ✅ PASS
|
||
- **File/Lines:** `crates/cgcx-bot/src/main.rs:1008–1014, 1346–1364`
|
||
- **Evidence:**
|
||
- Callback handler:
|
||
```rust
|
||
"toggle_author" => {
|
||
let new_options = UploadOptions { show_author: !options.show_author, ..options };
|
||
...
|
||
}
|
||
```
|
||
- Keyboard button:
|
||
```rust
|
||
InlineKeyboardButton::callback("[ Toggle Author ]", "v1:opt:toggle_author"),
|
||
```
|
||
- Display text:
|
||
```rust
|
||
let author_text = if options.show_author { "Show author: <b>Yes</b>" } else { "Show author: <b>No</b>" };
|
||
```
|
||
|
||
---
|
||
|
||
## Summary
|
||
|
||
| Batch | Feature | Status |
|
||
|-------|---------|--------|
|
||
| 5 | Review action buttons (keyboard + handler + permission check) | ✅ PASS |
|
||
| 6 | GLOBAL_BAN config + propagation | ✅ PASS |
|
||
| 7 | Show/Hide Author toggle | ✅ PASS |
|
||
| 9 | Username change tracking | ✅ PASS |
|
||
|
||
**No issues found.** All inspected features are implemented and correctly wired.
|