Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
52769a3
:truck: Change tree of the event folder
Derpinou May 2, 2022
4c1b3cf
:zap: Client class optimization
Derpinou May 2, 2022
d4f4d3b
:rocket: Add a Database class for managing database cache and methods
Derpinou May 2, 2022
b03165e
:rocket: Add application command body (test)
Derpinou May 2, 2022
fec8758
:rocket: Support application commands registering
Derpinou May 2, 2022
442252e
:heavy_plus_sign: update opus, rest, discord-api-types, update some d…
Derpinou May 2, 2022
1b1d28e
:zap: Clean code & adapt to database changes
Derpinou May 2, 2022
1f72bb1
:alembic: Make in comment dbl auto post
Derpinou May 2, 2022
9a9099b
:card_file_box: Adding forgotted function
Derpinou May 3, 2022
7564e2b
:card_file_box: Performing database related changes.
Derpinou May 3, 2022
fcd50ac
:fire: Remove aliases (deprecated with / commands)
Derpinou May 3, 2022
032566e
:card_file_box: Performing database related changes.
Derpinou May 3, 2022
1fe02d7
:bug: Fixing bug from Collection#array() to Collection#toJSON()
Derpinou May 3, 2022
26fcabe
:fire: Remove getPrefix() method
Derpinou May 4, 2022
031dc55
:bulb: Comment code for dev
Derpinou May 4, 2022
a58f02e
:heavy_plus_sign: Add MongoDB
Derpinou May 4, 2022
1a0b95e
:card_file_box: Performing database related changes.
Derpinou May 11, 2022
1367d24
:sparkles: Introducing commands permissions
Derpinou May 11, 2022
2c9bc32
:sparkles: Support interaction
Derpinou May 11, 2022
1bce623
:sparkles: Add interactionCreate
Derpinou May 11, 2022
4c68ad1
:zap: Remove commands
Derpinou May 11, 2022
bebf0d2
:arrow_up: Upgrading mongoose version
Derpinou May 11, 2022
cb82340
:rocket: Add interaction support
Derpinou May 11, 2022
1febf68
:art: Use power of 10 instead some 0
Derpinou May 11, 2022
2d1a77c
:fire: Remove file for create messageCreate file
Derpinou May 11, 2022
e41101a
:wrench: Changing configuration files.
Derpinou May 11, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 1 addition & 48 deletions atlanta.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
require("./helpers/extenders");

const Sentry = require("@sentry/node"),
util = require("util"),
fs = require("fs"),
readdir = util.promisify(fs.readdir),
mongoose = require("mongoose"),
chalk = require("chalk");

