From 9ca0367ded6ca5330f69f57d5b37f011ec2317f2 Mon Sep 17 00:00:00 2001 From: iiAlosha <39468199+iiAlosha@users.noreply.github.com> Date: Mon, 3 Aug 2020 23:14:38 +0300 Subject: [PATCH] Main Files --- Commands/Bonus.js | 32 ++++++++++ Commands/Me.js | 23 ++++++++ Commands/Options.js | 30 ++++++++++ Commands/Reward.js | 34 +++++++++++ Commands/Top.js | 33 +++++++++++ Events/commandHandler.js | 20 +++++++ Helpers/Database.js | 78 ++++++++++++++++++++++++ Settings/Settings.json | 5 ++ bot.js | 124 +++++++++++++++++++++++++++++++++++++++ index.js | 37 ++++++++++++ package.json | 24 ++++++++ 11 files changed, 440 insertions(+) create mode 100644 Commands/Bonus.js create mode 100644 Commands/Me.js create mode 100644 Commands/Options.js create mode 100644 Commands/Reward.js create mode 100644 Commands/Top.js create mode 100644 Events/commandHandler.js create mode 100644 Helpers/Database.js create mode 100644 Settings/Settings.json create mode 100644 bot.js create mode 100644 index.js create mode 100644 package.json diff --git a/Commands/Bonus.js b/Commands/Bonus.js new file mode 100644 index 0000000..d02ccd0 --- /dev/null +++ b/Commands/Bonus.js @@ -0,0 +1,32 @@ +const Discord = require("discord.js"); +const Database = require("../Helpers/Database"); +// exports.onLoad = (client) => {}; +/** + * @param {Discord.Client} client + * @param {Discord.Message} message + * @param {Array} args + */ +exports.run = async (client, message, args) => { + if(!message.member.hasPermission("ADMINISTRATOR") && !message.member.hasPermission("MANAGE_GUILD")) return message.reply("you don't have a permission."); + + var victim = message.mentions.members.size > 0 ? message.mentions.members.first().id : args.length > 0 ? args[0] : undefined; + if(!victim) return message.reply("you didn't mention anyone."); + victim = message.guild.member(victim); + if(!victim) return message.reply("the member you mentioned must be on the server."); + + var num = Number(args[1]); + if(isNaN(num)) return message.reply("valid number."); + const db = new Database("./Servers/" + message.guild.id, "Invites"); + + var bonus = (db.add(`invites.${victim.id}.bonus`, num) || 0), total = (db.get(`invites.${victim.id}.total`) || 0); + message.reply(`${num} bonuses were successfully added to ${victim}.`); + + global.onUpdateInvite(victim, message.guild.id, total + bonus); +}; + +exports.conf = { + commands: ["bonus"], + usage: "[p]bonus ", + enabled: true, + guildOnly: true +}; \ No newline at end of file diff --git a/Commands/Me.js b/Commands/Me.js new file mode 100644 index 0000000..ad8adc7 --- /dev/null +++ b/Commands/Me.js @@ -0,0 +1,23 @@ +const Discord = require("discord.js"); +const Database = require("../Helpers/Database"); +// exports.onLoad = (client) => {}; +/** + * @param {Discord.Client} client + * @param {Discord.Message} message + * @param {Array} args + */ +exports.run = async (client, message, args) => { + const db = new Database("./Servers/" + message.guild.id, "Invites"); + var data = db.get(`invites.${message.member.id}`) || { total: 0, fake: 0, inviter: null, regular: 0, bonus: 0, leave: 0 }; + var embed = new Discord.MessageEmbed() + .setDescription(`**Total:** \`${data.total || 0}\`, **Regular:** \`${data.regular || 0}\`, **Bonus:** \`${data.bonus || 0}\`, **Leave:** \`${data.leave || 0}\`, (**Fake:** \`${data.fake || 0}\`)`) + .setColor("RANDOM"); + message.channel.send(embed); +}; + +exports.conf = { + commands: ["me"], + usage: "[p]me", + enabled: true, + guildOnly: true +}; \ No newline at end of file diff --git a/Commands/Options.js b/Commands/Options.js new file mode 100644 index 0000000..1b3f564 --- /dev/null +++ b/Commands/Options.js @@ -0,0 +1,30 @@ +const Discord = require("discord.js"); +const Database = require("../Helpers/Database"); +// exports.onLoad = (client) => {}; +/** + * @param {Discord.Client} client + * @param {Discord.Message} message + * @param {Array} args + */ +exports.run = async (client, message, args) => { + if(!message.member.hasPermission("ADMINISTRATOR") && !message.member.hasPermission("MANAGE_GUILD")) return message.reply("you don't have enough permission to do that.") + if(args.length <= 0) return message.reply("argument error"); + + var arg = args[0].toLocaleLowerCase(); + var types = ["leaveMessage", "welcomeMessage", "Channel", "defaultMessage"]; + + var type = types.find(_type => _type.toLocaleLowerCase() == arg); + if(!type) return message.reply("you can only use `leaveMessage`, `welcomeMessage`, `Channel` ve `defaultMessage` parameters."); + + const db = new Database("./Servers/" + message.guild.id, "Settings"); + db.set(`settings.${type}`, args.splice(1).join(" ")); + + message.reply(`Successfully created type to ${type}.`); +}; + +exports.conf = { + commands: ["options"], + usage: "[p]options ", + enabled: true, + guildOnly: true +}; \ No newline at end of file diff --git a/Commands/Reward.js b/Commands/Reward.js new file mode 100644 index 0000000..fbb6979 --- /dev/null +++ b/Commands/Reward.js @@ -0,0 +1,34 @@ +const Discord = require("discord.js"); +const Database = require("../Helpers/Database"); +// exports.onLoad = (client) => {}; +/** + * @param {Discord.Client} client + * @param {Discord.Message} message + * @param {Array} args + */ +exports.run = async (client, message, args) => { + if(!message.member.hasPermission("ADMINISTRATOR") && !message.member.hasPermission("MANAGE_GUILD")) return message.reply("you don't have a permission."); + if(args.length != 2) return message.reply("missing arguments."); + + var roleId = args[0], targetInvite = Number(args[1]); + if(!message.guild.roles.cache.has(roleId)) return message.reply("no such role."); + if(isNaN(targetInvite)) return message.reply("invalid number"); + + const db = new Database("./Servers/" + message.guild.id, "Rewards"); + + var rewards = db.get("rewards") || []; + rewards.push({ + Id: roleId, + Invite: targetInvite + }); + + db.set("rewards", rewards); + message.reply("a new reward was successfully added."); +}; + +exports.conf = { + commands: ["reward"], + usage: "[p]reward ", + enabled: true, + guildOnly: true +}; \ No newline at end of file diff --git a/Commands/Top.js b/Commands/Top.js new file mode 100644 index 0000000..bc5b257 --- /dev/null +++ b/Commands/Top.js @@ -0,0 +1,33 @@ +const Discord = require("discord.js"); +const Database = require("../Helpers/Database"); +// exports.onLoad = (client) => {}; +/** + * @param {Discord.Client} client + * @param {Discord.Message} message + * @param {Array} args + */ +exports.run = async (client, message, args) => { + const db = new Database("./Servers/" + message.guild.id, "Invites"); + var data = db.get(`invites`) || {}; + + var list = Object.keys(data).map(_data => { + return { + Id: _data, + Value: (data[_data].total || 0) + (data[_data].bonus || 0) + }; + }).sort((x, y) => y.Value - x.Value); + + var embed = new Discord.MessageEmbed() + .addField("Invites", ` + ** **${list.splice(0, 10).map((item, index) => `\`${index + 1}.\` <@${item.Id}>: \`${item.Value} invite\``).join("\n")} + `); + + message.channel.send(embed); +}; + +exports.conf = { + commands: ["top"], + usage: "[p]top", + enabled: true, + guildOnly: true +}; \ No newline at end of file diff --git a/Events/commandHandler.js b/Events/commandHandler.js new file mode 100644 index 0000000..91fbeaa --- /dev/null +++ b/Events/commandHandler.js @@ -0,0 +1,20 @@ +const Discord = require("discord.js"); + +/** + * @param {Discord.Message} message + */ +exports.execute = async (message) => { + if(message.author.bot || !message.content.startsWith(global.Settings.Prefix)) return; + + let args = message.content.split(" "); + let commandName = args[0].substring(global.Settings.Prefix.length); + args = args.splice(1); + let command = global.Commands.get(commandName); + if(!command || !command.conf.enabled || (command.conf.guildOnly && message.channel.type != "text")) return; + if(command) + command.run(message.client, message, args); +}; + +exports.conf = { + event: "message" +} \ No newline at end of file diff --git a/Helpers/Database.js b/Helpers/Database.js new file mode 100644 index 0000000..dbb9ef7 --- /dev/null +++ b/Helpers/Database.js @@ -0,0 +1,78 @@ +const fs = require("fs"); + +class Database { + constructor(location = "Database", name = "All.json"){ + if(location == "Database" && !fs.existsSync(`${__dirname}/Database`)) + { + fs.mkdirSync(`${__dirname}/Database`, {recursive: true}); + } + else if(!fs.existsSync(`${location}`)) + {fs.mkdirSync(`${__dirname}/${location}`, {recursive: true});} + let filePath = `${__dirname}/${location}/${name}.json`; + if(!fs.existsSync(filePath)) + fs.closeSync(fs.openSync(filePath, 'w')); + this.FilePath = filePath; + this.Location = location; + } + add(path, value){ + let data = this.get(path); + if(typeof data == "number") data += Number(value); + else data = Number(value); + this.set(path, data); + return data; + } + get(path){ + let data = this.read(), result = undefined; + if(!data) data = {}; + result = _get(path, data); + return result ? result : undefined; + } + set(path, value){ + let data = this.read(); + if(!data) data = {}; + data = _set(path, value, data); + fs.truncateSync(this.FilePath); + fs.writeFileSync(this.FilePath, JSON.stringify(data), {encoding: "utf-8"}); + return data; + } + sub(path, value){ + let data = this.get(path); + if(typeof data == "number") data -= Number(value); + else data = Number(value); + this.set(path, data); + return data; + } + read(){ + let data = fs.readFileSync(this.FilePath, {encoding: "utf-8"}); + if(!data || (data && data == null)) return {}; + let obj = JSON.parse(data); + return obj; + } +} + +function _set(path, value, obj = undefined){ + if(obj == undefined) return undefined; + let locations = path.split("."), output = {}; + output = obj; + let ref = output; + for (let index = 0; index < locations.length - 1; index++) { + if(!ref[locations[index]]) + ref = ref[locations[index]] = {}; + else + ref = ref[locations[index]]; + } + ref[locations[locations.length - 1]] = value; + return output; +} + +function _get(path, obj = {}){ + let locations = path.split("."), ref = obj; + for (let index = 0; index < locations.length - 1; index++) { + ref = ref[locations[index]] ? ref[locations[index]] : undefined; + if(!ref) return undefined; + } + let output = ref[locations[locations.length - 1]]; + return output; +} + +module.exports = Database; \ No newline at end of file diff --git a/Settings/Settings.json b/Settings/Settings.json new file mode 100644 index 0000000..e80a242 --- /dev/null +++ b/Settings/Settings.json @@ -0,0 +1,5 @@ +{ + "Token": "", + "Prefix": "!", + "Private_Server": true +} \ No newline at end of file diff --git a/bot.js b/bot.js new file mode 100644 index 0000000..d0a6d54 --- /dev/null +++ b/bot.js @@ -0,0 +1,124 @@ +const { Collection, Client } = require("discord.js"); +const Database = require("./Helpers/Database"); +const client = global.client; + +//#region Invite Manager +const Invites = new Collection(); + +//#region Load +client.on("ready", () => { + client.guilds.cache.forEach(guild => { + guild.fetchInvites().then(_invites => { + Invites.set(guild.id, _invites); + }).catch(err => { }); + }); +}); +client.on("inviteCreate", (invite) => { + var gi = Invites.get(invite.guild.id); + gi.set(invite.code, invite); + Invites.set(invite.guild.id, gi); +}); +client.on("inviteDelete", (invite) => { + console.log(invite.code + " kodu silindi."); + var gi = Invites.get(invite.guild.id); + gi.delete(invite.code); + Invites.set(invite.guild.id, gi); +}); +//#endregion + +//#region Counter +client.on("guildMemberAdd", (member) => { + //const gi = new Collection().concat(Invites.get(member.guild.id)); + const db = new Database("./Servers/" + member.guild.id, "Invites"), gi = Invites.get(member.guild.id).clone(), settings = new Database("./Servers/" + member.guild.id, "Settings").get("settings") || {}; + var guild = member.guild, fake = (Date.now() - member.createdAt) / (1000 * 60 * 60 * 24) <= 3 ? true : false, channel = guild.channels.cache.get(settings.Channel); + + guild.fetchInvites().then(invites => { + var invite = invites.find(_i => gi.has(_i.code) && gi.get(_i.code).maxUses != 1 && gi.get(_i.code).uses < _i.uses) || gi.find(_i => !invites.has(_i.code)) || guild.vanityURLCode; + + var content = `${member} is joined the server.`, total = 0, regular = 0, _fake = 0; + if(invite == guild.vanityURLCode) content = settings.defaultMessage ? settings.defaultMessage : `-member- is joined the server! But don't know that invitation he came up with. :tada:`; + else content = settings.welcomeMessage ? settings.welcomeMessage : `The -member-, joined the server using the invitation of the -target-.`; + + if (invite.inviter) { + db.set(`invites.${member.id}.inviter`, invite.inviter.id); + if(fake){ + total = db.add(`invites.${invite.inviter.id}.total`, 1); + _fake = db.add(`invites.${invite.inviter.id}.fake`, 1); + } + else{ + total = db.add(`invites.${invite.inviter.id}.total`, 1); + regular = db.add(`invites.${invite.inviter.id}.regular`, 1); + } + var im = guild.member(invite.inviter.id); + if(im) global.onUpdateInvite(im, guild.id, Number(total + (db.get(`invites.${invite.inviter.id}.bonus`) || 0))); + } + + db.set(`invites.${member.id}.isfake`, fake); + + if(channel){ + content = content + .replace("-member-", `${member}`) + .replace("-target-", `${invite.inviter}`) + .replace("-total-", `${total}`) + .replace("-regular-", `${regular}`) + .replace("-fakecount-", `${_fake}`) + .replace("-invite-", `${invite && invite.code != undefined ? invite.code : "what is that?"}`) + .replace("-fake-", `${fake}`); + channel.send(content); + } + }).catch(); +}); + +client.on("guildMemberRemove", (member) => { + const db = new Database("./Servers/" + member.guild.id, "Invites"), settings = new Database("./Servers/" + member.guild.id, "Settings").get("settings") || {}; + var total = 0, regular = 0, fakecount = 0, channel = member.guild.channels.cache.get(settings.Channel), content = settings.leaveMessage ? settings.leaveMessage : `${member} is left the server.`, data = db.get(`invites.${member.id}`); + if(!data){ + if(channel){ + content = content + .replace("-member-", `${member}`); + channel.send(content); + } + return; + } + + if(data.isfake && data.inviter){ + fakecount = db.sub(`invites.${data.inviter}.fake`, 1); + total = db.sub(`invites.${data.inviter}.total`, 1); + } + else if(data.inviter){ + regular = db.sub(`invites.${data.inviter}.regular`, 1); + total = db.sub(`invites.${data.inviter}.total`, 1); + } + db.add(`invites.${data.inviter}.leave`, 1); + if(channel){ + content = content + .replace("-member-", `${member}`) + .replace("-target-", `${data.inviter}`) + .replace("-total-", `${total}`) + .replace("-regular-", `${regular}`) + .replace("-fakecount-", `${fakecount}`) + .replace("-fake-", `${data.isfake}`); + channel.send(content); + } +}); +//#endregion + +//#region Reward +global.onUpdateInvite = (guildMember, guild, total) => { + if(!guildMember.manageable) return console.log("dokunamıyom"); + const rewards = new Database("./Servers/" + guild, "Rewards").get("rewards") || []; + if(rewards.length <= 0) return; + var taken = rewards.filter(reward => reward.Invite > total && guildMember.roles.cache.has(reward.Id)); + taken.forEach(take => { + guildMember.roles.remove(take.Id); + }); + var possible = rewards.filter(reward => reward.Invite <= total && !guildMember.roles.cache.has(reward.Id)); + possible.forEach(pos =>{ + guildMember.roles.add(pos.Id); + }); +} +//#endregion + +//#endregion + +client.login(global.Settings.Token); \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..558b4ef --- /dev/null +++ b/index.js @@ -0,0 +1,37 @@ +const Discord = require("discord.js"); +const fs = require("fs"); +const Settings = global.Settings = require("./Settings/Settings.json"); + +console.log("Launching bot..."); +let _client = new Discord.Client(); +if (Settings.Private_Server === true) { + _client = new Discord.Client({ + fetchAllMembers: true + }); +} +const client = global.client = _client; +const Commands = global.Commands = new Map(); + +console.log("--------------------------------"); +console.log("Loading commands..."); +fs.readdirSync("./Commands", { encoding: "utf-8" }).filter(file => file.endsWith(".js")).forEach(file => { + let prop = require(`./Commands/${file}`); + if (prop.conf.commands == undefined || prop.run == undefined) return console.error(`[COMMAND] ${file} is not load.`); + if (prop.conf.commands && prop.conf.commands.length > 0) { + prop.conf.commands.forEach(aliase => Commands.set(aliase, prop)); + } + if (prop.onLoad != undefined && typeof (prop.onLoad) == "function") prop.onLoad(client); + console.log(`[COMMAND] A total of ${prop.conf.commands.length} supporters have been installed for ${file}.`); +}); +console.log("--------------------------------"); +console.log("Loading events..."); +fs.readdirSync("./Events", { encoding: "utf-8" }).filter(file => file.endsWith(".js")).forEach(file => { + let prop = require(`./Events/${file}`); + client.on(prop.conf.event, prop.execute); + console.log(`[EVENT] ${file} is loaded.`); +}); + +console.log("--------------------------------"); +console.log("| Preparation has been completed. Starting the bot now |"); + +require("./bot.js"); \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..ca5c2d6 --- /dev/null +++ b/package.json @@ -0,0 +1,24 @@ +{ + "name": "discord-stat-bot", + "version": "1.0.0", + "description": "This bot is a simple Invite Manager. The data it invite activities.", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [ + "bot", + "invite", + "manager", + "invite-manager", + "discord", + "serendia", + "squad", + "Alosha" + ], + "author": "Alosha", + "license": "MIT", + "dependencies": { + "discord.js": "^12.2.0" + } +}