Compare commits

...

23 Commits

Author SHA1 Message Date
TheOnlyMace
4f57cccea5 Add Discord sharding support and related configurations
Some checks failed
CI / Bot (Python) (push) Successful in 12s
CI / Dashboard (Next.js) (push) Failing after 9s
Enhance the bot's architecture by introducing sharding capabilities, allowing for better scalability and performance. Update environment files to include sharding options, and modify the bot's core logic to handle shard connections and latencies. Implement shard-specific logging and API synchronization, ensuring that only the primary shard performs certain tasks. Update API schemas and routes to reflect shard information, improving the overall status reporting and monitoring of the bot's performance across multiple shards.
2026-07-21 23:09:35 +02:00
TheOnlyMace
36b32de34c Enhance AutoMod configuration by introducing event-specific settings and thresholds. Refactor Automod schemas to include event configurations, thresholds, and limits for ignored roles and channels. Update database interactions to support new structure and improve handling of AutoMod rules in cogs, ensuring dynamic thresholds for various events. Update dashboard components to accommodate new configurations and improve user experience in managing AutoMod settings.
Some checks failed
CI / Bot (Python) (push) Successful in 12s
CI / Dashboard (Next.js) (push) Failing after 9s
2026-07-21 23:05:05 +02:00
TheOnlyMace
d24b810164 Refactor command definitions across various cogs to replace hybrid commands with regular commands for improved consistency and clarity. Update command structures in moderation, music, and other cogs to enhance user experience and streamline command handling.
Some checks failed
CI / Bot (Python) (push) Successful in 12s
CI / Dashboard (Next.js) (push) Failing after 9s
2026-07-21 22:59:25 +02:00
TheOnlyMace
a52d84467d Refactor slash command synchronization logic to prevent duplicate commands in Discord. Update environment variables for command sync modes and enhance command clearing functionality. Improve command registration handling in the bot to streamline user experience.
Some checks failed
CI / Bot (Python) (push) Successful in 12s
CI / Dashboard (Next.js) (push) Failing after 9s
2026-07-21 22:53:51 +02:00
TheOnlyMace
1da2085087 Refactor command definitions across multiple cogs to replace hybrid commands with regular commands for consistency. This change enhances clarity and standardizes command handling throughout the bot.
Some checks failed
CI / Bot (Python) (push) Successful in 12s
CI / Dashboard (Next.js) (push) Failing after 8s
2026-07-21 22:50:11 +02:00
TheOnlyMace
20193404e8 Refactor command definitions in owner and moderation cogs for consistency. Change getinvite command to a regular command and update type hints for parameters in enlarge and roleicon commands to improve clarity and type safety.
Some checks failed
CI / Bot (Python) (push) Successful in 12s
CI / Dashboard (Next.js) (push) Failing after 8s
2026-07-21 22:47:29 +02:00
TheOnlyMace
299351463c Refactor welcome message handling in the Autorole cog to enhance user experience. Implement dynamic embed creation for guild join events, including updated branding and links to the dashboard and support server. Improve error handling for direct messages and audit log access.
Some checks failed
CI / Bot (Python) (push) Failing after 12s
CI / Dashboard (Next.js) (push) Failing after 9s
2026-07-21 22:45:50 +02:00
TheOnlyMace
6b0091f7d5 Update invite links to use dynamic Discord client ID and import necessary configuration constants. Refactor slash command synchronization logic for improved error handling and performance.
Some checks failed
CI / Bot (Python) (push) Failing after 12s
CI / Dashboard (Next.js) (push) Failing after 10s
2026-07-21 22:44:40 +02:00
TheOnlyMace
fc77f0a3c2 Implement slash command synchronization features in environment files and update command definitions to hybrid commands across various cogs. Enhance command registration for improved user experience and streamline command handling in the bot. 2026-07-21 22:41:41 +02:00
TheOnlyMace
f15c869993 Enhance Discord authentication and guild management by implementing caching for user and guild data to reduce API calls and improve performance. Update error handling for Discord API responses and refactor the guilds listing logic in the dashboard to streamline data retrieval. Adjust retry logic for rate limits and improve session error handling in the authentication flow.
Some checks failed
CI / Bot (Python) (push) Successful in 12s
CI / Dashboard (Next.js) (push) Failing after 9s
2026-07-21 22:33:30 +02:00
TheOnlyMace
60390009d1 Refactor dashboard notification handling and improve admin broadcast functionality. Ensure only admins can access global notifications, implement draft management for broadcast messages, and add event listeners for real-time updates across dashboard components.
Some checks failed
CI / Bot (Python) (push) Successful in 12s
CI / Dashboard (Next.js) (push) Failing after 9s
2026-07-21 22:30:08 +02:00
TheOnlyMace
18ef29f777 Refactor database path resolution in cogs and improve cog loading error handling. Update database connections in Giveaway, Nightmode, and Owner cogs to use a centralized path resolver. Enhance cog loading feedback with success and failure messages.
Some checks failed
CI / Bot (Python) (push) Successful in 12s
CI / Dashboard (Next.js) (push) Failing after 9s
2026-07-21 22:28:18 +02:00
TheOnlyMace
9006b06c09 Enhance Discord integration by adding optional bot permissions in environment files and updating the dashboard to include an "Add Bot to your Server" button. Refactor authentication logic to handle token refresh and improve error handling for Discord sessions. Update placeholder text for better clarity in the search input field.
Some checks failed
CI / Bot (Python) (push) Successful in 12s
CI / Dashboard (Next.js) (push) Failing after 8s
2026-07-21 22:19:13 +02:00
TheOnlyMace
8294c1b4f7 Update branding assets by replacing SVG logos with PNG versions for improved compatibility and performance. Update references in the BrandLogo component to use the new PNG logo. Additionally, update various favicon and touch icon files to align with the new branding.
Some checks failed
CI / Bot (Python) (push) Successful in 12s
CI / Dashboard (Next.js) (push) Failing after 9s
2026-07-21 21:58:37 +02:00
TheOnlyMace
831a3ac8ea Update dashboard styles and branding to reflect HexaHost theme. Change primary colors, background gradients, and text styles across various components. Enhance layout and navigation elements for improved user experience.
Some checks failed
CI / Bot (Python) (push) Successful in 13s
CI / Dashboard (Next.js) (push) Failing after 9s
2026-07-21 21:24:28 +02:00
TheOnlyMace
698d61ec6d Update requirements.txt to reflect project branding change from HexaHost to Axiom and add aiofiles dependency for file handling.
Some checks failed
CI / Bot (Python) (push) Successful in 13s
CI / Dashboard (Next.js) (push) Failing after 8s
2026-07-21 21:16:21 +02:00
TheOnlyMace
daf3338382 Refactor project branding from HexaHost to Axiom across all configurations, documentation, and code files. Update environment variables, Docker setup, and README to reflect the new brand name. Ensure consistency in naming conventions and improve clarity in setup instructions.
Some checks failed
CI / Bot (Python) (push) Failing after 12s
CI / Dashboard (Next.js) (push) Failing after 9s
2026-07-21 19:45:07 +02:00
TheOnlyMace
03c8f2ec2c Remove NexioHost badge from README for a cleaner presentation.
Some checks failed
CI / Bot (Python) (push) Failing after 12s
CI / Dashboard (Next.js) (push) Failing after 9s
2026-07-21 17:56:24 +02:00
TheOnlyMace
7dca4fb77a Update Docker setup documentation for HexaHost, enhancing clarity on prerequisites, configuration steps, and troubleshooting. Added detailed instructions for setting up Traefik, environment variables, and Discord integration.
Some checks failed
CI / Bot (Python) (push) Failing after 12s
CI / Dashboard (Next.js) (push) Failing after 9s
2026-07-21 17:55:26 +02:00
TheOnlyMace
9bcde844da Replace Creative Commons license with MIT License, updating copyright information and permissions for software usage and distribution.
Some checks failed
CI / Bot (Python) (push) Failing after 11s
CI / Dashboard (Next.js) (push) Failing after 9s
2026-07-21 17:46:46 +02:00
TheOnlyMace
41d5841d82 Enhance project configuration by setting output to "standalone" in Next.js config files and updating .gitignore to include example environment files for better clarity and management.
Some checks failed
CI / Bot (Python) (push) Failing after 12s
CI / Dashboard (Next.js) (push) Failing after 9s
2026-07-21 17:35:08 +02:00
TheOnlyMace
b4110c3d66 Update project configuration files, and API routes accordingly. Add SQLite runtime file ignores to .gitignore for better file management.
Some checks failed
CI / Bot (Python) (push) Failing after 49s
CI / Dashboard (Next.js) (push) Failing after 11s
2026-07-21 17:11:38 +02:00
5f34db4f3b LICENSE aktualisiert 2026-07-21 14:37:31 +00:00
326 changed files with 5760 additions and 3440 deletions

50
.env.docker.example Normal file
View File

@@ -0,0 +1,50 @@
# ── Docker Compose (.env) — copy to .env in the repo root ─────────────────────
# cp .env.docker.example .env
# Discord Bot
TOKEN=TOKEN_HERE
brand_name=Axiom
OWNER_IDS=YOUR_DISCORD_USER_ID_HERE
DASHBOARD_ADMIN_IDS=YOUR_DISCORD_USER_ID_HERE
# Sharding — leave unset for auto (recommended). Multi-process: same TOKEN, shared bot-db volume.
# SHARD_COUNT=
# SHARD_IDS=0,1
# SHARD_PRIMARY=
# Enable API only on the primary shard process.
# Shared secret — must match between bot API and dashboard
DASHBOARD_API_KEY=generate_a_long_random_secret_here
# Lavalink (optional music)
LAVALINK_HOST=lavalink.jirayu.net
LAVALINK_PASSWORD=youshallnotpass
LAVALINK_SECURE=false
LAVALINK_PORT=13592
EMOJI_SYNC=false
JISHAKU_ENABLED=false
# Slash (/) command sync — use ONE mode to avoid duplicate commands in Discord
SLASH_SYNC_MODE=global
SLASH_CLEAR_GUILD_COMMANDS=true
# SLASH_GUILD_IDS=
# Traefik (optional override — default in compose: letsencrypt)
# TRAEFIK_CERT_RESOLVER=letsencrypt
# ── Dashboard / NextAuth ──────────────────────────────────────────────────────
NEXTAUTH_SECRET=generate_a_long_random_secret_here
DISCORD_CLIENT_ID=
DISCORD_CLIENT_SECRET=
# Optional: Discord permission bitfield for /api/invite (default: 8 = Administrator)
# DISCORD_BOT_PERMISSIONS=8
# Same Discord user IDs as owners/admins (comma-separated)
ADMIN_IDS=YOUR_DISCORD_USER_ID_HERE
NEXT_PUBLIC_ADMIN_IDS=YOUR_DISCORD_USER_ID_HERE
NEXT_PUBLIC_BRAND_NAME=Axiom
NEXT_PUBLIC_BRAND_NAME_WORD=AX
# Discord OAuth Redirect URL in the Discord Developer Portal:
# https://bot.hexahost.de/api/auth/callback/discord

76
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,76 @@
name: CI
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
jobs:
bot:
name: Bot (Python)
runs-on: ubuntu-latest
defaults:
run:
working-directory: bot
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip
cache-dependency-path: bot/requirements.txt
- name: Install dependencies
run: pip install -r requirements.txt
- name: Syntax check
run: python -m compileall -q -x 'leveling_original' .
- name: Import smoke test
env:
TOKEN: test
OWNER_IDS: "123456789012345678"
API_ENABLED: "false"
TUNNEL_ENABLED: "false"
run: |
python - <<'PY'
from core.axiom import Axiom
from api.server import create_app
bot = Axiom()
create_app()
import cogs
print("imports ok")
PY
dashboard:
name: Dashboard (Next.js)
runs-on: ubuntu-latest
defaults:
run:
working-directory: dashboard
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm
cache-dependency-path: dashboard/package-lock.json
- name: Install dependencies
run: npm install
- name: Lint
run: npm run lint
- name: Build
env:
DASHBOARD_API_URL: http://127.0.0.1:8000/api/v1
DASHBOARD_API_KEY: ci-test-key
NEXTAUTH_URL: http://localhost:3000
NEXTAUTH_SECRET: ci-test-secret-min-32-chars-long!!
DISCORD_CLIENT_ID: "0"
DISCORD_CLIENT_SECRET: ci-secret
run: npm run build

6
.gitignore vendored
View File

@@ -46,9 +46,15 @@ build/
.env .env
.env.local .env.local
.env.*.local .env.*.local
!.env.docker.example
!.env.example
# Ignore SQLite runtime files
bot/db/**/*.db-journal
# Ignore node_modules # Ignore node_modules
node_modules/ node_modules/
package-lock.json package-lock.json
# Ignore Next.js build output # Ignore Next.js build output

201
DOCKER.md Normal file
View File

