added whitelist and more
This commit is contained in:
36
AGENTS.md
36
AGENTS.md
@@ -1,36 +0,0 @@
|
|||||||
# Repository Guidelines
|
|
||||||
|
|
||||||
## Project Structure & Module Organization
|
|
||||||
- `src/guardden/` is the main package: `bot.py` (bot lifecycle), `cogs/` (Discord commands/events), `services/` (business logic), `models/` (SQLAlchemy models), `config.py` (settings), and `utils/` (shared helpers).
|
|
||||||
- `tests/` holds pytest suites (`test_*.py`) for services and utilities.
|
|
||||||
- `migrations/` and `alembic.ini` define database migrations.
|
|
||||||
- `docker-compose.yml` and `Dockerfile` support containerized development/deployments.
|
|
||||||
- `.env.example` provides the configuration template.
|
|
||||||
|
|
||||||
## Build, Test, and Development Commands
|
|
||||||
- `pip install -e ".[dev,ai]"` installs dev tooling plus optional AI providers.
|
|
||||||
- `python -m guardden` runs the bot locally.
|
|
||||||
- `pytest` runs the full test suite; `pytest tests/test_verification.py::TestVerificationService::test_verify_correct` runs a single test.
|
|
||||||
- `ruff check src tests` lints; `ruff format src tests` formats.
|
|
||||||
- `mypy src` runs strict type checks.
|
|
||||||
- `docker compose up -d` starts the full stack; `docker compose up db -d` starts only Postgres.
|
|
||||||
|
|
||||||
## Coding Style & Naming Conventions
|
|
||||||
- Python 3.11 with 4-space indentation; keep lines within 100 chars (Ruff config).
|
|
||||||
- Prefer type hints and clean async patterns; mypy runs in strict mode.
|
|
||||||
- Naming: `snake_case` for modules/functions, `CamelCase` for classes, `UPPER_SNAKE` for constants.
|
|
||||||
- New cogs live in `src/guardden/cogs/` and should be wired in `_load_cogs()` in `src/guardden/bot.py`.
|
|
||||||
|
|
||||||
## Testing Guidelines
|
|
||||||
- Tests use pytest + pytest-asyncio (`asyncio_mode=auto`).
|
|
||||||
- Follow `test_*.py` file names and `test_*` function names; group related cases in `Test*` classes.
|
|
||||||
- Add or update tests for new services, automod rules, or AI provider behavior.
|
|
||||||
|
|
||||||
## Commit & Pull Request Guidelines
|
|
||||||
- Commit messages are short, imperative, and capitalized (e.g., `Fix: initialize guild config...`, `Add Discord bot setup...`).
|
|
||||||
- PRs should include a concise summary, tests run, and any config or migration notes; link related issues when available.
|
|
||||||
|
|
||||||
## Security & Configuration Tips
|
|
||||||
- Store secrets in `.env` (never commit); configuration keys are prefixed with `GUARDDEN_`.
|
|
||||||
- PostgreSQL is required; default URL is `postgresql://guardden:guardden@localhost:5432/guardden`.
|
|
||||||
- AI features require `GUARDDEN_AI_PROVIDER` plus the matching API key.
|
|
||||||
@@ -55,6 +55,8 @@ docker compose up -d
|
|||||||
- Spam tracking uses per-guild, per-user trackers with automatic cleanup
|
- Spam tracking uses per-guild, per-user trackers with automatic cleanup
|
||||||
- Scam detection uses compiled regex patterns in `SCAM_PATTERNS` list
|
- Scam detection uses compiled regex patterns in `SCAM_PATTERNS` list
|
||||||
- Results return `AutomodResult` dataclass with actions to take
|
- Results return `AutomodResult` dataclass with actions to take
|
||||||
|
- **Whitelist**: Users in `GuildSettings.whitelisted_user_ids` bypass ALL automod checks
|
||||||
|
- Users with "Manage Messages" permission also bypass automod
|
||||||
|
|
||||||
## AI Moderation System
|
## AI Moderation System
|
||||||
|
|
||||||
@@ -67,6 +69,7 @@ docker compose up -d
|
|||||||
- Sensitivity setting (0-100) adjusts thresholds per guild
|
- Sensitivity setting (0-100) adjusts thresholds per guild
|
||||||
- **NSFW-Only Filtering** (default: `True`): When enabled, only sexual content is filtered; violence, harassment, etc. are allowed
|
- **NSFW-Only Filtering** (default: `True`): When enabled, only sexual content is filtered; violence, harassment, etc. are allowed
|
||||||
- Filtering controlled by `nsfw_only_filtering` field in `GuildSettings`
|
- Filtering controlled by `nsfw_only_filtering` field in `GuildSettings`
|
||||||
|
- **Whitelist**: Users in `GuildSettings.whitelisted_user_ids` bypass ALL AI moderation checks
|
||||||
|
|
||||||
## Verification System
|
## Verification System
|
||||||
|
|
||||||
|
|||||||
311
DEV_GUIDE.md
311
DEV_GUIDE.md
@@ -1,311 +0,0 @@
|
|||||||
# GuardDen Development Guide
|
|
||||||
|
|
||||||
This guide provides everything you need to start developing GuardDen locally.
|
|
||||||
|
|
||||||
## 🚀 Quick Start
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Clone the repository
|
|
||||||
git clone <repository-url>
|
|
||||||
cd GuardDen
|
|
||||||
|
|
||||||
# 2. Set up development environment
|
|
||||||
./scripts/dev.sh setup
|
|
||||||
|
|
||||||
# 3. Configure environment variables
|
|
||||||
cp .env.example .env
|
|
||||||
# Edit .env with your Discord bot token and other settings
|
|
||||||
|
|
||||||
# 4. Start development environment
|
|
||||||
./scripts/dev.sh up
|
|
||||||
|
|
||||||
# 5. Run tests to verify setup
|
|
||||||
./scripts/dev.sh test
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📋 Development Commands
|
|
||||||
|
|
||||||
The `./scripts/dev.sh` script provides comprehensive development automation:
|
|
||||||
|
|
||||||
### Environment Management
|
|
||||||
```bash
|
|
||||||
./scripts/dev.sh setup # Set up development environment
|
|
||||||
./scripts/dev.sh up # Start development containers
|
|
||||||
./scripts/dev.sh down # Stop development containers
|
|
||||||
./scripts/dev.sh logs [service] # Show logs (optional service filter)
|
|
||||||
./scripts/dev.sh clean # Clean up development artifacts
|
|
||||||
```
|
|
||||||
|
|
||||||
### Code Quality
|
|
||||||
```bash
|
|
||||||
./scripts/dev.sh test # Run tests with coverage
|
|
||||||
./scripts/dev.sh lint # Run code quality checks
|
|
||||||
./scripts/dev.sh format # Format code with ruff
|
|
||||||
./scripts/dev.sh security # Run security scans
|
|
||||||
```
|
|
||||||
|
|
||||||
### Database Management
|
|
||||||
```bash
|
|
||||||
./scripts/dev.sh db migrate # Run database migrations
|
|
||||||
./scripts/dev.sh db revision "description" # Create new migration
|
|
||||||
./scripts/dev.sh db reset # Reset database (destructive)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Health & Monitoring
|
|
||||||
```bash
|
|
||||||
./scripts/dev.sh health check # Run health checks
|
|
||||||
./scripts/dev.sh health json # Health checks with JSON output
|
|
||||||
```
|
|
||||||
|
|
||||||
### Docker Operations
|
|
||||||
```bash
|
|
||||||
./scripts/dev.sh build # Build Docker images (bot + dashboard)
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🐳 Development Services
|
|
||||||
|
|
||||||
When you run `./scripts/dev.sh up`, the following services are available:
|
|
||||||
|
|
||||||
| Service | URL | Purpose |
|
|
||||||
|---------|-----|---------|
|
|
||||||
| GuardDen Bot | - | Discord bot with hot reloading |
|
|
||||||
| Dashboard | http://localhost:8080 | Web interface |
|
|
||||||
| PostgreSQL | localhost:5432 | Database |
|
|
||||||
| Redis | localhost:6379 | Caching & sessions |
|
|
||||||
| PgAdmin | http://localhost:5050 | Database administration |
|
|
||||||
| Redis Commander | http://localhost:8081 | Redis administration |
|
|
||||||
| MailHog | http://localhost:8025 | Email testing |
|
|
||||||
|
|
||||||
## 🖥️ Dashboard Frontend
|
|
||||||
|
|
||||||
The dashboard backend serves static assets from `dashboard/frontend/dist`.
|
|
||||||
|
|
||||||
Build the static assets:
|
|
||||||
```bash
|
|
||||||
cd dashboard/frontend
|
|
||||||
npm install
|
|
||||||
npm run build
|
|
||||||
```
|
|
||||||
|
|
||||||
Or run the Vite dev server for UI iteration:
|
|
||||||
```bash
|
|
||||||
cd dashboard/frontend
|
|
||||||
npm install
|
|
||||||
npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
The Vite dev server runs at `http://localhost:5173`.
|
|
||||||
|
|
||||||
The Vite dev server proxies `/api` and `/auth` to `http://localhost:8000`. If you're
|
|
||||||
using the Docker dev stack (dashboard at `http://localhost:8080`), either run the
|
|
||||||
dashboard backend locally on port 8000 or update the proxy target.
|
|
||||||
|
|
||||||
## 🧪 Testing
|
|
||||||
|
|
||||||
### Running Tests
|
|
||||||
```bash
|
|
||||||
# Run all tests with coverage
|
|
||||||
./scripts/dev.sh test
|
|
||||||
|
|
||||||
# Run specific test files
|
|
||||||
pytest tests/test_config.py
|
|
||||||
|
|
||||||
# Run tests with verbose output
|
|
||||||
pytest -v
|
|
||||||
|
|
||||||
# Run tests in parallel (faster)
|
|
||||||
pytest -n auto
|
|
||||||
```
|
|
||||||
|
|
||||||
### Test Structure
|
|
||||||
- `tests/conftest.py` - Test fixtures and configuration
|
|
||||||
- `tests/test_*.py` - Test modules
|
|
||||||
- Test coverage reports in `htmlcov/`
|
|
||||||
|
|
||||||
### Writing Tests
|
|
||||||
- Use pytest with async support (`pytest-asyncio`)
|
|
||||||
- Comprehensive fixtures available for database, Discord mocks, etc.
|
|
||||||
- Follow naming convention: `test_*` functions in `Test*` classes
|
|
||||||
|
|
||||||
## 🔧 Code Quality
|
|
||||||
|
|
||||||
### Pre-commit Hooks
|
|
||||||
Pre-commit hooks are automatically installed during setup:
|
|
||||||
- **Ruff**: Code formatting and linting
|
|
||||||
- **MyPy**: Type checking
|
|
||||||
- **Tests**: Run tests on relevant changes
|
|
||||||
|
|
||||||
### Manual Quality Checks
|
|
||||||
```bash
|
|
||||||
# Run all quality checks
|
|
||||||
./scripts/dev.sh lint
|
|
||||||
|
|
||||||
# Format code
|
|
||||||
./scripts/dev.sh format
|
|
||||||
|
|
||||||
# Type checking only
|
|
||||||
mypy src
|
|
||||||
|
|
||||||
# Security scanning
|
|
||||||
./scripts/dev.sh security
|
|
||||||
```
|
|
||||||
|
|
||||||
### Code Style
|
|
||||||
- **Line Length**: 100 characters (configured in pyproject.toml)
|
|
||||||
- **Imports**: Sorted with ruff
|
|
||||||
- **Type Hints**: Required for all public functions
|
|
||||||
- **Docstrings**: Google style for modules and classes
|
|
||||||
|
|
||||||
## 📊 Monitoring & Debugging
|
|
||||||
|
|
||||||
### Structured Logging
|
|
||||||
```python
|
|
||||||
from guardden.utils.logging import get_logger, bind_context
|
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
|
||||||
|
|
||||||
# Log with context
|
|
||||||
bind_context(user_id=123, guild_id=456)
|
|
||||||
logger.info("User performed action", action="kick", target="user#1234")
|
|
||||||
```
|
|
||||||
|
|
||||||
### Metrics Collection
|
|
||||||
```python
|
|
||||||
from guardden.utils.metrics import get_metrics
|
|
||||||
|
|
||||||
metrics = get_metrics()
|
|
||||||
metrics.record_command("ban", guild_id=123, status="success", duration=0.5)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Health Checks
|
|
||||||
```bash
|
|
||||||
# Check application health
|
|
||||||
./scripts/dev.sh health check
|
|
||||||
|
|
||||||
# Get detailed JSON health report
|
|
||||||
./scripts/dev.sh health json
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🗄️ Database Development
|
|
||||||
|
|
||||||
### Migrations
|
|
||||||
```bash
|
|
||||||
# Create new migration
|
|
||||||
./scripts/dev.sh db revision "add new table"
|
|
||||||
|
|
||||||
# Run migrations
|
|
||||||
./scripts/dev.sh db migrate
|
|
||||||
|
|
||||||
# Rollback one migration
|
|
||||||
./scripts/dev.sh db downgrade
|
|
||||||
```
|
|
||||||
|
|
||||||
### Database Access
|
|
||||||
- **PgAdmin**: http://localhost:5050 (admin@guardden.dev / admin)
|
|
||||||
- **Direct connection**: localhost:5432 (guardden / guardden_dev)
|
|
||||||
- **Test database**: In-memory SQLite for tests
|
|
||||||
|
|
||||||
## 🐛 Debugging
|
|
||||||
|
|
||||||
### Debug Mode
|
|
||||||
Development containers include debugging support:
|
|
||||||
- **Bot**: Debug port 5678
|
|
||||||
- **Dashboard**: Debug port 5679
|
|
||||||
|
|
||||||
### VS Code Configuration
|
|
||||||
Add to `.vscode/launch.json`:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"name": "Attach to Bot",
|
|
||||||
"type": "python",
|
|
||||||
"request": "attach",
|
|
||||||
"host": "localhost",
|
|
||||||
"port": 5678
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Log Analysis
|
|
||||||
```bash
|
|
||||||
# Follow all logs
|
|
||||||
./scripts/dev.sh logs
|
|
||||||
|
|
||||||
# Follow specific service logs
|
|
||||||
./scripts/dev.sh logs bot
|
|
||||||
./scripts/dev.sh logs dashboard
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔐 Security
|
|
||||||
|
|
||||||
### Environment Variables
|
|
||||||
- **Required**: `GUARDDEN_DISCORD_TOKEN`
|
|
||||||
- **Database**: `GUARDDEN_DATABASE_URL` (auto-configured for development)
|
|
||||||
- **AI**: `GUARDDEN_ANTHROPIC_API_KEY` or `GUARDDEN_OPENAI_API_KEY`
|
|
||||||
|
|
||||||
### Security Best Practices
|
|
||||||
- Never commit secrets to version control
|
|
||||||
- Use `.env` for local development secrets
|
|
||||||
- Run security scans regularly: `./scripts/dev.sh security`
|
|
||||||
- Keep dependencies updated
|
|
||||||
|
|
||||||
## 🚀 Deployment
|
|
||||||
|
|
||||||
### Building for Production
|
|
||||||
```bash
|
|
||||||
# Build optimized image
|
|
||||||
docker build -t guardden:latest .
|
|
||||||
|
|
||||||
# Build with AI dependencies
|
|
||||||
docker build --build-arg INSTALL_AI=true -t guardden:ai .
|
|
||||||
```
|
|
||||||
|
|
||||||
### CI/CD Pipeline
|
|
||||||
- **GitHub Actions**: Automated testing, security scanning, and deployment
|
|
||||||
- **Quality Gates**: 75%+ test coverage, type checking, security scans
|
|
||||||
- **Automated Deployments**: Staging (develop branch) and production (releases)
|
|
||||||
|
|
||||||
## 🆘 Troubleshooting
|
|
||||||
|
|
||||||
### Common Issues
|
|
||||||
|
|
||||||
**Port conflicts**:
|
|
||||||
```bash
|
|
||||||
# Check what's using a port
|
|
||||||
lsof -i :5432
|
|
||||||
|
|
||||||
# Use different ports in .env
|
|
||||||
POSTGRES_PORT=5433
|
|
||||||
REDIS_PORT=6380
|
|
||||||
```
|
|
||||||
|
|
||||||
**Permission errors**:
|
|
||||||
```bash
|
|
||||||
# Fix Docker permissions
|
|
||||||
sudo chown -R $USER:$USER data logs
|
|
||||||
```
|
|
||||||
|
|
||||||
**Database connection errors**:
|
|
||||||
```bash
|
|
||||||
# Reset development environment
|
|
||||||
./scripts/dev.sh down
|
|
||||||
./scripts/dev.sh clean
|
|
||||||
./scripts/dev.sh up
|
|
||||||
```
|
|
||||||
|
|
||||||
**Test failures**:
|
|
||||||
```bash
|
|
||||||
# Run tests with more verbose output
|
|
||||||
pytest -vvs
|
|
||||||
|
|
||||||
# Run specific failing test
|
|
||||||
pytest tests/test_config.py::TestSettingsValidation::test_discord_token_validation_valid -vvs
|
|
||||||
```
|
|
||||||
|
|
||||||
### Getting Help
|
|
||||||
1. Check logs: `./scripts/dev.sh logs`
|
|
||||||
2. Run health check: `./scripts/dev.sh health check`
|
|
||||||
3. Verify environment: `./scripts/dev.sh setup`
|
|
||||||
4. Check GitHub Issues for known problems
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Happy coding! 🎉
|
|
||||||
14
README.md
14
README.md
@@ -401,6 +401,20 @@ Edit config/wordlists/domain-allowlists.yml
|
|||||||
Edit config/wordlists/banned-words.yml
|
Edit config/wordlists/banned-words.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Whitelist Management (Admin only)
|
||||||
|
|
||||||
|
| Command | Description |
|
||||||
|
|---------|-------------|
|
||||||
|
| `!whitelist` | View all whitelisted users |
|
||||||
|
| `!whitelist add @user` | Add a user to the whitelist (bypasses all moderation) |
|
||||||
|
| `!whitelist remove @user` | Remove a user from the whitelist |
|
||||||
|
| `!whitelist clear` | Clear the entire whitelist |
|
||||||
|
|
||||||
|
**What is the whitelist?**
|
||||||
|
- Whitelisted users bypass **ALL** moderation checks (automod and AI moderation)
|
||||||
|
- Useful for trusted members, bots, or staff who need to post content that might trigger filters
|
||||||
|
- Users with "Manage Messages" permission are already exempt from moderation
|
||||||
|
|
||||||
### Diagnostics (Admin only)
|
### Diagnostics (Admin only)
|
||||||
|
|
||||||
| Command | Description |
|
| Command | Description |
|
||||||
|
|||||||
34
migrations/versions/20260125_add_whitelist.py
Normal file
34
migrations/versions/20260125_add_whitelist.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
"""Add whitelisted_user_ids column to guild_settings table.
|
||||||
|
|
||||||
|
Revision ID: 20260125_add_whitelist
|
||||||
|
Revises: 20260125_add_in_channel_warnings
|
||||||
|
Create Date: 2026-01-25 01:00:00.000000
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from alembic import op
|
||||||
|
from sqlalchemy.dialects.postgresql import JSONB
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = "20260125_add_whitelist"
|
||||||
|
down_revision = "20260125_add_in_channel_warnings"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
"""Add whitelisted_user_ids column to guild_settings table."""
|
||||||
|
op.add_column(
|
||||||
|
"guild_settings",
|
||||||
|
sa.Column(
|
||||||
|
"whitelisted_user_ids",
|
||||||
|
JSONB().with_variant(sa.JSON(), "sqlite"),
|
||||||
|
nullable=False,
|
||||||
|
server_default="[]",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
"""Remove whitelisted_user_ids column from guild_settings table."""
|
||||||
|
op.drop_column("guild_settings", "whitelisted_user_ids")
|
||||||
@@ -311,6 +311,126 @@ class Admin(commands.Cog):
|
|||||||
|
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@commands.group(name="whitelist", invoke_without_command=True)
|
||||||
|
@commands.guild_only()
|
||||||
|
async def whitelist_cmd(self, ctx: commands.Context) -> None:
|
||||||
|
"""Manage the moderation whitelist."""
|
||||||
|
config = await self.bot.guild_config.get_config(ctx.guild.id)
|
||||||
|
whitelisted_ids = config.whitelisted_user_ids if config else []
|
||||||
|
|
||||||
|
if not whitelisted_ids:
|
||||||
|
await ctx.send("No users are whitelisted.")
|
||||||
|
return
|
||||||
|
|
||||||
|
embed = discord.Embed(
|
||||||
|
title="Whitelisted Users",
|
||||||
|
description="These users bypass all moderation checks:",
|
||||||
|
color=discord.Color.blue(),
|
||||||
|
)
|
||||||
|
|
||||||
|
users_text = []
|
||||||
|
for user_id in whitelisted_ids[:25]: # Limit to 25 to avoid embed limits
|
||||||
|
user = ctx.guild.get_member(user_id)
|
||||||
|
if user:
|
||||||
|
users_text.append(f"• {user.mention} (`{user_id}`)")
|
||||||
|
else:
|
||||||
|
users_text.append(f"• Unknown User (`{user_id}`)")
|
||||||
|
|
||||||
|
embed.add_field(
|
||||||
|
name=f"Total: {len(whitelisted_ids)} users",
|
||||||
|
value="\n".join(users_text) if users_text else "None",
|
||||||
|
inline=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(whitelisted_ids) > 25:
|
||||||
|
embed.set_footer(text=f"Showing 25 of {len(whitelisted_ids)} users")
|
||||||
|
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@whitelist_cmd.command(name="add")
|
||||||
|
@commands.guild_only()
|
||||||
|
async def whitelist_add(self, ctx: commands.Context, user: discord.Member) -> None:
|
||||||
|
"""Add a user to the whitelist.
|
||||||
|
|
||||||
|
Whitelisted users bypass ALL moderation checks (automod and AI moderation).
|
||||||
|
"""
|
||||||
|
config = await self.bot.guild_config.get_config(ctx.guild.id)
|
||||||
|
whitelisted_ids = list(config.whitelisted_user_ids) if config else []
|
||||||
|
|
||||||
|
if user.id in whitelisted_ids:
|
||||||
|
await ctx.send(f"{user.mention} is already whitelisted.")
|
||||||
|
return
|
||||||
|
|
||||||
|
whitelisted_ids.append(user.id)
|
||||||
|
await self.bot.guild_config.update_settings(
|
||||||
|
ctx.guild.id, whitelisted_user_ids=whitelisted_ids
|
||||||
|
)
|
||||||
|
|
||||||
|
embed = discord.Embed(
|
||||||
|
title="✅ User Whitelisted",
|
||||||
|
description=f"{user.mention} has been added to the whitelist.",
|
||||||
|
color=discord.Color.green(),
|
||||||
|
)
|
||||||
|
embed.add_field(
|
||||||
|
name="What this means",
|
||||||
|
value="This user will bypass all automod and AI moderation checks.",
|
||||||
|
inline=False,
|
||||||
|
)
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@whitelist_cmd.command(name="remove")
|
||||||
|
@commands.guild_only()
|
||||||
|
async def whitelist_remove(self, ctx: commands.Context, user: discord.Member) -> None:
|
||||||
|
"""Remove a user from the whitelist."""
|
||||||
|
config = await self.bot.guild_config.get_config(ctx.guild.id)
|
||||||
|
whitelisted_ids = list(config.whitelisted_user_ids) if config else []
|
||||||
|
|
||||||
|
if user.id not in whitelisted_ids:
|
||||||
|
await ctx.send(f"{user.mention} is not whitelisted.")
|
||||||
|
return
|
||||||
|
|
||||||
|
whitelisted_ids.remove(user.id)
|
||||||
|
await self.bot.guild_config.update_settings(
|
||||||
|
ctx.guild.id, whitelisted_user_ids=whitelisted_ids
|
||||||
|
)
|
||||||
|
|
||||||
|
embed = discord.Embed(
|
||||||
|
title="🚫 User Removed from Whitelist",
|
||||||
|
description=f"{user.mention} has been removed from the whitelist.",
|
||||||
|
color=discord.Color.orange(),
|
||||||
|
)
|
||||||
|
embed.add_field(
|
||||||
|
name="What this means",
|
||||||
|
value="This user will now be subject to normal moderation checks.",
|
||||||
|
inline=False,
|
||||||
|
)
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@whitelist_cmd.command(name="clear")
|
||||||
|
@commands.guild_only()
|
||||||
|
async def whitelist_clear(self, ctx: commands.Context) -> None:
|
||||||
|
"""Clear the entire whitelist."""
|
||||||
|
config = await self.bot.guild_config.get_config(ctx.guild.id)
|
||||||
|
count = len(config.whitelisted_user_ids) if config else 0
|
||||||
|
|
||||||
|
if count == 0:
|
||||||
|
await ctx.send("The whitelist is already empty.")
|
||||||
|
return
|
||||||
|
|
||||||
|
await self.bot.guild_config.update_settings(ctx.guild.id, whitelisted_user_ids=[])
|
||||||
|
|
||||||
|
embed = discord.Embed(
|
||||||
|
title="🧹 Whitelist Cleared",
|
||||||
|
description=f"Removed {count} user(s) from the whitelist.",
|
||||||
|
color=discord.Color.red(),
|
||||||
|
)
|
||||||
|
embed.add_field(
|
||||||
|
name="What this means",
|
||||||
|
value="All users will now be subject to normal moderation checks.",
|
||||||
|
inline=False,
|
||||||
|
)
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
@commands.command(name="sync")
|
@commands.command(name="sync")
|
||||||
@commands.is_owner()
|
@commands.is_owner()
|
||||||
async def sync_commands(self, ctx: commands.Context) -> None:
|
async def sync_commands(self, ctx: commands.Context) -> None:
|
||||||
|
|||||||
@@ -287,6 +287,11 @@ class AIModeration(commands.Cog):
|
|||||||
logger.debug(f"AI moderation disabled for guild {message.guild.id}")
|
logger.debug(f"AI moderation disabled for guild {message.guild.id}")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Check if user is whitelisted
|
||||||
|
if message.author.id in config.whitelisted_user_ids:
|
||||||
|
logger.debug(f"Skipping whitelisted user {message.author}")
|
||||||
|
return
|
||||||
|
|
||||||
# Skip users with manage_messages permission (disabled for testing)
|
# Skip users with manage_messages permission (disabled for testing)
|
||||||
# if isinstance(message.author, discord.Member):
|
# if isinstance(message.author, discord.Member):
|
||||||
# if message.author.guild_permissions.manage_messages:
|
# if message.author.guild_permissions.manage_messages:
|
||||||
|
|||||||
@@ -283,6 +283,10 @@ class Automod(commands.Cog):
|
|||||||
if not config or not config.automod_enabled:
|
if not config or not config.automod_enabled:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Check if user is whitelisted
|
||||||
|
if message.author.id in config.whitelisted_user_ids:
|
||||||
|
return
|
||||||
|
|
||||||
result: AutomodResult | None = None
|
result: AutomodResult | None = None
|
||||||
|
|
||||||
# Check banned words
|
# Check banned words
|
||||||
|
|||||||
@@ -102,6 +102,11 @@ class GuildSettings(Base, TimestampMixin):
|
|||||||
# Notification settings
|
# Notification settings
|
||||||
send_in_channel_warnings: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
send_in_channel_warnings: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
||||||
|
|
||||||
|
# Whitelist settings
|
||||||
|
whitelisted_user_ids: Mapped[list[int]] = mapped_column(
|
||||||
|
JSONB().with_variant(JSON(), "sqlite"), default=list, nullable=False
|
||||||
|
)
|
||||||
|
|
||||||
# Verification settings
|
# Verification settings
|
||||||
verification_enabled: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
verification_enabled: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
||||||
verification_type: Mapped[str] = mapped_column(
|
verification_type: Mapped[str] = mapped_column(
|
||||||
|
|||||||
Reference in New Issue
Block a user