Skip to content

Commit 9da61f3

Browse files
committed
Fixed incorrect improts and paths according to the new layout
1 parent da42473 commit 9da61f3

14 files changed

Lines changed: 3475 additions & 3335 deletions

File tree

ARCHITECTURE.md

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Architecture
2+
3+
This file summarizes the runtime architecture and data model of the bot as implemented in the repository. It is derived directly from the code (index.js, utils, events, models).
4+
5+
## High-level components
6+
7+
- index.js
8+
- Loads commands and events dynamically from `commands/` and `events/`.
9+
- Initializes the `Database` singleton (`utils/database.js`) which wraps `models/schemas.js`.
10+
- Starts `TaskScheduler` (`utils/scheduler.js`) for periodic jobs.
11+
- Rotates bot presence and handles graceful shutdown and global error handlers.
12+
- Command loader
13+
- `deploy-commands.js` scans `commands/`, uses `SlashCommandBuilder` JSON via `command.data.toJSON()` and registers commands via Discord REST API.
14+
- Events
15+
- `events/interactionCreate.js` — central handler for slash commands, buttons, modals, select menus; enforces per-command cooldowns and handles many interactive flows (tickets, AI modals, truth-or-dare, feedback).
16+
- `events/messageCreate.js` — XP tracking, message-based AI auto-responses (when configured), and related side-effects.
17+
- Other events: `ready.js`, `guildMemberAdd.js`, `modalCreate.js`, `voiceStateUpdate.js`, `helpInteraction.js`.
18+
- Database layer
19+
- `utils/database.js` exposes model methods and utility functions for server config, user profile, tickets, AI rate limits, XP transactions, leaderboards, birthdays, shop items, anti-raid, and guild economy.
20+
- Models defined in `models/schemas.js` (see Data Models below).
21+
- Background scheduler
22+
- `utils/scheduler.js` uses `node-cron` to run:
23+
- daily resets (midnight UTC)
24+
- weekly resets (Monday midnight UTC)
25+
- hourly leaderboard updates
26+
- role checks every 30 minutes
27+
- birthday checks daily at 8:00 UTC
28+
29+
## Data models (high-level)
30+
31+
- ServerConfig — per-guild configuration: `aiEnabled`, `aiContext`, `aiChannels`, `aiMode`, `ticketCategoryId`, `ticketLogChannelId`, XP and role automation settings, birthday config, etc.
32+
- UserProfile — per-user-per-guild profile: `userId`, `guildId`, `wallet`, `bank`, `totalXp`, `level`, `messageCount`, `voiceMinutes`, `points`, `currentRoles`, `dailyStreak`, timestamps.
33+
- Ticket — support ticket records with messages array, status, priority, moderatorId, closedAt.
34+
- AIRateLimit — per-user rate limiting for AI requests (requestCount, lastRequest, resetAt).
35+
- XPTransaction — XP audit log entries.
36+
- Leaderboard — cached top users per guild.
37+
- Birthday — birthday records.
38+
- GuildEconomy, ShopItem, TruthOrDareConfig, AntiRaid — specialized configuration schemas.
39+
40+
(See `models/schemas.js` for full field lists and indexes.)
41+
42+
## Runtime flow
43+
44+
1. Startup (`node index.js`)
45+
- `index.js` loads commands and events and attempts to connect to MongoDB using `MONGODB_URI`.
46+
- Scheduler is created and registered.
47+
- Bot logs in with `DISCORD_TOKEN`.
48+
2. Interaction flow
49+
- Slash commands: `events/interactionCreate.js` receives chat input commands, enforces cooldowns, and calls the command's `execute(interaction, client)`.
50+
- Buttons/selects/modals: `interactionCreate` dispatches UI interactions to helper handlers (tickets, help navigation, AI modals, truth-or-dare buttons).
51+
3. Message flow
52+
- `messageCreate.js` handles XP awarding (rate-limited per user/time) and message-based AI auto-responses when the server `ServerConfig` allows it.
53+
4. Scheduler tasks
54+
- Cron jobs perform resets, leaderboard updates, and role assignment checks.
55+
56+
## Command & event structure
57+
58+
- Each command file exports at least `data` (SlashCommandBuilder) and `execute` function.
59+
- Commands may include a `cooldown` property (seconds) used by the interaction handler.
60+
- Commands are organized in folders (fun, moderation, economy, xp, ai, truth-or-dare, etc.).
61+
62+
## External integrations
63+
64+
- Discord (discord.js v14) — main runtime and components
65+
- MongoDB (mongoose) — persistence
66+
- Google Gemini via `@google/genai` — AI assistant features (requires `GEMINI_API_KEY`)
67+
- node-cron — scheduling
68+
69+
## Environment variables required by code
70+
71+
- `DISCORD_TOKEN` (required) — bot token
72+
- `CLIENT_ID` (required for `deploy-commands.js`) — application id
73+
- `GUILD_ID` (optional) — when present `deploy-commands.js` deploys commands to that guild
74+
- `MONGODB_URI` (required) — MongoDB connection string
75+
- `GEMINI_API_KEY` (optional) — Google Gemini key for AI
76+
- `PORT` (optional) — not used by default; an express server is present but commented out
77+
78+
## Permissions & Intents
79+
80+
- Intents requested in `index.js`: `Guilds`, `GuildMembers`, `GuildMessages`, `MessageContent`, `GuildMessageReactions`, `GuildVoiceStates`, `GuildPresences`.
81+
- Privileged intents (Message Content, Guild Members, Presences) must be enabled in the Discord Developer Portal to use the corresponding features.
82+
- Bot requires typical moderation permissions depending on features used (Ban/Kick, ManageChannels for tickets, ManageRoles for automatic role assignment, ManageMessages for purge, EmbedLinks + SendMessages).
83+
84+
## Scaling & operational notes
85+
86+
- Scheduler runs in-process; running multiple instances will duplicate scheduled jobs unless you coordinate (e.g., leader election or single scheduler process).
87+
- Database connections are per-process (the `Database` singleton avoids re-connecting repeatedly in the same process).
88+
- Consider using Redis or another cache if you need high-throughput leaderboards or cross-process rate-limiting.
89+
90+
## Extending the bot
91+
92+
- Add new commands: create a file in `commands/<category>/` exporting `data` and `execute`. Run `node deploy-commands.js` to register slash commands.
93+
- Add new events: place a new file in `events/` exporting `{ name, execute, once? }` and the loader in `index.js` will attach it.
94+
- New DB models: update `models/schemas.js` and expose them via `utils/database.js` for convenience.

