Add README.md

This commit is contained in:
Astra 2026-03-10 06:31:25 +00:00
parent 48b6ea0da0
commit f1efc1d937

301
README.md Normal file
View file

@ -0,0 +1,301 @@
# Telegram Join Approval Bot
A Telegram bot for managing and approving join requests to private groups with approval workflows, canned responses, and admin controls.
## Overview
This bot automates the process of approving new members joining a private Telegram group. When a user requests to join, the bot:
1. Sends them a prompt to explain why they want to join
2. Forwards their request to the admin chat with approve/decline/ban buttons
3. Allows admins to manage requests with customizable decline reasons
4. Notifies users of the approval decision
## Features
- **Automated Join Requests**: Intercepts and manages join requests to your target group
- **Admin Approval Workflow**: Approve, decline, or ban users with a single click
- **Join Reason Collection**: Users must provide a reason before their request reaches admins
- **Canned Responses**: Pre-configured decline messages for common rejection reasons
- **Flexible Admin Interface**:
- Approve, decline, or ban users
- Add custom decline reasons
- Configure bot messages and settings
- Organize requests in topic threads
- **Approval Notifications**: Optional message sent to approved users
- **Configurable Messages**: Customize entry and approval messages
- **User Banning**: Ban users for 24 hours with a single action
## How It Works
### Join Request Flow
```
User requests to join group
Bot sends entry prompt to user
Bot notifies admins with join request
(showing user info and join reason placeholder)
User sends their join reason
(message to bot in private chat)
Bot updates admin message with user's reason
Admin clicks Approve/Decline/Ban
User notified of decision (if configured)
User added/rejected/banned from group
```
### Architecture
The bot consists of several key components:
#### Main Entry Point (`main.go`)
- Initializes the bot with config from `config.yaml`
- Starts the long polling update loop
- Routes updates to appropriate handlers
#### Configuration (`config/config.go`)
- Loads settings from `config.yaml`
- Auto-generates template config if missing
- Supports hot-reloading configuration changes
#### Handlers
- **`join.go`**: Manages join request flow and user responses
- **`callbacks.go`**: Handles inline button actions (approve/decline/ban)
- **`admin.go`**: Processes admin commands for configuration
- **`handlers.go`**: Shared types and utilities
#### Key Data Structures
```go
// ExtendedChatJoinRequest tracks a user's approval request
type ExtendedChatJoinRequest struct {
*ChatJoinRequest // Telegram join request
JoinReason string // User's explanation
JoinRequestMessageID int // Admin notification message ID
}
// Bot maintains runtime state
type Bot struct {
API BotAPI // Telegram API client
Config Config // Configuration
WaitingForApproval map // In-memory user request tracking
}
```
## Configuration
The bot reads from `config.yaml` in its working directory. On first run, it creates a template:
```yaml
bot_token: "YOUR_BOT_TOKEN_HERE" # @BotFather token
admin_chat_id: 0 # Chat ID where admins review requests
admin_chat_topic_id: 0 # Optional: Topic ID in admin chat (0 = main)
target_chat_id: 0 # Private group to protect
entry_message: "Please explain why..." # Prompt shown to joining users
approval_message: "" # Message sent after approval (optional)
send_approval_message: false # Whether to send approval message
delete_request_after_decision: false # Auto-delete admin messages after decision
canned_decline_responses: # Pre-configured decline reasons
- "Your profile doesn't meet our criteria"
- "We're at capacity"
```
### Getting Required IDs
**Bot Token**: Create a bot with [@BotFather](https://t.me/botfather)
**Chat IDs**:
```bash
# Forward a message from the chat to @getidsbot
# It will show you the chat ID
```
## Admin Commands
Admins can use these commands in the admin chat:
### `/setentrymessage <message>`
Change the message shown when users request to join.
```
/setentrymessage Tell us about yourself and why you want to join!
```
### `/setapprovalmessage <message>`
Set a message sent to approved users. Must be set before enabling approval notifications.
```
/setapprovalmessage Welcome to our group! We're excited to have you.
```
### `/togglesendapproval`
Enable/disable sending the approval message to approved users.
### `/setadmintopic <topic_id>`
Direct admin messages to a specific topic thread (0 = main chat).
```
/setadmintopic 42
```
### `/info`
Display current bot configuration.
### `/edit <new_text>`
Reply to a message and use this to edit it. Useful for correcting admin notifications.
```
/edit User was banned incorrectly
```
## Approval Workflow
### Admin Actions
When a user requests to join, an admin sees:
```
New join #request from @username [123456789]
Join reason: "I'm interested in this community"
```
With inline buttons:
- **Approve** - Add user to group, optionally send approval message
- **Decline** - Reject request, show decline reason button panel
- **Ban** - Ban user for 24 hours (shows confirmation)
### Decline Responses
When declining with canned responses configured:
1. Admin clicks **Decline**
2. Message shows available canned responses as buttons
3. Admin clicks a canned response
4. User receives the selected reason
5. Admin message updates with the reason
Or, admin can reply to a decline message with custom text (with or without `/` prefix):
```
[Reply to decline message]
/We can only accept members with 2+ years experience
```
## Deployment
### Docker
Build and run the container:
```bash
docker build -t telegram-approval-bot .
docker run -it \
--mount type=bind,source=$PWD/config.yaml,target=/opt/config.yaml \
telegram-approval-bot
```
The Dockerfile:
- Builds a static binary with minimal dependencies
- Uses Alpine for small image size
- Runs as unprivileged user (UID 65532)
- Mounts config as a volume for persistence
### Compose Example
```yaml
version: '3'
services:
bot:
build: .
volumes:
- ./config.yaml:/opt/config.yaml
restart: unless-stopped
```
## Implementation Details
### State Management
Join requests are tracked in memory using a mutex-protected map:
```go
WaitingForApproval map[int64]*ExtendedChatJoinRequest
```
When a user provides their join reason, the bot:
1. Updates the request with their reason
2. Edits the admin message to show the reason
3. Keeps the message indexed by message ID for button handling
### Update Processing
The bot receives Telegram updates via long polling:
1. **ChatJoinRequest**: User requests to join → calls `HandleJoinRequest`
2. **CallbackQuery**: Admin clicks button → calls `HandleCallbackQuery`
3. **Message**: User sends reason or admin command → routes accordingly
### Message Formatting
Admin notifications use HTML formatting with:
- User display name with link
- Numeric user ID
- Join reason (HTML-escaped for safety)
- Admin action history
- Timestamp information
### Error Handling
- Failed API requests restore the original message
- Missing user state after restart shows helpful error
- Invalid callback data is logged without crashing
## Development
### Dependencies
- `github.com/OvyFlash/telegram-bot-api` - Telegram Bot API client
- `go.yaml.in/yaml/v3` - YAML configuration parsing
### Go Version
Requires Go 1.25.3+
### Building Locally
```bash
go build -o telegram-approval-bot ./...
./telegram-approval-bot
```
## Troubleshooting
### Bot doesn't respond to join requests
- Verify `target_chat_id` is correct
- Check bot has admin rights in the target group
- Ensure bot is configured to receive join request updates
### Admin messages don't appear
- Verify `admin_chat_id` is correct
- Check bot has message permission in admin chat
- If using topics, verify `admin_chat_topic_id` is set
### Approve/Decline buttons don't work
- Bot needs admin rights in target group
- Join request may have expired (Telegram timeout)
- Check logs for API errors
### Config changes don't apply
- Some changes require bot restart
- Use `/info` to verify current settings
- Check config.yaml for syntax errors
## License
[Specify your license here]