LTD-ManaagerBot/docs/en/modules.md

366 lines
12 KiB
Markdown

# LTD-ManagerBot Module Documentation
## Table of Contents
- [Quick Start](#quick-start)
- [Infrastructure Modules](#infrastructure-modules)
- [New Modules](#new-modules)
- [RCON Command Module](#rcon-command-module)
- [Gitea Webhook Module](#gitea-webhook-module)
- [Whitelist Audit Module](#whitelist-audit-module)
- [Configuration Reference](#configuration-reference)
---
## Quick Start
1. Copy the example configs from `src/main/resources/` to `config/`
2. Edit `config/application.yaml` — set database, API URLs, tokens
3. Edit `config/module.yaml` — uncomment and configure desired modules
4. Place SQL templates in `config/sql/` if using InvitationCodes or WhitelistAudit
5. Launch the bot
### Minimal `application.yaml` additions for new modules
```yaml
# Whitelist System API (required by WhitelistAuditModule)
whitelist-system:
url: "https://whitelist.your-server.top"
encrypted-token: "your-api-token-here"
```
---
## Infrastructure Modules
### GroupMessagePollingModule
Polls a QQ group's message history at a fixed interval and emits a `SharedFlow<List<MsgHistorySpecificMsg>>`. Other modules subscribe to this flow to react to messages.
```yaml
- name: "talkGroup"
type: "GROUP_MESSAGE_POLLING_MODULE"
enabled: true
config:
target-group-id: 538751386
poll-interval-millis: 5000 # optional, default 5000
msg-history-check: 15 # optional, default 15
```
### MailModule
Queues and sends emails via SMTP. Used by InvitationCodesModule and WhitelistAuditModule.
```yaml
- name: "talkGroup"
type: "MAIL_MODULE"
enabled: true
```
SMTP settings go in `application.yaml``mail:` section.
---
## New Modules
### RCON Command Module
**Type:** `RCON_COMMAND_MODULE`
Allows specified QQ users to execute arbitrary Minecraft RCON commands via QQ group messages, with a configurable blocklist to prevent dangerous operations.
#### Workflow
```
QQ Group: "rcon list"
├── User NOT in admin-ids → reply: "no permission"
├── Command matches blocklist → reply: "blocked"
└── Execute via RCON binary → reply with output
```
#### Example Config
```yaml
- name: "talkGroup"
type: "RCON_COMMAND_MODULE"
enabled: true
dependencies:
- name: "talkGroup"
type: "GROUP_MESSAGE_POLLING_MODULE"
config:
self-id: 3327379836
self-nick-name: "Bot"
command-prefix: "rcon"
admin-ids: [2561098830]
rcon-timeout-sec: 5
command-blocklist:
- "stop"
- "restart"
- "op"
- "deop"
- "whitelist"
- "ban"
- "ban-ip"
- "kick"
- "debug"
- "execute"
```
#### Config Reference
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `self-id` | long | yes | — | Bot's QQ ID |
| `self-nick-name` | string | yes | — | Bot's display name |
| `command-prefix` | string | yes | — | Trigger prefix in QQ group |
| `admin-ids` | long[] | yes | — | QQ IDs allowed to execute RCON |
| `command-blocklist` | string[] | yes | — | Blocked command prefixes (case-insensitive, `/`-prefix stripped) |
| `rcon-timeout-sec` | long | no | `5` | RCON timeout in seconds |
The RCON binary path and config path are read from `application.yaml``tools.rcon`.
#### Blocklist Matching
The blocklist uses **prefix matching** after stripping leading `/`:
- `"stop"` blocks: `stop`, `stop 10s`, `/stop`, `/minecraft:stop`
- `"ban"` blocks: `ban Steve`, `ban-ip`, `/ban`, etc.
---
### Gitea Webhook Module
**Type:** `GITEA_WEBHOOK_MODULE`
Starts an embedded HTTP server to receive [Gitea webhook](https://docs.gitea.com/usage/webhooks) events and forwards formatted notifications to a QQ group.
#### Supported Events
| Event | QQ Message Format |
|---|---|
| `push` | Author, branch, commit count, first 5 commit messages, compare URL |
| `issues` | Action (opened/closed/reopened), title, body preview, link |
| `pull_request` | Action, branches (head → base), state, link |
| `create` | Branch/tag created, author |
| `delete` | Branch/tag deleted, author |
| `release` | Tag name, release name, body preview, draft/prerelease flags |
| `repository` | Action (created/deleted/transferred) |
| `fork` | Source repo → forked repo |
#### Example Config
```yaml
- name: "talkGroup"
type: "GITEA_WEBHOOK_MODULE"
enabled: true
config:
webhook-port: 8080
webhook-path: "/gitea-webhook"
webhook-secret: "your-webhook-secret"
target-group-id: 538751386
events:
- "push"
- "issues"
- "pull_request"
- "create"
- "delete"
- "release"
```
#### Config Reference
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `webhook-port` | int | yes | — | HTTP server listen port |
| `webhook-path` | string | no | `/gitea-webhook` | Webhook endpoint path |
| `webhook-secret` | string | no | `""` | HMAC-SHA256 secret for signature verification |
| `target-group-id` | long | yes | — | QQ group to send notifications to |
| `events` | string[] | no | all | Event types to listen for |
#### Gitea-side Setup
In your Gitea repository → **Settings****Webhooks****Add Webhook****Gitea**:
- **Target URL**: `http://<server-ip>:8080/gitea-webhook`
- **Secret**: Same as `webhook-secret`
- **Trigger On**: Select desired events
#### Security
- Signature verification: `X-Gitea-Signature` header validated via HMAC-SHA256
- Empty `webhook-secret` disables verification (not recommended for production)
---
### Whitelist Audit Module
**Type:** `WHITELIST_AUDIT_MODULE`
Periodically checks the whitelist group membership against the whitelist API. Automatically rejects users who left the group, with a configurable grace period for re-activation via keywords in the main group. Supports admin-triggered manual audits with detailed per-user reporting.
**Storage:** MySQL `ltd_manager_bot.whitelist_audit` table (auto-created on first load).
#### Auto vs Manual Audit
| | Auto Audit | Manual Audit |
|---|---|---|
| Trigger | Every N minutes (poll-interval) | Admin sends keyword in whitelist group |
| Group messages | Silent (none) | Full summary with per-user detail |
| Email | Always sent for every action | Always sent for every action |
| Log prefix | `[自动]` | `[手动审计]` |
#### Lifecycle States
```
In Whitelist Group ───────────────────────────────► OK (no action)
└── User left group ──► Detected ──► Rejected (grace period starts)
├── Keyword in main group ──► Re-Activated
├── Warning threshold ──► Email sent (once)
└── Grace period expired ──► Permanently Removed
```
#### Example Config
```yaml
- name: "talkGroup"
type: "WHITELIST_AUDIT_MODULE"
enabled: true
dependencies:
- name: "talkGroup"
type: "GROUP_MESSAGE_POLLING_MODULE"
- name: "whitelistGroup"
type: "GROUP_MESSAGE_POLLING_MODULE"
- name: "talkGroup" # only if enable-email: true
type: "MAIL_MODULE"
config:
self-id: 3327379836
filter-qq-list: [2561098830, 3327379836]
audit-allowed-ids: [2561098830]
whitelist-group-polling-dep-name: "whitelistGroup"
audit-command-prefixes:
- "审计"
- "audit"
re-activation-keywords:
- "重新激活"
- "激活白名单"
grace-period-days: 7
expiry-warning-days: 2
poll-interval-minutes: 60
enable-email: false
# Email templates (omit = use built-in defaults)
email-reject-template: ""
email-warning-template: ""
email-removed-template: ""
email-reactivated-template: ""
```
#### Config Reference
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `self-id` | long | yes | — | Bot's QQ ID |
| `filter-qq-list` | long[] | yes | — | QQ IDs never auto-rejected |
| `audit-allowed-ids` | long[] | yes | — | QQ IDs allowed to trigger manual audit |
| `whitelist-group-polling-dep-name` | string | yes | — | Dependency name for the whitelist group polling module |
| `audit-command-prefixes` | string[] | no | `["审计"]` | Keywords to trigger manual audit (multiple) |
| `re-activation-keywords` | string[] | yes | — | Keywords to re-activate from main group |
| `grace-period-days` | int | yes | — | Days user has to re-activate after being rejected |
| `expiry-warning-days` | int | yes | — | Days before expiry to send warning |
| `poll-interval-minutes` | long | no | `60` | Auto-audit interval in minutes |
| `enable-email` | boolean | no | `false` | Enable email notifications (requires MailModule) |
| `email-reject-template` | string | no | `""` | Rejection email body. Placeholders: `${playerName}` `${graceDays}` `${keywords}` |
| `email-warning-template` | string | no | `""` | Expiry warning email body. Placeholders: `${playerName}` `${remainDays}` `${keywords}` |
| `email-removed-template` | string | no | `""` | Removal email body. Placeholders: `${playerName}` |
| `email-reactivated-template` | string | no | `""` | Re-activation email body. Placeholders: `${playerName}` `${graceDays}` |
#### Manual Audit Output Example
```
审计完成
────────────────
白名单总数: 42
在群正常: 35 人
新发现不在群(已拒绝): 2 人
• Steve(123456789)
• Alex(987654321)
宽限期中: Notch(111222333, 剩5天)
已过期删除: 1 人
• Hero(444555666)
过滤列表跳过: 3 人
```
#### Email Deduplication
Emails are sent exactly once per event:
| Email | Guard |
|---|---|
| Rejection | Only on first detection (`existing == null`) |
| Re-rejection | Only when previously-reactivated user leaves again |
| Expiry warning | `warningSentTime == 0L` — sent once |
| Removal | Record deleted from DB after send — never repeats |
| Re-activation | Only on successful keyword-triggered approve |
#### State Persistence
Audit state is stored in **MySQL** `ltd_manager_bot.whitelist_audit` table (auto-created, zero config). Survives bot restarts. Historical JSON file-based state is no longer used.
SQL templates are in `config/sql/whitelist/`:
- `create_audit_table.sql` — DDL
- `query_all_audit.sql` — fetch all records
- `query_audit_by_qq.sql` — fetch by QQ
- `upsert_audit.sql` — insert or update
- `delete_audit.sql` — remove record
#### Dependencies
| Dependency | Type | Required | Purpose |
|---|---|---|---|
| Main group polling | `GROUP_MESSAGE_POLLING_MODULE` | yes | Re-activation keyword monitoring |
| Whitelist group polling | `GROUP_MESSAGE_POLLING_MODULE` | yes | Audit command monitoring + member list |
| Mail module | `MAIL_MODULE` | if `enable-email: true` | Email notifications |
#### Whitetelist API Config
API URL and token are in `application.yaml` `whitelist-system:` section for security (auto-encrypted):
```yaml
whitelist-system:
url: "https://whitelist.your-server.top"
encrypted-token: "your-api-token-here"
```
---
## Configuration Reference
### SQL Templates
Some modules (InvitationCodesModule, GroupRequestHandlerModule) use SQL templates stored in `config/sql/`. Templates use `${placeholder}` syntax:
```sql
-- config/sql/invitation/query_qualification.sql
SELECT q.player_id, q.effective, q.is_used, q.qq, q.status
FROM ltd_manager_bot.qualified_user_info q
WHERE q.qq IN (${placeholders})
```
Usage in code:
```kotlin
val sql = SqlTemplate.fromFile("invitation/query_qualification.sql")
val result = sql.bind("placeholders" to "?, ?, ?")
```
### Message Filter Pipeline
All message-driven modules use a common `TriggerMessageFilter` pipeline:
```
IgnoreSelfFilter → NewMessageFilter → KeywordFilter → [CooldownFilter] → handler
```
This ensures messages from the bot itself are ignored, only new messages are processed, and only keyword-matching messages reach the handler.