commands/antimodules/antiraid.js

Lines changed: 143 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1,148 +1,162 @@
11
const { SlashCommandBuilder, EmbedBuilder } = require("discord.js");
2-
const Database = require("../../../utils/database");
2+
const Database = require("../../utils/database");
33

44
module.exports = {
5-
data: new SlashCommandBuilder()
6-
.setName("antiraid")
7-
.setDescription("🛡️ Simple anti-raid protection")
8-
.addSubcommand((subcommand) =>
9-
subcommand
10-
.setName("enable")
11-
.setDescription("Enable anti-raid protection")
12-
)
13-
.addSubcommand((subcommand) =>
14-
subcommand
15-
.setName("disable")
16-
.setDescription("Disable anti-raid protection")
17-
)
18-
.addSubcommand((subcommand) =>
19-
subcommand
20-
.setName("status")
21-
.setDescription("Check anti-raid status")
22-
),
5+
data: new SlashCommandBuilder()
6+
.setName("antiraid")
7+
.setDescription("🛡️ Simple anti-raid protection")
8+
.addSubcommand((subcommand) =>
9+
subcommand
10+
.setName("enable")
11+
.setDescription("Enable anti-raid protection"),
12+
)
13+
.addSubcommand((subcommand) =>
14+
subcommand
15+
.setName("disable")
16+
.setDescription("Disable anti-raid protection"),
17+
)
18+
.addSubcommand((subcommand) =>
19+
subcommand.setName("status").setDescription("Check anti-raid status"),
20+
),
2321

24-
async execute(interaction) {
25-
if (!interaction.member.permissions.has("Administrator")) {
26-
return interaction.reply({
27-
embeds: [
28-
new EmbedBuilder()
29-
.setColor("#ff0000")
30-
.setTitle("❌ No Permission")
31-
.setDescription("You need Administrator permissions to use this command.")
32-
],
33-
flags: 64
34-
});
35-
}
22+
async execute(interaction) {
23+
if (!interaction.member.permissions.has("Administrator")) {
24+
return interaction.reply({
25+
embeds: [
26+
new EmbedBuilder()
27+
.setColor("#ff0000")
28+
.setTitle("❌ No Permission")
29+
.setDescription(
30+
"You need Administrator permissions to use this command.",
31+
),
32+
],
33+
flags: 64,
34+
});
35+
}
3636

37-
const subcommand = interaction.options.getSubcommand();
37+
const subcommand = interaction.options.getSubcommand();
3838

39-
try {
40-
const db = Database; // Use the exported instance
41-
await db.ensureConnection(); // Ensure connection is established
42-
43-
switch (subcommand) {
44-
case "enable":
45-
await handleEnable(interaction, db);
46-
break;
47-
case "disable":
48-
await handleDisable(interaction, db);
49-
break;
50-
case "status":
51-
await handleStatus(interaction, db);
52-
break;
53-
}
54-
} catch (error) {
55-
console.error("Anti-raid command error:", error);
56-
57-
await interaction.reply({
58-
embeds: [
59-
new EmbedBuilder()
60-
.setColor("#ff0000")
61-
.setTitle("❌ Error")
62-
.setDescription("An error occurred while processing anti-raid command.")
63-
],
64-
flags: 64
65-
});
66-
}
67-
},
39+
try {
40+
const db = await Database.getInstance();
41+
await db.ensureConnection();
42+
43+
switch (subcommand) {
44+
case "enable":
45+
await handleEnable(interaction, db);
46+
break;
47+
case "disable":
48+
await handleDisable(interaction, db);
49+
break;
50+
case "status":
51+
await handleStatus(interaction, db);
52+
break;
53+
}
54+
} catch (error) {
55+
console.error("Anti-raid command error:", error);
56+
57+
await interaction.reply({
58+
embeds: [
59+
new EmbedBuilder()
60+
.setColor("#ff0000")
61+
.setTitle("❌ Error")
62+
.setDescription(
63+
"An error occurred while processing anti-raid command.",
64+
),
65+
],
66+
flags: 64,
67+
});
68+
}
69+
},
6870
};
6971