const config = require("./config");
Expand All @@ -21,50 +17,7 @@ if(config.apiKeys.sentryDSN){
const Atlanta = require("./base/Atlanta"),
client = new Atlanta();

const init = async () => {

// Search for all commands
const directories = await readdir("./commands/");
client.logger.log(`Loading a total of ${directories.length} categories.`, "log");
directories.forEach(async (dir) => {
const commands = await readdir("./commands/"+dir+"/");
commands.filter((cmd) => cmd.split(".").pop() === "js").forEach((cmd) => {
const response = client.loadCommand("./commands/"+dir, cmd);
if(response){
client.logger.log(response, "error");
}
});
});

// Then we load events, which will include our message and ready event.
const evtFiles = await readdir("./events/");
client.logger.log(`Loading a total of ${evtFiles.length} events.`, "log");
evtFiles.forEach((file) => {
const eventName = file.split(".")[0];
client.logger.log(`Loading Event: ${eventName}`);
const event = new (require(`./events/${file}`))(client);
client.on(eventName, (...args) => event.run(...args));
delete require.cache[require.resolve(`./events/${file}`)];
});

client.login(client.config.token); // Log in to the discord api

// connect to mongoose database
mongoose.connect(client.config.mongoDB, { useNewUrlParser: true, useUnifiedTopology: true }).then(() => {
client.logger.log("Connected to the Mongodb database.", "log");
}).catch((err) => {
client.logger.log("Unable to connect to the Mongodb database. Error:"+err, "error");
});

const languages = require("./helpers/languages");
client.translations = await languages();

const autoUpdateDocs = require("./helpers/autoUpdateDocs.js");
autoUpdateDocs.update(client);

};

init();
client.init().catch(console.error);

// if there are errors, log them
client.on("disconnect", () => client.logger.log("Bot is disconnecting...", "warn"))
Expand Down
179 changes: 92 additions & 87 deletions base/Atlanta.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,18 @@ const { MessageEmbed, Util, Client, Collection, Intents } = require("discord.js"
const { GiveawaysManager } = require("discord-giveaways");
const { Player } = require("discord-player");
const { Client: Joker } = require("blague.xyz");
const { readdir } = require("fs/promises");
const { REST } = require("@discordjs/rest");
const { Routes } = require("discord-api-types/v9");

const util = require("util"),
AmeClient = require("amethyste-api"),
path = require("path"),
moment = require("moment");
const {sep} = require("path");
const mongoose = require("mongoose");
const languages = require("../helpers/languages");
const autoUpdateDocs = require("../helpers/autoUpdateDocs");

moment.relativeTimeThreshold("s", 60);
moment.relativeTimeThreshold("ss", 5);
Expand Down Expand Up @@ -36,32 +43,23 @@ class Atlanta extends Client {
this.customEmojis = require("../emojis.json"); // load the bot's emojis
this.languages = require("../languages/language-meta.json"); // Load the bot's languages
this.commands = new Collection(); // Creates new commands collection
this.aliases = new Collection(); // Creates new command aliases collection
this.logger = require("../helpers/logger"); // Load the logger file
this.wait = util.promisify(setTimeout); // client.wait(1000) - Wait 1 second
this.functions = require("../helpers/functions"); // Load the functions file
this.guildsData = require("../base/Guild"); // Guild mongoose model
this.usersData = require("../base/User"); // User mongoose model
this.membersData = require("../base/Member"); // Member mongoose model
this.logs = require("../base/Log"); // Log mongoose model
this.dashboard = require("../dashboard/app"); // Dashboard app
this.queues = new Collection(); // This collection will be used for the music
this.states = {}; // Used for the dashboard
this.knownGuilds = [];
this.database = new (require("./database"))(this); // Load the database file
this.cmdCooldown = new Map(); // Used for the command cooldown

this.databaseCache = {};
this.databaseCache.users = new Collection();
this.databaseCache.guilds = new Collection();
this.databaseCache.members = new Collection();

this.databaseCache.usersReminds = new Collection(); // members with active reminds
this.databaseCache.mutedUsers = new Collection(); // members who are currently muted

if(this.config.apiKeys.amethyste){
if(this.config.apiKeys.amethyste) {
this.AmeAPI = new AmeClient(this.config.apiKeys.amethyste);
}

if(this.config.apiKeys.blagueXYZ){
if(this.config.apiKeys.blagueXYZ) {
this.joker = new Joker(this.config.apiKeys.blagueXYZ, {
defaultLanguage: "en"
});
Expand Down Expand Up @@ -162,6 +160,27 @@ class Atlanta extends Client {
});
}

async init() {
await this.loadCommands();
await this.loadEvents();
await this.login(this.config.token);
mongoose.connect(this.config.mongoDB,(err) => {
if (err) {
this.logger.log("Unable to connect to the Mongodb database. Error:"+err, "error");
}
else {
this.logger.log("Connected to the Mongodb database.", "log");

}
});
this.translations = await languages();
autoUpdateDocs.update(this);
//Deploy commands
if (this.config.deployCommands) {
await this.registerCommands();
}
}

get defaultLanguage(){
return this.languages.find((language) => language.default).name;
}
Expand Down Expand Up @@ -192,24 +211,70 @@ class Atlanta extends Client {
}

// This function is used to load a command and add it to the collection
loadCommand (commandPath, commandName) {
async loadCommands () {
const content = await readdir("./commands/").catch(console.error);
if (!content || !content.length) return console.error("Please create folder in \"commands\" folder.");
const groups = [];
content.forEach(element => {
if (!element.includes(".")) groups.push(element);
});
for (const folder of groups) {
const files = await readdir(`./commands/${folder}`).catch(console.error);
if (!files || !files.length) return console.error(`Please create files in "${folder}" folder.`);
files.filter((file) => file.split(".").pop() === "js").forEach(element => {
try {
const command = new (require(`../commands/${folder}${sep}${element}`))(this);
this.logger.log(`Loading Command: ${command.help.name}. 👌`, "log");
if (command.init) {
command.init(this);
}
this.commands.set(command.help.name, command);
} catch (e) {
console.error(`Unable to load command ${element}: ${e}`);
}
});
}
}

async registerCommands() {
const rest = new REST({ version: "9" }).setToken(this.config.token);
const commands = this.commands.map(c => c.applicationCommandBody);
try {
const props = new (require(`.${commandPath}${path.sep}${commandName}`))(this);
this.logger.log(`Loading Command: ${props.help.name}. 👌`, "log");
props.conf.location = commandPath;
if (props.init){
props.init(this);
}
this.commands.set(props.help.name, props);
props.help.aliases.forEach((alias) => {
this.aliases.set(alias, props.help.name);
this.logger.log("Started refreshing application (/) commands.", "log");

await rest.put(
Routes.applicationCommands(this.user.id),
{ body: commands },
);
this.logger.log("Successfully reloaded application (/) commands.", "log");
} catch (error) {
console.error(error);
}
}

// This function is used to load an event and add it to the collection
async loadEvents () {
const folders = await readdir("./events/").catch(console.error);
if (!folders || !folders.length) return console.error("Please create folder in \"commands\" folder.");
const groups = [];
folders.forEach(element => {
if (!element.includes(".")) groups.push(element);
});
for (const directory of groups) {
const files = await readdir(`./events/${directory}`).catch(console.error);
files.filter((file) => file.split(".").pop() === "js").forEach(file => {
try {
const event = new (require(`../events/${directory}/${file}`))(this);
this.logger.log(`Loading Event: ${file.split(".")[0]}`);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
this.logger.log(`Loading Event: ${file.split(".")[0]}`);
this.logger.log(`Loading Event: ${file.split(".")[0]}`, "log");

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"log" is set by default if the second arg of log() is not specified

this.on(file.split(".")[0], (...args) => event.run(...args));
} catch (e) {
console.error(`Unable to load event ${file.split(".")[0]}: ${e}`);
}
});
return false;
} catch (e) {
return `Unable to load command ${commandName}: ${e}`;
}
}


// This function is used to unload a command (you need to load them again)
async unloadCommand (commandPath, commandName) {
let command;
Expand All @@ -228,66 +293,6 @@ class Atlanta extends Client {
return false;
}

// This function is used to find a user data or create it
async findOrCreateUser({ id: userID }, isLean){
if(this.databaseCache.users.get(userID)){
return isLean ? this.databaseCache.users.get(userID).toJSON() : this.databaseCache.users.get(userID);
} else {
let userData = (isLean ? await this.usersData.findOne({ id: userID }).lean() : await this.usersData.findOne({ id: userID }));
if(userData){
if(!isLean) this.databaseCache.users.set(userID, userData);
return userData;
} else {
userData = new this.usersData({ id: userID });
await userData.save();
this.databaseCache.users.set(userID, userData);
return isLean ? userData.toJSON() : userData;
}
}
}

// This function is used to find a member data or create it
async findOrCreateMember({ id: memberID, guildID }, isLean){
if(this.databaseCache.members.get(`${memberID}${guildID}`)){
return isLean ? this.databaseCache.members.get(`${memberID}${guildID}`).toJSON() : this.databaseCache.members.get(`${memberID}${guildID}`);
} else {
let memberData = (isLean ? await this.membersData.findOne({ guildID, id: memberID }).lean() : await this.membersData.findOne({ guildID, id: memberID }));
if(memberData){
if(!isLean) this.databaseCache.members.set(`${memberID}${guildID}`, memberData);
return memberData;
} else {
memberData = new this.membersData({ id: memberID, guildID: guildID });
await memberData.save();
const guild = await this.findOrCreateGuild({ id: guildID });
if(guild){
guild.members.push(memberData._id);
await guild.save();
}
this.databaseCache.members.set(`${memberID}${guildID}`, memberData);
return isLean ? memberData.toJSON() : memberData;
}
}
}

// This function is used to find a guild data or create it
async findOrCreateGuild({ id: guildID }, isLean){
if(this.databaseCache.guilds.get(guildID)){
return isLean ? this.databaseCache.guilds.get(guildID).toJSON() : this.databaseCache.guilds.get(guildID);
} else {
let guildData = (isLean ? await this.guildsData.findOne({ id: guildID }).populate("members").lean() : await this.guildsData.findOne({ id: guildID }).populate("members"));
if(guildData){
if(!isLean) this.databaseCache.guilds.set(guildID, guildData);
return guildData;
} else {
guildData = new this.guildsData({ id: guildID });
await guildData.save();
this.databaseCache.guilds.set(guildID, guildData);
return isLean ? guildData.toJSON() : guildData;
}
}
}


// This function is used to resolve a user from a string
async resolveUser(search){
let user = null;
Expand All @@ -302,7 +307,7 @@ class Atlanta extends Client {
if(search.match(/^!?(\w+)#(\d+)$/)){
const username = search.match(/^!?(\w+)#(\d+)$/)[0];
const discriminator = search.match(/^!?(\w+)#(\d+)$/)[1];
user = this.users.find((u) => u.username === username && u.discriminator === discriminator);
user = this.users.cache.find((u) => u.username === username && u.discriminator === discriminator);
if(user) return user;
}
user = await this.users.fetch(search).catch(() => {});
Expand Down
26 changes: 19 additions & 7 deletions base/Command.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,34 @@
const path = require("path");
const {Permissions} = require("discord.js");

module.exports = class Command {
constructor(client, {
name = null,
description = false,
dirname = false,
enabled = true,
guildOnly = false,
aliases = new Array(),
botPermissions = new Array(),
memberPermissions = new Array(),
memberPermissions = [],
botPermissions = [],
nsfw = false,
ownerOnly = false,
cooldown = 3000
cooldown = 3000,
options = {}
})
{
const category = (dirname ? dirname.split(path.sep)[parseInt(dirname.split(path.sep).length-1, 10)] : "Other");
memberPermissions.forEach((p, i) => {
memberPermissions[i] = Permissions.FLAGS[p];
});
const bit = memberPermissions.reduce((a, b) => a | b, 0n).toString();
const category = dirname ? dirname.split(path.sep)[dirname.split(path.sep).length - 1] : "Other";
this.client = client;
this.conf = { enabled, guildOnly, memberPermissions, botPermissions, nsfw, ownerOnly, cooldown};
this.help = { name, category, aliases };
this.conf = { enabled, guildOnly, botPermissions, nsfw, ownerOnly, cooldown};
this.help = { name, category };
this.applicationCommandBody = {name, description, options, dm_permission: !guildOnly};


if (bit !== "0") {
this.applicationCommandBody["default_member_permissions"] = bit;
}
}
};
Loading