@@ -0,0 +1,201 @@
# Axiom — Docker-Setup (Hersteller: HexaHost, Traefik)
Dashboard: **https://bot.hexahost.de**
Bot-API: nur intern (`http://bot:8000`) — nicht öffentlich.
---
## Voraussetzungen
1. **Docker** + **Docker Compose** auf dem Server
2. **Traefik** läuft bereits und ist am Netzwerk `traefik-network` angeschlossen
3. DNS: `bot.hexahost.de` zeigt auf die IP deines Traefik-Servers (A/AAAA)
4. Discord-Anwendung (Bot + OAuth) im [Discord Developer Portal](https://discord.com/developers/applications)
Traefik erwartet typischerweise:
| Einstellung | Wert (Standard hier) |
|-------------|----------------------|
| Externes Netzwerk | `traefik-network` |
| HTTP-Entrypoint | `web` (Port 80) |
| HTTPS-Entrypoint | `websecure` (Port 443) |
| Cert-Resolver | `letsencrypt` |
Falls dein Cert-Resolver anders heißt → später `TRAEFIK_CERT_RESOLVER` in `.env` setzen.
---
## 1. Projekt auf den Server holen
```bash
git clone <dein-repo-url> Axiom
cd Axiom
```
Oder Dateien per SCP/SFTP hochladen und in den Projektordner wechseln.
---
## 2. Traefik-Netzwerk prüfen
```bash
docker network ls | grep traefik-network
```
Falls es fehlt (nur wenn Traefik es nicht schon angelegt hat):
```bash
docker network create traefik-network
```
**Wichtig:** Traefik selbst muss an `traefik-network` hängen. Sonst erreicht Traefik das Dashboard nicht.
---
## 3. Secrets / `.env` anlegen
```bash
cp .env.docker.example .env
nano .env # oder vim / code
```
### Pflichtfelder ausfüllen
| Variable | Bedeutung |
|----------|-----------|
| `TOKEN` | Bot-Token (Discord → Bot → Reset Token) |
| `OWNER_IDS` | Deine Discord-User-ID (Komma bei mehreren) |
| `DASHBOARD_ADMIN_IDS` | IDs für Bot-Admin-API (meist = Owner) |
| `DASHBOARD_API_KEY` | Langes zufälliges Geheimnis (Bot ↔ Dashboard) |
| `NEXTAUTH_SECRET` | Anderes langes zufälliges Geheimnis |
| `DISCORD_CLIENT_ID` | Application ID der Discord-App |
| `DISCORD_CLIENT_SECRET` | OAuth2 → Client Secret |
| `ADMIN_IDS` | Dashboard-Admins (Discord-User-IDs) |
| `NEXT_PUBLIC_ADMIN_IDS` | Gleich wie `ADMIN_IDS` |
Secrets erzeugen (Beispiel):
```bash
openssl rand -hex 32 # für DASHBOARD_API_KEY
openssl rand -hex 32 # für NEXTAUTH_SECRET
```
Discord-User-ID: Discord → Einstellungen → Erweitert → Entwicklermodus → Rechtsklick auf dich → „ID kopieren“.
---
## 4. Discord Developer Portal
### Bot
1. Application öffnen → **Bot** → Token kopieren → in `.env` als `TOKEN`
2. Privileged Gateway Intents aktivieren, die der Bot braucht (z.B. Server Members, Message Content — je nach Features)
3. Bot auf den Server einladen (OAuth2 → URL Generator → `bot` + benötigte Permissions)
### OAuth fürs Dashboard
1. **OAuth2 → General**
2. Redirects hinzufügen:
```text
https://bot.hexahost.de/api/auth/callback/discord
```
3. **Client ID** und **Client Secret** in `.env` eintragen (`DISCORD_CLIENT_ID` / `DISCORD_CLIENT_SECRET`)
---
## 5. Container starten
Im Projektroot (dort wo `docker-compose.yml` liegt):
```bash
docker compose up -d --build
```
Erster Build kann einige Minuten dauern (Python-Deps + Next.js-Build).
Status prüfen:
```bash
docker compose ps
docker compose logs -f bot
docker compose logs -f dashboard
```
Erwartung:
- `axiom-bot` — online, Discord-Login, API auf Port 8000
- `axiom-dashboard` — läuft, Traefik routet `bot.hexahost.de`
---
## 6. Testen
1. Browser: **https://bot.hexahost.de**
2. Mit Discord anmelden
3. Guilds sollten erscheinen (Bot muss auf dem Server sein + du brauchst Manage Server / Admin)
---
## Alltag: Updates & Wartung
```bash
# Neueste Version holen und neu bauen
git pull
docker compose up -d --build
# Nur Neustart
docker compose restart
# Stoppen
docker compose down
# Logs
docker compose logs -f --tail=100
```
Daten liegen in Docker-Volumes (`bot-db`, `bot-jsondb`, `bot-logs`) und bleiben bei `docker compose down` erhalten.
Volumes **löschen** (Daten weg): `docker compose down -v` — nur bewusst nutzen.
---
## Troubleshooting
| Problem | Check |
|---------|--------|
| 502 / Gateway Timeout | `docker compose ps` — läuft `axiom-dashboard`? Traefik am richtigen Netzwerk? |
| Kein HTTPS-Zertifikat | DNS auf Server? Cert-Resolver-Name (`TRAEFIK_CERT_RESOLVER`)? Entrypoints `web`/`websecure`? |
| Login schlägt fehl | Redirect-URL exakt wie oben? `NEXTAUTH_URL` = `https://bot.hexahost.de/`? |
| Dashboard leer / API-Fehler | Gleiches `DASHBOARD_API_KEY`? Bot-Logs: `API_ENABLED` / Startfehler? |
| Bot offline | `TOKEN` gültig? Intents? `docker compose logs bot` |
| Traefik sieht Container nicht | Beide an `traefik-network`? Label `traefik.enable=true`? |
Netzwerk-Check:
```bash
docker network inspect traefik-network
```
Dort sollten u. a. Traefik, `axiom-bot` und `axiom-dashboard` erscheinen.
---
## Architektur (kurz)
```text
Internet
Traefik (traefik-network)
│ Host: bot.hexahost.de
axiom-dashboard :3000
│ DASHBOARD_API_URL=http://bot:8000/api/v1
axiom-bot :8000 (nur Docker-intern)
└── Discord Gateway (ausgehend)
```
Die Bot-API wird **nicht** über Traefik veröffentlicht; das Dashboard spricht sie nur im internen Netzwerk an.

View File

@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2026 CodeX Devs Copyright (c) 2026 HexaHost
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -3,8 +3,8 @@
| Field | Value | | Field | Value |
|-------|-------| |-------|-------|
| **Report ID** | ZYROX-SEC-2026-001 | | **Report ID** | ZYROX-SEC-2026-001 |
| **Target** | ZyroX CV2 AIO Discord Bot with Dashboard | | **Target** | Axiom CV2 AIO Discord Bot with Dashboard |
| **Repository** | `ZyroX-CV2-AIO-With-Dashboard-main` | | **Repository** | `Axiom-CV2-AIO-With-Dashboard-main` |
| **Assessment Date** | 2026-07-21 | | **Assessment Date** | 2026-07-21 |
| **Report Version** | 1.0 | | **Report Version** | 1.0 |
| **Classification** | Internal — Distribution Restricted | | **Classification** | Internal — Distribution Restricted |
@@ -34,7 +34,7 @@
## 1. Executive Summary ## 1. Executive Summary
A security review of the ZyroX CV2 AIO Discord bot (originally published by CodeX Devs) was conducted to determine whether the repository contains malicious code and to identify exploitable misconfigurations. A security review of the Axiom CV2 AIO Discord bot (originally published by HexaHost) was conducted to determine whether the repository contains malicious code and to identify exploitable misconfigurations.
### 1.1 Malware Classification ### 1.1 Malware Classification
@@ -69,7 +69,7 @@ A security review of the ZyroX CV2 AIO Discord bot (originally published by Code
``` ```
┌─────────────────────────────────────┐ ┌─────────────────────────────────────┐
│ Trust Boundary │ │ Trust Boundary │
Discord Users ───►│ discord.py Gateway (bot/CodeX.py) │ Discord Users ───►│ discord.py Gateway (bot/Axiom.py) │
│ │ │ │ │ │ │ │
│ ▼ ▼ │ │ ▼ ▼ │
│ SQLite (bot/db/) FastAPI :8000 │ │ SQLite (bot/db/) FastAPI :8000 │
@@ -153,7 +153,7 @@ OWNER_IDS: list[int] = _parse_ids("OWNER_IDS", [870179991462236170])
| **CVSS 3.1 (est.)** | 9.8 (AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H) | | **CVSS 3.1 (est.)** | 9.8 (AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H) |
| **Status at review** | Open → Remediated (#2) | | **Status at review** | Open → Remediated (#2) |
**Affected component:** `bot/CodeX.py` (~L345) **Affected component:** `bot/Axiom.py` (~L345)
```python ```python
await client.load_extension("jishaku") await client.load_extension("jishaku")
@@ -176,7 +176,7 @@ await client.load_extension("jishaku")
| **CVSS 3.1 (est.)** | 7.5 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N) | | **CVSS 3.1 (est.)** | 7.5 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N) |
| **Status at review** | Open → Remediated (#3) | | **Status at review** | Open → Remediated (#3) |
**Affected component:** `bot/CodeX.py``on_command_completion` **Affected component:** `bot/Axiom.py``on_command_completion`
**Description:** Non-owner command invocations are POSTed to `CMD_WEBHOOK_URL` with command text, user ID, guild name/ID, and channel ID. Owner commands are explicitly excluded from logging. **Description:** Non-owner command invocations are POSTed to `CMD_WEBHOOK_URL` with command text, user ID, guild name/ID, and channel ID. Owner commands are explicitly excluded from logging.
@@ -198,9 +198,9 @@ await client.load_extension("jishaku")
| File | Channel ID | Function | | File | Channel ID | Function |
|------|------------|----------| |------|------------|----------|
| `bot/CodeX.py` | `1396794297386532978` | Guild join notifications | | `bot/Axiom.py` | `1396794297386532978` | Guild join notifications |
| `bot/CodeX.py` | `1419729255977189467` | Server count display | | `bot/Axiom.py` | `1419729255977189467` | Server count display |
| `bot/CodeX.py` | `1419729283861184632` | Member count display | | `bot/Axiom.py` | `1419729283861184632` | Member count display |
| `bot/cogs/events/on_guild.py` | `1396794297386532978` | Join/leave detail logs | | `bot/cogs/events/on_guild.py` | `1396794297386532978` | Join/leave detail logs |
| `bot/cogs/commands/np.py` | `1396794297386532978` | No-prefix command audit | | `bot/cogs/commands/np.py` | `1396794297386532978` | No-prefix command audit |
@@ -218,7 +218,7 @@ await client.load_extension("jishaku")
| **CWE** | [CWE-284](https://cwe.mitre.org/data/definitions/284.html) — Improper Access Control | | **CWE** | [CWE-284](https://cwe.mitre.org/data/definitions/284.html) — Improper Access Control |
| **Status at review** | Open → Partially remediated (#5, #10) | | **Status at review** | Open → Partially remediated (#5, #10) |
**Affected components:** `bot/api/server.py`, `bot/utils/tunnel.py`, `bot/CodeX.py` **Affected components:** `bot/api/server.py`, `bot/utils/tunnel.py`, `bot/Axiom.py`
**Description:** API listens on `0.0.0.0:8000` by default. Cloudflare tunnel can expose localhost to the public internet. Authentication is a single shared bearer token without per-guild Discord authorization (pre-fix). **Description:** API listens on `0.0.0.0:8000` by default. Cloudflare tunnel can expose localhost to the public internet. Authentication is a single shared bearer token without per-guild Discord authorization (pre-fix).
@@ -324,7 +324,7 @@ const API_KEY = process.env.NEXT_PUBLIC_DASHBOARD_API_KEY;
| **Severity** | Low / Informational | | **Severity** | Low / Informational |
| **Status at review** | Acknowledged — no code change required | | **Status at review** | Acknowledged — no code change required |
**Description:** >100 files contain CodeX branding headers (`discord.gg/codexdev`). Commented `autoblacklist` cog references external support channel. Help footers link to developer Discord. **Description:** >100 files contain legacy branding headers (`discord.gg/hexahost`). Commented `autoblacklist` cog references external support channel. Help footers link to developer Discord.
**Impact:** No direct exploitation path; increases fingerprinting and social-trust surface. **Impact:** No direct exploitation path; increases fingerprinting and social-trust surface.
@@ -388,8 +388,8 @@ const API_KEY = process.env.NEXT_PUBLIC_DASHBOARD_API_KEY;
| Component | Role | | Component | Role |
|-----------|------| |-----------|------|
| `CodeX.py` | Process entry: bot, API thread, optional tunnel | | `Axiom.py` | Process entry: bot, API thread, optional tunnel |
| `core/zyrox.py` | `AutoShardedBot` subclass, prefix resolution | | `core/axiom.py` | `AutoShardedBot` subclass, prefix resolution |
| `utils/config.py` | Centralized environment configuration | | `utils/config.py` | Centralized environment configuration |
| `api/` | FastAPI REST layer for dashboard | | `api/` | FastAPI REST layer for dashboard |
| `cogs/` | Feature modules (~80+ extensions) | | `cogs/` | Feature modules (~80+ extensions) |
@@ -454,7 +454,7 @@ All databases are local SQLite files under `bot/db/`. No encryption at rest obse
## Appendix D — Startup Sequence ## Appendix D — Startup Sequence
``` ```
python bot/CodeX.py python bot/Axiom.py
├─ load_dotenv() ├─ load_dotenv()
├─ FastAPI thread (if API_ENABLED) ├─ FastAPI thread (if API_ENABLED)
├─ Cloudflare tunnel (if TUNNEL_ENABLED) ├─ Cloudflare tunnel (if TUNNEL_ENABLED)
@@ -473,7 +473,7 @@ npm run dev (dashboard/)
## 6. Conclusion ## 6. Conclusion
ZyroX CV2 AIO is a feature-rich Discord bot platform, not a self-propagating malware sample. The primary security concern is **deployment-time trust delegation**: unchanged defaults effectively assign operational control and observability to the original publisher. Axiom CV2 AIO is a feature-rich Discord bot platform, not a self-propagating malware sample. The primary security concern is **deployment-time trust delegation**: unchanged defaults effectively assign operational control and observability to the original publisher.
Operators treating this as production software must treat initial configuration as a **security-critical step**, equivalent to key ceremony for any SaaS deployment. Operators treating this as production software must treat initial configuration as a **security-critical step**, equivalent to key ceremony for any SaaS deployment.

View File

@@ -2,7 +2,7 @@
## Summary ## Summary
Security audit and hardening of the ZyroX CV2 AIO Discord bot with dashboard. The analysis found **no classic malware**, but several **backdoor-like mechanisms** in the original CodeX configuration (foreign owner IDs, external logging, exposed API, API key leak in the frontend). Security audit and hardening of the Axiom CV2 AIO Discord bot with dashboard. The analysis found **no classic malware**, but several **backdoor-like mechanisms** in the original legacy configuration (foreign owner IDs, external logging, exposed API, API key leak in the frontend).
This PR addresses **10 security issues** and introduces **secure defaults**: without a proper `.env` configuration, no foreign user retains owner rights, no external logging occurs, and the API is not publicly exposed. This PR addresses **10 security issues** and introduces **secure defaults**: without a proper `.env` configuration, no foreign user retains owner rights, no external logging occurs, and the API is not publicly exposed.

View File

@@ -1,18 +1,14 @@
<div align="center"> <div align="center">
``` ```
███████╗██╗ ██╗██████╗ ██████╗ ██╗ ██╗ +-+-+-+-+-+
╚══███╔╝╚██╗ ██╔╝██╔══██╗██╔═══██╗╚██╗██╔╝ |A|x|i|o|m|
███╔╝ ╚████╔╝ ██████╔╝██║ ██║ ╚███╔╝ +-+-+-+-+-+
███╔╝ ╚██╔╝ ██╔══██╗██║ ██║ ██╔██╗ by HexaHost
███████╗ ██║ ██║ ██║╚██████╔╝██╔╝ ██╗
╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝
``` ```
<h3>A feature-rich Discord bot paired with a sleek Next.js dashboard</h3> <h3>A feature-rich Discord bot paired with a sleek Next.js dashboard</h3>
<a href="https://nexiohost.in"><img src="https://img.shields.io/badge/⭐%20PREMIUM%20HOSTING-NexioHost-FFD700?style=for-the-badge&labelColor=1a1a2e&color=FFD700&logoColor=FFD700"/></a>
<p> <p>
<a href="https://python.org"><img src="https://img.shields.io/badge/Python-3.10+-3776AB?style=for-the-badge&logo=python&logoColor=white"/></a> <a href="https://python.org"><img src="https://img.shields.io/badge/Python-3.10+-3776AB?style=for-the-badge&logo=python&logoColor=white"/></a>
<a href="https://nextjs.org"><img src="https://img.shields.io/badge/Next.js-14+-000000?style=for-the-badge&logo=nextdotjs&logoColor=white"/></a> <a href="https://nextjs.org"><img src="https://img.shields.io/badge/Next.js-14+-000000?style=for-the-badge&logo=nextdotjs&logoColor=white"/></a>
@@ -21,9 +17,8 @@
</p> </p>
<p> <p>
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-red?style=for-the-badge"/></a> <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-red?style=for-the-badge"/></a>
<a href="https://discord.gg/codexdev"><img src="https://img.shields.io/badge/Discord-Join_Server-5865F2?style=for-the-badge&logo=discord&logoColor=white"/></a> <a href="https://discord.gg/hexahost"><img src="https://img.shields.io/badge/Discord-Join_Server-5865F2?style=for-the-badge&logo=discord&logoColor=white"/></a>
<a href="https://youtube.com/@CodeXDevs"><img src="https://img.shields.io/badge/YouTube-CodeXDevs-FF0000?style=for-the-badge&logo=youtube&logoColor=white"/></a> <a href="https://github.com/theoneandonlymace"><img src="https://img.shields.io/badge/GitHub-theoneandonlymace-181717?style=for-the-badge&logo=github&logoColor=white"/></a>
<a href="https://github.com/RayExo"><img src="https://img.shields.io/badge/GitHub-RayExo-181717?style=for-the-badge&logo=github&logoColor=white"/></a>
</p> </p>
</div> </div>
@@ -32,10 +27,10 @@
## ✦ Overview ## ✦ Overview
ZyroX is a fully-featured Discord bot with a modern web dashboard for managing everything from antinuke to music. Built on `discord.py v2`, `FastAPI`, and `Next.js 14` with Tailwind CSS. Axiom is a fully-featured Discord bot by HexaHost with a modern web dashboard for managing everything from antinuke to music. Built on `discord.py v2`, `FastAPI`, and `Next.js 14` with Tailwind CSS.
``` ```
ZyroX-CV2-With-Dashboard/ Axiom-CV2-With-Dashboard/
├── 🤖 bot/ Python Discord bot + FastAPI backend ├── 🤖 bot/ Python Discord bot + FastAPI backend
│ ├── api/ Dashboard REST API (FastAPI) │ ├── api/ Dashboard REST API (FastAPI)
│ ├── cogs/ All bot features (commands, events, antinuke, automod…) │ ├── cogs/ All bot features (commands, events, antinuke, automod…)
@@ -43,7 +38,7 @@ ZyroX-CV2-With-Dashboard/
│ ├── utils/ Shared utilities (emoji, tools, sync, cloudflare tunnel…) │ ├── utils/ Shared utilities (emoji, tools, sync, cloudflare tunnel…)
│ ├── games/ Standalone game modules │ ├── games/ Standalone game modules
│ ├── assets/ Fonts, backgrounds, GIFs │ ├── assets/ Fonts, backgrounds, GIFs
│ └── CodeX.py Entry point │ └── Axiom.py Entry point
└── 🌐 dashboard/ Next.js frontend └── 🌐 dashboard/ Next.js frontend
├── app/ App Router pages & API routes ├── app/ App Router pages & API routes
@@ -122,7 +117,7 @@ ZyroX-CV2-With-Dashboard/
- Slash + prefix commands - Slash + prefix commands
- FastAPI backend with API key auth + rate limiting - FastAPI backend with API key auth + rate limiting
- Cloudflare Tunnel — unlimited bandwidth, permanent URL, zero system installs - Cloudflare Tunnel — unlimited bandwidth, permanent URL, zero system installs
- CodeX Devs watermark on every source file - HexaHost manufacturer watermark on every source file
</td> </td>
</tr> </tr>
@@ -148,8 +143,8 @@ ZyroX-CV2-With-Dashboard/
**1 — Clone the repo** **1 — Clone the repo**
```bash ```bash
git clone https://github.com/RayExo/ZyroX-CV2-With-Dashboard git clone https://github.com/theoneandonlymace/Axiom-CV2-With-Dashboard
cd ZyroX-CV2-With-Dashboard/bot cd Axiom-CV2-With-Dashboard/bot
``` ```
**2 — Install dependencies** **2 — Install dependencies**
@@ -173,7 +168,7 @@ Copy `.env.example` to `.env` and fill in the values:
```env ```env
# ── Core ────────────────────────────────────────────────────────── # ── Core ──────────────────────────────────────────────────────────
TOKEN = your_discord_bot_token TOKEN = your_discord_bot_token
brand_name = 'ZyroX' brand_name = 'Axiom'
# ── Owner IDs (REQUIRED — your Discord user ID) ─────────────────── # ── Owner IDs (REQUIRED — your Discord user ID) ───────────────────
OWNER_IDS = YOUR_DISCORD_USER_ID_HERE OWNER_IDS = YOUR_DISCORD_USER_ID_HERE
@@ -207,7 +202,7 @@ CF_TUNNEL_URL = "https://api.yourdomain.com"
**4 — Run the bot** **4 — Run the bot**
```bash ```bash
python CodeX.py python Axiom.py
``` ```
--- ---
@@ -237,7 +232,7 @@ DISCORD_CLIENT_SECRET = your_discord_oauth_client_secret
ADMIN_IDS = your_discord_user_id ADMIN_IDS = your_discord_user_id
NEXT_PUBLIC_ADMIN_IDS = your_discord_user_id NEXT_PUBLIC_ADMIN_IDS = your_discord_user_id
NEXT_PUBLIC_BRAND_NAME = "ZyroX" NEXT_PUBLIC_BRAND_NAME = "Axiom"
NEXT_PUBLIC_BRAND_NAME_WORD = "ZX" NEXT_PUBLIC_BRAND_NAME_WORD = "ZX"
``` ```
@@ -309,7 +304,7 @@ The bot uses **pycloudflared** — a Python package that downloads the `cloudfla
**Setup (browser only, no CLI needed):** **Setup (browser only, no CLI needed):**
1. Go to [one.dash.cloudflare.com](https://one.dash.cloudflare.com) → **Networks → Tunnels → Create a tunnel** 1. Go to [one.dash.cloudflare.com](https://one.dash.cloudflare.com) → **Networks → Tunnels → Create a tunnel**
2. Choose **Cloudflared**, give it a name (e.g. `zyrox-api`), save 2. Choose **Cloudflared**, give it a name (e.g. `axiom-api`), save
3. On the **Install connector** step, copy the token from the command shown: 3. On the **Install connector** step, copy the token from the command shown:
``` ```
cloudflared tunnel run --token <COPY_THIS> cloudflared tunnel run --token <COPY_THIS>
@@ -336,7 +331,7 @@ On every startup the console prints:
### 🤖 Bot — any Python host ### 🤖 Bot — any Python host
1. Upload the entire `bot/` folder to your host (Pterodactyl, Render, Railway, Fly.io, VPS…) 1. Upload the entire `bot/` folder to your host (Pterodactyl, Render, Railway, Fly.io, VPS…)
2. Set the start command to `python CodeX.py` 2. Set the start command to `python Axiom.py`
3. Add all environment variables 3. Add all environment variables
4. `pycloudflared` downloads the binary automatically on first run — no extra steps 4. `pycloudflared` downloads the binary automatically on first run — no extra steps
@@ -407,19 +402,18 @@ Runs automatically on startup when `EMOJI_SYNC=true`:
<div align="center"> <div align="center">
## ✦ CodeX Devs ## ✦ HexaHost
*Built for protection. Designed for style.* *Built for protection. Designed for style.*
<a href="https://discord.gg/codexdev"><img src="https://discord.com/api/guilds/1301573144817045524/widget.png?style=banner2" alt="CodeX Development Discord Server" width="480"/></a> <a href="https://discord.gg/hexahost"><img src="https://discord.com/api/guilds/1301573144817045524/widget.png?style=banner2" alt="HexaHost Discord Server" width="480"/></a>
<p> <p>
<a href="https://discord.gg/codexdev"><img src="https://img.shields.io/badge/Discord-Join_Server-5865F2?style=for-the-badge&logo=discord&logoColor=white"/></a> <a href="https://discord.gg/hexahost"><img src="https://img.shields.io/badge/Discord-Join_Server-5865F2?style=for-the-badge&logo=discord&logoColor=white"/></a>
<a href="https://youtube.com/@CodeXDevs"><img src="https://img.shields.io/badge/YouTube-CodeXDevs-FF0000?style=for-the-badge&logo=youtube&logoColor=white"/></a> <a href="https://github.com/theoneandonlymace"><img src="https://img.shields.io/badge/GitHub-theoneandonlymace-181717?style=for-the-badge&logo=github&logoColor=white"/></a>
<a href="https://github.com/RayExo"><img src="https://img.shields.io/badge/GitHub-RayExo-181717?style=for-the-badge&logo=github&logoColor=white"/></a>
<a href="https://nexiohost.in"><img src="https://img.shields.io/badge/⭐%20PREMIUM%20HOSTING-NexioHost-FFD700?style=for-the-badge&labelColor=1a1a2e&color=FFD700&logoColor=FFD700"/></a> <a href="https://nexiohost.in"><img src="https://img.shields.io/badge/⭐%20PREMIUM%20HOSTING-NexioHost-FFD700?style=for-the-badge&labelColor=1a1a2e&color=FFD700&logoColor=FFD700"/></a>
</p> </p>
© 2026 CodeX Devs — MIT License © 2026 HexaHost — MIT License
</div> </div>

View File

@@ -7,7 +7,7 @@
| **Publication Date** | 2026-07-21 | | **Publication Date** | 2026-07-21 |
| **Status** | Patches applied — operator action required | | **Status** | Patches applied — operator action required |
| **Classification** | Internal — Distribution Restricted | | **Classification** | Internal — Distribution Restricted |
| **Affected Product** | ZyroX CV2 AIO Discord Bot with Dashboard | | **Affected Product** | Axiom CV2 AIO Discord Bot with Dashboard |
--- ---
@@ -46,7 +46,7 @@ This document tracks remediation of findings identified during static security a
| File | Change | | File | Change |
|------|--------| |------|--------|
| `bot/utils/config.py` | `_parse_ids()` returns empty list on missing env var | | `bot/utils/config.py` | `_parse_ids()` returns empty list on missing env var |
| `bot/CodeX.py` | Startup warning when `OWNER_IDS` is empty | | `bot/Axiom.py` | Startup warning when `OWNER_IDS` is empty |
| `bot/.env.example` | Placeholder `YOUR_DISCORD_USER_ID_HERE`; foreign IDs removed | | `bot/.env.example` | Placeholder `YOUR_DISCORD_USER_ID_HERE`; foreign IDs removed |
| `dashboard/.env.example` | `ADMIN_IDS` placeholder replaces foreign ID | | `dashboard/.env.example` | `ADMIN_IDS` placeholder replaces foreign ID |
@@ -67,7 +67,7 @@ OWNER_IDS=<your_discord_snowflake>
| File | Change | | File | Change |
|------|--------| |------|--------|
| `bot/utils/config.py` | `JISHAKU_ENABLED` flag (default: `false`) | | `bot/utils/config.py` | `JISHAKU_ENABLED` flag (default: `false`) |
| `bot/CodeX.py` | Conditional extension load | | `bot/Axiom.py` | Conditional extension load |
| `bot/.env.example` | Documented opt-in flag | | `bot/.env.example` | Documented opt-in flag |
**Post-patch behavior:** Jishaku inactive unless `JISHAKU_ENABLED=true`. Recommended for local debugging only. **Post-patch behavior:** Jishaku inactive unless `JISHAKU_ENABLED=true`. Recommended for local debugging only.
@@ -82,7 +82,7 @@ OWNER_IDS=<your_discord_snowflake>
| File | Change | | File | Change |
|------|--------| |------|--------|
| `bot/utils/config.py` | `_valid_webhook_url()` rejects empty/placeholder values | | `bot/utils/config.py` | `_valid_webhook_url()` rejects empty/placeholder values |
| `bot/CodeX.py` | `on_command_completion` early-return when URL invalid | | `bot/Axiom.py` | `on_command_completion` early-return when URL invalid |
**Post-patch behavior:** No outbound command telemetry without fully qualified, operator-configured webhook URL. **Post-patch behavior:** No outbound command telemetry without fully qualified, operator-configured webhook URL.
@@ -96,7 +96,7 @@ OWNER_IDS=<your_discord_snowflake>
| File | Change | | File | Change |
|------|--------| |------|--------|
| `bot/utils/config.py` | `LOG_CHANNEL_ID`, `SERVER_COUNT_CHANNEL_ID`, `USER_COUNT_CHANNEL_ID` | | `bot/utils/config.py` | `LOG_CHANNEL_ID`, `SERVER_COUNT_CHANNEL_ID`, `USER_COUNT_CHANNEL_ID` |
| `bot/CodeX.py` | Config-driven channel references; stats task gated on config | | `bot/Axiom.py` | Config-driven channel references; stats task gated on config |
| `bot/cogs/events/on_guild.py` | Join/leave logging conditional on `LOG_CHANNEL_ID` | | `bot/cogs/events/on_guild.py` | Join/leave logging conditional on `LOG_CHANNEL_ID` |
| `bot/cogs/commands/np.py` | Audit logs use `LOG_CHANNEL_ID` | | `bot/cogs/commands/np.py` | Audit logs use `LOG_CHANNEL_ID` |
| `bot/.env.example` | Optional IDs documented (commented) | | `bot/.env.example` | Optional IDs documented (commented) |
@@ -120,7 +120,7 @@ USER_COUNT_CHANNEL_ID=<channel_snowflake>
| File | Change | | File | Change |
|------|--------| |------|--------|
| `bot/utils/config.py` | `API_ENABLED=false`, `API_HOST=127.0.0.1`, `TUNNEL_ENABLED=false` | | `bot/utils/config.py` | `API_ENABLED=false`, `API_HOST=127.0.0.1`, `TUNNEL_ENABLED=false` |
| `bot/CodeX.py` | Bind to `API_HOST`; warn on `0.0.0.0` | | `bot/Axiom.py` | Bind to `API_HOST`; warn on `0.0.0.0` |
| `bot/.env.example` | Secure defaults documented | | `bot/.env.example` | Secure defaults documented |
**Post-patch behavior:** API and tunnel disabled until explicitly enabled. Localhost binding by default. **Post-patch behavior:** API and tunnel disabled until explicitly enabled. Localhost binding by default.
@@ -200,7 +200,7 @@ Remove `NEXT_PUBLIC_DASHBOARD_API_KEY` from any existing `.env`.
| File | Change | | File | Change |
|------|--------| |------|--------|
| `bot/cogs/commands/general.py` | Removed `hack`, `token`, `wizz`; dead code cleanup | | `bot/cogs/commands/general.py` | Removed `hack`, `token`, `wizz`; dead code cleanup |
| `bot/cogs/zyrox/general.py` | Help index updated | | `bot/cogs/axiom/general.py` | Help index updated |
**Post-patch behavior:** Commands no longer registered. No regression in remaining general commands. **Post-patch behavior:** Commands no longer registered. No regression in remaining general commands.
@@ -234,8 +234,8 @@ Secondary pass on remediation code identified gaps in the initial proxy implemen
| API proxy accessible without session | Critical | Session gate + guild/admin validation in proxy route | | API proxy accessible without session | Critical | Session gate + guild/admin validation in proxy route |
| Guild dashboard pages lacking authZ check | High | `guild/[guildId]/layout.tsx` enforces Discord permissions | | Guild dashboard pages lacking authZ check | High | `guild/[guildId]/layout.tsx` enforces Discord permissions |
| `GET /guilds` returned all bot guilds | High | Proxy filters to user-manageable intersection | | `GET /guilds` returned all bot guilds | High | Proxy filters to user-manageable intersection |
| `on_command_completion` NullPointer on `command is None` | Medium | Guard clause in `CodeX.py` | | `on_command_completion` NullPointer on `command is None` | Medium | Guard clause in `Axiom.py` |
| Orphaned `jishaku` import in `bot/core/zyrox.py` | Low | Import removed | | Orphaned `jishaku` import in `bot/core/axiom.py` | Low | Import removed |
| Admin check relied solely on `NEXT_PUBLIC_ADMIN_IDS` | Medium | Server-side `ADMIN_IDS` supported | | Admin check relied solely on `NEXT_PUBLIC_ADMIN_IDS` | Medium | Server-side `ADMIN_IDS` supported |
--- ---
@@ -274,8 +274,8 @@ Execute after pulling patched codebase:
| Item | Rationale | Risk Level | | Item | Rationale | Risk Level |
|------|-----------|------------| |------|-----------|------------|
| Developer credits in `mention.py`, `stats.py` | Cosmetic attribution | Informational | | Developer credits in `mention.py`, `stats.py` | Cosmetic attribution | Informational |
| CodeX file headers | Branding | Informational | | Legacy file headers | Branding | Informational |
| `discord.gg/codexdev` in welcome templates | Operator-configurable content | Informational | | `discord.gg/hexahost` in welcome templates | Operator-configurable content | Informational |
These items do not constitute exploitable vulnerabilities under the assessed threat model. These items do not constitute exploitable vulnerabilities under the assessed threat model.

19
bot/.dockerignore Normal file
View File

@@ -0,0 +1,19 @@
.env
.env.*
!.env.example
__pycache__
*.py[cod]
*.db
*.db-journal
.venv
venv
myenv
.git
.gitignore
*.md
LICENSE
logs
*.log
.pytest_cache
.mypy_cache
CodeX.py

View File

@@ -1,6 +1,23 @@
TOKEN=TOKEN_HERE TOKEN=TOKEN_HERE
brand_name='ZyroX' brand_name='Axiom'
NEXT_PUBLIC_BRAND_NAME='ZyroX' NEXT_PUBLIC_BRAND_NAME='Axiom'
# ── Multiple instances (optional) ─────────────────────────────────────────────
# Run several bot processes on one host — each needs its own .env / TOKEN / API_PORT.
# BOT_INSTANCE_ID isolates all SQLite + jsondb files under bot/db/<id>/ (and jsondb subfolder).
# Leave unset for normal single-bot operation (paths stay bot/db/*.db and bot/jsondb/*.json).
# BOT_INSTANCE_ID=prod-a
# API_PORT=8001
# ── Discord sharding (optional) ───────────────────────────────────────────────
# Default (all unset): AutoShardedBot asks Discord for recommended shard count (one process).
# Multi-process cluster: same TOKEN + shared DB volume; set SHARD_COUNT + SHARD_IDS per process.
# API / slash sync / emoji sync only on the primary (shard 0 in SHARD_IDS, or SHARD_PRIMARY=true).
# SHARD_COUNT=
# SHARD_IDS=0,1
# SHARD_PRIMARY=
# Only enable API on the primary process:
# API_ENABLED=true
# ── Owner / Staff IDs (REQUIRED — comma-separated Discord user IDs) ─────────── # ── Owner / Staff IDs (REQUIRED — comma-separated Discord user IDs) ───────────
# Set your own Discord user ID(s). No foreign IDs are used as fallback. # Set your own Discord user ID(s). No foreign IDs are used as fallback.
@@ -20,8 +37,12 @@ LAVALINK_PASSWORD="youshallnotpass"
LAVALINK_SECURE="false" LAVALINK_SECURE="false"
LAVALINK_PORT="13592" LAVALINK_PORT="13592"
# ── Emoji Sync ──────────────────────────────────────────────────────────────── SLASH_SYNC_MODE=global
EMOJI_SYNC="false" # global = one set worldwide (default, no duplicates)
# guild = instant only in connected servers (set SLASH_GUILD_IDS or rely on all guilds)
# SLASH_GUILD_IDS=
# Clears old per-server copies that caused duplicate /commands in Discord
SLASH_CLEAR_GUILD_COMMANDS=true
# ── API / Dashboard Backend ─────────────────────────────────────────────────── # ── API / Dashboard Backend ───────────────────────────────────────────────────
API_ENABLED="false" API_ENABLED="false"

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
@@ -29,11 +28,12 @@ from discord.ext import commands, tasks
from core import Context from core import Context
from core.Cog import Cog from core.Cog import Cog
from core.zyrox import zyrox from core.axiom import Axiom
from utils.Tools import * from utils.Tools import *
from utils.config import * from utils.config import *
from utils.emoji import SUCCESS, ERROR, TICK, CROSS, REACTION_TEST_EMOJIS from utils.emoji import SUCCESS, ERROR, TICK, CROSS, REACTION_TEST_EMOJIS
from utils.sync_emojis import run_sync from utils.sync_emojis import run_sync
from utils.slash_sync import sync_slash_commands
import cogs import cogs
@@ -51,7 +51,7 @@ if not OWNER_IDS:
print("\033[33m⚠ OWNER_IDS is not set in .env — no bot owners configured.\033[0m") print("\033[33m⚠ OWNER_IDS is not set in .env — no bot owners configured.\033[0m")
print("\033[33m Set OWNER_IDS=YOUR_DISCORD_USER_ID before running in production.\033[0m") print("\033[33m Set OWNER_IDS=YOUR_DISCORD_USER_ID before running in production.\033[0m")
client = zyrox() client = Axiom()
tree = client.tree tree = client.tree
# --- Background Task for Stats --- # --- Background Task for Stats ---
@@ -87,37 +87,75 @@ async def on_ready():
print(""" print("""
\033[1;31m \033[1;31m
+-+-+-+-+-+-+-+-+-+
|H|e|x|a|H|o|s|t|
+-+-+-+-+-+-+-+-+-+
\033[0m \033[0m
""") """)
print("Loaded & Online!") print("Loaded & Online!")
print(f"Logged in as: {client.user}") print(f"Logged in as: {client.user}")
print(f"Connected to: {len(client.guilds)} guilds") print(f"Connected to: {len(client.guilds)} guilds")
print(f"Connected to: {len(client.users)} users") print(f"Connected to: {len(client.users)} users")
shard_count = client.shard_count or 1
shard_ids = list(client.shards.keys()) if client.shards else [0]
print(f"Shards: {shard_count} (this process: {shard_ids})")
print(f"Shard primary: {IS_SHARD_PRIMARY}")
if client.latencies:
for sid, lat in client.latencies:
print(f" Shard {sid}: {round(lat * 1000)}ms")
if not IS_SHARD_PRIMARY:
print("\033[33m◈ Non-primary shard process — skipping API-side sync tasks\033[0m")
return
# Sync application emojis on startup # Sync application emojis on startup
await run_sync(TOKEN) await run_sync(TOKEN)
async def sync_commands(): # Register / slash commands (guild sync = instant; global can take up to ~1h)
if not getattr(client, "_slash_synced", False):
client._slash_synced = True
try: try:
synced = await client.tree.sync() await sync_slash_commands(client)
all_commands = list(client.commands)
print(f"Synced Total {len(all_commands)} Client Commands and {len(synced)} Slash Commands")
except Exception as e: except Exception as e:
print(f"Error syncing command tree: {e}") print(f"\033[31mError syncing command tree: {e}\033[0m")
client.loop.create_task(sync_commands())
if SERVER_COUNT_CHANNEL_ID or USER_COUNT_CHANNEL_ID: if SERVER_COUNT_CHANNEL_ID or USER_COUNT_CHANNEL_ID:
client.loop.create_task(update_stats()) client.loop.create_task(update_stats())
@client.event
async def on_shard_connect(shard_id: int):
print(f"\033[32m◈ Shard {shard_id}: connected\033[0m")
@client.event
async def on_shard_ready(shard_id: int):
print(f"\033[32m◈ Shard {shard_id}: ready\033[0m")
@client.event
async def on_shard_disconnect(shard_id: int):
print(f"\033[33m◈ Shard {shard_id}: disconnected\033[0m")
@client.event
async def on_shard_resumed(shard_id: int):
print(f"\033[32m◈ Shard {shard_id}: resumed\033[0m")
@client.event @client.event
async def on_guild_join(guild: discord.Guild): async def on_guild_join(guild: discord.Guild):
# Only guild-mode needs per-server registration; global mode must not
# copy commands into the guild or Discord shows duplicates (/afk twice).
if IS_SHARD_PRIMARY:
try:
from utils.slash_sync import _sync_mode, sync_guild
if _sync_mode() == "guild":
synced = await sync_guild(client, guild, copy_global=True)
print(f"◈ Slash sync for new guild {guild.id}: {len(synced)} command(s)")
except Exception as e:
print(f"Slash sync on guild join failed: {e}")
if not LOG_CHANNEL_ID: if not LOG_CHANNEL_ID:
return return
log_channel = client.get_channel(LOG_CHANNEL_ID) log_channel = client.get_channel(LOG_CHANNEL_ID)
@@ -322,6 +360,9 @@ def run_api():
uvicorn.run(fastapi_app, host=API_HOST, port=API_PORT, log_level="warning") uvicorn.run(fastapi_app, host=API_HOST, port=API_PORT, log_level="warning")
def keep_alive(): def keep_alive():
if not IS_SHARD_PRIMARY:
print(f"\033[33m◈ API Server: Skipped (non-primary shard process)\033[0m")
return
if not API_ENABLED: if not API_ENABLED:
print(f"\033[33m◈ API Server: Disabled via API_ENABLED=false\033[0m") print(f"\033[33m◈ API Server: Disabled via API_ENABLED=false\033[0m")
return return
@@ -335,7 +376,10 @@ keep_alive()
# --- Cloudflare Tunnel (HTTPS for API) — only when explicitly enabled --- # --- Cloudflare Tunnel (HTTPS for API) — only when explicitly enabled ---
from utils.tunnel import start_tunnel from utils.tunnel import start_tunnel
start_tunnel() if IS_SHARD_PRIMARY:
start_tunnel()
else:
print("\033[33m◈ Cloudflare Tunnel: Skipped (non-primary shard process)\033[0m")
# --- Main Bot Execution --- # --- Main Bot Execution ---
async def main(): async def main():

29
bot/Dockerfile Normal file
View File

@@ -0,0 +1,29 @@
# Axiom Discord Bot + FastAPI dashboard backend (by HexaHost)
FROM python:3.12-slim-bookworm
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1
WORKDIR /app
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
libffi-dev \
libjpeg62-turbo-dev \
zlib1g-dev \
libsodium-dev \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
# Persist SQLite / JSON data outside the image
RUN mkdir -p /app/db /app/jsondb /app/logs
EXPOSE 8000
CMD ["python", "Axiom.py"]

View File

@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2026 CodeX Devs Copyright (c) 2026 HexaHost
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,15 +1,13 @@
<div align="center"> <div align="center">
``` ```
███████╗██╗ ██╗██████╗ ██████╗ ██╗ ██╗ +-+-+-+-+-+
╚══███╔╝╚██╗ ██╔╝██╔══██╗██╔═══██╗╚██╗██╔╝ |A|x|i|o|m|
███╔╝ ╚████╔╝ ██████╔╝██║ ██║ ╚███╔╝ +-+-+-+-+-+
███╔╝ ╚██╔╝ ██╔══██╗██║ ██║ ██╔██╗ by HexaHost
███████╗ ██║ ██║ ██║╚██████╔╝██╔╝ ██╗
╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝
``` ```
<h3>ZyroX Bot — Python Discord Bot + FastAPI Backend</h3> <h3>Axiom Bot — Python Discord Bot + FastAPI Backend</h3>
<a href="https://nexiohost.in"><img src="https://img.shields.io/badge/⭐%20PREMIUM%20HOSTING-NexioHost-FFD700?style=for-the-badge&labelColor=1a1a2e&color=FFD700&logoColor=FFD700"/></a> <a href="https://nexiohost.in"><img src="https://img.shields.io/badge/⭐%20PREMIUM%20HOSTING-NexioHost-FFD700?style=for-the-badge&labelColor=1a1a2e&color=FFD700&logoColor=FFD700"/></a>
@@ -20,9 +18,8 @@
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-red?style=for-the-badge"/></a> <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-red?style=for-the-badge"/></a>
</p> </p>
<p> <p>
<a href="https://discord.gg/codexdev"><img src="https://img.shields.io/badge/Discord-Join_Server-5865F2?style=for-the-badge&logo=discord&logoColor=white"/></a> <a href="https://discord.gg/hexahost"><img src="https://img.shields.io/badge/Discord-Join_Server-5865F2?style=for-the-badge&logo=discord&logoColor=white"/></a>
<a href="https://youtube.com/@CodeXDevs"><img src="https://img.shields.io/badge/YouTube-CodeXDevs-FF0000?style=for-the-badge&logo=youtube&logoColor=white"/></a> <a href="https://github.com/theoneandonlymace"><img src="https://img.shields.io/badge/GitHub-theoneandonlymace-181717?style=for-the-badge&logo=github&logoColor=white"/></a>
<a href="https://github.com/RayExo"><img src="https://img.shields.io/badge/GitHub-RayExo-181717?style=for-the-badge&logo=github&logoColor=white"/></a>
</p> </p>
</div> </div>
@@ -31,7 +28,7 @@
## ✦ Overview ## ✦ Overview
This folder contains the ZyroX Discord bot built on `discord.py v2` alongside a `FastAPI` backend that powers the web dashboard. Everything runs from a single `python CodeX.py` command. This folder contains the Axiom Discord bot built on `discord.py v2` alongside a `FastAPI` backend that powers the web dashboard. Everything runs from a single `python Axiom.py` command.
``` ```
bot/ bot/
@@ -43,12 +40,12 @@ bot/
│ ├── commands/ All slash & prefix command modules │ ├── commands/ All slash & prefix command modules
│ ├── events/ General Discord event listeners │ ├── events/ General Discord event listeners
│ ├── moderation/ Moderation action modules │ ├── moderation/ Moderation action modules
│ └── zyrox/ Core ZyroX feature cogs │ └── axiom/ Help / feature index cogs
├── core/ Bot client, context, cog base classes ├── core/ Bot client, context, cog base classes
├── games/ Standalone game logic + button views ├── games/ Standalone game logic + button views
├── utils/ Emoji, tools, sync, Cloudflare tunnel ├── utils/ Emoji, tools, sync, Cloudflare tunnel
├── assets/ Fonts, backgrounds, GIFs ├── assets/ Fonts, backgrounds, GIFs
└── CodeX.py Entry point └── Axiom.py Entry point
``` ```
--- ---
@@ -136,7 +133,7 @@ bot/
- Slash + prefix commands - Slash + prefix commands
- Cloudflare Tunnel via pycloudflared — zero system installs, unlimited traffic - Cloudflare Tunnel via pycloudflared — zero system installs, unlimited traffic
- Single `OWNER_IDS` env var controls all permission checks - Single `OWNER_IDS` env var controls all permission checks
- CodeX Devs watermark on every source file - HexaHost manufacturer watermark on every source file
</td> </td>
</tr> </tr>
@@ -178,7 +175,7 @@ Create a `.env` file (copy from `.env.example`):
```env ```env
# ── Core ────────────────────────────────────────────────────────── # ── Core ──────────────────────────────────────────────────────────
TOKEN = your_discord_bot_token TOKEN = your_discord_bot_token
brand_name = 'ZyroX' brand_name = 'Axiom'
# ── Owner IDs (REQUIRED — your Discord user ID) ─────────────────── # ── Owner IDs (REQUIRED — your Discord user ID) ───────────────────
OWNER_IDS = YOUR_DISCORD_USER_ID_HERE OWNER_IDS = YOUR_DISCORD_USER_ID_HERE
@@ -212,7 +209,7 @@ CF_TUNNEL_URL = "https://api.yourdomain.com"
### 3 — Run ### 3 — Run
```bash ```bash
python CodeX.py python Axiom.py
``` ```
--- ---
@@ -262,7 +259,7 @@ Uses **pycloudflared** — downloads the `cloudflared` binary automatically on f
**Setup (browser only — no CLI needed):** **Setup (browser only — no CLI needed):**
1. Go to [one.dash.cloudflare.com](https://one.dash.cloudflare.com) → **Networks → Tunnels → Create a tunnel** 1. Go to [one.dash.cloudflare.com](https://one.dash.cloudflare.com) → **Networks → Tunnels → Create a tunnel**
2. Choose **Cloudflared**, name it (e.g. `zyrox-api`), save 2. Choose **Cloudflared**, name it (e.g. `axiom-api`), save
3. On **Install connector**, copy the token from the command shown: 3. On **Install connector**, copy the token from the command shown:
``` ```
cloudflared tunnel run --token <COPY_THIS_TOKEN> cloudflared tunnel run --token <COPY_THIS_TOKEN>
@@ -304,7 +301,7 @@ When `EMOJI_SYNC=true`, the bot syncs application emojis on every startup:
Upload the entire `bot/` folder to your host and set the start command to: Upload the entire `bot/` folder to your host and set the start command to:
```bash ```bash
python CodeX.py python Axiom.py
``` ```
`pycloudflared` downloads the binary on first run — no extra steps on any host. `pycloudflared` downloads the binary on first run — no extra steps on any host.
@@ -331,19 +328,18 @@ python CodeX.py
<div align="center"> <div align="center">
## ✦ CodeX Devs ## ✦ HexaHost
*Built for protection. Designed for style.* *Built for protection. Designed for style.*
<a href="https://discord.gg/codexdev"><img src="https://discord.com/api/guilds/1301573144817045524/widget.png?style=banner2" alt="CodeX Development Discord Server" width="480"/></a> <a href="https://discord.gg/hexahost"><img src="https://discord.com/api/guilds/1301573144817045524/widget.png?style=banner2" alt="HexaHost Discord Server" width="480"/></a>
<p> <p>
<a href="https://discord.gg/codexdev"><img src="https://img.shields.io/badge/Discord-Join_Server-5865F2?style=for-the-badge&logo=discord&logoColor=white"/></a> <a href="https://discord.gg/hexahost"><img src="https://img.shields.io/badge/Discord-Join_Server-5865F2?style=for-the-badge&logo=discord&logoColor=white"/></a>
<a href="https://youtube.com/@CodeXDevs"><img src="https://img.shields.io/badge/YouTube-CodeXDevs-FF0000?style=for-the-badge&logo=youtube&logoColor=white"/></a> <a href="https://github.com/theoneandonlymace"><img src="https://img.shields.io/badge/GitHub-theoneandonlymace-181717?style=for-the-badge&logo=github&logoColor=white"/></a>
<a href="https://github.com/RayExo"><img src="https://img.shields.io/badge/GitHub-RayExo-181717?style=for-the-badge&logo=github&logoColor=white"/></a>
<a href="https://nexiohost.in"><img src="https://img.shields.io/badge/⭐%20PREMIUM%20HOSTING-NexioHost-FFD700?style=for-the-badge&labelColor=1a1a2e&color=FFD700&logoColor=FFD700"/></a> <a href="https://nexiohost.in"><img src="https://img.shields.io/badge/⭐%20PREMIUM%20HOSTING-NexioHost-FFD700?style=for-the-badge&labelColor=1a1a2e&color=FFD700&logoColor=FFD700"/></a>
</p> </p>
© 2026 CodeX Devs — MIT License © 2026 HexaHost — MIT License
</div> </div>

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
@@ -16,6 +15,8 @@ import aiosqlite
import asyncio import asyncio
from typing import Dict from typing import Dict
from utils.db_paths import resolve_db_path
class DatabaseManager: class DatabaseManager:
""" """
A simple manager for persistent SQLite connections to avoid A simple manager for persistent SQLite connections to avoid
@@ -29,6 +30,7 @@ class DatabaseManager:
""" """
Retrieves an existing connection or creates a new one for the given path. Retrieves an existing connection or creates a new one for the given path.
""" """
db_path = resolve_db_path(db_path)
async with self._lock: async with self._lock:
if db_path not in self._connections: if db_path not in self._connections:
# We use check_same_thread=False because aiosqlite handles # We use check_same_thread=False because aiosqlite handles

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
@@ -21,13 +20,13 @@ from slowapi import Limiter
from slowapi.util import get_remote_address from slowapi.util import get_remote_address
if TYPE_CHECKING: if TYPE_CHECKING:
from core.zyrox import zyrox from core.axiom import Axiom
# Initialize rate limiter # Initialize rate limiter
limiter = Limiter(key_func=get_remote_address, default_limits=["1000 per minute"]) limiter = Limiter(key_func=get_remote_address, default_limits=["1000 per minute"])
# Global reference to the bot instance # Global reference to the bot instance
_bot_instance: Optional["zyrox"] = None _bot_instance: Optional["Axiom"] = None
# Security scheme # Security scheme
security = HTTPBearer() security = HTTPBearer()
@@ -54,18 +53,18 @@ def verify_api_key(credentials: HTTPAuthorizationCredentials = Security(security
) )
return credentials.credentials return credentials.credentials
def set_bot(bot_instance: "zyrox"): def set_bot(bot_instance: "Axiom"):
""" """
Sets the global bot instance. Sets the global bot instance.
This should be called in CodeX.py during startup. This should be called in Axiom.py during startup.
""" """
global _bot_instance global _bot_instance
_bot_instance = bot_instance _bot_instance = bot_instance
def get_bot() -> "zyrox": def get_bot() -> "Axiom":
""" """
FastAPI dependency to retrieve the Discord bot instance. FastAPI dependency to retrieve the Discord bot instance.
Usage: bot: zyrox = Depends(get_bot) Usage: bot: Axiom = Depends(get_bot)
""" """
if _bot_instance is None: if _bot_instance is None:
raise HTTPException( raise HTTPException(

View File

@@ -1,10 +1,21 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ Discord OAuth permission checks for dashboard API requests # ║
# ║ +-+-+-+-+-+-+-+-+ ║
# ║ |H|e|x|a|H|o|s|t| ║
# ║ +-+-+-+-+-+-+-+-+ ║
# ║ ║
# ║ © 2026 HexaHost — All Rights Reserved ║
# ║ ║
# ║ discord ── https://discord.gg/hexahost ║
# ║ github ── https://github.com/theoneandonlymace ║
# ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from __future__ import annotations from __future__ import annotations
import asyncio
import re import re
import time
from typing import Any from typing import Any
import aiohttp import aiohttp
@@ -17,6 +28,17 @@ ADMINISTRATOR = 0x8
GUILD_PATH_RE = re.compile(r"^/api/v1/guilds/(\d+)(?:/|$)") GUILD_PATH_RE = re.compile(r"^/api/v1/guilds/(\d+)(?:/|$)")
# Short-lived process caches — cut Discord 429s from dashboard reloads
_USER_CACHE_TTL = 60.0
_GUILDS_CACHE_TTL = 60.0
_user_cache: dict[str, tuple[float, dict[str, Any]]] = {}
_guilds_cache: dict[str, tuple[float, list[dict[str, Any]]]] = {}
_guilds_inflight: dict[str, asyncio.Future[list[dict[str, Any]]]] = {}
def _token_key(access_token: str) -> str:
return f"{access_token[:12]}:{len(access_token)}:{access_token[-8:]}"
def _parse_admin_ids() -> list[str]: def _parse_admin_ids() -> list[str]:
import os import os
@@ -37,33 +59,92 @@ def can_manage_guild(guild: dict[str, Any]) -> bool:
return bool(perms & ADMINISTRATOR) or bool(perms & MANAGE_GUILD) return bool(perms & ADMINISTRATOR) or bool(perms & MANAGE_GUILD)
def _discord_auth_error(status: int) -> HTTPException:
if status == 429:
return HTTPException(
status_code=429,
detail="Discord rate limit — please wait a few seconds and retry.",
)
if status in (401, 403):
return HTTPException(
status_code=401,
detail="Invalid or expired Discord access token. Please sign out and sign in again.",
)
return HTTPException(
status_code=403,
detail=f"Discord API error ({status}).",
)
async def fetch_user_guilds(access_token: str) -> list[dict[str, Any]]: async def fetch_user_guilds(access_token: str) -> list[dict[str, Any]]:
key = _token_key(access_token)
cached = _guilds_cache.get(key)
if cached and cached[0] > time.monotonic():
return cached[1]
existing = _guilds_inflight.get(key)
if existing is not None:
return await existing
loop = asyncio.get_running_loop()
fut: asyncio.Future[list[dict[str, Any]]] = loop.create_future()
_guilds_inflight[key] = fut
try:
guilds = await _fetch_user_guilds_uncached(access_token)
_guilds_cache[key] = (time.monotonic() + _GUILDS_CACHE_TTL, guilds)
fut.set_result(guilds)
return guilds
except Exception as exc:
fut.set_exception(exc)
raise
finally:
_guilds_inflight.pop(key, None)
async def _fetch_user_guilds_uncached(access_token: str) -> list[dict[str, Any]]:
max_attempts = 3
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
for attempt in range(1, max_attempts + 1):
async with session.get( async with session.get(
"https://discord.com/api/users/@me/guilds", "https://discord.com/api/users/@me/guilds",
headers={"Authorization": f"Bearer {access_token}"}, headers={"Authorization": f"Bearer {access_token}"},
) as resp: ) as resp:
if resp.status != 200: if resp.status == 200:
raise HTTPException(
status_code=403,
detail="Invalid or expired Discord access token.",
)
data = await resp.json() data = await resp.json()
return data if isinstance(data, list) else [] return data if isinstance(data, list) else []
if resp.status == 429 and attempt < max_attempts:
retry_after = 1.0
try:
body = await resp.json()
retry_after = float(body.get("retry_after", 1))
except Exception:
retry_after = float(resp.headers.get("Retry-After", "1") or 1)
await asyncio.sleep(min(max(retry_after, 0.3), 5.0))
continue
raise _discord_auth_error(resp.status)
raise _discord_auth_error(429)
async def verify_discord_token(access_token: str) -> dict[str, Any]: async def verify_discord_token(access_token: str) -> dict[str, Any]:
key = _token_key(access_token)
cached = _user_cache.get(key)
if cached and cached[0] > time.monotonic():
return cached[1]
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.get( async with session.get(
"https://discord.com/api/users/@me", "https://discord.com/api/users/@me",
headers={"Authorization": f"Bearer {access_token}"}, headers={"Authorization": f"Bearer {access_token}"},
) as resp: ) as resp:
if resp.status != 200: if resp.status != 200:
raise HTTPException( raise _discord_auth_error(resp.status)
status_code=403, user = await resp.json()
detail="Invalid or expired Discord access token.", _user_cache[key] = (time.monotonic() + _USER_CACHE_TTL, user)
) return user
return await resp.json()
async def user_can_manage_guild(access_token: str, guild_id: int) -> bool: async def user_can_manage_guild(access_token: str, guild_id: int) -> bool:

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
from fastapi import APIRouter, Depends, HTTPException from fastapi import APIRouter, Depends, HTTPException
from api.dependencies import get_bot from api.dependencies import get_bot
@@ -20,11 +20,11 @@ import os
import aiosqlite import aiosqlite
if TYPE_CHECKING: if TYPE_CHECKING:
from core.zyrox import zyrox from core.axiom import Axiom
router = APIRouter() router = APIRouter()
CONFIG_DB = "db/admin_config.db" CONFIG_DB = db_path("admin_config.db")
async def init_db(): async def init_db():
async with aiosqlite.connect(CONFIG_DB) as db: async with aiosqlite.connect(CONFIG_DB) as db:
@@ -38,7 +38,7 @@ import psutil
import time import time
@router.get("/stats", response_model=AdminStats) @router.get("/stats", response_model=AdminStats)
async def get_admin_stats(bot: "zyrox" = Depends(get_bot)): async def get_admin_stats(bot: "Axiom" = Depends(get_bot)):
# Calculate DB size and shard info # Calculate DB size and shard info
total_size: float = 0.0 total_size: float = 0.0
db_count = 0 db_count = 0
@@ -87,7 +87,16 @@ async def get_admin_stats(bot: "zyrox" = Depends(get_bot)):
AdminNodeStatus( AdminNodeStatus(
name="Auth Sockets", name="Auth Sockets",
status="Healthy", status="Healthy",
load=f"Shard: {bot.shard_count} | Latency: {round(bot.latency * 1000)}ms", load=(
f"Shards: {bot.shard_count or 1} | "
f"Latency: {round(bot.latency * 1000)}ms"
+ (
" | "
+ ", ".join(f"s{sid}:{round(lat * 1000)}ms" for sid, lat in bot.latencies)
if bot.latencies and len(bot.latencies) > 1
else ""
)
),
icon="Lock" icon="Lock"
) )
] ]

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
@@ -20,26 +19,33 @@ from utils.config import *
if TYPE_CHECKING: if TYPE_CHECKING:
from core.zyrox import zyrox from core.axiom import Axiom
router = APIRouter() router = APIRouter()
@router.get("/status", response_model=BotStatus, summary="Get bot status", description="Returns real-time health metrics, latency, and scale information.") @router.get("/status", response_model=BotStatus, summary="Get bot status", description="Returns real-time health metrics, latency, and scale information.")
async def get_status(bot: "zyrox" = Depends(get_bot)): async def get_status(bot: "Axiom" = Depends(get_bot)):
""" """
Returns the live status of the bot. Returns the live status of the bot.
""" """
shard_ids = list(bot.shards.keys()) if bot.shards else ([0] if bot.shard_count else [])
shard_latencies = [
{"id": sid, "latency_ms": round(lat * 1000, 2)}
for sid, lat in (bot.latencies or [])
]
return BotStatus( return BotStatus(
user=str(bot.user), user=str(bot.user),
id=str(bot.user.id) if bot.user else None, id=str(bot.user.id) if bot.user else None,
latency=bot.latency * 1000, latency=bot.latency * 1000,
guild_count=len(bot.guilds), guild_count=len(bot.guilds),
user_count=sum(g.member_count or 0 for g in bot.guilds), user_count=sum(g.member_count or 0 for g in bot.guilds),
shards=bot.shard_count shards=bot.shard_count,
shard_ids=shard_ids,
shard_latencies=shard_latencies,
) )
@router.get("/info", response_model=BotInfo, summary="Get bot info", description="Returns general information about the bot including command count and user reach.") @router.get("/info", response_model=BotInfo, summary="Get bot info", description="Returns general information about the bot including command count and user reach.")
async def get_bot_info(bot: "zyrox" = Depends(get_bot)): async def get_bot_info(bot: "Axiom" = Depends(get_bot)):
""" """
Get general information about the Discord bot. Get general information about the Discord bot.
""" """

View File

@@ -1,23 +1,23 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path, jsondb_path
from fastapi import APIRouter, Depends, HTTPException, Request from fastapi import APIRouter, Depends, HTTPException, Request
from api.dependencies import get_bot, limiter from api.dependencies import get_bot, limiter
from api.discord_auth import require_discord_session, get_manageable_guild_ids from api.discord_auth import get_manageable_guild_ids, get_discord_headers
from api.db_manager import db_manager from api.db_manager import db_manager
from api.schemas import ( from api.schemas import (
GuildSummary, GuildDetails, PrefixConfig, AutomodConfig, GuildSummary, GuildDetails, PrefixConfig, AutomodConfig, AutomodEventConfig,
TicketConfig, LevelingConfig, LoggingConfig, TicketEmbed, TicketConfig, LevelingConfig, LoggingConfig, TicketEmbed,
TicketCategory, LevelingEmbedStyle, PrefixUpdate, TicketCategory, LevelingEmbedStyle, PrefixUpdate,
AutomodUpdate, LevelingUpdate, LoggingUpdate, TicketUpdate, AutomodUpdate, LevelingUpdate, LoggingUpdate, TicketUpdate,
@@ -30,24 +30,39 @@ from api.schemas import (
RRConfig, RRUpdate, ReactionRoleEntry, RRConfig, RRUpdate, ReactionRoleEntry,
InviteStat, InvitesLeaderboard InviteStat, InvitesLeaderboard
) )
from utils.automod_settings import (
EVENT_ID_TO_DB,
THRESHOLD_META,
MAX_IGNORED,
NSFW_KEYWORDS,
normalize_event_id,
normalize_punishment,
ensure_thresholds_table,
get_all_thresholds,
set_thresholds,
)
from typing import TYPE_CHECKING, List, Optional from typing import TYPE_CHECKING, List, Optional
import math import math
import aiosqlite import aiosqlite
import json import json
import os import os
import discord
if TYPE_CHECKING: if TYPE_CHECKING:
from core.zyrox import zyrox from core.axiom import Axiom
router = APIRouter() router = APIRouter()
@router.get("/", response_model=List[GuildSummary], summary="List all guilds", description="Returns guilds the authenticated user can manage that the bot is in.") @router.get("/", response_model=List[GuildSummary], summary="List all guilds", description="Returns guilds the authenticated user can manage that the bot is in.")
async def list_guilds(request: Request, bot: "zyrox" = Depends(get_bot)): async def list_guilds(request: Request, bot: "Axiom" = Depends(get_bot)):
""" """
Lists guilds the bot is in, filtered to those the caller can manage on Discord. Lists guilds the bot is in, filtered to those the caller can manage on Discord.
Session is already verified by middleware — only fetch manageable guild IDs here.
""" """
token, _ = await require_discord_session(request) token, _ = get_discord_headers(request)
if not token:
raise HTTPException(status_code=403, detail="X-Discord-Access-Token header is required.")
manageable_ids = await get_manageable_guild_ids(token) manageable_ids = await get_manageable_guild_ids(token)
guilds_list = [] guilds_list = []
@@ -64,7 +79,7 @@ async def list_guilds(request: Request, bot: "zyrox" = Depends(get_bot)):
return guilds_list return guilds_list
@router.get("/{guild_id}", response_model=GuildDetails, summary="Get guild details", description="Returns detailed metrics and metadata for a specific Discord guild.") @router.get("/{guild_id}", response_model=GuildDetails, summary="Get guild details", description="Returns detailed metrics and metadata for a specific Discord guild.")
async def get_guild_details(guild_id: int, bot: "zyrox" = Depends(get_bot)): async def get_guild_details(guild_id: int, bot: "Axiom" = Depends(get_bot)):
""" """
Returns detailed info for a specific guild by its ID. Returns detailed info for a specific guild by its ID.
""" """
@@ -87,7 +102,7 @@ async def get_guild_prefix(guild_id: int):
""" """
Retrieves the custom prefix for a specific guild. Retrieves the custom prefix for a specific guild.
""" """
db = await db_manager.get_connection('db/prefix.db') db = await db_manager.get_connection(db_path('prefix.db'))
cursor = await db.execute("SELECT prefix FROM prefixes WHERE guild_id = ?", (guild_id,)) cursor = await db.execute("SELECT prefix FROM prefixes WHERE guild_id = ?", (guild_id,))
row = await cursor.fetchone() row = await cursor.fetchone()
prefix = row[0] if row else ">" prefix = row[0] if row else ">"
@@ -101,7 +116,7 @@ async def update_guild_prefix(guild_id: int, data: PrefixUpdate):
if not data.prefix or len(data.prefix) > 10: if not data.prefix or len(data.prefix) > 10:
raise HTTPException(status_code=400, detail="Invalid prefix. Must be 1-10 characters.") raise HTTPException(status_code=400, detail="Invalid prefix. Must be 1-10 characters.")
db = await db_manager.get_connection('db/prefix.db') db = await db_manager.get_connection(db_path('prefix.db'))
await db.execute( await db.execute(
"INSERT OR REPLACE INTO prefixes (guild_id, prefix) VALUES (?, ?)", "INSERT OR REPLACE INTO prefixes (guild_id, prefix) VALUES (?, ?)",
(guild_id, data.prefix) (guild_id, data.prefix)
@@ -117,79 +132,265 @@ async def get_guild_automod(guild_id: int):
""" """
Retrieves the AutoMod configuration for a specific guild. Retrieves the AutoMod configuration for a specific guild.
""" """
db = await db_manager.get_connection('db/automod.db') db = await db_manager.get_connection(db_path('automod.db'))
# Check enabled status await ensure_thresholds_table(db)
cursor = await db.execute("SELECT enabled FROM automod WHERE guild_id = ?", (guild_id,)) cursor = await db.execute("SELECT enabled FROM automod WHERE guild_id = ?", (guild_id,))
enabled_row = await cursor.fetchone() enabled_row = await cursor.fetchone()
enabled = bool(enabled_row[0]) if enabled_row else False enabled = bool(enabled_row[0]) if enabled_row else False
# Get punishments cursor = await db.execute(
cursor = await db.execute("SELECT event, punishment FROM automod_punishments WHERE guild_id = ?", (guild_id,)) "SELECT event, punishment FROM automod_punishments WHERE guild_id = ?",
punishments = {row[0]: row[1] for row in await cursor.fetchall()} (guild_id,),
)
raw_punishments = {row[0]: row[1] for row in await cursor.fetchall()}
# Get ignored items events: dict[str, AutomodEventConfig] = {}
cursor = await db.execute("SELECT type, id FROM automod_ignored WHERE guild_id = ?", (guild_id,)) punishments_out: dict[str, str] = {}
for event_id, db_name in EVENT_ID_TO_DB.items():
present = db_name in raw_punishments
pun = raw_punishments.get(db_name)
if event_id == "anti_nsfw_link":
events[event_id] = AutomodEventConfig(
enabled=present,
punishment="block_message",
readonly_punishment=True,
)
if present:
punishments_out[event_id] = "block_message"
else:
norm = normalize_punishment(pun) if present else None
events[event_id] = AutomodEventConfig(
enabled=present,
punishment=norm or ("Mute" if present else None),
readonly_punishment=False,
)
if present and norm:
punishments_out[event_id] = norm
cursor = await db.execute(
"SELECT type, id FROM automod_ignored WHERE guild_id = ?", (guild_id,)
)
ignored_items = await cursor.fetchall() ignored_items = await cursor.fetchall()
ignored_roles = [row[1] for row in ignored_items if row[0] == 'role'] ignored_roles = [row[1] for row in ignored_items if row[0] == "role"]
ignored_channels = [row[1] for row in ignored_items if row[0] == 'channel'] ignored_channels = [row[1] for row in ignored_items if row[0] == "channel"]
# Get logging channel cursor = await db.execute(
cursor = await db.execute("SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild_id,)) "SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild_id,)
)
logging_row = await cursor.fetchone() logging_row = await cursor.fetchone()
logging_channel = logging_row[0] if logging_row else None logging_channel = logging_row[0] if logging_row else None
thresholds = await get_all_thresholds(guild_id)
return AutomodConfig( return AutomodConfig(
guild_id=guild_id, guild_id=guild_id,
enabled=enabled, enabled=enabled,
punishments=punishments, punishments=punishments_out,
events=events,
thresholds=thresholds,
threshold_meta=THRESHOLD_META,
ignored_roles=ignored_roles, ignored_roles=ignored_roles,
ignored_channels=ignored_channels, ignored_channels=ignored_channels,
logging_channel=logging_channel logging_channel=logging_channel,
limits={"max_ignored_roles": MAX_IGNORED, "max_ignored_channels": MAX_IGNORED},
) )
async def _sync_nsfw_rule(
bot: "Axiom",
guild_id: int,
*,
enabled: bool,
ignored_roles: list[int],
ignored_channels: list[int],
) -> None:
guild = bot.get_guild(guild_id)
if not guild:
return
existing = None
try:
rules = await guild.fetch_automod_rules()
existing = next((r for r in rules if r.name == "Anti NSFW Links"), None)
except (discord.Forbidden, discord.HTTPException):
return
if not enabled:
if existing:
try:
await existing.delete(reason="Automod NSFW disabled via dashboard")
except (discord.Forbidden, discord.HTTPException):
pass
return
exempt_roles = [discord.Object(i) for i in ignored_roles[:MAX_IGNORED]]
exempt_channels = [discord.Object(i) for i in ignored_channels[:MAX_IGNORED]]
try:
if existing:
await existing.edit(
exempt_roles=exempt_roles,
exempt_channels=exempt_channels,
enabled=True,
reason="Automod NSFW updated via dashboard",
)
else:
await guild.create_automod_rule(
name="Anti NSFW Links",
event_type=discord.AutoModRuleEventType.message_send,
trigger=discord.AutoModTrigger(
type=discord.AutoModRuleTriggerType.keyword,
keyword_filter=NSFW_KEYWORDS,
),
actions=[
discord.AutoModRuleAction(type=discord.AutoModRuleActionType.block_message),
],
enabled=True,
exempt_roles=exempt_roles,
exempt_channels=exempt_channels,
reason="Automod NSFW enabled via dashboard",
)
except (discord.Forbidden, discord.HTTPException) as e:
print(f"Automod NSFW sync error for guild {guild_id}: {e}")
@router.patch("/{guild_id}/automod", summary="Update AutoMod config", description="Partially updates the AutoMod configuration components.") @router.patch("/{guild_id}/automod", summary="Update AutoMod config", description="Partially updates the AutoMod configuration components.")
async def patch_guild_automod(guild_id: int, data: AutomodUpdate): async def patch_guild_automod(
guild_id: int,
data: AutomodUpdate,
bot: "Axiom" = Depends(get_bot),
):
""" """
Updates parts of the AutoMod configuration for a specific guild. Updates parts of the AutoMod configuration for a specific guild.
""" """
db = await db_manager.get_connection('db/automod.db') db = await db_manager.get_connection(db_path('automod.db'))
await ensure_thresholds_table(db)
if data.enabled is not None: if data.enabled is not None:
await db.execute( await db.execute(
"INSERT OR REPLACE INTO automod (guild_id, enabled) VALUES (?, ?)", "INSERT OR REPLACE INTO automod (guild_id, enabled) VALUES (?, ?)",
(guild_id, 1 if data.enabled else 0) (guild_id, 1 if data.enabled else 0),
) )
if data.punishments is not None: # Build canonical enabled events from events{} and/or legacy punishments{}
for event, punishment in data.punishments.items(): events_payload = data.events
if events_payload is None and data.punishments is not None:
events_payload = {}
for raw_key, raw_pun in data.punishments.items():
eid = normalize_event_id(raw_key)
if not eid:
continue
if eid == "anti_nsfw_link":
events_payload[eid] = AutomodEventConfig(
enabled=True, punishment="block_message", readonly_punishment=True
)
else:
pun = normalize_punishment(raw_pun) or "Mute"
events_payload[eid] = AutomodEventConfig(enabled=True, punishment=pun)
nsfw_enabled: bool | None = None
if events_payload is not None:
await db.execute( await db.execute(
"INSERT OR REPLACE INTO automod_punishments (guild_id, event, punishment) VALUES (?, ?, ?)", "DELETE FROM automod_punishments WHERE guild_id = ?", (guild_id,)
(guild_id, event, punishment)
) )
for raw_id, cfg in events_payload.items():
eid = normalize_event_id(raw_id)
if not eid or not cfg.enabled:
if eid == "anti_nsfw_link":
nsfw_enabled = False
continue
db_name = EVENT_ID_TO_DB[eid]
if eid == "anti_nsfw_link":
await db.execute(
"INSERT INTO automod_punishments (guild_id, event, punishment) VALUES (?, ?, ?)",
(guild_id, db_name, "Block message"),
)
nsfw_enabled = True
else:
pun = normalize_punishment(cfg.punishment) or "Mute"
await db.execute(
"INSERT INTO automod_punishments (guild_id, event, punishment) VALUES (?, ?, ?)",
(guild_id, db_name, pun),
)
# Full-replace: omitted/disabled NSFW must drop the Discord rule
if nsfw_enabled is None:
nsfw_enabled = False
if data.ignored_roles is not None: if data.thresholds is not None:
await db.execute("DELETE FROM automod_ignored WHERE guild_id = ? AND type = 'role'", (guild_id,)) await set_thresholds(db, guild_id, data.thresholds)
for role_id in data.ignored_roles:
ignored_roles = data.ignored_roles
ignored_channels = data.ignored_channels
if ignored_roles is not None:
ignored_roles = list(dict.fromkeys(ignored_roles))[:MAX_IGNORED]
await db.execute(
"DELETE FROM automod_ignored WHERE guild_id = ? AND type = 'role'",
(guild_id,),
)
for role_id in ignored_roles:
await db.execute( await db.execute(
"INSERT OR REPLACE INTO automod_ignored (guild_id, type, id) VALUES (?, 'role', ?)", "INSERT OR REPLACE INTO automod_ignored (guild_id, type, id) VALUES (?, 'role', ?)",
(guild_id, role_id) (guild_id, role_id),
) )
if data.ignored_channels is not None: if ignored_channels is not None:
await db.execute("DELETE FROM automod_ignored WHERE guild_id = ? AND type = 'channel'", (guild_id,)) ignored_channels = list(dict.fromkeys(ignored_channels))[:MAX_IGNORED]
for channel_id in data.ignored_channels: await db.execute(
"DELETE FROM automod_ignored WHERE guild_id = ? AND type = 'channel'",
(guild_id,),
)
for channel_id in ignored_channels:
await db.execute( await db.execute(
"INSERT OR REPLACE INTO automod_ignored (guild_id, type, id) VALUES (?, 'channel', ?)", "INSERT OR REPLACE INTO automod_ignored (guild_id, type, id) VALUES (?, 'channel', ?)",
(guild_id, channel_id) (guild_id, channel_id),
) )
if data.logging_channel is not None: if data.clear_logging:
await db.execute(
"DELETE FROM automod_logging WHERE guild_id = ?", (guild_id,)
)
elif data.logging_channel is not None:
if data.logging_channel == 0:
await db.execute(
"DELETE FROM automod_logging WHERE guild_id = ?", (guild_id,)
)
else:
await db.execute( await db.execute(
"INSERT OR REPLACE INTO automod_logging (guild_id, log_channel) VALUES (?, ?)", "INSERT OR REPLACE INTO automod_logging (guild_id, log_channel) VALUES (?, ?)",
(guild_id, data.logging_channel) (guild_id, data.logging_channel),
) )
await db.commit() await db.commit()
# Resolve current ignore lists for NSFW sync if not in this payload
if ignored_roles is None or ignored_channels is None:
cursor = await db.execute(
"SELECT type, id FROM automod_ignored WHERE guild_id = ?", (guild_id,)
)
items = await cursor.fetchall()
if ignored_roles is None:
ignored_roles = [r[1] for r in items if r[0] == "role"]
if ignored_channels is None:
ignored_channels = [r[1] for r in items if r[0] == "channel"]
if nsfw_enabled is None and (data.ignored_roles is not None or data.ignored_channels is not None):
# Keep Discord rule exempts in sync when ignores change
cursor = await db.execute(
"SELECT 1 FROM automod_punishments WHERE guild_id = ? AND event = ?",
(guild_id, EVENT_ID_TO_DB["anti_nsfw_link"]),
)
nsfw_enabled = bool(await cursor.fetchone())
if nsfw_enabled is not None:
await _sync_nsfw_rule(
bot,
guild_id,
enabled=nsfw_enabled,
ignored_roles=ignored_roles or [],
ignored_channels=ignored_channels or [],
)
return {"status": "success", "guild_id": guild_id} return {"status": "success", "guild_id": guild_id}
@router.get("/{guild_id}/tickets", response_model=TicketConfig, summary="Get Ticket config", description="Retrieves the support ticket system setup, categories, and staff roles.") @router.get("/{guild_id}/tickets", response_model=TicketConfig, summary="Get Ticket config", description="Retrieves the support ticket system setup, categories, and staff roles.")
@@ -197,7 +398,7 @@ async def get_guild_tickets(guild_id: int):
""" """
Retrieves the ticket system configuration for a specific guild. Retrieves the ticket system configuration for a specific guild.
""" """
db = await db_manager.get_connection('db/ticket.db') db = await db_manager.get_connection(db_path('ticket.db'))
# Get basic config # Get basic config
cursor = await db.execute( cursor = await db.execute(
@@ -263,7 +464,7 @@ async def patch_guild_tickets(guild_id: int, data: TicketUpdate):
""" """
Updates the ticket system configuration for a specific guild. Updates the ticket system configuration for a specific guild.
""" """
db = await db_manager.get_connection('db/ticket.db') db = await db_manager.get_connection(db_path('ticket.db'))
# Initialize config row if not exists # Initialize config row if not exists
cursor = await db.execute("SELECT guild_id FROM guild_configs WHERE guild_id = ?", (guild_id,)) cursor = await db.execute("SELECT guild_id FROM guild_configs WHERE guild_id = ?", (guild_id,))
@@ -322,7 +523,7 @@ async def get_guild_leveling(guild_id: int):
""" """
Retrieves the leveling system configuration for a specific guild. Retrieves the leveling system configuration for a specific guild.
""" """
db = await db_manager.get_connection('db/leveling.db') db = await db_manager.get_connection(db_path('leveling.db'))
cursor = await db.execute("SELECT * FROM leveling_settings WHERE guild_id = ?", (guild_id,)) cursor = await db.execute("SELECT * FROM leveling_settings WHERE guild_id = ?", (guild_id,))
row = await cursor.fetchone() row = await cursor.fetchone()
@@ -357,7 +558,7 @@ async def patch_guild_leveling(guild_id: int, data: LevelingUpdate):
""" """
Updates parts of the leveling configuration for a specific guild. Updates parts of the leveling configuration for a specific guild.
""" """
db = await db_manager.get_connection('db/leveling.db') db = await db_manager.get_connection(db_path('leveling.db'))
# We use a series of updates or a single dynamic update. # We use a series of updates or a single dynamic update.
# For simplicity and robustness with INSERT OR REPLACE: # For simplicity and robustness with INSERT OR REPLACE:
@@ -400,7 +601,7 @@ async def get_guild_welcome(guild_id: int):
import aiosqlite import aiosqlite
import json import json
async with aiosqlite.connect("db/welcome.db") as db: async with aiosqlite.connect(db_path("welcome.db")) as db:
async with db.execute("SELECT welcome_type, welcome_message, channel_id, embed_data, auto_delete_duration FROM welcome WHERE guild_id = ?", (guild_id,)) as cursor: async with db.execute("SELECT welcome_type, welcome_message, channel_id, embed_data, auto_delete_duration FROM welcome WHERE guild_id = ?", (guild_id,)) as cursor:
row = await cursor.fetchone() row = await cursor.fetchone()
@@ -432,7 +633,7 @@ async def patch_guild_welcome(guild_id: int, data: WelcomeUpdate):
import aiosqlite import aiosqlite
import json import json
async with aiosqlite.connect("db/welcome.db") as db: async with aiosqlite.connect(db_path("welcome.db")) as db:
# Get existing or create # Get existing or create
async with db.execute("SELECT welcome_type, welcome_message, channel_id, embed_data, auto_delete_duration FROM welcome WHERE guild_id = ?", (guild_id,)) as cursor: async with db.execute("SELECT welcome_type, welcome_message, channel_id, embed_data, auto_delete_duration FROM welcome WHERE guild_id = ?", (guild_id,)) as cursor:
row = await cursor.fetchone() row = await cursor.fetchone()
@@ -468,7 +669,7 @@ async def patch_guild_welcome(guild_id: int, data: WelcomeUpdate):
async def get_guild_antinuke(guild_id: int): async def get_guild_antinuke(guild_id: int):
import aiosqlite import aiosqlite
async with aiosqlite.connect("db/anti.db") as db: async with aiosqlite.connect(db_path("anti.db")) as db:
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild_id,)) as cursor: async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild_id,)) as cursor:
row = await cursor.fetchone() row = await cursor.fetchone()
@@ -490,7 +691,7 @@ async def get_guild_antinuke(guild_id: int):
async def patch_guild_antinuke(guild_id: int, data: AntiNukeUpdate): async def patch_guild_antinuke(guild_id: int, data: AntiNukeUpdate):
import aiosqlite import aiosqlite
async with aiosqlite.connect("db/anti.db") as db: async with aiosqlite.connect(db_path("anti.db")) as db:
if data.status is not None: if data.status is not None:
# Get existing or create # Get existing or create
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild_id,)) as cursor: async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild_id,)) as cursor:
@@ -538,7 +739,7 @@ async def patch_guild_antinuke(guild_id: int, data: AntiNukeUpdate):
async def get_guild_verification(guild_id: int): async def get_guild_verification(guild_id: int):
import aiosqlite import aiosqlite
async with aiosqlite.connect("db/verification.db") as db: async with aiosqlite.connect(db_path("verification.db")) as db:
async with db.execute("SELECT verification_channel_id, verified_role_id, log_channel_id, verification_method, enabled FROM verification_config WHERE guild_id = ?", (guild_id,)) as cursor: async with db.execute("SELECT verification_channel_id, verified_role_id, log_channel_id, verification_method, enabled FROM verification_config WHERE guild_id = ?", (guild_id,)) as cursor:
row = await cursor.fetchone() row = await cursor.fetchone()
@@ -564,7 +765,7 @@ async def get_guild_verification(guild_id: int):
async def patch_guild_verification(guild_id: int, data: VerificationUpdate): async def patch_guild_verification(guild_id: int, data: VerificationUpdate):
import aiosqlite import aiosqlite
async with aiosqlite.connect("db/verification.db") as db: async with aiosqlite.connect(db_path("verification.db")) as db:
async with db.execute("SELECT * FROM verification_config WHERE guild_id = ?", (guild_id,)) as cursor: async with db.execute("SELECT * FROM verification_config WHERE guild_id = ?", (guild_id,)) as cursor:
row = await cursor.fetchone() row = await cursor.fetchone()
@@ -589,7 +790,7 @@ async def get_guild_vanityroles(guild_id: int):
import aiosqlite import aiosqlite
setups = [] setups = []
async with aiosqlite.connect("db/vanity.db") as db: async with aiosqlite.connect(db_path("vanity.db")) as db:
async with db.execute("SELECT vanity, role_id, log_channel_id FROM vanity_roles WHERE guild_id = ?", (guild_id,)) as cursor: async with db.execute("SELECT vanity, role_id, log_channel_id FROM vanity_roles WHERE guild_id = ?", (guild_id,)) as cursor:
rows = await cursor.fetchall() rows = await cursor.fetchall()
for row in rows: for row in rows:
@@ -604,7 +805,7 @@ async def get_guild_vanityroles(guild_id: int):
async def post_guild_vanityroles(guild_id: int, data: VanityRoleSetup): async def post_guild_vanityroles(guild_id: int, data: VanityRoleSetup):
import aiosqlite import aiosqlite
async with aiosqlite.connect("db/vanity.db") as db: async with aiosqlite.connect(db_path("vanity.db")) as db:
await db.execute( await db.execute(
"INSERT OR REPLACE INTO vanity_roles (guild_id, vanity, role_id, log_channel_id, current_status) VALUES (?, ?, ?, ?, NULL)", "INSERT OR REPLACE INTO vanity_roles (guild_id, vanity, role_id, log_channel_id, current_status) VALUES (?, ?, ?, ?, NULL)",
(guild_id, data.vanity.lower(), data.role_id, data.log_channel_id) (guild_id, data.vanity.lower(), data.role_id, data.log_channel_id)
@@ -617,7 +818,7 @@ async def post_guild_vanityroles(guild_id: int, data: VanityRoleSetup):
async def delete_guild_vanityroles(guild_id: int, vanity: str): async def delete_guild_vanityroles(guild_id: int, vanity: str):
import aiosqlite import aiosqlite
async with aiosqlite.connect("db/vanity.db") as db: async with aiosqlite.connect(db_path("vanity.db")) as db:
await db.execute("DELETE FROM vanity_roles WHERE guild_id = ? AND vanity = ?", (guild_id, vanity.lower())) await db.execute("DELETE FROM vanity_roles WHERE guild_id = ? AND vanity = ?", (guild_id, vanity.lower()))
await db.commit() await db.commit()
@@ -628,7 +829,7 @@ async def delete_guild_vanityroles(guild_id: int, vanity: str):
async def get_guild_autorole(guild_id: int): async def get_guild_autorole(guild_id: int):
import aiosqlite import aiosqlite
async with aiosqlite.connect("db/autorole.db") as db: async with aiosqlite.connect(db_path("autorole.db")) as db:
# Ensure table exists # Ensure table exists
await db.execute(""" await db.execute("""
CREATE TABLE IF NOT EXISTS autorole ( CREATE TABLE IF NOT EXISTS autorole (
@@ -662,7 +863,7 @@ async def get_guild_autorole(guild_id: int):
async def patch_guild_autorole(guild_id: int, data: AutoRoleUpdate): async def patch_guild_autorole(guild_id: int, data: AutoRoleUpdate):
import aiosqlite import aiosqlite
async with aiosqlite.connect("db/autorole.db") as db: async with aiosqlite.connect(db_path("autorole.db")) as db:
await db.execute(""" await db.execute("""
CREATE TABLE IF NOT EXISTS autorole ( CREATE TABLE IF NOT EXISTS autorole (
guild_id INTEGER PRIMARY KEY, guild_id INTEGER PRIMARY KEY,
@@ -701,7 +902,7 @@ async def get_guild_welcome(guild_id: int):
import aiosqlite import aiosqlite
import json import json
async with aiosqlite.connect("db/welcome.db") as db: async with aiosqlite.connect(db_path("welcome.db")) as db:
async with db.execute("SELECT welcome_type, welcome_message, channel_id, embed_data, auto_delete_duration FROM welcome WHERE guild_id = ?", (guild_id,)) as cursor: async with db.execute("SELECT welcome_type, welcome_message, channel_id, embed_data, auto_delete_duration FROM welcome WHERE guild_id = ?", (guild_id,)) as cursor:
row = await cursor.fetchone() row = await cursor.fetchone()
@@ -730,7 +931,7 @@ async def patch_guild_welcome(guild_id: int, data: WelcomeUpdate):
import aiosqlite import aiosqlite
import json import json
async with aiosqlite.connect("db/welcome.db") as db: async with aiosqlite.connect(db_path("welcome.db")) as db:
async with db.execute("SELECT welcome_type, welcome_message, channel_id, embed_data, auto_delete_duration FROM welcome WHERE guild_id = ?", (guild_id,)) as cursor: async with db.execute("SELECT welcome_type, welcome_message, channel_id, embed_data, auto_delete_duration FROM welcome WHERE guild_id = ?", (guild_id,)) as cursor:
row = await cursor.fetchone() row = await cursor.fetchone()
@@ -766,7 +967,7 @@ async def patch_guild_welcome(guild_id: int, data: WelcomeUpdate):
@router.delete("/{guild_id}/welcome", summary="Delete Welcome config") @router.delete("/{guild_id}/welcome", summary="Delete Welcome config")
async def delete_guild_welcome(guild_id: int): async def delete_guild_welcome(guild_id: int):
import aiosqlite import aiosqlite
async with aiosqlite.connect("db/welcome.db") as db: async with aiosqlite.connect(db_path("welcome.db")) as db:
await db.execute("DELETE FROM welcome WHERE guild_id = ?", (guild_id,)) await db.execute("DELETE FROM welcome WHERE guild_id = ?", (guild_id,))
await db.commit() await db.commit()
return {"status": "success"} return {"status": "success"}
@@ -775,7 +976,7 @@ async def delete_guild_welcome(guild_id: int):
@router.get("/{guild_id}/tracking", response_model=TrackingConfig, summary="Get Tracking config") @router.get("/{guild_id}/tracking", response_model=TrackingConfig, summary="Get Tracking config")
async def get_guild_tracking(guild_id: int): async def get_guild_tracking(guild_id: int):
import aiosqlite import aiosqlite
async with aiosqlite.connect("db/invite.db") as db: async with aiosqlite.connect(db_path("invite.db")) as db:
async with db.execute("SELECT channel_id FROM logging WHERE guild_id = ?", (guild_id,)) as cursor: async with db.execute("SELECT channel_id FROM logging WHERE guild_id = ?", (guild_id,)) as cursor:
row = await cursor.fetchone() row = await cursor.fetchone()
return TrackingConfig(guild_id=guild_id, channel_id=row[0] if row else None) return TrackingConfig(guild_id=guild_id, channel_id=row[0] if row else None)
@@ -783,7 +984,7 @@ async def get_guild_tracking(guild_id: int):
@router.patch("/{guild_id}/tracking", summary="Update Tracking config") @router.patch("/{guild_id}/tracking", summary="Update Tracking config")
async def patch_guild_tracking(guild_id: int, data: TrackingUpdate): async def patch_guild_tracking(guild_id: int, data: TrackingUpdate):
import aiosqlite import aiosqlite
async with aiosqlite.connect("db/invite.db") as db: async with aiosqlite.connect(db_path("invite.db")) as db:
await db.execute("INSERT OR REPLACE INTO logging (guild_id, channel_id) VALUES (?, ?)", (guild_id, data.channel_id)) await db.execute("INSERT OR REPLACE INTO logging (guild_id, channel_id) VALUES (?, ?)", (guild_id, data.channel_id))
await db.commit() await db.commit()
return {"status": "success"} return {"status": "success"}
@@ -820,7 +1021,7 @@ async def get_guild_j2c(guild_id: int):
return J2CConfig(guild_id=str(guild_id)) return J2CConfig(guild_id=str(guild_id))
@router.patch("/{guild_id}/j2c", summary="Update J2C config") @router.patch("/{guild_id}/j2c", summary="Update J2C config")
async def patch_guild_j2c(guild_id: int, data: J2CUpdate, bot: "zyrox" = Depends(get_bot)): async def patch_guild_j2c(guild_id: int, data: J2CUpdate, bot: "Axiom" = Depends(get_bot)):
import aiosqlite import aiosqlite
def to_id(val): def to_id(val):
@@ -903,7 +1104,7 @@ async def patch_guild_j2c(guild_id: int, data: J2CUpdate, bot: "zyrox" = Depends
@router.get("/{guild_id}/joindm", response_model=JoinDMConfig, summary="Get JoinDM config") @router.get("/{guild_id}/joindm", response_model=JoinDMConfig, summary="Get JoinDM config")
async def get_guild_joindm(guild_id: int): async def get_guild_joindm(guild_id: int):
config_file = 'jsondb/joindm_messages.json' config_file = jsondb_path('joindm_messages.json')
os.makedirs('jsondb', exist_ok=True) os.makedirs('jsondb', exist_ok=True)
if os.path.exists(config_file): if os.path.exists(config_file):
@@ -925,7 +1126,7 @@ async def get_guild_joindm(guild_id: int):
@router.patch("/{guild_id}/joindm", summary="Update JoinDM config") @router.patch("/{guild_id}/joindm", summary="Update JoinDM config")
async def patch_guild_joindm(guild_id: int, data: JoinDMUpdate): async def patch_guild_joindm(guild_id: int, data: JoinDMUpdate):
config_file = 'jsondb/joindm_messages.json' config_file = jsondb_path('joindm_messages.json')
os.makedirs('jsondb', exist_ok=True) os.makedirs('jsondb', exist_ok=True)
messages = {} messages = {}
@@ -950,7 +1151,7 @@ async def patch_guild_joindm(guild_id: int, data: JoinDMUpdate):
@router.get("/{guild_id}/customroles", response_model=CustomRoleConfig, summary="Get CustomRoles config") @router.get("/{guild_id}/customroles", response_model=CustomRoleConfig, summary="Get CustomRoles config")
async def get_guild_customroles(guild_id: int): async def get_guild_customroles(guild_id: int):
import aiosqlite import aiosqlite
async with aiosqlite.connect('db/customrole.db') as db: async with aiosqlite.connect(db_path('customrole.db')) as db:
async with db.execute("SELECT staff, girl, vip, guest, frnd, reqrole FROM roles WHERE guild_id = ?", (guild_id,)) as cursor: async with db.execute("SELECT staff, girl, vip, guest, frnd, reqrole FROM roles WHERE guild_id = ?", (guild_id,)) as cursor:
row = await cursor.fetchone() row = await cursor.fetchone()
if row: if row:
@@ -975,7 +1176,7 @@ async def patch_guild_customroles(guild_id: int, data: CustomRoleUpdate):
try: return int(val) try: return int(val)
except: return None except: return None
async with aiosqlite.connect('db/customrole.db') as db: async with aiosqlite.connect(db_path('customrole.db')) as db:
async with db.execute("SELECT * FROM roles WHERE guild_id = ?", (guild_id,)) as cursor: async with db.execute("SELECT * FROM roles WHERE guild_id = ?", (guild_id,)) as cursor:
row = await cursor.fetchone() row = await cursor.fetchone()
@@ -1000,7 +1201,7 @@ async def patch_guild_customroles(guild_id: int, data: CustomRoleUpdate):
return {"status": "success"} return {"status": "success"}
@router.get("/{guild_id}/logging", response_model=LoggingConfig, summary="Get Logging config", description="Retrieves the event logging configuration and designated log channels.") @router.get("/{guild_id}/logging", response_model=LoggingConfig, summary="Get Logging config", description="Retrieves the event logging configuration and designated log channels.")
async def get_guild_logging(guild_id: int, bot: "zyrox" = Depends(get_bot)): async def get_guild_logging(guild_id: int, bot: "Axiom" = Depends(get_bot)):
""" """
Retrieves the logging configuration for a specific guild. Retrieves the logging configuration for a specific guild.
""" """
@@ -1013,7 +1214,7 @@ async def get_guild_logging(guild_id: int, bot: "zyrox" = Depends(get_bot)):
# Try reading from file as fallback # Try reading from file as fallback
import json import json
import os import os
config_file = "jsondb/logging_config.json" config_file = jsondb_path("logging_config.json")
if os.path.exists(config_file): if os.path.exists(config_file):
try: try:
with open(config_file, "r") as f: with open(config_file, "r") as f:
@@ -1044,7 +1245,7 @@ async def get_guild_logging(guild_id: int, bot: "zyrox" = Depends(get_bot)):
) )
@router.patch("/{guild_id}/logging", summary="Update Logging config", description="Updates which Discord events are logged and where they are posted.") @router.patch("/{guild_id}/logging", summary="Update Logging config", description="Updates which Discord events are logged and where they are posted.")
async def patch_guild_logging(guild_id: int, data: LoggingUpdate, bot: "zyrox" = Depends(get_bot)): async def patch_guild_logging(guild_id: int, data: LoggingUpdate, bot: "Axiom" = Depends(get_bot)):
""" """
Updates the logging configuration for a specific guild. Updates the logging configuration for a specific guild.
""" """
@@ -1076,8 +1277,8 @@ async def patch_guild_logging(guild_id: int, data: LoggingUpdate, bot: "zyrox" =
return {"status": "success", "guild_id": guild_id} return {"status": "success", "guild_id": guild_id}
@router.get("/{guild_id}/leveling/leaderboard", response_model=List[LeaderboardEntry], summary="Get leveling leaderboard", description="Returns top users by XP for a specific guild.") @router.get("/{guild_id}/leveling/leaderboard", response_model=List[LeaderboardEntry], summary="Get leveling leaderboard", description="Returns top users by XP for a specific guild.")
async def get_leveling_leaderboard(guild_id: int, bot: "zyrox" = Depends(get_bot)): async def get_leveling_leaderboard(guild_id: int, bot: "Axiom" = Depends(get_bot)):
db = await db_manager.get_connection('db/leveling.db') db = await db_manager.get_connection(db_path('leveling.db'))
cursor = await db.execute( cursor = await db.execute(
"SELECT user_id, xp FROM user_xp WHERE guild_id = ? ORDER BY xp DESC LIMIT 100", "SELECT user_id, xp FROM user_xp WHERE guild_id = ? ORDER BY xp DESC LIMIT 100",
(guild_id,) (guild_id,)
@@ -1116,7 +1317,7 @@ async def get_leveling_leaderboard(guild_id: int, bot: "zyrox" = Depends(get_bot
return leaderboard return leaderboard
@router.get("/{guild_id}/channels", response_model=List[DiscordChannel], summary="Get guild channels", description="Returns a list of all channels for the specific guild.") @router.get("/{guild_id}/channels", response_model=List[DiscordChannel], summary="Get guild channels", description="Returns a list of all channels for the specific guild.")
async def get_guild_channels(guild_id: int, bot: "zyrox" = Depends(get_bot)): async def get_guild_channels(guild_id: int, bot: "Axiom" = Depends(get_bot)):
guild = bot.get_guild(guild_id) guild = bot.get_guild(guild_id)
if not guild: if not guild:
raise HTTPException(status_code=404, detail="Guild not found") raise HTTPException(status_code=404, detail="Guild not found")
@@ -1136,7 +1337,7 @@ async def get_guild_channels(guild_id: int, bot: "zyrox" = Depends(get_bot)):
return channels return channels
@router.get("/{guild_id}/roles", response_model=List[DiscordRole], summary="Get guild roles", description="Returns a list of roles for the specific guild.") @router.get("/{guild_id}/roles", response_model=List[DiscordRole], summary="Get guild roles", description="Returns a list of roles for the specific guild.")
async def get_guild_roles(guild_id: int, bot: "zyrox" = Depends(get_bot)): async def get_guild_roles(guild_id: int, bot: "Axiom" = Depends(get_bot)):
guild = bot.get_guild(guild_id) guild = bot.get_guild(guild_id)
if not guild: if not guild:
raise HTTPException(status_code=404, detail="Guild not found") raise HTTPException(status_code=404, detail="Guild not found")
@@ -1164,7 +1365,7 @@ async def get_guild_roles(guild_id: int, bot: "zyrox" = Depends(get_bot)):
@router.get("/{guild_id}/autoreact", response_model=AutoReactConfig, summary="Get AutoReact config") @router.get("/{guild_id}/autoreact", response_model=AutoReactConfig, summary="Get AutoReact config")
async def get_guild_autoreact(guild_id: int): async def get_guild_autoreact(guild_id: int):
import aiosqlite import aiosqlite
async with aiosqlite.connect("db/autoreact.db") as db: async with aiosqlite.connect(db_path("autoreact.db")) as db:
await db.execute(""" await db.execute("""
CREATE TABLE IF NOT EXISTS autoreact ( CREATE TABLE IF NOT EXISTS autoreact (
guild_id INTEGER, guild_id INTEGER,
@@ -1185,7 +1386,7 @@ async def get_guild_autoreact(guild_id: int):
@router.get("/{guild_id}/invcrole", response_model=InvcConfig, summary="Get Invc Role config") @router.get("/{guild_id}/invcrole", response_model=InvcConfig, summary="Get Invc Role config")
async def get_guild_invcrole(guild_id: int): async def get_guild_invcrole(guild_id: int):
db = await db_manager.get_connection('db/invc.db') db = await db_manager.get_connection(db_path('invc.db'))
# Use execute instead of with for shared connection # Use execute instead of with for shared connection
await db.execute(""" await db.execute("""
CREATE TABLE IF NOT EXISTS vcroles ( CREATE TABLE IF NOT EXISTS vcroles (
@@ -1209,7 +1410,7 @@ async def get_guild_invcrole(guild_id: int):
@router.patch("/{guild_id}/invcrole", summary="Update Invc Role config") @router.patch("/{guild_id}/invcrole", summary="Update Invc Role config")
async def patch_guild_invcrole(guild_id: int, data: InvcUpdate): async def patch_guild_invcrole(guild_id: int, data: InvcUpdate):
db = await db_manager.get_connection('db/invc.db') db = await db_manager.get_connection(db_path('invc.db'))
# Get existing row to merge # Get existing row to merge
cursor = await db.execute("SELECT role_id, enabled FROM vcroles WHERE guild_id = ?", (guild_id,)) cursor = await db.execute("SELECT role_id, enabled FROM vcroles WHERE guild_id = ?", (guild_id,))
@@ -1246,7 +1447,7 @@ async def patch_guild_invcrole(guild_id: int, data: InvcUpdate):
@router.get("/{guild_id}/autoreact", response_model=AutoReactConfig, summary="Get AutoReact config") @router.get("/{guild_id}/autoreact", response_model=AutoReactConfig, summary="Get AutoReact config")
async def get_guild_autoreact(guild_id: int): async def get_guild_autoreact(guild_id: int):
import aiosqlite import aiosqlite
async with aiosqlite.connect("db/autoreact.db") as db: async with aiosqlite.connect(db_path("autoreact.db")) as db:
await db.execute(""" await db.execute("""
CREATE TABLE IF NOT EXISTS autoreact ( CREATE TABLE IF NOT EXISTS autoreact (
guild_id INTEGER, guild_id INTEGER,
@@ -1264,7 +1465,7 @@ async def get_guild_autoreact(guild_id: int):
@router.patch("/{guild_id}/autoreact", summary="Update AutoReact config") @router.patch("/{guild_id}/autoreact", summary="Update AutoReact config")
async def patch_guild_autoreact(guild_id: int, data: AutoReactUpdate): async def patch_guild_autoreact(guild_id: int, data: AutoReactUpdate):
db = await db_manager.get_connection("db/autoreact.db") db = await db_manager.get_connection(db_path("autoreact.db"))
await db.execute(""" await db.execute("""
CREATE TABLE IF NOT EXISTS autoreact ( CREATE TABLE IF NOT EXISTS autoreact (
guild_id INTEGER, guild_id INTEGER,
@@ -1287,7 +1488,7 @@ async def get_guild_invites(guild_id: int):
table_name = f"invites_{guild_id}" table_name = f"invites_{guild_id}"
data_list = [] data_list = []
db = await db_manager.get_connection("db/invite.db") db = await db_manager.get_connection(db_path("invite.db"))
# Check if table exists # Check if table exists
async with db.execute("SELECT name FROM sqlite_master WHERE type='table' AND name=?", (table_name,)) as cursor: async with db.execute("SELECT name FROM sqlite_master WHERE type='table' AND name=?", (table_name,)) as cursor:
exists = await cursor.fetchone() exists = await cursor.fetchone()

View File

@@ -1,19 +1,18 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from pydantic import BaseModel, HttpUrl from pydantic import BaseModel, HttpUrl
from typing import Dict, List, Optional from typing import Any, Dict, List, Optional
# --- Bot Schemas --- # --- Bot Schemas ---
@@ -32,6 +31,8 @@ class BotStatus(BaseModel):
guild_count: int guild_count: int
user_count: int user_count: int
shards: Optional[int] shards: Optional[int]
shard_ids: Optional[List[int]] = None
shard_latencies: Optional[List[Dict[str, Any]]] = None
# --- Guild Schemas --- # --- Guild Schemas ---
@@ -68,13 +69,24 @@ class PrefixConfig(BaseModel):
guild_id: int guild_id: int
prefix: str prefix: str
class AutomodEventConfig(BaseModel):
enabled: bool = False
punishment: Optional[str] = None # Mute | Kick | Ban | block_message (NSFW)
readonly_punishment: bool = False
class AutomodConfig(BaseModel): class AutomodConfig(BaseModel):
guild_id: int guild_id: int
enabled: bool enabled: bool
punishments: Dict[str, str] # Legacy flat map (API event ids or bot names) — kept for older clients
ignored_roles: List[int] punishments: Dict[str, str] = {}
ignored_channels: List[int] events: Dict[str, AutomodEventConfig] = {}
logging_channel: Optional[int] thresholds: Dict[str, Dict[str, float]] = {}
threshold_meta: Dict[str, List[Dict[str, Any]]] = {}
ignored_roles: List[int] = []
ignored_channels: List[int] = []
logging_channel: Optional[int] = None
limits: Dict[str, int] = {"max_ignored_roles": 10, "max_ignored_channels": 10}
class TicketCategory(BaseModel): class TicketCategory(BaseModel):
name: str name: str
@@ -300,10 +312,14 @@ class TicketUpdate(BaseModel):
class AutomodUpdate(BaseModel): class AutomodUpdate(BaseModel):
enabled: Optional[bool] = None enabled: Optional[bool] = None
punishments: Optional[Dict[str, str]] = None punishments: Optional[Dict[str, str]] = None # legacy
events: Optional[Dict[str, AutomodEventConfig]] = None
thresholds: Optional[Dict[str, Dict[str, float]]] = None
ignored_roles: Optional[List[int]] = None ignored_roles: Optional[List[int]] = None
ignored_channels: Optional[List[int]] = None ignored_channels: Optional[List[int]] = None
# Use a sentinel-friendly optional: omit = no change; null = clear logging
logging_channel: Optional[int] = None logging_channel: Optional[int] = None
clear_logging: Optional[bool] = None
class LevelingUpdate(BaseModel): class LevelingUpdate(BaseModel):
enabled: Optional[bool] = None enabled: Optional[bool] = None

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
@@ -53,8 +52,8 @@ async def lifespan(app: FastAPI):
def create_app() -> FastAPI: def create_app() -> FastAPI:
""" """
Initializes the FastAPI application for the CodeX Bot Dashboard. Initializes the FastAPI application for the Axiom Bot Dashboard.
The bot instance will be attached to app.state.bot in CodeX.py at runtime. The bot instance will be attached to app.state.bot in Axiom.py at runtime.
""" """
app = FastAPI( app = FastAPI(
title=f"{BRAND_NAME} Bot API", title=f"{BRAND_NAME} Bot API",

BIN
bot/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

3
bot/assets/logo.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 500 KiB

View File

@@ -1,21 +1,22 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from __future__ import annotations from __future__ import annotations
from core import zyrox
from colorama import Fore, Style, init
from colorama import Fore, Style
from core import Axiom
from utils.config import BotName
from .commands.help import Help from .commands.help import Help
from .commands.general import General from .commands.general import General
@@ -25,7 +26,7 @@ from .commands.welcome import Welcomer
from .commands.fun import Fun from .commands.fun import Fun
from .commands.Games import Games from .commands.Games import Games
from .commands.extra import Extra from .commands.extra import Extra
from .commands.owner import Owner from .commands.owner import Owner, Badges
from .commands.voice import Voice from .commands.voice import Voice
from .commands.afk import afk from .commands.afk import afk
from .commands.ignore import Ignore from .commands.ignore import Ignore
@@ -39,8 +40,6 @@ from .commands.blacklist import Blacklist
from .commands.block import Block from .commands.block import Block
from .commands.nightmode import Nightmode from .commands.nightmode import Nightmode
from .commands.tracking import Tracking from .commands.tracking import Tracking
from .commands.owner import Badges
#from .commands.map import Map
from .commands.autoresponder import AutoResponder from .commands.autoresponder import AutoResponder
from .commands.customrole import Customrole from .commands.customrole import Customrole
from .commands.autorole import AutoRole from .commands.autorole import AutoRole
@@ -83,9 +82,7 @@ from .commands.Birthday import Birthdays
from .commands.nitro import Nitro from .commands.nitro import Nitro
from .commands.image import ImageCommands from .commands.image import ImageCommands
from .commands.youtube import Youtube from .commands.youtube import Youtube
#____________ Events _____________
#from .events.autoblacklist import AutoBlacklist
from .events.Errors import Errors from .events.Errors import Errors
from .events.on_guild import Guild from .events.on_guild import Guild
from .events.autorole import Autorole2 from .events.autorole import Autorole2
@@ -94,43 +91,37 @@ from .events.greet2 import greet
from .events.mention import Mention from .events.mention import Mention
from .events.react import React from .events.react import React
from .events.autoreact import AutoReactListener from .events.autoreact import AutoReactListener
#from .events.topgg import TopGG
from .events.ai import AIResponses from .events.ai import AIResponses
from .events.stickymessage import StickyMessageListener from .events.stickymessage import StickyMessageListener
########-------HELP-------######## from .axiom.antinuke import _antinuke
from .zyrox.antinuke import _antinuke from .axiom.extra import _extra
from .zyrox.extra import _extra from .axiom.general import _general
from .zyrox.general import _general from .axiom.automod import _automod
from .zyrox.automod import _automod from .axiom.moderation import _moderation
from .zyrox.moderation import _moderation from .axiom.music import _music
#from .zyrox.inviteTracker import _inviteTracker from .axiom.fun import _fun
from .zyrox.music import _music from .axiom.games import _games
from .zyrox.fun import _fun from .axiom.ignore import _ignore
from .zyrox.games import _games from .axiom.server import _server
from .zyrox.ignore import _ignore from .axiom.voice import _voice
from .zyrox.server import _server from .axiom.welcome import _welcome
from .zyrox.voice import _voice from .axiom.giveaway import _giveaway
from .zyrox.welcome import _welcome from .axiom.ticket import _ticket
from .zyrox.giveaway import _giveaway from .axiom.logging import _logging
from .zyrox.ticket import _ticket from .axiom.vanity import _vanity
#from .axon.vanityroles import Vanityroles69999 from .axiom.inviteTracker import inviteTracker
from .zyrox.logging import _logging from .axiom.counting import _Counting
from .zyrox.vanity import _vanity from .axiom.j2c import _J2C
from .zyrox.inviteTracker import inviteTracker from .axiom.ai import _ai
from .zyrox.counting import _Counting from .axiom.booster import __boost
from .zyrox.j2c import _J2C from .axiom.leveling import _leveling
from .zyrox.ai import _ai from .axiom.sticky import _sticky
from .zyrox.booster import __boost from .axiom.verify import _verify
from .zyrox.leveling import _leveling from .axiom.encryption import _encrypt
from .zyrox.sticky import _sticky from .axiom.mc import _mc
from .zyrox.verify import _verify from .axiom.joindm import _joindm
from .zyrox.encryption import _encrypt from .axiom.birth import _birth
from .zyrox.mc import _mc
from .zyrox.joindm import _joindm
from .zyrox.birth import _birth
#########ANTINUKE#########
from .antinuke.anti_member_update import AntiMemberUpdate from .antinuke.anti_member_update import AntiMemberUpdate
from .antinuke.antiban import AntiBan from .antinuke.antiban import AntiBan
@@ -150,15 +141,6 @@ from .antinuke.antiwebhook import AntiWebhookUpdate
from .antinuke.antiwebhookcr import AntiWebhookCreate from .antinuke.antiwebhookcr import AntiWebhookCreate
from .antinuke.antiwebhookdl import AntiWebhookDelete from .antinuke.antiwebhookdl import AntiWebhookDelete
#Extra Optional Events
#from .antinuke.antiemocr import AntiEmojiCreate
#from .antinuke.antiemodl import AntiEmojiDelete
#from .antinuke.antiemoup import AntiEmojiUpdate
#from .antinuke.antisticker import AntiSticker
#from .antinuke.antiunban import AntiUnban
############ AUTOMOD ############
from .automod.antispam import AntiSpam from .automod.antispam import AntiSpam
from .automod.anticaps import AntiCaps from .automod.anticaps import AntiCaps
from .automod.antilink import AntiLink from .automod.antilink import AntiLink
@@ -166,7 +148,6 @@ from .automod.anti_invites import AntiInvite
from .automod.anti_mass_mention import AntiMassMention from .automod.anti_mass_mention import AntiMassMention
from .automod.anti_emoji_spam import AntiEmojiSpam from .automod.anti_emoji_spam import AntiEmojiSpam
from .moderation.ban import Ban from .moderation.ban import Ban
from .moderation.unban import Unban from .moderation.unban import Unban
from .moderation.timeout import Mute from .moderation.timeout import Mute
@@ -180,197 +161,49 @@ from .moderation.warn import Warn
from .moderation.role import Role from .moderation.role import Role
from .moderation.message import Message from .moderation.message import Message
from .moderation.moderation import Moderation from .moderation.moderation import Moderation
from .moderation.mod_hub import ModHub
from .moderation.topcheck import TopCheck from .moderation.topcheck import TopCheck
from .moderation.snipe import Snipe from .moderation.snipe import Snipe
# Load order preserved from legacy manual registration.
from utils.config import BotName COG_CLASSES: tuple[type, ...] = (
Help, General, Music, Automod, Welcomer, Fun, Tracking, Games, Extra,
async def setup(bot: zyrox): Voice, Owner, Customrole, afk, Embed, Media, Ignore, Invcrole, Giveaway,
cogs_to_load = [ Steal, Booster, Timer, Blacklist, Block, Nightmode, Badges, Antinuke,
Help, General, Moderation, Automod, Welcomer, Fun, Games, Extra, Whitelist, Unwhitelist, Extraowner, Slots, Blackjack, Stats, Emergency,
Voice, Owner, Customrole, afk, Embed, Media, Ignore, TicketCog, Logging, Status, NoPrefix, FilterCog, Global, TicketCog, Logging, QR, VanityRoles,
Invcrole, Steal, Timer, ReactionRoles, Messages, TranslateCog, FastGreet, Jail, JoinToCreate, AI,
Blacklist, Block, Nightmode, Badges, Antinuke, Whitelist, StaffDMCog, Leveling, StickyMessage, Verification, Minecraft, encryption,
Unwhitelist, Extraowner, Blackjack, Slots, Guild, Errors, Autorole2, Autorole, greet, AutoResponder, calculator, joindm, Birthdays, Nitro, ImageCommands, Youtube,
Mention, AutoRole, React, AntiMemberUpdate, AntiBan, AntiBotAdd, _antinuke, _extra, _general, _automod, _moderation, _music, _fun, _games,
AntiChannelCreate, AntiChannelDelete, AntiChannelUpdate, AntiEveryone, AntiGuildUpdate, _ignore, _server, _voice, _welcome, _giveaway, _ticket, _logging, _vanity,
AntiIntegration, AntiKick, AntiPrune, AntiRoleCreate, AntiRoleDelete, inviteTracker, Counting, _Counting, _J2C, _ai, __boost, _leveling, _sticky,
AntiRoleUpdate, AntiWebhookUpdate, AntiWebhookCreate, _verify, _encrypt, _mc, _joindm, _birth,
AntiWebhookDelete, AntiSpam, AntiCaps, AntiLink, AntiInvite, AntiMassMention, Stats, Status, NoPrefix, FilterCog, AutoReaction, AutoReactListener, Ban, Unban, Mute, Unmute, Lock, Unlock, Hide, Unhide, Kick, Warn, Role, Message, Moderation, TopCheck, Snipe, Global, QR, VanityRoles, ReactionRoles, Messages, TranslateCog, FastGreet, Jail, inviteTracker,Counting,AI Guild, Errors, Autorole2, Autorole, greet, AutoResponder, Mention, AutoRole,
] React, AutoReaction, AutoReactListener, NotifCommands, StickyMessageListener,
AIResponses,
AntiMemberUpdate, AntiBan, AntiBotAdd, AntiChannelCreate, AntiChannelDelete,
AntiChannelUpdate, AntiEveryone, AntiGuildUpdate, AntiIntegration, AntiKick,
AntiPrune, AntiRoleCreate, AntiRoleDelete, AntiRoleUpdate, AntiWebhookUpdate,
AntiWebhookCreate, AntiWebhookDelete,
AntiSpam, AntiCaps, AntiInvite, AntiLink, AntiMassMention, AntiEmojiSpam,
Ban, Unban, Mute, Unmute, Lock, Unlock, Hide, Unhide, Kick, Warn, Role,
Message, Moderation, ModHub, TopCheck, Snipe,
)
await bot.add_cog(Help(bot)) async def setup(bot: Axiom) -> None:
await bot.add_cog(General(bot)) loaded = 0
await bot.add_cog(Music(bot)) for cog_cls in COG_CLASSES:
await bot.add_cog(Automod(bot)) try:
await bot.add_cog(Welcomer(bot)) await bot.add_cog(cog_cls(bot))
await bot.add_cog(Fun(bot)) loaded += 1
await bot.add_cog(Tracking(bot)) print(Fore.GREEN + Style.BRIGHT + f"Loaded cog: {cog_cls.__name__}")
await bot.add_cog(Games(bot)) except Exception as e:
await bot.add_cog(Extra(bot)) print(
await bot.add_cog(Voice(bot)) Fore.RED
await bot.add_cog(Owner(bot)) + Style.BRIGHT
await bot.add_cog(Customrole(bot)) + f"Failed cog {getattr(cog_cls, '__name__', cog_cls)}: {type(e).__name__}: {e}"
await bot.add_cog(afk(bot)) )
await bot.add_cog(Embed(bot))
await bot.add_cog(Media(bot))
await bot.add_cog(Ignore(bot))
await bot.add_cog(Invcrole(bot))
await bot.add_cog(Giveaway(bot))
await bot.add_cog(Steal(bot))
await bot.add_cog(Booster(bot))
await bot.add_cog(Timer(bot))
await bot.add_cog(Blacklist(bot))
await bot.add_cog(Block(bot))
await bot.add_cog(Nightmode(bot))
await bot.add_cog(Badges(bot))
await bot.add_cog(Antinuke(bot))
await bot.add_cog(Whitelist(bot))
await bot.add_cog(Unwhitelist(bot))
await bot.add_cog(Extraowner(bot))
await bot.add_cog(Slots(bot))
await bot.add_cog(Blackjack(bot))
await bot.add_cog(Stats(bot))
await bot.add_cog(Emergency(bot))
await bot.add_cog(Status(bot))
await bot.add_cog(NoPrefix(bot))
await bot.add_cog(FilterCog(bot))
await bot.add_cog(Global(bot))
# await bot.add_cog(Map(bot))
await bot.add_cog(TicketCog(bot))
await bot.add_cog(Logging(bot))
await bot.add_cog(QR(bot))
await bot.add_cog(VanityRoles(bot))
await bot.add_cog(ReactionRoles(bot))
await bot.add_cog(Messages(bot))
await bot.add_cog(TranslateCog(bot))
await bot.add_cog(FastGreet(bot))
await bot.add_cog(Jail(bot))
await bot.add_cog(JoinToCreate(bot))
await bot.add_cog(AI(bot))
await bot.add_cog(StaffDMCog(bot))
await bot.add_cog(Leveling(bot))
await bot.add_cog(StickyMessage(bot))
await bot.add_cog(Verification(bot))
await bot.add_cog(Minecraft(bot))
await bot.add_cog(encryption(bot))
await bot.add_cog(calculator(bot))
await bot.add_cog(joindm(bot))
await bot.add_cog(Birthdays(bot))
await bot.add_cog(Nitro(bot))
await bot.add_cog(ImageCommands(bot))
await bot.add_cog(Youtube(bot))
await bot.add_cog(_antinuke(bot)) print(Fore.GREEN + Style.BRIGHT + f"Loaded {loaded}/{len(COG_CLASSES)} {BotName} cogs.")
await bot.add_cog(_extra(bot))
await bot.add_cog(_general(bot))
await bot.add_cog(_automod(bot))
await bot.add_cog(_moderation(bot))
await bot.add_cog(_music(bot))
await bot.add_cog(_fun(bot))
await bot.add_cog(_games(bot))
await bot.add_cog(_ignore(bot))
await bot.add_cog(_server(bot))
await bot.add_cog(_voice(bot))
await bot.add_cog(_welcome(bot))
await bot.add_cog(_giveaway(bot))
await bot.add_cog(_ticket(bot))
await bot.add_cog(_logging(bot))
await bot.add_cog(_vanity(bot))
await bot.add_cog(inviteTracker(bot))
await bot.add_cog(Counting(bot))
await bot.add_cog(_Counting(bot))
await bot.add_cog(_J2C(bot))
await bot.add_cog(_ai(bot))
await bot.add_cog(__boost(bot))
await bot.add_cog(_leveling(bot))
await bot.add_cog(_sticky(bot))
await bot.add_cog(_verify(bot))
await bot.add_cog(_encrypt(bot))
await bot.add_cog(_mc(bot))
await bot.add_cog(_joindm(bot))
await bot.add_cog(_birth(bot))
#await bot.add_cog(AutoBlacklist(bot))
await bot.add_cog(Guild(bot))
await bot.add_cog(Errors(bot))
await bot.add_cog(Autorole2(bot))
await bot.add_cog(Autorole(bot))
await bot.add_cog(greet(bot))
await bot.add_cog(AutoResponder(bot))
await bot.add_cog(Mention(bot))
await bot.add_cog(AutoRole(bot))
await bot.add_cog(React(bot))
await bot.add_cog(AutoReaction(bot))
await bot.add_cog(AutoReactListener(bot))
await bot.add_cog(NotifCommands(bot))
await bot.add_cog(StickyMessageListener(bot))
await bot.add_cog(AIResponses(bot))
await bot.add_cog(AntiMemberUpdate(bot))
await bot.add_cog(AntiBan(bot))
await bot.add_cog(AntiBotAdd(bot))
await bot.add_cog(AntiChannelCreate(bot))
await bot.add_cog(AntiChannelDelete(bot))
await bot.add_cog(AntiChannelUpdate(bot))
await bot.add_cog(AntiEveryone(bot))
await bot.add_cog(AntiGuildUpdate(bot))
await bot.add_cog(AntiIntegration(bot))
await bot.add_cog(AntiKick(bot))
await bot.add_cog(AntiPrune(bot))
await bot.add_cog(AntiRoleCreate(bot))
await bot.add_cog(AntiRoleDelete(bot))
await bot.add_cog(AntiRoleUpdate(bot))
await bot.add_cog(AntiWebhookUpdate(bot))
await bot.add_cog(AntiWebhookCreate(bot))
await bot.add_cog(AntiWebhookDelete(bot))
#Extra Optional Events
#await bot.add_cog(AntiEmojiCreate(bot))
#await bot.add_cog(AntiEmojiDelete(bot))
#await bot.add_cog(AntiEmojiUpdate(bot))
#await bot.add_cog(AntiSticker(bot))
#await bot.add_cog(AntiUnban(bot))
await bot.add_cog(AntiSpam(bot))
await bot.add_cog(AntiCaps(bot))
await bot.add_cog(AntiInvite(bot))
await bot.add_cog(AntiLink(bot))
await bot.add_cog(AntiMassMention(bot))
await bot.add_cog(AntiEmojiSpam(bot))
await bot.add_cog(Ban(bot))
await bot.add_cog(Unban(bot))
await bot.add_cog(Mute(bot))
await bot.add_cog(Unmute(bot))
await bot.add_cog(Lock(bot))
await bot.add_cog(Unlock(bot))
await bot.add_cog(Hide(bot))
await bot.add_cog(Unhide(bot))
await bot.add_cog(Kick(bot))
await bot.add_cog(Warn(bot))
await bot.add_cog(Role(bot))
await bot.add_cog(Message(bot))
await bot.add_cog(Moderation(bot))
await bot.add_cog(TopCheck(bot))
await bot.add_cog(Snipe(bot))
for cog in cogs_to_load:
print(Fore.RED + Style.BRIGHT + f"Loaded cog: {cog.__name__}")
print(Fore.RED + Style.BRIGHT + f"All {BotName} Cogs loaded successfully.")

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from discord.ext import commands from discord.ext import commands
@@ -61,7 +61,7 @@ class AntiIntegration(commands.Cog):
return True return True
async def is_blacklisted_guild(self, guild_id): async def is_blacklisted_guild(self, guild_id):
async with aiosqlite.connect('db/block.db') as block_db: async with aiosqlite.connect(db_path('block.db')) as block_db:
cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),)) cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),))
return await cursor.fetchone() is not None return await cursor.fetchone() is not None
@@ -70,7 +70,7 @@ class AntiIntegration(commands.Cog):
if await self.is_blacklisted_guild(guild.id): if await self.is_blacklisted_guild(guild.id):
return return
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor: async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
antinuke_status = await cursor.fetchone() antinuke_status = await cursor.fetchone()
@@ -89,7 +89,7 @@ class AntiIntegration(commands.Cog):
if executor.id in {guild.owner_id, self.bot.user.id}: if executor.id in {guild.owner_id, self.bot.user.id}:
return return
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT owner_id FROM extraowners WHERE guild_id = ? AND owner_id = ?", async with db.execute("SELECT owner_id FROM extraowners WHERE guild_id = ? AND owner_id = ?",
(guild.id, executor.id)) as cursor: (guild.id, executor.id)) as cursor:
extraowner_status = await cursor.fetchone() extraowner_status = await cursor.fetchone()

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from discord.ext import commands from discord.ext import commands
@@ -26,7 +26,7 @@ class AntiMemberUpdate(commands.Cog):
self.cooldowns = {} self.cooldowns = {}
async def is_blacklisted_guild(self, guild_id): async def is_blacklisted_guild(self, guild_id):
async with aiosqlite.connect('db/block.db') as block_db: async with aiosqlite.connect(db_path('block.db')) as block_db:
cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),)) cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),))
return await cursor.fetchone() is not None return await cursor.fetchone() is not None
@@ -71,7 +71,7 @@ class AntiMemberUpdate(commands.Cog):
if await self.is_blacklisted_guild(guild.id): if await self.is_blacklisted_guild(guild.id):
return return
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor: async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
antinuke_status = await cursor.fetchone() antinuke_status = await cursor.fetchone()
if not antinuke_status or not antinuke_status[0]: if not antinuke_status or not antinuke_status[0]:
@@ -88,7 +88,7 @@ class AntiMemberUpdate(commands.Cog):
if executor.id in {guild.owner_id, self.bot.user.id}: if executor.id in {guild.owner_id, self.bot.user.id}:
return return
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT owner_id FROM extraowners WHERE guild_id = ? AND owner_id = ?", async with db.execute("SELECT owner_id FROM extraowners WHERE guild_id = ? AND owner_id = ?",
(guild.id, executor.id)) as cursor: (guild.id, executor.id)) as cursor:
extra_owner_status = await cursor.fetchone() extra_owner_status = await cursor.fetchone()

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from discord.ext import commands from discord.ext import commands
@@ -59,7 +59,7 @@ class AntiBan(commands.Cog):
@commands.Cog.listener() @commands.Cog.listener()
async def on_member_ban(self, guild, user): async def on_member_ban(self, guild, user):
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor: async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
antinuke_status = await cursor.fetchone() antinuke_status = await cursor.fetchone()
if not antinuke_status or not antinuke_status[0]: if not antinuke_status or not antinuke_status[0]:

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from discord.ext import commands from discord.ext import commands
@@ -63,7 +63,7 @@ class AntiBotAdd(commands.Cog):
return return
guild = member.guild guild = member.guild
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor: async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
antinuke_status = await cursor.fetchone() antinuke_status = await cursor.fetchone()

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from discord.ext import commands from discord.ext import commands
@@ -89,7 +89,7 @@ class AntiChannelCreate(commands.Cog):
async def on_guild_channel_create(self, channel): async def on_guild_channel_create(self, channel):
guild = channel.guild guild = channel.guild
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor: async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
antinuke_status = await cursor.fetchone() antinuke_status = await cursor.fetchone()
if not antinuke_status or not antinuke_status[0]: if not antinuke_status or not antinuke_status[0]:

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from discord.ext import commands from discord.ext import commands
@@ -60,7 +60,7 @@ class AntiChannelDelete(commands.Cog):
@commands.Cog.listener() @commands.Cog.listener()
async def on_guild_channel_delete(self, channel): async def on_guild_channel_delete(self, channel):
guild = channel.guild guild = channel.guild
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor: async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
antinuke_status = await cursor.fetchone() antinuke_status = await cursor.fetchone()
if not antinuke_status or not antinuke_status[0]: if not antinuke_status or not antinuke_status[0]:

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from discord.ext import commands from discord.ext import commands
@@ -60,7 +60,7 @@ class AntiChannelUpdate(commands.Cog):
@commands.Cog.listener() @commands.Cog.listener()
async def on_guild_channel_update(self, before, after): async def on_guild_channel_update(self, before, after):
guild = before.guild guild = before.guild
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor: async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
antinuke_status = await cursor.fetchone() antinuke_status = await cursor.fetchone()
if not antinuke_status or not antinuke_status[0]: if not antinuke_status or not antinuke_status[0]:

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from discord.ext import commands from discord.ext import commands
@@ -44,7 +44,7 @@ class AntiEveryone(commands.Cog):
guild = message.guild guild = message.guild
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor: async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
antinuke_status = await cursor.fetchone() antinuke_status = await cursor.fetchone()

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from discord.ext import commands from discord.ext import commands
@@ -61,7 +61,7 @@ class AntiGuildUpdate(commands.Cog):
return True return True
async def is_blacklisted_guild(self, guild_id): async def is_blacklisted_guild(self, guild_id):
async with aiosqlite.connect('db/block.db') as block_db: async with aiosqlite.connect(db_path('block.db')) as block_db:
cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),)) cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),))
return await cursor.fetchone() is not None return await cursor.fetchone() is not None
@@ -71,7 +71,7 @@ class AntiGuildUpdate(commands.Cog):
if await self.is_blacklisted_guild(guild.id): if await self.is_blacklisted_guild(guild.id):
return return
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor: async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
antinuke_status = await cursor.fetchone() antinuke_status = await cursor.fetchone()
@@ -93,7 +93,7 @@ class AntiGuildUpdate(commands.Cog):
if executor.id in {guild.owner_id, self.bot.user.id}: if executor.id in {guild.owner_id, self.bot.user.id}:
return return
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT serverup FROM whitelisted_users WHERE guild_id = ? AND user_id = ?", async with db.execute("SELECT serverup FROM whitelisted_users WHERE guild_id = ? AND user_id = ?",
(guild.id, executor.id)) as cursor: (guild.id, executor.id)) as cursor:
whitelist_status = await cursor.fetchone() whitelist_status = await cursor.fetchone()

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from discord.ext import commands from discord.ext import commands
@@ -26,7 +26,7 @@ class AntiKick(commands.Cog):
self.cooldowns = {} self.cooldowns = {}
async def is_blacklisted_guild(self, guild_id): async def is_blacklisted_guild(self, guild_id):
async with aiosqlite.connect('db/block.db') as block_db: async with aiosqlite.connect(db_path('block.db')) as block_db:
cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),)) cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),))
return await cursor.fetchone() is not None return await cursor.fetchone() is not None
@@ -70,7 +70,7 @@ class AntiKick(commands.Cog):
if await self.is_blacklisted_guild(member.guild.id): if await self.is_blacklisted_guild(member.guild.id):
return return
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (member.guild.id,)) as cursor: async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (member.guild.id,)) as cursor:
antinuke_status = await cursor.fetchone() antinuke_status = await cursor.fetchone()
if not antinuke_status or not antinuke_status[0]: if not antinuke_status or not antinuke_status[0]:
@@ -87,7 +87,7 @@ class AntiKick(commands.Cog):
if executor.id in {member.guild.owner_id, self.bot.user.id}: if executor.id in {member.guild.owner_id, self.bot.user.id}:
return return
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT owner_id FROM extraowners WHERE guild_id = ? AND owner_id = ?", async with db.execute("SELECT owner_id FROM extraowners WHERE guild_id = ? AND owner_id = ?",
(member.guild.id, executor.id)) as cursor: (member.guild.id, executor.id)) as cursor:
extraowner_status = await cursor.fetchone() extraowner_status = await cursor.fetchone()

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from discord.ext import commands from discord.ext import commands
@@ -42,7 +42,7 @@ class AntiPrune(commands.Cog):
@commands.Cog.listener() @commands.Cog.listener()
async def on_member_remove(self, member): async def on_member_remove(self, member):
guild = member.guild guild = member.guild
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor: async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
antinuke_status = await cursor.fetchone() antinuke_status = await cursor.fetchone()

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from discord.ext import commands from discord.ext import commands
@@ -26,7 +26,7 @@ class AntiRoleCreate(commands.Cog):
self.cooldowns = {} self.cooldowns = {}
async def is_blacklisted_guild(self, guild_id): async def is_blacklisted_guild(self, guild_id):
async with aiosqlite.connect('db/block.db') as block_db: async with aiosqlite.connect(db_path('block.db')) as block_db:
cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),)) cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),))
return await cursor.fetchone() is not None return await cursor.fetchone() is not None
@@ -71,7 +71,7 @@ class AntiRoleCreate(commands.Cog):
if await self.is_blacklisted_guild(guild.id): if await self.is_blacklisted_guild(guild.id):
return return
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor: async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
antinuke_status = await cursor.fetchone() antinuke_status = await cursor.fetchone()
if not antinuke_status or not antinuke_status[0]: if not antinuke_status or not antinuke_status[0]:
@@ -89,7 +89,7 @@ class AntiRoleCreate(commands.Cog):
if executor.id in {guild.owner_id, self.bot.user.id}: if executor.id in {guild.owner_id, self.bot.user.id}:
return return
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT owner_id FROM extraowners WHERE guild_id = ? AND owner_id = ?", async with db.execute("SELECT owner_id FROM extraowners WHERE guild_id = ? AND owner_id = ?",
(guild.id, executor.id)) as cursor: (guild.id, executor.id)) as cursor:
extra_owner_status = await cursor.fetchone() extra_owner_status = await cursor.fetchone()

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from discord.ext import commands from discord.ext import commands
@@ -26,7 +26,7 @@ class AntiRoleDelete(commands.Cog):
self.cooldowns = {} self.cooldowns = {}
async def is_blacklisted_guild(self, guild_id): async def is_blacklisted_guild(self, guild_id):
async with aiosqlite.connect('db/block.db') as block_db: async with aiosqlite.connect(db_path('block.db')) as block_db:
cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),)) cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),))
return await cursor.fetchone() is not None return await cursor.fetchone() is not None
@@ -71,7 +71,7 @@ class AntiRoleDelete(commands.Cog):
if await self.is_blacklisted_guild(guild.id): if await self.is_blacklisted_guild(guild.id):
return return
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor: async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
antinuke_status = await cursor.fetchone() antinuke_status = await cursor.fetchone()
if not antinuke_status or not antinuke_status[0]: if not antinuke_status or not antinuke_status[0]:
@@ -89,7 +89,7 @@ class AntiRoleDelete(commands.Cog):
if executor.id in {guild.owner_id, self.bot.user.id}: if executor.id in {guild.owner_id, self.bot.user.id}:
return return
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT owner_id FROM extraowners WHERE guild_id = ? AND owner_id = ?", async with db.execute("SELECT owner_id FROM extraowners WHERE guild_id = ? AND owner_id = ?",
(guild.id, executor.id)) as cursor: (guild.id, executor.id)) as cursor:
extra_owner_status = await cursor.fetchone() extra_owner_status = await cursor.fetchone()

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from discord.ext import commands from discord.ext import commands
@@ -26,7 +26,7 @@ class AntiRoleUpdate(commands.Cog):
self.cooldowns = {} self.cooldowns = {}
async def is_blacklisted_guild(self, guild_id): async def is_blacklisted_guild(self, guild_id):
async with aiosqlite.connect('db/block.db') as block_db: async with aiosqlite.connect(db_path('block.db')) as block_db:
cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),)) cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),))
return await cursor.fetchone() is not None return await cursor.fetchone() is not None
@@ -71,7 +71,7 @@ class AntiRoleUpdate(commands.Cog):
if await self.is_blacklisted_guild(guild.id): if await self.is_blacklisted_guild(guild.id):
return return
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor: async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
antinuke_status = await cursor.fetchone() antinuke_status = await cursor.fetchone()
if not antinuke_status or not antinuke_status[0]: if not antinuke_status or not antinuke_status[0]:
@@ -89,7 +89,7 @@ class AntiRoleUpdate(commands.Cog):
if executor.id in {guild.owner_id, self.bot.user.id}: if executor.id in {guild.owner_id, self.bot.user.id}:
return return
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT rlup FROM whitelisted_users WHERE guild_id = ? AND user_id = ?", async with db.execute("SELECT rlup FROM whitelisted_users WHERE guild_id = ? AND user_id = ?",
(guild.id, executor.id)) as cursor: (guild.id, executor.id)) as cursor:
whitelist_status = await cursor.fetchone() whitelist_status = await cursor.fetchone()

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from discord.ext import commands from discord.ext import commands
@@ -58,7 +58,7 @@ class AntiWebhookUpdate(commands.Cog):
return True return True
async def is_blacklisted_guild(self, guild_id): async def is_blacklisted_guild(self, guild_id):
async with aiosqlite.connect('db/block.db') as block_db: async with aiosqlite.connect(db_path('block.db')) as block_db:
cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),)) cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),))
return await cursor.fetchone() is not None return await cursor.fetchone() is not None
@@ -68,7 +68,7 @@ class AntiWebhookUpdate(commands.Cog):
if await self.is_blacklisted_guild(guild.id): if await self.is_blacklisted_guild(guild.id):
return return
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor: async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
antinuke_status = await cursor.fetchone() antinuke_status = await cursor.fetchone()
@@ -87,7 +87,7 @@ class AntiWebhookUpdate(commands.Cog):
if executor.id in {guild.owner_id, self.bot.user.id}: if executor.id in {guild.owner_id, self.bot.user.id}:
return return
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT mngweb FROM whitelisted_users WHERE guild_id = ? AND user_id = ?", async with db.execute("SELECT mngweb FROM whitelisted_users WHERE guild_id = ? AND user_id = ?",
(guild.id, executor.id)) as cursor: (guild.id, executor.id)) as cursor:
whitelist_status = await cursor.fetchone() whitelist_status = await cursor.fetchone()

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from discord.ext import commands from discord.ext import commands
@@ -58,7 +58,7 @@ class AntiWebhookCreate(commands.Cog):
return True return True
async def is_blacklisted_guild(self, guild_id): async def is_blacklisted_guild(self, guild_id):
async with aiosqlite.connect('db/block.db') as block_db: async with aiosqlite.connect(db_path('block.db')) as block_db:
cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),)) cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),))
return await cursor.fetchone() is not None return await cursor.fetchone() is not None
@@ -68,7 +68,7 @@ class AntiWebhookCreate(commands.Cog):
if await self.is_blacklisted_guild(guild.id): if await self.is_blacklisted_guild(guild.id):
return return
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor: async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
antinuke_status = await cursor.fetchone() antinuke_status = await cursor.fetchone()
@@ -87,7 +87,7 @@ class AntiWebhookCreate(commands.Cog):
if executor.id in {guild.owner_id, self.bot.user.id}: if executor.id in {guild.owner_id, self.bot.user.id}:
return return
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT mngweb FROM whitelisted_users WHERE guild_id = ? AND user_id = ?", async with db.execute("SELECT mngweb FROM whitelisted_users WHERE guild_id = ? AND user_id = ?",
(guild.id, executor.id)) as cursor: (guild.id, executor.id)) as cursor:
whitelist_status = await cursor.fetchone() whitelist_status = await cursor.fetchone()

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from discord.ext import commands from discord.ext import commands
@@ -58,7 +58,7 @@ class AntiWebhookDelete(commands.Cog):
return True return True
async def is_blacklisted_guild(self, guild_id): async def is_blacklisted_guild(self, guild_id):
async with aiosqlite.connect('db/block.db') as block_db: async with aiosqlite.connect(db_path('block.db')) as block_db:
cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),)) cursor = await block_db.execute("SELECT 1 FROM guild_blacklist WHERE guild_id = ?", (str(guild_id),))
return await cursor.fetchone() is not None return await cursor.fetchone() is not None
@@ -68,7 +68,7 @@ class AntiWebhookDelete(commands.Cog):
if await self.is_blacklisted_guild(guild.id): if await self.is_blacklisted_guild(guild.id):
return return
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor: async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
antinuke_status = await cursor.fetchone() antinuke_status = await cursor.fetchone()
@@ -87,7 +87,7 @@ class AntiWebhookDelete(commands.Cog):
if executor.id in {guild.owner_id, self.bot.user.id}: if executor.id in {guild.owner_id, self.bot.user.id}:
return return
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT mngweb FROM whitelisted_users WHERE guild_id = ? AND user_id = ?", async with db.execute("SELECT mngweb FROM whitelisted_users WHERE guild_id = ? AND user_id = ?",
(guild.id, executor.id)) as cursor: (guild.id, executor.id)) as cursor:
whitelist_status = await cursor.fetchone() whitelist_status = await cursor.fetchone()

View File

@@ -1,3 +1,4 @@
from utils.db_paths import db_path
import discord import discord
from discord.ext import commands from discord.ext import commands
import aiosqlite import aiosqlite
@@ -29,7 +30,7 @@ class AntiEmojiCreate(commands.Cog):
@commands.Cog.listener() @commands.Cog.listener()
async def on_guild_emojis_update(self, guild, before, after): async def on_guild_emojis_update(self, guild, before, after):
if len(after) > len(before): if len(after) > len(before):
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor: async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
antinuke_status = await cursor.fetchone() antinuke_status = await cursor.fetchone()

View File

@@ -1,3 +1,4 @@
from utils.db_paths import db_path
import discord import discord
from discord.ext import commands from discord.ext import commands
import aiosqlite import aiosqlite
@@ -29,7 +30,7 @@ class AntiEmojiDelete(commands.Cog):
@commands.Cog.listener() @commands.Cog.listener()
async def on_guild_emojis_update(self, guild, before, after): async def on_guild_emojis_update(self, guild, before, after):
if len(after) < len(before): if len(after) < len(before):
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor: async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
antinuke_status = await cursor.fetchone() antinuke_status = await cursor.fetchone()

View File

@@ -1,3 +1,4 @@
from utils.db_paths import db_path
import discord import discord
from discord.ext import commands from discord.ext import commands
import aiosqlite import aiosqlite
@@ -29,7 +30,7 @@ class AntiEmojiUpdate(commands.Cog):
@commands.Cog.listener() @commands.Cog.listener()
async def on_guild_emojis_update(self, guild, before, after): async def on_guild_emojis_update(self, guild, before, after):
if len(after) == len(before): # An emoji was updated if len(after) == len(before): # An emoji was updated
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor: async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
antinuke_status = await cursor.fetchone() antinuke_status = await cursor.fetchone()

View File

@@ -1,3 +1,4 @@
from utils.db_paths import db_path
import discord import discord
from discord.ext import commands from discord.ext import commands
from datetime import timedelta, datetime from datetime import timedelta, datetime
@@ -34,7 +35,7 @@ class AntiSticker(commands.Cog):
else: else:
action = discord.AuditLogAction.sticker_update action = discord.AuditLogAction.sticker_update
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor: async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
antinuke_status = await cursor.fetchone() antinuke_status = await cursor.fetchone()

View File

@@ -1,3 +1,4 @@
from utils.db_paths import db_path
import discord import discord
from discord.ext import commands from discord.ext import commands
import aiosqlite import aiosqlite
@@ -26,7 +27,7 @@ class AntiUnban(commands.Cog):
@commands.Cog.listener() @commands.Cog.listener()
async def on_member_unban(self, guild, user): async def on_member_unban(self, guild, user):
async with aiosqlite.connect('db/anti.db') as db: async with aiosqlite.connect(db_path('anti.db')) as db:
async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor: async with db.execute("SELECT status FROM antinuke WHERE guild_id = ?", (guild.id,)) as cursor:
antinuke_status = await cursor.fetchone() antinuke_status = await cursor.fetchone()

View File

@@ -1,16 +1,17 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
from utils.automod_settings import get_thresholds
import discord import discord
from utils.emoji import TICK from utils.emoji import TICK
@@ -23,38 +24,37 @@ import asyncio
class AntiEmojiSpam(commands.Cog): class AntiEmojiSpam(commands.Cog):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
self.emoji_threshold = 5
async def is_automod_enabled(self, guild_id): async def is_automod_enabled(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT enabled FROM automod WHERE guild_id = ?", (guild_id,)) cursor = await db.execute("SELECT enabled FROM automod WHERE guild_id = ?", (guild_id,))
result = await cursor.fetchone() result = await cursor.fetchone()
return result is not None and result[0] == 1 return result is not None and result[0] == 1
async def is_anti_emoji_spam_enabled(self, guild_id): async def is_anti_emoji_spam_enabled(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti emoji spam'", (guild_id,)) cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti emoji spam'", (guild_id,))
result = await cursor.fetchone() result = await cursor.fetchone()
return result is not None return result is not None
async def get_ignored_channels(self, guild_id): async def get_ignored_channels(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'channel'", (guild_id,)) cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'channel'", (guild_id,))
return [row[0] for row in await cursor.fetchall()] return [row[0] for row in await cursor.fetchall()]
async def get_ignored_roles(self, guild_id): async def get_ignored_roles(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'role'", (guild_id,)) cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'role'", (guild_id,))
return [row[0] for row in await cursor.fetchall()] return [row[0] for row in await cursor.fetchall()]
async def get_punishment(self, guild_id): async def get_punishment(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti emoji spam'", (guild_id,)) cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti emoji spam'", (guild_id,))
result = await cursor.fetchone() result = await cursor.fetchone()
return result[0] if result else None return result[0] if result else None
async def log_action(self, guild, user, channel, action, reason): async def log_action(self, guild, user, channel, action, reason):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild.id,)) cursor = await db.execute("SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild.id,))
log_channel_id = await cursor.fetchone() log_channel_id = await cursor.fetchone()
@@ -118,17 +118,20 @@ class AntiEmojiSpam(commands.Cog):
emoji_count = len(emoji_pattern.findall(message.content)) emoji_count = len(emoji_pattern.findall(message.content))
th = await get_thresholds(guild_id, "anti_emoji_spam")
emoji_threshold = int(th.get("max_emojis", 5))
mute_minutes = float(th.get("mute_minutes", 1))
if emoji_count > self.emoji_threshold: if emoji_count > emoji_threshold:
punishment = await self.get_punishment(guild_id) punishment = await self.get_punishment(guild_id)
action_taken = None action_taken = None
reason = f"Emoji Spam ({emoji_count} emojis)" reason = f"Emoji Spam ({emoji_count} emojis)"
try: try:
if punishment == "Mute": if punishment == "Mute":
timeout_duration = discord.utils.utcnow() + timedelta(minutes=1) timeout_duration = discord.utils.utcnow() + timedelta(minutes=mute_minutes)
await user.edit(timed_out_until=timeout_duration, reason=reason) await user.edit(timed_out_until=timeout_duration, reason=reason)
action_taken = "Muted for 1 minute" action_taken = f"Muted for {int(mute_minutes)} minutes"
elif punishment == "Kick": elif punishment == "Kick":
await user.kick(reason=reason) await user.kick(reason=reason)
action_taken = "Kicked" action_taken = "Kicked"

View File

@@ -1,16 +1,17 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
from utils.automod_settings import get_thresholds
import discord import discord
from utils.emoji import TICK from utils.emoji import TICK
@@ -26,35 +27,35 @@ class AntiInvite(commands.Cog):
self.invite_pattern = re.compile(r'(https?://)?(www\.)?(discord\.gg|discordapp\.com/invite|discord\.com/invite)/\S+') self.invite_pattern = re.compile(r'(https?://)?(www\.)?(discord\.gg|discordapp\.com/invite|discord\.com/invite)/\S+')
async def is_automod_enabled(self, guild_id): async def is_automod_enabled(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT enabled FROM automod WHERE guild_id = ?", (guild_id,)) cursor = await db.execute("SELECT enabled FROM automod WHERE guild_id = ?", (guild_id,))
result = await cursor.fetchone() result = await cursor.fetchone()
return result is not None and result[0] == 1 return result is not None and result[0] == 1
async def is_anti_invites_enabled(self, guild_id): async def is_anti_invites_enabled(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti invites'", (guild_id,)) cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti invites'", (guild_id,))
result = await cursor.fetchone() result = await cursor.fetchone()
return result is not None return result is not None
async def get_ignored_channels(self, guild_id): async def get_ignored_channels(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'channel'", (guild_id,)) cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'channel'", (guild_id,))
return [row[0] for row in await cursor.fetchall()] return [row[0] for row in await cursor.fetchall()]
async def get_ignored_roles(self, guild_id): async def get_ignored_roles(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'role'", (guild_id,)) cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'role'", (guild_id,))
return [row[0] for row in await cursor.fetchall()] return [row[0] for row in await cursor.fetchall()]
async def get_punishment(self, guild_id): async def get_punishment(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti invites'", (guild_id,)) cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti invites'", (guild_id,))
result = await cursor.fetchone() result = await cursor.fetchone()
return result[0] if result else None return result[0] if result else None
async def log_action(self, guild, user, channel, action, reason): async def log_action(self, guild, user, channel, action, reason):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild.id,)) cursor = await db.execute("SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild.id,))
log_channel_id = await cursor.fetchone() log_channel_id = await cursor.fetchone()
@@ -105,15 +106,17 @@ class AntiInvite(commands.Cog):
if any(invite.code == invite_code for invite in invite): if any(invite.code == invite_code for invite in invite):
return return
th = await get_thresholds(guild_id, "anti_invites")
mute_minutes = float(th.get("mute_minutes", 12))
punishment = await self.get_punishment(guild_id) punishment = await self.get_punishment(guild_id)
action_taken = None action_taken = None
reason = "Posted an invite link" reason = "Posted an invite link"
try: try:
if punishment == "Mute": if punishment == "Mute":
timeout_duration = discord.utils.utcnow() + timedelta(minutes=12) timeout_duration = discord.utils.utcnow() + timedelta(minutes=mute_minutes)
await user.edit(timed_out_until=timeout_duration, reason="Posted an invite link") await user.edit(timed_out_until=timeout_duration, reason="Posted an invite link")
action_taken = "Muted for 12 minutes" action_taken = f"Muted for {int(mute_minutes)} minutes"
elif punishment == "Kick": elif punishment == "Kick":
await user.kick(reason="Posted an invite link") await user.kick(reason="Posted an invite link")
action_taken = "Kicked" action_taken = "Kicked"

View File

@@ -1,16 +1,17 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
from utils.automod_settings import get_thresholds
import discord import discord
from utils.emoji import TICK from utils.emoji import TICK
@@ -22,39 +23,38 @@ import asyncio
class AntiMassMention(commands.Cog): class AntiMassMention(commands.Cog):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
self.mass_mention_threshold = 5
async def is_automod_enabled(self, guild_id): async def is_automod_enabled(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT enabled FROM automod WHERE guild_id = ?", (guild_id,)) cursor = await db.execute("SELECT enabled FROM automod WHERE guild_id = ?", (guild_id,))
result = await cursor.fetchone() result = await cursor.fetchone()
return result is not None and result[0] == 1 return result is not None and result[0] == 1
async def is_anti_mass_mention_enabled(self, guild_id): async def is_anti_mass_mention_enabled(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti mass mention'", (guild_id,)) cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti mass mention'", (guild_id,))
result = await cursor.fetchone() result = await cursor.fetchone()
return result is not None return result is not None
async def get_ignored_channels(self, guild_id): async def get_ignored_channels(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'channel'", (guild_id,)) cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'channel'", (guild_id,))
return [row[0] for row in await cursor.fetchall()] return [row[0] for row in await cursor.fetchall()]
async def get_ignored_roles(self, guild_id): async def get_ignored_roles(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'role'", (guild_id,)) cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'role'", (guild_id,))
return [row[0] for row in await cursor.fetchall()] return [row[0] for row in await cursor.fetchall()]
async def get_punishment(self, guild_id): async def get_punishment(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti mass mention'", (guild_id,)) cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti mass mention'", (guild_id,))
result = await cursor.fetchone() result = await cursor.fetchone()
return result[0] if result else None return result[0] if result else None
async def log_action(self, guild, user, channel, action, reason): async def log_action(self, guild, user, channel, action, reason):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild.id,)) cursor = await db.execute("SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild.id,))
log_channel_id = await cursor.fetchone() log_channel_id = await cursor.fetchone()
@@ -97,17 +97,21 @@ class AntiMassMention(commands.Cog):
return return
th = await get_thresholds(guild_id, "anti_mass_mention")
mention_threshold = int(th.get("max_mentions", 5))
mute_minutes = float(th.get("mute_minutes", 3))
mention_count = message.content.count("<@") mention_count = message.content.count("<@")
if mention_count >= self.mass_mention_threshold: if mention_count >= mention_threshold:
punishment = await self.get_punishment(guild_id) punishment = await self.get_punishment(guild_id)
action_taken = None action_taken = None
reason = f"Mass Mention ({mention_count} mentions)" reason = f"Mass Mention ({mention_count} mentions)"
try: try:
if punishment == "Mute": if punishment == "Mute":
timeout_duration = discord.utils.utcnow() + timedelta(minutes=3) timeout_duration = discord.utils.utcnow() + timedelta(minutes=mute_minutes)
await user.edit(timed_out_until=timeout_duration, reason=reason) await user.edit(timed_out_until=timeout_duration, reason=reason)
action_taken = "Muted for 3 minutes" action_taken = f"Muted for {int(mute_minutes)} minutes"
elif punishment == "Kick": elif punishment == "Kick":
await user.kick(reason=reason) await user.kick(reason=reason)
action_taken = "Kicked" action_taken = "Kicked"

View File

@@ -1,16 +1,17 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
from utils.automod_settings import get_thresholds
import discord import discord
from utils.emoji import TICK from utils.emoji import TICK
@@ -22,39 +23,37 @@ from datetime import timedelta
class AntiCaps(commands.Cog): class AntiCaps(commands.Cog):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
self.caps_threshold = 70
self.mute_duration = 2 * 60
async def is_automod_enabled(self, guild_id): async def is_automod_enabled(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT enabled FROM automod WHERE guild_id = ?", (guild_id,)) cursor = await db.execute("SELECT enabled FROM automod WHERE guild_id = ?", (guild_id,))
result = await cursor.fetchone() result = await cursor.fetchone()
return result is not None and result[0] == 1 return result is not None and result[0] == 1
async def is_anti_caps_enabled(self, guild_id): async def is_anti_caps_enabled(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti caps'", (guild_id,)) cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti caps'", (guild_id,))
result = await cursor.fetchone() result = await cursor.fetchone()
return result is not None return result is not None
async def get_ignored_channels(self, guild_id): async def get_ignored_channels(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'channel'", (guild_id,)) cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'channel'", (guild_id,))
return [row[0] for row in await cursor.fetchall()] return [row[0] for row in await cursor.fetchall()]
async def get_ignored_roles(self, guild_id): async def get_ignored_roles(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'role'", (guild_id,)) cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'role'", (guild_id,))
return [row[0] for row in await cursor.fetchall()] return [row[0] for row in await cursor.fetchall()]
async def get_punishment(self, guild_id): async def get_punishment(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti caps'", (guild_id,)) cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti caps'", (guild_id,))
result = await cursor.fetchone() result = await cursor.fetchone()
return result[0] if result else None return result[0] if result else None
async def log_action(self, guild, user, channel, action, reason): async def log_action(self, guild, user, channel, action, reason):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild.id,)) cursor = await db.execute("SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild.id,))
log_channel_id = await cursor.fetchone() log_channel_id = await cursor.fetchone()
@@ -74,9 +73,6 @@ class AntiCaps(commands.Cog):
@commands.Cog.listener() @commands.Cog.listener()
async def on_message(self, message): async def on_message(self, message):
if len(message.content) < 45:
return
if message.author.bot: if message.author.bot:
return return
@@ -85,6 +81,14 @@ class AntiCaps(commands.Cog):
channel = message.channel channel = message.channel
guild_id = guild.id guild_id = guild.id
th = await get_thresholds(guild_id, "anti_caps")
min_length = int(th.get("min_length", 45))
caps_threshold = float(th.get("percent", 70))
mute_minutes = float(th.get("mute_minutes", 1))
if len(message.content) < min_length:
return
if not await self.is_automod_enabled(guild_id) or not await self.is_anti_caps_enabled(guild_id): if not await self.is_automod_enabled(guild_id) or not await self.is_anti_caps_enabled(guild_id):
return return
@@ -103,16 +107,16 @@ class AntiCaps(commands.Cog):
caps_count = sum(1 for c in message.content if c.isupper()) caps_count = sum(1 for c in message.content if c.isupper())
caps_percentage = (caps_count / len(message.content)) * 100 caps_percentage = (caps_count / len(message.content)) * 100
if caps_percentage > self.caps_threshold: if caps_percentage > caps_threshold:
punishment = await self.get_punishment(guild_id) punishment = await self.get_punishment(guild_id)
action_taken = None action_taken = None
reason = "Excessive Caps" reason = "Excessive Caps"
try: try:
if punishment == "Mute": if punishment == "Mute":
timeout_duration = discord.utils.utcnow() + timedelta(minutes=1) timeout_duration = discord.utils.utcnow() + timedelta(minutes=mute_minutes)
await user.edit(timed_out_until=timeout_duration, reason="Excessive Caps") await user.edit(timed_out_until=timeout_duration, reason="Excessive Caps")
action_taken = "Muted for 1 minutes" action_taken = f"Muted for {int(mute_minutes)} minutes"
elif punishment == "Kick": elif punishment == "Kick":
await user.kick(reason="Excessive Caps") await user.kick(reason="Excessive Caps")
action_taken = "Kicked" action_taken = "Kicked"

View File

@@ -1,16 +1,17 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
from utils.automod_settings import get_thresholds
import discord import discord
from utils.emoji import TICK from utils.emoji import TICK
@@ -29,35 +30,35 @@ class AntiLink(commands.Cog):
self.spotify_pattern = re.compile(r'^https://open\.spotify\.com/track/\S+') self.spotify_pattern = re.compile(r'^https://open\.spotify\.com/track/\S+')
async def is_automod_enabled(self, guild_id): async def is_automod_enabled(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT enabled FROM automod WHERE guild_id = ?", (guild_id,)) cursor = await db.execute("SELECT enabled FROM automod WHERE guild_id = ?", (guild_id,))
result = await cursor.fetchone() result = await cursor.fetchone()
return result is not None and result[0] == 1 return result is not None and result[0] == 1
async def is_anti_link_enabled(self, guild_id): async def is_anti_link_enabled(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti link'", (guild_id,)) cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti link'", (guild_id,))
result = await cursor.fetchone() result = await cursor.fetchone()
return result is not None return result is not None
async def get_ignored_channels(self, guild_id): async def get_ignored_channels(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'channel'", (guild_id,)) cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'channel'", (guild_id,))
return [row[0] for row in await cursor.fetchall()] return [row[0] for row in await cursor.fetchall()]
async def get_ignored_roles(self, guild_id): async def get_ignored_roles(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'role'", (guild_id,)) cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'role'", (guild_id,))
return [row[0] for row in await cursor.fetchall()] return [row[0] for row in await cursor.fetchall()]
async def get_punishment(self, guild_id): async def get_punishment(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti link'", (guild_id,)) cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti link'", (guild_id,))
result = await cursor.fetchone() result = await cursor.fetchone()
return result[0] if result else None return result[0] if result else None
async def log_action(self, guild, user, channel, action, reason): async def log_action(self, guild, user, channel, action, reason):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild.id,)) cursor = await db.execute("SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild.id,))
log_channel_id = await cursor.fetchone() log_channel_id = await cursor.fetchone()
@@ -107,15 +108,17 @@ class AntiLink(commands.Cog):
if self.spotify_pattern.search(message.content): if self.spotify_pattern.search(message.content):
return return
th = await get_thresholds(guild_id, "anti_link")
mute_minutes = float(th.get("mute_minutes", 7))
punishment = await self.get_punishment(guild_id) punishment = await self.get_punishment(guild_id)
action_taken = None action_taken = None
reason = "Posted a link" reason = "Posted a link"
try: try:
if punishment == "Mute": if punishment == "Mute":
timeout_duration = discord.utils.utcnow() + timedelta(minutes=7) timeout_duration = discord.utils.utcnow() + timedelta(minutes=mute_minutes)
await user.edit(timed_out_until=timeout_duration, reason=reason) await user.edit(timed_out_until=timeout_duration, reason=reason)
action_taken = "Muted for 7 minutes" action_taken = f"Muted for {int(mute_minutes)} minutes"
elif punishment == "Kick": elif punishment == "Kick":
await user.kick(reason=reason) await user.kick(reason=reason)
action_taken = "Kicked" action_taken = "Kicked"

View File

@@ -1,16 +1,17 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
from utils.automod_settings import get_thresholds
import discord import discord
from utils.emoji import TICK from utils.emoji import TICK
@@ -22,41 +23,39 @@ from datetime import timedelta
class AntiSpam(commands.Cog): class AntiSpam(commands.Cog):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
self.spam_threshold = 5
self.mute_duration = 12 * 60
self.recent_messages = {} self.recent_messages = {}
async def is_automod_enabled(self, guild_id): async def is_automod_enabled(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT enabled FROM automod WHERE guild_id = ?", (guild_id,)) cursor = await db.execute("SELECT enabled FROM automod WHERE guild_id = ?", (guild_id,))
result = await cursor.fetchone() result = await cursor.fetchone()
return result is not None and result[0] == 1 return result is not None and result[0] == 1
async def is_anti_spam_enabled(self, guild_id): async def is_anti_spam_enabled(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti spam'", (guild_id,)) cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti spam'", (guild_id,))
result = await cursor.fetchone() result = await cursor.fetchone()
return result is not None return result is not None
async def get_ignored_channels(self, guild_id): async def get_ignored_channels(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'channel'", (guild_id,)) cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'channel'", (guild_id,))
return [row[0] for row in await cursor.fetchall()] return [row[0] for row in await cursor.fetchall()]
async def get_ignored_roles(self, guild_id): async def get_ignored_roles(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'role'", (guild_id,)) cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'role'", (guild_id,))
return [row[0] for row in await cursor.fetchall()] return [row[0] for row in await cursor.fetchall()]
async def get_punishment(self, guild_id): async def get_punishment(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti spam'", (guild_id,)) cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti spam'", (guild_id,))
result = await cursor.fetchone() result = await cursor.fetchone()
return result[0] if result else None return result[0] if result else None
async def log_action(self, guild, user, channel, action, reason): async def log_action(self, guild, user, channel, action, reason):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild.id,)) cursor = await db.execute("SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild.id,))
log_channel_id = await cursor.fetchone() log_channel_id = await cursor.fetchone()
@@ -99,21 +98,26 @@ class AntiSpam(commands.Cog):
return return
current_time = message.created_at.timestamp() current_time = message.created_at.timestamp()
th = await get_thresholds(guild_id, "anti_spam")
window = float(th.get("window_seconds", 10))
spam_threshold = int(th.get("max_messages", 5))
mute_minutes = float(th.get("mute_minutes", 12))
user_messages = self.recent_messages.get(user.id, []) user_messages = self.recent_messages.get(user.id, [])
user_messages = [msg for msg in user_messages if current_time - msg < 10] user_messages = [msg for msg in user_messages if current_time - msg < window]
user_messages.append(current_time) user_messages.append(current_time)
self.recent_messages[user.id] = user_messages self.recent_messages[user.id] = user_messages
if len(user_messages) > self.spam_threshold: if len(user_messages) > spam_threshold:
punishment = await self.get_punishment(guild_id) punishment = await self.get_punishment(guild_id)
action_taken = None action_taken = None
reason = "Spamming" reason = "Spamming"
try: try:
if punishment == "Mute": if punishment == "Mute":
timeout_duration = discord.utils.utcnow() + timedelta(minutes=12) timeout_duration = discord.utils.utcnow() + timedelta(minutes=mute_minutes)
await user.edit(timed_out_until=timeout_duration, reason="Spamming") await user.edit(timed_out_until=timeout_duration, reason="Spamming")
action_taken = "Muted for 12 minutes" action_taken = f"Muted for {int(mute_minutes)} minutes"
elif punishment == "Kick": elif punishment == "Kick":
await user.kick(reason="Spamming") await user.kick(reason="Spamming")
action_taken = "Kicked" action_taken = "Kicked"

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import jsondb_path
import discord import discord
from discord.ext import commands, tasks from discord.ext import commands, tasks
@@ -56,7 +56,7 @@ class Birthdays(commands.Cog):
@commands.has_permissions(administrator=True) @commands.has_permissions(administrator=True)
@commands.guild_only() @commands.guild_only()
async def birthday_setup(self, ctx: commands.Context, channel: discord.TextChannel, role: discord.Role): async def birthday_setup(self, ctx: commands.Context, channel: discord.TextChannel, role: discord.Role):
db = read_db('jsondb/birthday_logs.json') db = read_db(jsondb_path('birthday_logs.json'))
guild_id = str(ctx.guild.id) guild_id = str(ctx.guild.id)
if guild_id not in db: if guild_id not in db:
@@ -65,7 +65,7 @@ class Birthdays(commands.Cog):
db[guild_id]["birthday_channel_id"] = channel.id db[guild_id]["birthday_channel_id"] = channel.id
db[guild_id]["birthday_role_id"] = role.id db[guild_id]["birthday_role_id"] = role.id
write_db('jsondb/birthday_logs.json', db) write_db(jsondb_path('birthday_logs.json'), db)
await ctx.send(view=CV2("Birthday Setup", f"Birthday log channel set to {channel.mention} and birthday role set to {role.mention}.")) await ctx.send(view=CV2("Birthday Setup", f"Birthday log channel set to {channel.mention} and birthday role set to {role.mention}."))
@@ -104,9 +104,9 @@ class Birthdays(commands.Cog):
return return
date = f"{month}-{day}-{year}" date = f"{month}-{day}-{year}"
db = read_db('jsondb/birthdays.json') db = read_db(jsondb_path('birthdays.json'))
db[str(ctx.author.id)] = date db[str(ctx.author.id)] = date
write_db('jsondb/birthdays.json', db) write_db(jsondb_path('birthdays.json'), db)
await ctx.send(view=CV2("Success", f"Your birthday has been set to {date}.")) await ctx.send(view=CV2("Success", f"Your birthday has been set to {date}."))
except asyncio.TimeoutError: except asyncio.TimeoutError:
@@ -117,11 +117,11 @@ class Birthdays(commands.Cog):
help="Remove your birthday.") help="Remove your birthday.")
@commands.guild_only() @commands.guild_only()
async def remove_birthday(self, ctx: commands.Context): async def remove_birthday(self, ctx: commands.Context):
db = read_db('jsondb/birthdays.json') db = read_db(jsondb_path('birthdays.json'))
if str(ctx.author.id) in db: if str(ctx.author.id) in db:
del db[str(ctx.author.id)] del db[str(ctx.author.id)]
write_db('jsondb/birthdays.json', db) write_db(jsondb_path('birthdays.json'), db)
await ctx.send(view=CV2("Success", "Your birthday has been removed.")) await ctx.send(view=CV2("Success", "Your birthday has been removed."))
else: else:
await ctx.send(view=CV2("Error", "You have no birthday set.")) await ctx.send(view=CV2("Error", "You have no birthday set."))
@@ -133,7 +133,7 @@ class Birthdays(commands.Cog):
async def list_birthdays(self, ctx: commands.Context): async def list_birthdays(self, ctx: commands.Context):
now = datetime.datetime.now() now = datetime.datetime.now()
today_date = now.strftime("%m-%d") today_date = now.strftime("%m-%d")
db = read_db('jsondb/birthdays.json') db = read_db(jsondb_path('birthdays.json'))
members_with_birthday = [ctx.guild.get_member(int(user_id)) for user_id, date in db.items() if date.startswith(today_date)] members_with_birthday = [ctx.guild.get_member(int(user_id)) for user_id, date in db.items() if date.startswith(today_date)]
@@ -148,7 +148,7 @@ class Birthdays(commands.Cog):
help="Check your birthday.") help="Check your birthday.")
@commands.guild_only() @commands.guild_only()
async def check_birthday(self, ctx: commands.Context): async def check_birthday(self, ctx: commands.Context):
db = read_db('jsondb/birthdays.json') db = read_db(jsondb_path('birthdays.json'))
if str(ctx.author.id) in db: if str(ctx.author.id) in db:
date = db[str(ctx.author.id)] date = db[str(ctx.author.id)]
@@ -160,8 +160,8 @@ class Birthdays(commands.Cog):
async def check_birthdays(self): async def check_birthdays(self):
now = datetime.datetime.now() now = datetime.datetime.now()
today_date = now.strftime("%m-%d") today_date = now.strftime("%m-%d")
db = read_db('jsondb/birthdays.json') db = read_db(jsondb_path('birthdays.json'))
guild_settings = read_db('jsondb/birthday_logs.json') guild_settings = read_db(jsondb_path('birthday_logs.json'))
for user_id, birthday in db.items(): for user_id, birthday in db.items():
if birthday.startswith(today_date): if birthday.startswith(today_date):

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,21 +1,20 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
import discord import discord
from discord.ext import commands from discord.ext import commands
import os import os
from core import Cog, zyrox, Context from core import Cog, Axiom, Context
import games as games import games as games
from utils.Tools import * from utils.Tools import *
from utils.cv2 import CV2 from utils.cv2 import CV2
@@ -26,15 +25,30 @@ import asyncio
class Games(Cog): class Games(Cog):
"""Zyrox Games""" """Axiom Games"""
def __init__(self, client: zyrox): def __init__(self, client: Axiom):
self.client = client self.client = client
@commands.hybrid_group(
name="game",
description="Play mini-games with friends or the bot.",
fallback="help",
invoke_without_command=True,
)
@blacklist_check()
@ignore_check()
@commands.cooldown(1, 3, commands.BucketType.user)
@commands.guild_only()
async def game(self, ctx: Context):
"""Games root — use `/game <subcommand>` or `>game <subcommand>`."""
if ctx.subcommand_passed is None:
await ctx.send_help(ctx.command)
ctx.command.reset_cooldown(ctx)
@commands.hybrid_command(name="chess", @game.command(name="chess",
help="Play Chess with a user.", help="Play Chess with a user.",
usage="Chess <user>") usage="game chess <user>")
@blacklist_check() @blacklist_check()
@ignore_check() @ignore_check()
@commands.cooldown(1, 3, commands.BucketType.user) @commands.cooldown(1, 3, commands.BucketType.user)
@@ -50,10 +64,10 @@ class Games(Cog):
await game.start(ctx) await game.start(ctx)
@commands.hybrid_command(name="rps", @game.command(name="rps",
help="Play Rock Paper Scissor with bot/user.", help="Play Rock Paper Scissor with bot/user.",
aliases=["rockpaperscissors"], aliases=["rockpaperscissors"],
usage="Rockpaperscissors") usage="game rps [user]")
@blacklist_check() @blacklist_check()
@ignore_check() @ignore_check()
@commands.cooldown(1, 3, commands.BucketType.user) @commands.cooldown(1, 3, commands.BucketType.user)
@@ -63,10 +77,10 @@ class Games(Cog):
game = btn.BetaRockPaperScissors(player) game = btn.BetaRockPaperScissors(player)
await game.start(ctx, timeout=120) await game.start(ctx, timeout=120)
@commands.hybrid_command(name="tic-tac-toe", @game.command(name="tictactoe",
help="play tic-tac-toe game with a user.", help="play tic-tac-toe game with a user.",
aliases=["ttt", "tictactoe"], aliases=["ttt", "tic-tac-toe"],
usage="Ticktactoe <member>") usage="game tictactoe <member>")
@blacklist_check() @blacklist_check()
@ignore_check() @ignore_check()
@commands.cooldown(1, 3, commands.BucketType.user) @commands.cooldown(1, 3, commands.BucketType.user)
@@ -81,9 +95,9 @@ class Games(Cog):
game = btn.BetaTictactoe(cross=ctx.author, circle=player) game = btn.BetaTictactoe(cross=ctx.author, circle=player)
await game.start(ctx, timeout=30) await game.start(ctx, timeout=30)
@commands.hybrid_command(name="wordle", @game.command(name="wordle",
help="Wordle Game | Play with bot.", help="Wordle Game | Play with bot.",
usage="Wordle") usage="game wordle")
@blacklist_check() @blacklist_check()
@ignore_check() @ignore_check()
@commands.cooldown(1, 3, commands.BucketType.user) @commands.cooldown(1, 3, commands.BucketType.user)
@@ -93,10 +107,10 @@ class Games(Cog):
game = games.Wordle() game = games.Wordle()
await game.start(ctx, timeout=120) await game.start(ctx, timeout=120)
@commands.hybrid_command(name="2048", @game.command(name="2048",
help="Play 2048 game with bot.", help="Play 2048 game with bot.",
aliases=["twenty48"], aliases=["twenty48"],
usage="2048") usage="game 2048")
@blacklist_check() @blacklist_check()
@ignore_check() @ignore_check()
@commands.cooldown(1, 3, commands.BucketType.user) @commands.cooldown(1, 3, commands.BucketType.user)
@@ -106,10 +120,10 @@ class Games(Cog):
game = btn.BetaTwenty48() game = btn.BetaTwenty48()
await game.start(ctx, win_at=2048) await game.start(ctx, win_at=2048)
@commands.hybrid_command(name="memory-game", @game.command(name="memory",
help="How strong is your memory?", help="How strong is your memory?",
aliases=["memory"], aliases=["memory-game"],
usage="memory-game") usage="game memory")
@blacklist_check() @blacklist_check()
@ignore_check() @ignore_check()
@commands.cooldown(1, 3, commands.BucketType.user) @commands.cooldown(1, 3, commands.BucketType.user)
@@ -119,10 +133,10 @@ class Games(Cog):
game = btn.MemoryGame() game = btn.MemoryGame()
await game.start(ctx) await game.start(ctx)
@commands.hybrid_command(name="number-slider", @game.command(name="slider",
help="slide numbers with bot", help="slide numbers with bot",
aliases=["slider"], aliases=["number-slider"],
usage="slider") usage="game slider")
@blacklist_check() @blacklist_check()
@ignore_check() @ignore_check()
@commands.cooldown(1, 3, commands.BucketType.user) @commands.cooldown(1, 3, commands.BucketType.user)
@@ -132,10 +146,10 @@ class Games(Cog):
game = btn.NumberSlider() game = btn.NumberSlider()
await game.start(ctx) await game.start(ctx)
@commands.hybrid_command(name="battleship", @game.command(name="battleship",
help="Play battleship game with your friend.", help="Play battleship game with your friend.",
aliases=["battle-ship"], aliases=["battle-ship"],
usage="battleship <user>") usage="game battleship <user>")
@blacklist_check() @blacklist_check()
@ignore_check() @ignore_check()
@commands.cooldown(1, 3, commands.BucketType.user) @commands.cooldown(1, 3, commands.BucketType.user)
@@ -165,10 +179,10 @@ class Games(Cog):
async def _end_country_guesser(self, ctx: Context): async def _end_country_guesser(self, ctx: Context):
await self.country_guesser_game.end_game_manually(ctx)""" await self.country_guesser_game.end_game_manually(ctx)"""
@commands.hybrid_command(name="connectfour", @game.command(name="connectfour",
help="Play Connect Four game with user.", help="Play Connect Four game with user.",
aliases=["c4", "connect-four", "connect4"], aliases=["c4", "connect-four", "connect4"],
usage="connectfour <user>") usage="game connectfour <user>")
@blacklist_check() @blacklist_check()
@ignore_check() @ignore_check()
@commands.cooldown(1, 3, commands.BucketType.user) @commands.cooldown(1, 3, commands.BucketType.user)
@@ -185,10 +199,10 @@ class Games(Cog):
@commands.hybrid_command(name="lights-out", @game.command(name="lightsout",
help="Play Lights Show game with bot.", help="Play Lights Show game with bot.",
aliases=["lightsout"], aliases=["lights-out"],
usage="Lights-out") usage="game lightsout")
@blacklist_check() @blacklist_check()
@ignore_check() @ignore_check()
@commands.cooldown(1, 3, commands.BucketType.user) @commands.cooldown(1, 3, commands.BucketType.user)

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from discord.ext import commands from discord.ext import commands
@@ -23,7 +23,7 @@ from utils.config import *
class Invcrole(commands.Cog): class Invcrole(commands.Cog):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
self.db_path = 'db/invc.db' self.db_path = db_path('invc.db')
self.bot.loop.create_task(self.create_table()) self.bot.loop.create_task(self.create_table())
async def create_table(self): async def create_table(self):

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
import aiosqlite import aiosqlite
@@ -27,7 +27,7 @@ class Media(commands.Cog):
async def set_db(self): async def set_db(self):
async with aiosqlite.connect('db/media.db') as db: async with aiosqlite.connect(db_path('media.db')) as db:
await db.execute(''' await db.execute('''
CREATE TABLE IF NOT EXISTS media_channels ( CREATE TABLE IF NOT EXISTS media_channels (
guild_id INTEGER PRIMARY KEY, guild_id INTEGER PRIMARY KEY,
@@ -47,7 +47,13 @@ class Media(commands.Cog):
async def on_ready(self): async def on_ready(self):
await self.set_db() await self.set_db()
@commands.hybrid_group(name="media", help="Setup Media channel, Media channel will not allow users to send messages other than media files.", invoke_without_command=True) @commands.hybrid_group(
name="media",
description="Setup Media channel; only media files are allowed.",
help="Setup Media channel, Media channel will not allow users to send messages other than media files.",
fallback="help",
invoke_without_command=True,
)
@blacklist_check() @blacklist_check()
@ignore_check() @ignore_check()
@commands.cooldown(1, 3, commands.BucketType.user) @commands.cooldown(1, 3, commands.BucketType.user)
@@ -62,7 +68,7 @@ class Media(commands.Cog):
@commands.cooldown(1, 3, commands.BucketType.user) @commands.cooldown(1, 3, commands.BucketType.user)
@commands.has_permissions(administrator=True) @commands.has_permissions(administrator=True)
async def setup(self, ctx, *, channel: discord.TextChannel): async def setup(self, ctx, *, channel: discord.TextChannel):
async with aiosqlite.connect('db/media.db') as db: async with aiosqlite.connect(db_path('media.db')) as db:
async with db.execute('SELECT channel_id FROM media_channels WHERE guild_id = ?', (ctx.guild.id,)) as cursor: async with db.execute('SELECT channel_id FROM media_channels WHERE guild_id = ?', (ctx.guild.id,)) as cursor:
result = await cursor.fetchone() result = await cursor.fetchone()
if result: if result:
@@ -80,7 +86,7 @@ class Media(commands.Cog):
@commands.cooldown(1, 3, commands.BucketType.user) @commands.cooldown(1, 3, commands.BucketType.user)
@commands.has_permissions(administrator=True) @commands.has_permissions(administrator=True)
async def remove(self, ctx): async def remove(self, ctx):
async with aiosqlite.connect('db/media.db') as db: async with aiosqlite.connect(db_path('media.db')) as db:
async with db.execute('SELECT channel_id FROM media_channels WHERE guild_id = ?', (ctx.guild.id,)) as cursor: async with db.execute('SELECT channel_id FROM media_channels WHERE guild_id = ?', (ctx.guild.id,)) as cursor:
result = await cursor.fetchone() result = await cursor.fetchone()
if not result: if not result:
@@ -98,7 +104,7 @@ class Media(commands.Cog):
@commands.cooldown(1, 3, commands.BucketType.user) @commands.cooldown(1, 3, commands.BucketType.user)
@commands.has_permissions(administrator=True) @commands.has_permissions(administrator=True)
async def config(self, ctx): async def config(self, ctx):
async with aiosqlite.connect('db/media.db') as db: async with aiosqlite.connect(db_path('media.db')) as db:
async with db.execute('SELECT channel_id FROM media_channels WHERE guild_id = ?', (ctx.guild.id,)) as cursor: async with db.execute('SELECT channel_id FROM media_channels WHERE guild_id = ?', (ctx.guild.id,)) as cursor:
result = await cursor.fetchone() result = await cursor.fetchone()
if not result: if not result:
@@ -124,7 +130,7 @@ class Media(commands.Cog):
@commands.cooldown(1, 3, commands.BucketType.user) @commands.cooldown(1, 3, commands.BucketType.user)
@commands.has_permissions(administrator=True) @commands.has_permissions(administrator=True)
async def bypass_add(self, ctx, user: discord.Member): async def bypass_add(self, ctx, user: discord.Member):
async with aiosqlite.connect('db/media.db') as db: async with aiosqlite.connect(db_path('media.db')) as db:
async with db.execute('SELECT COUNT(*) FROM media_bypass WHERE guild_id = ?', (ctx.guild.id,)) as cursor: async with db.execute('SELECT COUNT(*) FROM media_bypass WHERE guild_id = ?', (ctx.guild.id,)) as cursor:
count = await cursor.fetchone() count = await cursor.fetchone()
if count[0] >= 25: if count[0] >= 25:
@@ -148,7 +154,7 @@ class Media(commands.Cog):
@commands.cooldown(1, 3, commands.BucketType.user) @commands.cooldown(1, 3, commands.BucketType.user)
@commands.has_permissions(administrator=True) @commands.has_permissions(administrator=True)
async def bypass_remove(self, ctx, user: discord.Member): async def bypass_remove(self, ctx, user: discord.Member):
async with aiosqlite.connect('db/media.db') as db: async with aiosqlite.connect(db_path('media.db')) as db:
async with db.execute('SELECT 1 FROM media_bypass WHERE guild_id = ? AND user_id = ?', (ctx.guild.id, user.id)) as cursor: async with db.execute('SELECT 1 FROM media_bypass WHERE guild_id = ? AND user_id = ?', (ctx.guild.id, user.id)) as cursor:
result = await cursor.fetchone() result = await cursor.fetchone()
if not result: if not result:
@@ -166,7 +172,7 @@ class Media(commands.Cog):
@commands.cooldown(1, 3, commands.BucketType.user) @commands.cooldown(1, 3, commands.BucketType.user)
@commands.has_permissions(administrator=True) @commands.has_permissions(administrator=True)
async def bypass_show(self, ctx): async def bypass_show(self, ctx):
async with aiosqlite.connect('db/media.db') as db: async with aiosqlite.connect(db_path('media.db')) as db:
async with db.execute('SELECT user_id FROM media_bypass WHERE guild_id = ?', (ctx.guild.id,)) as cursor: async with db.execute('SELECT user_id FROM media_bypass WHERE guild_id = ?', (ctx.guild.id,)) as cursor:
result = await cursor.fetchall() result = await cursor.fetchall()
if not result: if not result:
@@ -183,16 +189,16 @@ class Media(commands.Cog):
if message.author.bot: if message.author.bot:
return return
async with aiosqlite.connect('db/media.db') as db: async with aiosqlite.connect(db_path('media.db')) as db:
async with db.execute('SELECT channel_id FROM media_channels WHERE guild_id = ?', (message.guild.id,)) as cursor: async with db.execute('SELECT channel_id FROM media_channels WHERE guild_id = ?', (message.guild.id,)) as cursor:
media_channel = await cursor.fetchone() media_channel = await cursor.fetchone()
if media_channel and message.channel.id == media_channel[0]: if media_channel and message.channel.id == media_channel[0]:
async with aiosqlite.connect('db/block.db') as block_db: async with aiosqlite.connect(db_path('block.db')) as block_db:
async with block_db.execute('SELECT 1 FROM user_blacklist WHERE user_id = ?', (message.author.id,)) as cursor: async with block_db.execute('SELECT 1 FROM user_blacklist WHERE user_id = ?', (message.author.id,)) as cursor:
blacklisted = await cursor.fetchone() blacklisted = await cursor.fetchone()
async with aiosqlite.connect('db/media.db') as db: async with aiosqlite.connect(db_path('media.db')) as db:
async with db.execute('SELECT 1 FROM media_bypass WHERE guild_id = ? AND user_id = ?', (message.guild.id, message.author.id)) as cursor: async with db.execute('SELECT 1 FROM media_bypass WHERE guild_id = ? AND user_id = ?', (message.guild.id, message.author.id)) as cursor:
bypassed = await cursor.fetchone() bypassed = await cursor.fetchone()
@@ -221,7 +227,7 @@ class Media(commands.Cog):
] ]
if len(self.infractions[message.author.id]) >= 5: if len(self.infractions[message.author.id]) >= 5:
async with aiosqlite.connect('db/block.db') as block_db: async with aiosqlite.connect(db_path('block.db')) as block_db:
await block_db.execute('INSERT OR IGNORE INTO user_blacklist (user_id) VALUES (?)', (message.author.id,)) await block_db.execute('INSERT OR IGNORE INTO user_blacklist (user_id) VALUES (?)', (message.author.id,))
await block_db.commit() await block_db.commit()

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from discord.ext import commands from discord.ext import commands
@@ -24,7 +24,7 @@ from utils.cv2 import CV2, build_container
from utils.emoji import TICK, MENTION, SEED, TIME from utils.emoji import TICK, MENTION, SEED, TIME
from utils.config import * from utils.config import *
DB_PATH = "db/afk.db" DB_PATH = db_path("afk.db")
THEME_COLOR = 0xFF0000 THEME_COLOR = 0xFF0000
FOOTER_TEXT = f"Developed by {BRAND_NAME}" FOOTER_TEXT = f"Developed by {BRAND_NAME}"

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import os import os
import discord import discord
@@ -323,19 +323,19 @@ class AI (commands .Cog ):
import os import os
db_path ="db/ai_data.db" ai_db = db_path("ai_data.db")
if os .path .exists (db_path ): if os .path .exists (ai_db ):
try : try :
test_conn =await aiosqlite .connect (db_path ) test_conn =await aiosqlite .connect (ai_db )
await test_conn .execute ("SELECT name FROM sqlite_master WHERE type='table';") await test_conn .execute ("SELECT name FROM sqlite_master WHERE type='table';")
await test_conn .close () await test_conn .close ()
except Exception as e : except Exception as e :
os .remove (db_path ) os .remove (ai_db )
logger .info ("Removed corrupted AI database, creating new one") logger .info ("Removed corrupted AI database, creating new one")
self .bot .db =await aiosqlite .connect (db_path ) self .bot .db =await aiosqlite .connect (ai_db )
logger .info ("AI database connection initialized") logger .info ("AI database connection initialized")
await self .bot .db .execute (""" await self .bot .db .execute ("""
@@ -401,12 +401,12 @@ class AI (commands .Cog ):
import aiosqlite import aiosqlite
import os import os
db_path ="db/ai_data.db" ai_db = db_path("ai_data.db")
if not os .path .exists (db_path ): if not os .path .exists (ai_db ):
logger .info ("AI database doesn't exist, will be created on first use") logger .info ("AI database doesn't exist, will be created on first use")
return return
self .bot .db =await aiosqlite .connect (db_path ) self .bot .db =await aiosqlite .connect (ai_db )
logger .info ("AI database connection initialized for loading") logger .info ("AI database connection initialized for loading")
@@ -590,7 +590,7 @@ class AI (commands .Cog ):
system_context .append ({ system_context .append ({
"role":"system", "role":"system",
"content":"You are a Discord bot with many features including moderation, entertainment, music, games, AI capabilities, and utilities. Support server: https://discord.gg/codexdev" "content":"You are a Discord bot with many features including moderation, entertainment, music, games, AI capabilities, and utilities. Support server: https://discord.gg/hexahost"
}) })
else : else :
@@ -602,7 +602,7 @@ You have a caring, helpful personality and can remember conversations with users
Be natural, conversational, and genuine in your responses. Don't be overly formal or robotic. Use the conversation history to provide personalized responses that feel like talking to a real friend who happens to be very knowledgeable and helpful. Be natural, conversational, and genuine in your responses. Don't be overly formal or robotic. Use the conversation history to provide personalized responses that feel like talking to a real friend who happens to be very knowledgeable and helpful.
Support server: https://discord.gg/codexdev""" Support server: https://discord.gg/hexahost"""
}) })

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from utils.emoji import CROSS, MANAGER, REDDOT, TICK from utils.emoji import CROSS, MANAGER, REDDOT, TICK
@@ -31,7 +31,7 @@ class Unwhitelist(commands.Cog):
#@commands.Cog.listener() #@commands.Cog.listener()
async def initialize_db(self): async def initialize_db(self):
self.db = await aiosqlite.connect('db/anti.db') self.db = await aiosqlite.connect(db_path('anti.db'))
@commands.hybrid_command(name='unwhitelist', aliases=['unwl'], help="Unwhitelist a user from antinuke") @commands.hybrid_command(name='unwhitelist', aliases=['unwl'], help="Unwhitelist a user from antinuke")
@commands.has_permissions(administrator=True) @commands.has_permissions(administrator=True)

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from utils.emoji import ARROWRED, CROSS, DISABLE, ENABLE, MANAGER, TICK from utils.emoji import ARROWRED, CROSS, DISABLE, ENABLE, MANAGER, TICK
@@ -32,7 +32,7 @@ class Whitelist(commands.Cog):
#@commands.Cog.listener() #@commands.Cog.listener()
async def initialize_db(self): async def initialize_db(self):
self.db = await aiosqlite.connect('db/anti.db') self.db = await aiosqlite.connect(db_path('anti.db'))
await self.db.execute(''' await self.db.execute('''
CREATE TABLE IF NOT EXISTS whitelisted_users ( CREATE TABLE IF NOT EXISTS whitelisted_users (
guild_id INTEGER, guild_id INTEGER,
@@ -57,16 +57,34 @@ class Whitelist(commands.Cog):
''') ''')
await self.db.commit() await self.db.commit()
@commands.hybrid_command(name='whitelist', aliases=['wl'], help="Whitelists a user from antinuke for a specific action.") @commands.hybrid_group(
name="whitelist",
aliases=["wl"],
description="Manage antinuke whitelist.",
fallback="help",
invoke_without_command=True,
help="Whitelists a user from antinuke for a specific action.",
)
@blacklist_check() @blacklist_check()
@ignore_check() @ignore_check()
@commands.cooldown(1, 5, commands.BucketType.user) @commands.cooldown(1, 5, commands.BucketType.user)
@commands.max_concurrency(1, per=commands.BucketType.default, wait=False) @commands.max_concurrency(1, per=commands.BucketType.default, wait=False)
@commands.guild_only() @commands.guild_only()
@commands.has_permissions(administrator=True) @commands.has_permissions(administrator=True)
async def whitelist(self, ctx):
"""Whitelist root — use `/whitelist <subcommand>` or `>whitelist <subcommand>`."""
if ctx.subcommand_passed is None:
await ctx.send_help(ctx.command)
ctx.command.reset_cooldown(ctx)
async def whitelist(self, ctx, member: discord.Member = None): @whitelist.command(name="add", help="Whitelists a user from antinuke for a specific action.")
@blacklist_check()
@ignore_check()
@commands.cooldown(1, 5, commands.BucketType.user)
@commands.max_concurrency(1, per=commands.BucketType.default, wait=False)
@commands.guild_only()
@commands.has_permissions(administrator=True)
async def whitelist_add(self, ctx, member: discord.Member = None):
if ctx.guild.member_count < 2: if ctx.guild.member_count < 2:
view = CV2(f"{CROSS} Error", "Your Server Doesn't Meet My 30 Member Criteria") view = CV2(f"{CROSS} Error", "Your Server Doesn't Meet My 30 Member Criteria")
return await ctx.send(view=view) return await ctx.send(view=view)
@@ -101,7 +119,7 @@ class Whitelist(commands.Cog):
view = CV2( view = CV2(
"__Whitelist Commands__", "__Whitelist Commands__",
"**Adding a user to the whitelist means that no actions will be taken against them if they trigger the Anti-Nuke Module.**", "**Adding a user to the whitelist means that no actions will be taken against them if they trigger the Anti-Nuke Module.**",
f"**Usage**\n{ARROWRED} `{prefix}whitelist @user/id`\n{ARROWRED} `{prefix}wl @user`" f"**Usage**\n{ARROWRED} `{prefix}whitelist add @user/id`\n{ARROWRED} `{prefix}wl add @user`"
) )
return await ctx.send(view=view) return await ctx.send(view=view)
@@ -252,7 +270,7 @@ class Whitelist(commands.Cog):
await msg.edit(view=None) await msg.edit(view=None)
@commands.hybrid_command(name='whitelisted', aliases=['wlist'], help="Shows the list of whitelisted users.") @whitelist.command(name="list", aliases=["whitelisted", "wlist"], help="Shows the list of whitelisted users.")
@blacklist_check() @blacklist_check()
@ignore_check() @ignore_check()
@commands.cooldown(1, 5, commands.BucketType.user) @commands.cooldown(1, 5, commands.BucketType.user)
@@ -308,7 +326,7 @@ class Whitelist(commands.Cog):
await ctx.send(view=view) await ctx.send(view=view)
@commands.hybrid_command(name="whitelistreset", aliases=['wlreset'], help="Resets the whitelisted users.") @whitelist.command(name="reset", aliases=["whitelistreset", "wlreset"], help="Resets the whitelisted users.")
@blacklist_check() @blacklist_check()
@ignore_check() @ignore_check()
@commands.cooldown(1, 10, commands.BucketType.user) @commands.cooldown(1, 10, commands.BucketType.user)

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from utils.emoji import CROSS, EMOTE, TICK, ZSAFE, ZSETTINGS from utils.emoji import CROSS, EMOTE, TICK, ZSAFE, ZSETTINGS
@@ -31,7 +31,7 @@ class Antinuke(commands.Cog):
self.bot.loop.create_task(self.initialize_db()) self.bot.loop.create_task(self.initialize_db())
async def initialize_db(self): async def initialize_db(self):
self.db = await aiosqlite.connect('db/anti.db') self.db = await aiosqlite.connect(db_path('anti.db'))
await self.db.execute(''' await self.db.execute('''
CREATE TABLE IF NOT EXISTS antinuke ( CREATE TABLE IF NOT EXISTS antinuke (
guild_id INTEGER PRIMARY KEY, guild_id INTEGER PRIMARY KEY,

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from utils.emoji import CROSS, DISABLE, ENABLE, TICK, TICK_ALT from utils.emoji import CROSS, DISABLE, ENABLE, TICK, TICK_ALT
@@ -113,7 +113,7 @@ class Automod(commands.Cog):
self.bot.loop.create_task(self.init_db()) self.bot.loop.create_task(self.init_db())
async def get_exempt_roles_channels(self, guild_id): async def get_exempt_roles_channels(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
roles_cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'role'", (guild_id,)) roles_cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'role'", (guild_id,))
channels_cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'channel'", (guild_id,)) channels_cursor = await db.execute("SELECT id FROM automod_ignored WHERE guild_id = ? AND type = 'channel'", (guild_id,))
@@ -124,18 +124,18 @@ class Automod(commands.Cog):
async def is_automod_enabled(self, guild_id): async def is_automod_enabled(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT enabled FROM automod WHERE guild_id = ?", (guild_id,)) cursor = await db.execute("SELECT enabled FROM automod WHERE guild_id = ?", (guild_id,))
result = await cursor.fetchone() result = await cursor.fetchone()
return result is not None and result[0] == 1 return result is not None and result[0] == 1
async def update_punishments(self, guild_id, event, punishment): async def update_punishments(self, guild_id, event, punishment):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
await db.execute("INSERT OR REPLACE INTO automod_punishments (guild_id, event, punishment) VALUES (?, ?, ?)", (guild_id, event, punishment)) await db.execute("INSERT OR REPLACE INTO automod_punishments (guild_id, event, punishment) VALUES (?, ?, ?)", (guild_id, event, punishment))
await db.commit() await db.commit()
async def get_current_punishments(self, guild_id): async def get_current_punishments(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
async with db.execute( async with db.execute(
"SELECT event, punishment FROM automod_punishments WHERE guild_id = ? AND event != 'Anti NSFW link'", "SELECT event, punishment FROM automod_punishments WHERE guild_id = ? AND event != 'Anti NSFW link'",
(guild_id,) (guild_id,)
@@ -143,7 +143,7 @@ class Automod(commands.Cog):
return await cursor.fetchall() return await cursor.fetchall()
async def is_anti_nsfw_enabled(self, guild_id): async def is_anti_nsfw_enabled(self, guild_id):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti NSFW link'", (guild_id,)) cursor = await db.execute("SELECT punishment FROM automod_punishments WHERE guild_id = ? AND event = 'Anti NSFW link'", (guild_id,))
result = await cursor.fetchone() result = await cursor.fetchone()
return result is not None return result is not None
@@ -151,7 +151,7 @@ class Automod(commands.Cog):
async def init_db(self): async def init_db(self):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
await db.execute(""" await db.execute("""
CREATE TABLE IF NOT EXISTS automod ( CREATE TABLE IF NOT EXISTS automod (
guild_id INTEGER PRIMARY KEY, guild_id INTEGER PRIMARY KEY,
@@ -181,13 +181,30 @@ class Automod(commands.Cog):
PRIMARY KEY (guild_id) PRIMARY KEY (guild_id)
) )
""") """)
await db.execute("""
CREATE TABLE IF NOT EXISTS automod_thresholds (
guild_id INTEGER,
event TEXT,
key TEXT,
value REAL,
PRIMARY KEY (guild_id, event, key)
)
""")
await db.commit() await db.commit()
@commands.hybrid_group(invoke_without_command=True) @commands.hybrid_group(
name="automod",
aliases=["am"],
invoke_without_command=True,
with_app_command=True,
description="Configure server Automod (enable, disable, punishments, ignores).",
fallback="help",
)
@blacklist_check() @blacklist_check()
@ignore_check() @ignore_check()
@commands.cooldown(1, 4, commands.BucketType.user) @commands.cooldown(1, 4, commands.BucketType.user)
async def automod(self, ctx): async def automod(self, ctx):
"""Automod root — use `/automod <subcommand>` or `>automod <subcommand>`."""
if ctx.subcommand_passed is None: if ctx.subcommand_passed is None:
await ctx.send_help(ctx.command) await ctx.send_help(ctx.command)
ctx.command.reset_cooldown(ctx) ctx.command.reset_cooldown(ctx)
@@ -271,7 +288,7 @@ class Automod(commands.Cog):
async def enable_automod(self, ctx, guild_id, selected_events, interaction): async def enable_automod(self, ctx, guild_id, selected_events, interaction):
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
await db.execute("INSERT OR REPLACE INTO automod (guild_id, enabled) VALUES (?, 1)", (guild_id,)) await db.execute("INSERT OR REPLACE INTO automod (guild_id, enabled) VALUES (?, 1)", (guild_id,))
for event in selected_events: for event in selected_events:
await db.execute("INSERT OR REPLACE INTO automod_punishments (guild_id, event, punishment) VALUES (?, ?, ?)", (guild_id, event, self.default_punishment)) await db.execute("INSERT OR REPLACE INTO automod_punishments (guild_id, event, punishment) VALUES (?, ?, ?)", (guild_id, event, self.default_punishment))
@@ -328,7 +345,7 @@ class Automod(commands.Cog):
log_channel = await interaction.guild.create_text_channel(f"{BRAND_NAME.lower()}-automod", overwrites=overwrites) log_channel = await interaction.guild.create_text_channel(f"{BRAND_NAME.lower()}-automod", overwrites=overwrites)
guild_id = interaction.guild.id guild_id = interaction.guild.id
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
await db.execute("INSERT OR REPLACE INTO automod_logging (guild_id, log_channel) VALUES (?, ?)", (guild_id, log_channel.id)) await db.execute("INSERT OR REPLACE INTO automod_logging (guild_id, log_channel) VALUES (?, ?)", (guild_id, log_channel.id))
await db.commit() await db.commit()
@@ -440,7 +457,7 @@ class Automod(commands.Cog):
await ctx.send(view=CV2(f"Automod Settings for {ctx.guild.name}", f"Uhh, looks like your server hasn\'t enabled Automoderation.\n\nCurrent Status: {DISABLE} Disabled\nTo Enable use `{ctx.prefix}automod enable`")) await ctx.send(view=CV2(f"Automod Settings for {ctx.guild.name}", f"Uhh, looks like your server hasn\'t enabled Automoderation.\n\nCurrent Status: {DISABLE} Disabled\nTo Enable use `{ctx.prefix}automod enable`"))
return return
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT 1 FROM automod_ignored WHERE guild_id = ? AND type = 'channel' AND id = ?", (guild_id, channel.id)) cursor = await db.execute("SELECT 1 FROM automod_ignored WHERE guild_id = ? AND type = 'channel' AND id = ?", (guild_id, channel.id))
if await cursor.fetchone() is not None: if await cursor.fetchone() is not None:
await ctx.send(view=CV2("__Channel Already Whitelisted!__", f"{CROSS} The channel {channel.mention} is already in the ignore list.\n\n➜ Use **{ctx.prefix}automod unignore channel {channel.mention}** to remove it.")) await ctx.send(view=CV2("__Channel Already Whitelisted!__", f"{CROSS} The channel {channel.mention} is already in the ignore list.\n\n➜ Use **{ctx.prefix}automod unignore channel {channel.mention}** to remove it."))
@@ -491,7 +508,7 @@ class Automod(commands.Cog):
await ctx.send(view=CV2(f"Automod Settings for {ctx.guild.name}", f"Uhh, looks like your server hasn\'t enabled Automoderation.\n\nCurrent Status: {DISABLE} Disabled\nTo Enable use `{ctx.prefix}automod enable`")) await ctx.send(view=CV2(f"Automod Settings for {ctx.guild.name}", f"Uhh, looks like your server hasn\'t enabled Automoderation.\n\nCurrent Status: {DISABLE} Disabled\nTo Enable use `{ctx.prefix}automod enable`"))
return return
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT 1 FROM automod_ignored WHERE guild_id = ? AND type = 'role' AND id = ?", (guild_id, role.id)) cursor = await db.execute("SELECT 1 FROM automod_ignored WHERE guild_id = ? AND type = 'role' AND id = ?", (guild_id, role.id))
if await cursor.fetchone() is not None: if await cursor.fetchone() is not None:
@@ -545,7 +562,7 @@ class Automod(commands.Cog):
return return
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT type, id FROM automod_ignored WHERE guild_id = ?", (guild_id,)) cursor = await db.execute("SELECT type, id FROM automod_ignored WHERE guild_id = ?", (guild_id,))
ignored_items = await cursor.fetchall() ignored_items = await cursor.fetchall()
@@ -592,7 +609,7 @@ class Automod(commands.Cog):
await ctx.send(view=CV2(f"Automod Settings for {ctx.guild.name}", f"Uhh, looks like your server hasn\'t enabled Automoderation.\n\nCurrent Status: {DISABLE} Disabled\nTo Enable use `{ctx.prefix}automod enable`")) await ctx.send(view=CV2(f"Automod Settings for {ctx.guild.name}", f"Uhh, looks like your server hasn\'t enabled Automoderation.\n\nCurrent Status: {DISABLE} Disabled\nTo Enable use `{ctx.prefix}automod enable`"))
return return
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
await db.execute("DELETE FROM automod_ignored WHERE guild_id = ?", (guild_id,)) await db.execute("DELETE FROM automod_ignored WHERE guild_id = ?", (guild_id,))
await db.commit() await db.commit()
await ctx.send(view=CV2(f"Automod Settings for {ctx.guild.name}", f"** {TICK} | All ignored channels and roles have been reset!**\n\nTo view current Automod settings use `{ctx.prefix}automod config`")) await ctx.send(view=CV2(f"Automod Settings for {ctx.guild.name}", f"** {TICK} | All ignored channels and roles have been reset!**\n\nTo view current Automod settings use `{ctx.prefix}automod config`"))
@@ -639,7 +656,7 @@ class Automod(commands.Cog):
except discord.HTTPException: except discord.HTTPException:
pass pass
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
result = await db.execute("DELETE FROM automod_ignored WHERE guild_id = ? AND type = 'channel' AND id = ?", (guild_id, channel.id)) result = await db.execute("DELETE FROM automod_ignored WHERE guild_id = ? AND type = 'channel' AND id = ?", (guild_id, channel.id))
await db.commit() await db.commit()
@@ -682,7 +699,7 @@ class Automod(commands.Cog):
pass pass
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
result = await db.execute("DELETE FROM automod_ignored WHERE guild_id = ? AND type = 'role' AND id = ?", (guild_id, role.id)) result = await db.execute("DELETE FROM automod_ignored WHERE guild_id = ? AND type = 'role' AND id = ?", (guild_id, role.id))
await db.commit() await db.commit()
@@ -719,7 +736,7 @@ class Automod(commands.Cog):
elif view.value: elif view.value:
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
await db.execute("DELETE FROM automod WHERE guild_id = ?", (guild_id,)) await db.execute("DELETE FROM automod WHERE guild_id = ?", (guild_id,))
await db.execute("DELETE FROM automod_punishments WHERE guild_id = ?", (guild_id,)) await db.execute("DELETE FROM automod_punishments WHERE guild_id = ?", (guild_id,))
await db.execute("DELETE FROM automod_ignored WHERE guild_id = ?", (guild_id,)) await db.execute("DELETE FROM automod_ignored WHERE guild_id = ?", (guild_id,))
@@ -768,7 +785,7 @@ class Automod(commands.Cog):
items_str.append(f"**{event}**: {punishment or 'None'}") items_str.append(f"**{event}**: {punishment or 'None'}")
if await self.is_anti_nsfw_enabled(guild_id): if await self.is_anti_nsfw_enabled(guild_id):
items_str.append("**Anti NSFW Links**: Block Message") items_str.append("**Anti NSFW Links**: Block Message")
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
cursor = await db.execute("SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild_id,)) cursor = await db.execute("SELECT log_channel FROM automod_logging WHERE guild_id = ?", (guild_id,))
log_channel_id = await cursor.fetchone() log_channel_id = await cursor.fetchone()
if log_channel_id and log_channel_id[0]: if log_channel_id and log_channel_id[0]:
@@ -799,7 +816,7 @@ class Automod(commands.Cog):
await ctx.send(view=CV2(f"Automod Settings for {ctx.guild.name}", f"Uhh, looks like your server hasn\'t enabled Automoderation.\n\nCurrent Status: {DISABLE} Disabled\nTo Enable use `{ctx.prefix}automod enable`")) await ctx.send(view=CV2(f"Automod Settings for {ctx.guild.name}", f"Uhh, looks like your server hasn\'t enabled Automoderation.\n\nCurrent Status: {DISABLE} Disabled\nTo Enable use `{ctx.prefix}automod enable`"))
return return
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
await db.execute("INSERT OR REPLACE INTO automod_logging (guild_id, log_channel) VALUES (?, ?)", (guild_id, channel.id)) await db.execute("INSERT OR REPLACE INTO automod_logging (guild_id, log_channel) VALUES (?, ?)", (guild_id, channel.id))
await db.commit() await db.commit()
await ctx.send(view=CV2(f"Automod Settings for {ctx.guild.name}", f"**{TICK} | Automoderation Logging channel set to {channel.mention}.**\n\n➜ Use `{ctx.prefix}automod config` to view current Automod settings.")) await ctx.send(view=CV2(f"Automod Settings for {ctx.guild.name}", f"**{TICK} | Automoderation Logging channel set to {channel.mention}.**\n\n➜ Use `{ctx.prefix}automod config` to view current Automod settings."))
@@ -809,7 +826,7 @@ class Automod(commands.Cog):
async def on_guild_remove(self, guild): async def on_guild_remove(self, guild):
guild_id = guild.id guild_id = guild.id
async with aiosqlite.connect("db/automod.db") as db: async with aiosqlite.connect(db_path("automod.db")) as db:
await db.execute("DELETE FROM automod WHERE guild_id = ?", (guild_id,)) await db.execute("DELETE FROM automod WHERE guild_id = ?", (guild_id,))
await db.execute("DELETE FROM automod_punishments WHERE guild_id = ?", (guild_id,)) await db.execute("DELETE FROM automod_punishments WHERE guild_id = ?", (guild_id,))
await db.execute("DELETE FROM automod_ignored WHERE guild_id = ?", (guild_id,)) await db.execute("DELETE FROM automod_ignored WHERE guild_id = ?", (guild_id,))

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from utils.emoji import CROSS, ICONS_WARNING, TICK from utils.emoji import CROSS, ICONS_WARNING, TICK
@@ -28,7 +28,7 @@ from utils.cv2 import CV2, build_container
class AutoReaction(commands.Cog): class AutoReaction(commands.Cog):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
self.db_path = 'db/autoreact.db' self.db_path = db_path('autoreact.db')
self.bot.loop.create_task(self.setup_database()) self.bot.loop.create_task(self.setup_database())
async def setup_database(self): async def setup_database(self):

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from utils.emoji import CROSS, TICK from utils.emoji import CROSS, TICK
@@ -25,7 +25,7 @@ from utils.cv2 import CV2, build_container
DB_PATH = "db/autoresponder.db" DB_PATH = db_path("autoresponder.db")
class AutoResponder(commands.Cog): class AutoResponder(commands.Cog):
def __init__(self, bot): def __init__(self, bot):

View File

@@ -1,18 +1,18 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from __future__ import annotations from __future__ import annotations
from utils.db_paths import db_path
import discord import discord
from utils.emoji import CROSS, ICONS_WARNING, TICK from utils.emoji import CROSS, ICONS_WARNING, TICK
import aiosqlite import aiosqlite
@@ -33,7 +33,7 @@ logging.basicConfig(
datefmt="%H:%M:%S", datefmt="%H:%M:%S",
) )
DATABASE_PATH = 'db/autorole.db' DATABASE_PATH = db_path('autorole.db')
class BasicView(discord.ui.View): class BasicView(discord.ui.View):
def __init__(self, ctx: commands.Context, timeout=60): def __init__(self, ctx: commands.Context, timeout=60):

View File

@@ -1,14 +1,13 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝

View File

@@ -1,16 +1,16 @@
# ╔══════════════════════════════════════════════════════════════════╗ # ╔══════════════════════════════════════════════════════════════════╗
# ║ ║ # ║ ║
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ # ║ |H|e|x|a|H|o|s|t|
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ # ║ +-+-+-+-+-+-+-+-+
# ║ ║ # ║ ║
# ║ © 2026 CodeX Devs — All Rights Reserved ║ # ║ © 2026 HexaHost — All Rights Reserved
# ║ ║ # ║ ║
# ║ discord ── https://discord.gg/codexdev # ║ discord ── https://discord.gg/hexahost
# ║ youtube ── https://youtube.com/@CodeXDevs # ║ github ── https://github.com/theoneandonlymace
# ║ github ── https://github.com/RayExo ║
# ║ ║ # ║ ║
# ╚══════════════════════════════════════════════════════════════════╝ # ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
import discord import discord
from utils.emoji import CROSS, TICK from utils.emoji import CROSS, TICK
@@ -55,7 +55,7 @@ class BlacklistWordSource(menus.ListPageSource):
return embed return embed
DB_PATH = "db/blword.db" DB_PATH = db_path("blword.db")
async def create_blacklist_table(): async def create_blacklist_table():

Some files were not shown because too many files have changed in this diff Show More