7072
async function handleEnable(interaction, db) {
71-
try {
72-
await db.GuildConfig.findOneAndUpdate(
73-
{ guildId: interaction.guild.id },
74-
{
75-
$set: {
76-
antiRaidEnabled: true,
77-
antiRaidThreshold: 5,
78-
antiRaidTimeWindow: 10000 // 10 seconds
79-
}
80-
},
81-
{ upsert: true, new: true }
82-
);
73+
try {
74+
await db.GuildConfig.findOneAndUpdate(
75+
{ guildId: interaction.guild.id },
76+
{
77+
$set: {
78+
antiRaidEnabled: true,
79+
antiRaidThreshold: 5,
80+
antiRaidTimeWindow: 10000, // 10 seconds
81+
},
82+
},
83+
{ upsert: true, new: true },
84+
);
8385

84-
await interaction.reply({
85-
embeds: [
86-
new EmbedBuilder()
87-
.setColor("#00ff00")
88-
.setTitle("✅ Anti-Raid Enabled")
89-
.setDescription("Anti-raid protection has been enabled with default settings.")
90-
.addFields(
91-
{ name: "Threshold", value: "5 joins", inline: true },
92-
{ name: "Time Window", value: "10 seconds", inline: true }
93-
)
94-
]
95-
});
96-
} catch (error) {
97-
console.error("Error enabling anti-raid:", error);
98-
throw error;
99-
}
86+
await interaction.reply({
87+
embeds: [
88+
new EmbedBuilder()
89+
.setColor("#00ff00")
90+
.setTitle("✅ Anti-Raid Enabled")
91+
.setDescription(
92+
"Anti-raid protection has been enabled with default settings.",
93+
)
94+
.addFields(
95+
{ name: "Threshold", value: "5 joins", inline: true },
96+
{ name: "Time Window", value: "10 seconds", inline: true },
97+
),
98+
],
99+
});
100+
} catch (error) {
101+
console.error("Error enabling anti-raid:", error);
102+
throw error;
103+
}
100104
}
101105

