Compare commits
23 Commits
cd68e42de2
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f57cccea5 | ||
|
|
36b32de34c | ||
|
|
d24b810164 | ||
|
|
a52d84467d | ||
|
|
1da2085087 | ||
|
|
20193404e8 | ||
|
|
299351463c | ||
|
|
6b0091f7d5 | ||
|
|
fc77f0a3c2 | ||
|
|
f15c869993 | ||
|
|
60390009d1 | ||
|
|
18ef29f777 | ||
|
|
9006b06c09 | ||
|
|
8294c1b4f7 | ||
|
|
831a3ac8ea | ||
|
|
698d61ec6d | ||
|
|
daf3338382 | ||
|
|
03c8f2ec2c | ||
|
|
7dca4fb77a | ||
|
|
9bcde844da | ||
|
|
41d5841d82 | ||
|
|
b4110c3d66 | ||
| 5f34db4f3b |
50
.env.docker.example
Normal file
50
.env.docker.example
Normal 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
76
.github/workflows/ci.yml
vendored
Normal 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
6
.gitignore
vendored
@@ -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
201
DOCKER.md
Normal 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.
|
||||||
2
LICENSE
2
LICENSE
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|
||||||
|
|||||||
50
README.md
50
README.md
@@ -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>
|
||||||
|
|||||||
@@ -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
19
bot/.dockerignore
Normal 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
|
||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
29
bot/Dockerfile
Normal 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"]
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -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.
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
BIN
bot/assets/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 188 KiB |
3
bot/assets/logo.svg
Normal file
3
bot/assets/logo.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 500 KiB |
@@ -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.")
|
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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]:
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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]:
|
||||||
|
|||||||
@@ -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]:
|
||||||
|
|||||||
@@ -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]:
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
@@ -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):
|
||||||
|
|||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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}"
|
||||||
|
|
||||||
|
|||||||
@@ -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"""
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,))
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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 ║
|
|
||||||
# ║ ║
|
# ║ ║
|
||||||
# ╚══════════════════════════════════════════════════════════════════╝
|
# ╚══════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
|
|||||||
@@ -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
Reference in New Issue
Block a user