102106
async function handleDisable(interaction, db) {
103-
try {
104-
await db.GuildConfig.findOneAndUpdate(
105-
{ guildId: interaction.guild.id },
106-
{ $set: { antiRaidEnabled: false } },
107-
{ upsert: true, new: true }
108-
);
107+
try {
108+
await db.GuildConfig.findOneAndUpdate(
109+
{ guildId: interaction.guild.id },
110+
{ $set: { antiRaidEnabled: false } },
111+
{ upsert: true, new: true },
112+
);
109113

110-
await interaction.reply({
111-
embeds: [
112-
new EmbedBuilder()
113-
.setColor("#ff0000")
114-
.setTitle("❌ Anti-Raid Disabled")
115-
.setDescription("Anti-raid protection has been disabled.")
116-
]
117-
});
118-
} catch (error) {
119-
console.error("Error disabling anti-raid:", error);
120-
throw error;
121-
}
114+
await interaction.reply({
115+
embeds: [
116+
new EmbedBuilder()
117+
.setColor("#ff0000")
118+
.setTitle("❌ Anti-Raid Disabled")
119+
.setDescription("Anti-raid protection has been disabled."),
120+
],
121+
});
122+
} catch (error) {
123+
console.error("Error disabling anti-raid:", error);
124+
throw error;
125+
}
122126
}
123127

124128
async function handleStatus(interaction, db) {
125-
try {
126-
const config = await db.GuildConfig.findOne({ guildId: interaction.guild.id });
127-
128-
const isEnabled = config?.antiRaidEnabled || false;
129-
const threshold = config?.antiRaidThreshold || 5;
130-
const timeWindow = config?.antiRaidTimeWindow || 10000;
129+
try {
130+
const config = await db.GuildConfig.findOne({
131+
guildId: interaction.guild.id,
132+
});
133+
134+
const isEnabled = config?.antiRaidEnabled || false;
135+
const threshold = config?.antiRaidThreshold || 5;
136+
const timeWindow = config?.antiRaidTimeWindow || 10000;
131137

132-
await interaction.reply({
133-
embeds: [
134-
new EmbedBuilder()
135-
.setColor(isEnabled ? "#00ff00" : "#ff0000")
136-
.setTitle("🛡️ Anti-Raid Status")
137-
.addFields(
138-
{ name: "Status", value: isEnabled ? "✅ Enabled" : "❌ Disabled", inline: true },
139-
{ name: "Threshold", value: `${threshold} joins`, inline: true },
140-
{ name: "Time Window", value: `${timeWindow / 1000} seconds`, inline: true }
141-
)
142-
]
143-
});
144-
} catch (error) {
145-
console.error("Error checking anti-raid status:", error);
146-
throw error;
147-
}
138+
await interaction.reply({
139+
embeds: [
140+
new EmbedBuilder()
141+
.setColor(isEnabled ? "#00ff00" : "#ff0000")
142+
.setTitle("🛡️ Anti-Raid Status")
143+
.addFields(
144+
{
145+
name: "Status",
146+
value: isEnabled ? "✅ Enabled" : "❌ Disabled",
147+
inline: true,
148+
},
149+
{ name: "Threshold", value: `${threshold} joins`, inline: true },
150+
{
151+
name: "Time Window",
152+
value: `${timeWindow / 1000} seconds`,
153+
inline: true,
154+
},
155+
),
156+
],
157+
});
158+
} catch (error) {
159+
console.error("Error checking anti-raid status:", error);
160+
throw error;
161+
}
148162
}

0 commit comments

Comments
 (0)