Merge remote-tracking branch 'Shasha/DB-Rework'

This commit is contained in:
Neko-Life 2021-07-21 11:52:52 +07:00
commit 5f5b8a480f
35 changed files with 1155 additions and 509 deletions

51
Main.js
View file

@ -56,7 +56,7 @@ client.on('ready', async () => {
client.on("message", async msg => {
if (!client.matchTimestamp) client.matchTimestamp = 0;//getUTCComparison(msg.createdTimestamp);
if (!msg.author.dbLoaded && !msg.author.bot) await msg.author.dbLoad();
if (!msg.author.DB) await msg.author.dbLoad();
lgr.message.letsChat(msg);
if (msg.mentions.has(client.user) && !msg.isCommand && msg.channel.id != configFile.chatChannel) {
@ -72,7 +72,7 @@ client.on("message", async msg => {
if (!msg.guild) {
//console.log(`(${msg.channel.recipient.id}) ${msg.channel.recipient.tag}: (${msg.author.id}) ${msg.author.tag}: ${msg.content}`);
} else {
if (!msg.guild.dbLoaded) await msg.guild.dbLoad();
if (!msg.guild.DB) await msg.guild.dbLoad();
lgr.message.giveNickHeart(msg);
}
@ -81,7 +81,7 @@ client.on("message", async msg => {
client.on("guildMemberRemove", async (member) => {
//console.log(`User ${memberLeave.displayName} (${memberLeave.user.tag}) (${memberLeave.id}) left ${memberLeave.guild.name} (${memberLeave.guild.id}). Now it has ${memberLeave.guild.memberCount} total members count.`);
if (!member.guild.dbLoaded) await member.guild.dbLoad();
if (!member.guild.DB) await member.guild.dbLoad();
lgr.guildMemberRemove(member);
});
@ -97,8 +97,8 @@ client.on("guildDelete", leaveShaGuild => {
client.on("guildMemberAdd", async (member) => {
//console.log(`New member ${newMember.displayName} (${newMember.user.tag}) (${newMember.id}) joined ${newMember.guild.name} (${newMember.guild.id})! Now it has ${newMember.guild.memberCount} total members count.`);
if (!member.guild.dbLoaded) await member.guild.dbLoad();
if (!member.user.dbLoaded && !member.user.bot) await member.user.dbLoad();
if (!member.guild.DB) await member.guild.dbLoad();
if (!member.user.DB && !member.user.bot) await member.user.dbLoad();
lgr.guildMemberAdd(member);
});
@ -107,49 +107,52 @@ client.on("guildBanAdd", async (GUILD, USER) => {
});
client.on("messageDelete", async (msg) => {
if (msg.author && !msg.author.dbLoaded && !msg.author.bot) await msg.author.dbLoad();
if (msg.author && !msg.author.DB) await msg.author.dbLoad();
if (msg.guild) {
if (!msg.guild.dbLoaded) await msg.guild.dbLoad();
if (!msg.guild.DB) await msg.guild.dbLoad();
lgr.messageDelete(msg);
}
});
client.on("messageUpdate", async (msgold, msgnew) => {
if (msgnew.author && !msgnew.author.dbLoaded && !msgnew.author.bot) await msgnew.author.dbLoad();
if (!msgnew.author?.DB) await msgnew.author?.dbLoad();
if (msgnew.guild) {
if (!msgnew.guild.dbLoaded) await msgnew.guild.dbLoad();
if (!msgnew.guild.DB) await msgnew.guild.dbLoad();
lgr.messageUpdate(msgold, msgnew);
}
});
client.on("guildMemberUpdate", async (memberold, membernew) => {
//console.log(memberold.toJSON(), "\n\n", membernew.toJSON());
if (!membernew.user.dbLoaded && !membernew.user.bot) await membernew.user.dbLoad();
if (!membernew.guild.dbLoaded) await membernew.guild.dbLoad();
if (!membernew.user.DB) await membernew.user.dbLoad();
if (!membernew.guild.DB) await membernew.guild.dbLoad();
lgr.guildMemberUpdate(memberold, membernew);
});
client.on("shardReady", (shard) => {
client.on("shardReady", async (shard) => {
const log = client.channels.cache.get(configFile.shardChannel);
const emb = defaultEventLogEmbed(client.guilds.cache.get(configFile.home));
if (!log.guild.DB) await log.guild.dbLoad();
const emb = defaultEventLogEmbed(log.guild);
emb.setTitle("Shard #" + shard)
.setDescription("**CONNECTED**")
.setColor(getColor("blue"));
trySend(client, log, emb);
});
client.on("shardReconnecting", (shard) => {
client.on("shardReconnecting", async (shard) => {
const log = client.channels.cache.get(configFile.shardChannel);
const emb = defaultEventLogEmbed(client.guilds.cache.get(configFile.home));
if (!log.guild.DB) await log.guild.dbLoad();
const emb = defaultEventLogEmbed(log.guild);
emb.setTitle("Shard #" + shard)
.setDescription("**RECONNECTING**")
.setColor(getColor("cyan"));
trySend(client, log, emb);
});
client.on("shardDisconnect", (e, shard) => {
client.on("shardDisconnect", async (e, shard) => {
const log = client.channels.cache.get(configFile.shardChannel);
const emb = defaultEventLogEmbed(client.guilds.cache.get(configFile.home));
if (!log.guild.DB) await log.guild.dbLoad();
const emb = defaultEventLogEmbed(log.guild);
emb.setTitle("Shard #" + shard)
.setDescription("**DISCONNECTED\n\nTARGET:**```js\n" + JSON.stringify(e.target, (k, v) => v ?? undefined, 2) + "```")
.addField("CODE", e.code, true)
@ -159,18 +162,20 @@ client.on("shardDisconnect", (e, shard) => {
trySend(client, log, emb);
});
client.on("shardResume", (shard) => {
client.on("shardResume", async (shard) => {
const log = client.channels.cache.get(configFile.shardChannel);
const emb = defaultEventLogEmbed(client.guilds.cache.get(configFile.home));
if (!log.guild.DB) await log.guild.dbLoad();
const emb = defaultEventLogEmbed(log.guild);
emb.setTitle("Shard #" + shard)
.setDescription("**RESUMED**")
.setColor(getColor("green"));
trySend(client, log, emb);
});
client.on("shardError", (e, shard) => {
client.on("shardError", async (e, shard) => {
const log = client.channels.cache.get(configFile.shardChannel);
const emb = defaultEventLogEmbed(client.guilds.cache.get(configFile.home));
if (!log.guild.DB) await log.guild.dbLoad();
const emb = defaultEventLogEmbed(log.guild);
emb.setTitle("Shard #" + shard)
.setDescription("**ERROR**")
.setColor(getColor("red"));
@ -179,8 +184,8 @@ client.on("shardError", (e, shard) => {
});
client.on("commandRun", async (c, u, msg) => {
if (!msg.author.dbLoaded) await msg.author.dbLoad();
if (msg.guild && !msg.guild.dbLoaded) await msg.guild.dbLoad();
if (!msg.author.DB) await msg.author.dbLoad();
if (msg.guild && !msg.guild.DB) await msg.guild.dbLoad();
});
client.on("warn", a => console.log("warn", typeof a, a));

View file

@ -13,16 +13,16 @@ module.exports = class f extends commando.Command {
});
}
async run(msg, arg) {
if (!msg.author.dbLoaded) await msg.author.dbLoad();
if (!msg.author.DB) await msg.author.dbLoad();
if (arg) {
msg.author.F = arg;
msg.author.DB.F = arg;
await msg.author.setF(arg)
};
return trySend(msg.client, msg,
msg.author.F + msg.author.F + msg.author.F + "\n" +
msg.author.F + "\n" +
msg.author.F + msg.author.F + msg.author.F + "\n" +
msg.author.F + "\n" +
msg.author.F);
msg.author.DB.F + msg.author.DB.F + msg.author.DB.F + "\n" +
msg.author.DB.F + "\n" +
msg.author.DB.F + msg.author.DB.F + msg.author.DB.F + "\n" +
msg.author.DB.F + "\n" +
msg.author.DB.F);
}
};

View file

@ -21,7 +21,7 @@ module.exports = class say extends commando.Command {
sendThis.disableMentions = "none";
}
const sent = await trySend(this.client, msg, sendThis);
if (args != '' && msg.channel.guild && msg.member.hasPermission("MANAGE_MESSAGES") && !/^<@\!?\d{17,19}>\s.+/.test(msg.content)) {
if (args != '' && msg.channel.guild && msg.member.hasPermission("MANAGE_MESSAGES") && !(new RegExp("^<@\!?" + msg.client.user.id + ">\s")).test(msg.content)) {
tryDelete(msg);
}
ranLog(msg, sent.content);

View file

@ -4,51 +4,51 @@ const emoteMessage = require("../../resources/emoteMessage");
const { ranLog, errLog, trySend, tryReact, findChannelRegEx, cleanMentionID, getChannel } = require("../../resources/functions");
module.exports = class send extends commando.Command {
constructor(client) {
super(client, {
name: "send",
memberName: "send",
group: "fun",
description: "Send message to designated channel.",
guildOnly:true
});
constructor(client) {
super(client, {
name: "send",
memberName: "send",
group: "fun",
description: "Send message to designated channel.",
guildOnly: true
});
}
async run(msg, args) {
const comarg = args.trim().split(/ +/);
if (!comarg[0]) {
return trySend(this.client, msg, 'Where?!?');
}
async run(msg, args ) {
const comarg = args.trim().split(/ +/);
if (!comarg[0]) {
return trySend(this.client, msg, 'Where?!?');
}
const search = cleanMentionID(comarg[0]),
sendTheMes = emoteMessage(this.client, args.slice(comarg[0].length).trim());
let channel = getChannel(msg, search, ["category", "voice"]);
if (!channel) {
return trySend(this.client, msg, "That channel is like your gf. Doesn't exist <:yeLife:796401669188354090>");
}
if (!channel.permissionsFor(msg.author).has("SEND_MESSAGES") || !channel.permissionsFor(msg.author).has("VIEW_CHANNEL")) {
return trySend(this.client, msg, "No <:yeLife:796401669188354090>");
}
const search = cleanMentionID(comarg[0]),
sendTheMes = emoteMessage(this.client, args.slice(comarg[0].length).trim());
let channel = getChannel(msg, search, ["category", "voice"]);
if (!channel) {
return trySend(this.client, msg, "That channel is like your gf. Doesn't exist <:yeLife:796401669188354090>");
}
if (!channel.permissionsFor(msg.author).has("SEND_MESSAGES") || !channel.permissionsFor(msg.author).has("VIEW_CHANNEL")) {
return trySend(this.client, msg, "No <:yeLife:796401669188354090>");
}
try {
if (sendTheMes.length === 0) {
return trySend(this.client, channel, `<@!${msg.author.id}>, If you wanna send nothin then why you even typed that <:bruhLife:798789686242967554>`);
}
const sendThis = { content: sendTheMes, disableMentions: "all" };
if (msg.member?.hasPermission("MENTION_EVERYONE")) sendThis.disableMentions = "none";
const send = await trySend(this.client, channel, sendThis);
const filter = () => true,
collector = send.createReactionCollector(filter, { time: 15 * 6 * 1000 });
collector.on('collect', r => {
try {
if (sendTheMes.length === 0) {
return trySend(this.client, channel, `<@!${msg.author.id}>, If you wanna send nothin then why you even typed that <:bruhLife:798789686242967554>`);
}
const sendThis = {content:sendTheMes, disableMentions:"all"};
if (msg.member?.hasPermission("MENTION_EVERYONE")) sendThis.disableMentions = "none";
const send = await trySend(this.client, channel, sendThis);
const filter = () => true,
collector = send.createReactionCollector(filter, {time: 15*6*1000, dispose:true});
collector.on('collect', r => {
try {
msg.react(r.emoji);
} catch (e) {}
});
collector.on('remove', async r => await msg.reactions.resolve(r).id.remove(r.id));
if (send) {
ranLog(msg, send.content.slice(0, 1900) + "\n\nSent to: " + `[${send.channel.name}](${send.url}) <#${send.channel.id}> (${send.channel.id})`);
tryReact(msg, 'yeLife:796401669188354090');
}
return send;
} catch (e) {
return errLog(e, msg, this.client);
}
msg.react(r.emoji);
} catch (e) { }
});
collector.on('remove', async r => msg.reactions.resolve(r).remove());
if (send) {
ranLog(msg, send.content.slice(0, 1900) + "\n\nSent to: " + `[${send.channel.name}](${send.url}) <#${send.channel.id}> (${send.channel.id})`);
tryReact(msg, 'yeLife:796401669188354090');
}
return send;
} catch (e) {
return errLog(e, msg, this.client);
}
}
};

View file

@ -2,7 +2,7 @@
const commando = require("@iceprod/discord.js-commando");
const { trySend } = require("../../resources/functions");
const interactEmbed = require("./interactEmbed");
const interactEmbed = require("./rsc/interactEmbed");
module.exports = class cuddle extends commando.Command {
constructor(client) {

View file

@ -2,7 +2,7 @@
const commando = require("@iceprod/discord.js-commando");
const { trySend } = require("../../resources/functions");
const interactEmbed = require("./interactEmbed");
const interactEmbed = require("./rsc/interactEmbed");
module.exports = class feed extends commando.Command {
constructor(client) {

View file

@ -2,7 +2,7 @@
const commando = require("@iceprod/discord.js-commando");
const { trySend } = require("../../resources/functions");
const interactEmbed = require("./interactEmbed");
const interactEmbed = require("./rsc/interactEmbed");
module.exports = class hug extends commando.Command {
constructor(client) {

View file

@ -2,7 +2,7 @@
const commando = require("@iceprod/discord.js-commando");
const { trySend } = require("../../resources/functions");
const interactEmbed = require("./interactEmbed");
const interactEmbed = require("./rsc/interactEmbed");
module.exports = class kiss extends commando.Command {
constructor(client) {

View file

@ -2,7 +2,7 @@
const commando = require("@iceprod/discord.js-commando");
const { trySend } = require("../../resources/functions");
const interactEmbed = require("./interactEmbed");
const interactEmbed = require("./rsc/interactEmbed");
module.exports = class pat extends commando.Command {
constructor(client) {

View file

@ -2,7 +2,7 @@
const commando = require("@iceprod/discord.js-commando");
const { trySend } = require("../../resources/functions");
const interactEmbed = require("./interactEmbed");
const interactEmbed = require("./rsc/interactEmbed");
module.exports = class poke extends commando.Command {
constructor(client) {

View file

@ -0,0 +1,131 @@
'use strict';
const { default: fetchNeko } = require("nekos-best.js");
const { parseComa, getMember, defaultImageEmbed } = require("../../../resources/functions");
module.exports = async (msg, arg, name, endsaT = "") => {
msg.channel.startTyping();
let shoot = msg.member,
target = [],
iC = 0;
if (!arg) {
shoot = msg.guild.member(msg.client.user);
target.push(msg.member.displayName);
}
if (!shoot.user.DB) await shoot.user.dbLoad();
const args = parseComa(arg);
if (args?.length > 0) {
const mul = {
H: {
l: 0,
i: -1
},
C: {}
}
for (const key of args) {
if (!key || key.length === 0) continue;
const t = getMember(msg.guild, key)?.[0]?.displayName;
if (!t) continue;
if (t === shoot.displayName) {
const ifH = target.includes("themself (is this even physically possible)");
if (ifH) {
target.filter((v, i) => {
if (v === "themself (is this even physically possible)") {
mul.H.i = i;
mul.H.l++;
}
});
} else {
target.push("themself (is this even physically possible)");
}
} else {
const ifC = target.includes(t);
if (ifC) {
target.filter((v, i) => {
if (v === t) {
if (!mul.C[v]) {
mul.C[v] = {
l: 1,
i: i
};
} else {
mul.C[v].l++;
}
}
});
} else {
target.push(t);
}
}
}
if (mul.H.i > -1) {
switch (mul.H.l) {
case 1:
target[mul.H.i] += " twice!";
break;
case 2:
target[mul.H.i] += " thrice!!";
break;
default:
target[mul.H.i] += ` ${mul.H.l++} times LMFAO`;
}
}
for (const li in mul.C) {
const d = mul.C[li];
d.l++;
switch (d.l) {
case 2:
target[d.i] += " twice";
break;
case 3:
target[d.i] += " thrice XD";
break;
default:
target[d.i] += ` ${d.l} times ❤️`;
}
}
}
let lT, tN, sT;
if (target.length > 1) {
lT = target[target.length - 1];
sT = target.slice(0, -1);
tN = sT.join(", ") + ` and ${lT}`;
} else {
if (target.length === 1) tN = target[0];
}
if (target.length > 0) iC += target.length;
let ss;
if (tN) {
ss = name.endsWith("s") ? name + "es" : name + "s";
const aT = `${shoot.displayName} ${ss} ${tN} ${tN.endsWith(" times LMFAO") ? "" : endsaT}`,
count = shoot.user.DB.interactions[name] + (iC > 0 ? 1 : 0),
emb = defaultImageEmbed(msg, await fetchNeko(name));
let num;
if (count) {
const u = count?.toString();
if (u?.endsWith("1") && !u.endsWith("11")) {
num = count + "st";
} else {
if (u?.endsWith("2") && !u.endsWith("12")) {
num = count + "nd";
} else {
if (u?.endsWith("3") && !u.endsWith("13")) {
num = count + "rd";
} else {
num = count + "th";
}
}
}
} else {
shoot.user.DB.interactions[name] = 0;
num = "First";
}
shoot.user.DB.interactions[name] += iC;
shoot.user.setInteractions(shoot.user.DB.interactions);
emb.setAuthor(aT.length > 256 ? `${shoot.displayName} ${ss} so many friends ❤️❤️❤️` : aT, shoot.user.displayAvatarURL({ size: 128, format: "png", dynamic: true }))
.setFooter((emb.footer.text ? emb.footer.text + "・" : "") + num + ` ${name} from ` + shoot.displayName + " ❤️");
return emb;
} else {
return "ERROR 404 partner not found <:yeLife:796401669188354090>";
}
}

View file

@ -2,7 +2,7 @@
const commando = require("@iceprod/discord.js-commando");
const { trySend } = require("../../resources/functions");
const interactEmbed = require("./interactEmbed");
const interactEmbed = require("./rsc/interactEmbed");
module.exports = class slap extends commando.Command {
constructor(client) {

View file

@ -2,7 +2,7 @@
const commando = require("@iceprod/discord.js-commando");
const { trySend } = require("../../resources/functions");
const interactEmbed = require("./interactEmbed");
const interactEmbed = require("./rsc/interactEmbed");
module.exports = class tickle extends commando.Command {
constructor(client) {

View file

@ -16,14 +16,14 @@ module.exports = class eventlog extends commando.Command {
});
}
async run(msg, arg) {
if (!msg.guild.dbLoaded) await msg.guild.dbLoad();
if (!msg.guild.DB) await msg.guild.dbLoad();
const set = parseDoubleDash(arg);
let eventChannels = msg.guild.eventChannels;
let eventChannels = msg.guild.DB.settings.eventChannels;
if (set.length < 2 && set[0].length === 0) return trySend(this.client, msg, await resultEmbed(this));
let report = "", joinlog, leavelog, channellog, banlog, unbanlog, mesEdlog = { channel: undefined, ignore: [] }, invitelog, rolelog,
guildlog, membernicklog, emotelog, memberroleslog, remove = false, [setMesEdIgnore, setMesDelIgnore] = [false, false], mesDellog = { channel: undefined, ignore: [] };
for (const args of set) {
if (args.startsWith("r ")) remove = true;
if (args.startsWith("rm ")) remove = true;
if (args.startsWith("j ")) {
if (remove) eventChannels.join = undefined; else {
leavelog = getChannel(msg, args.slice("j".length).trim(), ["category", "voice"])?.id;
@ -217,7 +217,7 @@ module.exports = class eventlog extends commando.Command {
async function resultEmbed(the) {
const emb = defaultImageEmbed(msg, null, "Event Log Channels Configuration");
emb
.setDescription(`Set configuration using \`\`\`js\n${msg.guild.commandPrefix + the.name} [--remove] --<Category> <Channel_[Mention | Name | ID]>\`\`\`**Categories:** \`\`\`js\n[MESSAGE[EDIT, DELETE]: --[e, d] [IGNORE: -i <Channel_[Mention | Name | ID]>], JOIN: --j, LEAVE: --l, MEMBER: --p, MEMBERROLE: --mr, BAN: --b, UNBAN: --u, GUILD: --g, ROLE: --r, CHANNEL: --c, EMOJI: --em, INVITE: --i]\`\`\``)
.setDescription(`Set configuration using \`\`\`js\n${msg.guild.commandPrefix + the.name} [--rm] --<Category> <Channel_[Mention | Name | ID]>\`\`\`**Categories:** \`\`\`js\n[MESSAGE[EDIT, DELETE]: --[e, d] IGNORE: -i, JOIN: --j, LEAVE: --l, MEMBER: --p, MEMBERROLE: --mr, BAN: --b, UNBAN: --u, GUILD: --g, ROLE: --r, CHANNEL: --c, EMOJI: --em, INVITE: --i]\`\`\``)
.addField(`Message Edit`, eventChannels?.mesEd?.channel ? `<#${eventChannels?.mesEd.channel}>\n**Ignores:** ${eventChannels?.mesEd?.ignore?.length > 0 ?
"<#" + eventChannels?.mesEd.ignore.join(">, <#") + ">" : "None"}`
: "Not set", true)

View file

@ -1,11 +1,19 @@
'use strict';
const commando = require("@iceprod/discord.js-commando");
const { trySend, findMemberRegEx, cleanMentionID, findChannelRegEx, findRoleRegEx, defaultImageEmbed, parseDoubleDash, parseComa, getRole } = require("../../resources/functions");
const { trySend, findMemberRegEx, cleanMentionID, findChannelRegEx, findRoleRegEx, defaultImageEmbed, parseDoubleDash, parseComa, getRole, defaultEventLogEmbed } = require("../../resources/functions");
const { database } = require("../../database/mongo");
const col = database.collection("Guild");
const schedule = database.collection("Schedule");
const { scheduler } = require("../../resources/scheduler");
const { DateTime, Settings, Interval } = require("luxon");
const muteSetting = require("./src/muteSetting");
const fn = require("./src/duration");
const durationFn = fn.duration;
const targetUser = require("./src/targetUser");
const configureMuteRole = require("./src/configureMuteRole");
const { makeJSONMessage } = require("../../resources/debug");
Settings.defaultZone = "utc";
/*{
footer: {
@ -46,8 +54,14 @@ module.exports = class mute extends commando.Command {
memberName: "mute",
group: "moderation",
description: "Mute.",
details: `Run \`${client.commandPrefix}mute --s -r role_[name|ID|mention] -d [duration]\` to set up a mute role.\n` +
`Or if you're too lazy you can run \`${client.commandPrefix}mute --cmr -n [name] -c color_[name|hex|number]\` to make a new mute role and let me set it up for you. ` +
`You can view server as the newly created mute role and override my default settings later.\n` +
`Example:\`\`\`\n--s -r muted -d 69y420mo36w49d69h4m420s\n` +
`--s -r none -d 0\n--cmr -n Muted -c black\`\`\``,
guildOnly: true,
userPermissions: ['MANAGE_ROLES']
userPermissions: ['MANAGE_ROLES'],
clientPermissions: ['MANAGE_ROLES']
});
}
/**
@ -56,229 +70,85 @@ module.exports = class mute extends commando.Command {
* @returns
*/
async run(msg, arg) {
if (!msg.guild.dbLoaded) msg.guild.dbLoad();
const muteSettingsDoc = msg.guild.moderation.mute,
defaultDurationDoc = muteSettingsDoc.defaultDuration,
msg.channel.startTyping();
if (!msg.guild.DB) await msg.guild.dbLoad();
const MOD = msg.guild.DB.moderation.settings,
MUTE = MOD.mute || {},
args = parseDoubleDash(arg),
mentions = parseComa(args.shift()),
durationRegExp = /\d+(?![^ymwdhs])[ymwdhs]?o?/gi,
invokedAt = msg.createdAt,
duration = {
year: invokedAt.getFullYear(),
month: invokedAt.getMonth(),
date: invokedAt.getDate(),
hour: invokedAt.getHours(),
minute: invokedAt.getMinutes(),
second: invokedAt.getSeconds()
};
let theSettingUp = {
role: undefined,
defaultDuration: {
date: undefined,
string: undefined
}
},
durationHasSet = false,
settingUp = false,
settingRole = false,
settingRoleHasSet = false,
settingDuration = false,
settingDurationHasSet = false,
[timeForMessage, targetUser] = [["Indefinite"], []],
reason = "No reason provided.",
resultMsg = "";
for (const argument of args) {
const setArg = argument.toLowerCase().trim();
if (/^settings?$/i.test(setArg)) {
settingUp = true;
}
if (settingUp && /^durations?$/i.test(setArg)) {
settingDuration = true;
}
if (settingUp && /^role$/i.test(setArg)) {
settingRole = true;
}
if (/^\d{1,16}(?![^ymwdhs])[ymwdhs]?o?/i.test(argument.trim()) && !durationHasSet) {
const durationArg = argument.match(durationRegExp);
for (const value of durationArg) {
const val = parseInt(value.match(/\d+/)[0], 10);
if (value.endsWith("h") || value.endsWith("ho")) {
duration.hour = duration.hour + val;
continue;
}
if (value.endsWith("y")) {
duration.year = duration.year + val;
continue;
}
if (value.endsWith("mo")) {
duration.month = duration.month + val;
continue;
}
if (value.endsWith("w")) {
duration.date = duration.date + 7 * val;
continue;
}
if (value.endsWith("d")) {
duration.date = duration.date + val;
continue;
}
if (value.endsWith("m") || !/\D/.test(value)) {
duration.minute = duration.minute + val;
continue;
}
if (value.endsWith("s")) {
duration.second = duration.second + val;
continue;
}
}
durationHasSet = true;
} else {
if (!settingRole && argument.length > 0 && argument !== "--") {
reason = argument.trim();
} else {
if (settingRole && !settingRoleHasSet && argument.length > 0 && argument !== "--" && setArg !== "role") {
settingRoleHasSet = true;
const key = cleanMentionID(argument);
let role = getRole(msg.guild, key)?.id;
if (role || /^none$/i.test(key)) {
theSettingUp.role = role;
} else {
resultMsg += `No role found for: **${argument}**\n`;
}
}
}
}
}
const roleConfCheck = msg.guild.roles.cache.get(muteSettingsDoc?.role);
if (!roleConfCheck && !settingUp) {
resultMsg += `No mute role configured! Run \`${msg.guild.commandPrefix}${this.name} --settings <--role --<role_[name | ID]>> [--duration --<duration>\` to set it up.`;
}
let untilDate = new Date(String(duration.year), String(duration.month), String(duration.date), String(duration.hour), String(duration.minute), String(duration.second));
if (untilDate.toString() === "Invalid Date") untilDate = "Indefinite";
if (untilDate?.toUTCString() === invokedAt.toUTCString() && !settingDuration) {
if (defaultDurationDoc?.date?.valueOf() > 0) {
untilDate = new Date(invokedAt.valueOf() + defaultDurationDoc.date.valueOf() - 1000);
} else {
untilDate = "Indefinite";
}
}
if (untilDate instanceof Date) {
timeForMessage = [];
const elapsedTime = new Date(untilDate.valueOf() - invokedAt.valueOf() + 1000),
elapsed = [
elapsedTime.getFullYear() - 1970,
elapsedTime.getMonth(),
elapsedTime.getDate() - 1,
elapsedTime.getHours(),
elapsedTime.getMinutes(),
elapsedTime.getSeconds()
],
elapsedName = [
"year",
"month",
"day",
"hour",
"minute",
"second"
];
mentions = parseComa(args?.shift());
for (let index = 0; index < elapsed.length; index++) {
if (elapsed[index] > 0) {
let mes = `${elapsed[index]} ${elapsedName[index]}`;
if (elapsed[index] > 1) {
mes += "s";
} else { }
timeForMessage.push(mes);
} else { }
}
if (timeForMessage.length > 1) {
timeForMessage[timeForMessage.length - 2] += " and";
}
if (settingDuration && !settingDurationHasSet && timeForMessage.length > 0) {
settingDurationHasSet = true;
theSettingUp.defaultDuration.date = elapsedTime,
theSettingUp.defaultDuration.string = timeForMessage.join(" ");
if (!MOD.mute) msg.guild.DB.moderation.settings.mute = {};
let reason = "No reason provided", duration = {}, resultMsg = "", targetUsers = [];
if (args?.[1]) {
for (const ARG of args) {
const U = ARG.slice(2).trim();
if (/^cmr(\s|$)/.test(ARG)) return configureMuteRole(msg, ARG.slice(3).trim());
if (/^s(\s|$)/.test(ARG)) return muteSetting(msg, U);
if (/^[\-\+]?\d{1,16}(?![^ymwdhs])[ymwdhs]?o?/i.test(ARG.trim())) {
duration = durationFn(msg.editedAt || msg.createdAt, ARG.trim());
} else if (!ARG || ARG === "--" || ARG.trim().length === 0) continue; else reason = ARG.trim();
}
} else if (!MUTE.role || !msg.guild.roles.cache.get(MUTE.role)) {
return trySend(this.client, msg, `No mute role configured!\n\n**[ADMINISTRATOR]**\nRun \`${msg.guild.commandPrefix + this.name} --s -r role_[name|ID|mention] -d [duration]\` to set it up.\n` +
`Or if you're too lazy you can run \`${msg.guild.commandPrefix + this.name} --cmr -n [name] -c color_[name|hex|number]\` to make a new mute role and let me set it up for you. ` +
`You can view server as the new mute role and override my default settings later.\n` +
`Example:\`\`\`\n--s -r muted -d 69y420mo36w49d69h4m420s\n` +
`--s -r none -d 0\n--cmr -n Muted -c black\`\`\``);
}
if (settingUp || !roleConfCheck && !settingUp) {
if (settingRoleHasSet) {
await col.updateOne({ document: msg.guild.id }, { $set: { "moderation.settings.mute.role": theSettingUp.role } }, { upsert: true }).catch(e => { return trySend(this.client, msg, "```js\n" + e.stack + "```") });
}
if (durationHasSet) {
await col.updateOne({ document: msg.guild.id }, { $set: { "moderation.settings.mute.defaultDuration": theSettingUp.defaultDuration } }, { upsert: true }).catch(e => { return trySend(this.client, msg, "```js\n" + e.stack + "```") });
}
const defaultDurationDoc = muteSettingsDoc?.defaultDuration,
roleDoc = muteSettingsDoc?.role;
let settings = defaultImageEmbed(msg);
settings
.setTitle("Mute Configuration")
.addField("Role", roleDoc ? "<@&" + roleDoc + ">" : "Not set")
.addField("Duration", defaultDurationDoc?.string ?? "Not set");
return trySend(this.client, msg, { content: resultMsg, embed: settings });
}
for (const usermention of mentions) {
if (usermention.length > 0) {
let found = [],
nameid = cleanMentionID(usermention);
if (/^\d{17,19}$/.test(nameid)) {
const findmem = msg.guild.member(nameid);
if (findmem) {
found.push(findmem.user);
} else {
await this.client.users.fetch(nameid).then(fetchUser => found.push(fetchUser)).catch(() => { });
}
} else {
found = findMemberRegEx(msg, nameid).map(r => r.user);
}
if (found.length > 0 && found[0] !== null) {
const foundDupli = targetUser.findIndex(r => r === found[0]);
if (foundDupli !== -1) {
resultMsg += `**[WARNING]** Duplicate for user **${targetUser[foundDupli].tag}** with keyword: **${usermention.trim()}**\n`;
} else {
targetUser.push(found[0]);
if (found.length > 1) {
resultMsg += `**[WARNING]** Multiple users found for: **${usermention.trim()}**\n`;
}
}
} else {
resultMsg += `Can't find user: **${usermention.trim()}**\n`;
}
} else {
if (!settingUp && mentions[0].length === 0) {
return trySend(this.client, msg, "Args: `<[user_[mention|ID|name]]> -- [reason] -- [duration]`. Use `,` to provide multiple user.\nExample:```js\n" + `${msg.guild.commandPrefix}${this.name} 580703409934696449, @Shasha#1234, ur mom,#6969,^fuck\\s(ur)?\\s.{5}#\\d+69$--69y69mo69w420d420h420m420s -- Saying "joe"\`\`\``);
}
}
if (!duration.invoked) duration.invoked = DateTime.fromJSDate(msg.editedAt || msg.createdAt);
if (!duration.until && MUTE.defaultDuration?.duration) duration.until = duration.invoked.plus(MUTE.defaultDuration.duration.object);
if (duration.until?.invalid) duration.until = undefined; else if (duration.until && !duration.duration) {
duration.interval = Interval.fromDateTimes(duration.invoked, duration.until);
duration.duration = fn.intervalToDuration(duration.interval);
}
if (mentions?.length > 0) {
const FR = await targetUser(msg, mentions, targetUsers, resultMsg);
targetUsers = FR.targetUser;
resultMsg = FR.resultMsg;
} else return trySend(this.client, msg, "Args: `<[user_[mention|ID|name]]> -- [reason] -- [duration]`. Use `,` to provide multiple user. `--s` to view settings.\nExample:```js\n" + `${msg.guild.commandPrefix + this.name} 580703409934696449, @Shasha#1234, ur mom,#6969,^yuck\\s(ur)?\\s.{5}#\\d+69$--69y69mo69w420d420h420m420s -- Saying "joe"\`\`\``);
let infractionToDoc;
if (targetUser.length > 0) {
let targetMember = [],
notInServer = [];
for (const user of targetUser) {
const member = msg.guild.member(user);
if (member) {
const pushIt = member.toJSON();
pushIt.rolesID = member.roles.cache.map(r => r.id);
targetMember.push(pushIt);
} else {
const pushIt = user.toJSON();
notInServer.push(pushIt);
}
}
const infractionCase = msg.guild.infractions?.length;
if (targetUsers.length > 0) {
let infractionCase = msg.guild.DB.moderation.infractions?.length,
muted = [], cant = [], already = [], infractionN = [];
infractionToDoc = {
infraction: infractionCase ? infractionCase + 1 : 1,
by: targetUser,
infraction: infractionCase ? infractionCase++ : 1,
by: targetUsers,
moderator: msg.author,
punishment: "mute",
at: invokedAt,
for: timeForMessage,
until: untilDate,
reason: reason,
msg: msg.toJSON(),
members: targetMember,
users: notInServer
msg: msg.toJSON()
}
await col.updateOne({ document: msg.guild.id }, { $push: { "moderation.infractions": infractionToDoc } }, { upsert: true });
for (const EXEC of targetUsers) {
try {
const RES = await EXEC.mute(msg.guild, { duration: duration, infraction: infractionToDoc.infraction, moderator: msg.member }, reason);
if (RES.infraction) infractionN.push(RES.infraction);
muted.push(EXEC.id);
} catch (e) {
if (/Missing Permissions|someone with higher position/.test(e.message)) cant.push(EXEC.id);
else if (/already muted/.test(e.message)) already.push(EXEC.id); else trySend(msg.client, msg, e.message); continue;
}
const emb = defaultEventLogEmbed(msg.guild);
emb.setTitle("You have been muted")
.setDescription("**Reason**\n" + reason)
.addField("At", duration.invoked.toFormat(fn.DT_PRINT_FORMAT), true)
.addField("For", duration.duration?.strings.join(" ") || "Indefinite", true)
.addField("Until", duration.until?.toFormat(fn.DT_PRINT_FORMAT) || "Never", true);
EXEC.createDM().then(r => trySend(msg.client, r, emb));
}
if (muted.length > 0) {
infractionToDoc.executed = muted;
infractionToDoc.aborted = already;
infractionToDoc.failed = cant;
msg.guild.addInfraction(infractionToDoc);
}
const NAME = msg.guild.id + "/" + infractionToDoc.infraction,
newUnmuteSchedule = {
name: NAME,
@ -286,35 +156,30 @@ module.exports = class mute extends commando.Command {
worker: {
argv: [NAME]
},
date: untilDate
date: duration.until?.toJSDate()
};
let emb = defaultImageEmbed(msg, null, "Infraction #" + infractionToDoc.infraction);
if (cant.length > 0) emb.addField("Can't mute", "<@" + cant.join(">, <@") + ">\n\n**You can't mute someone with higher position than you <:nekokekLife:852865942530949160>**");
if (already.length > 0) emb.addField("Already muted", "<@" + already.join(">, <@") + ">\n\nDuration updated for these users");
let mutedStr = "", mutedArr = [];
if (muted.length > 0) for (const U of muted) {
const tU = "<@" + U + ">\n";
if ((mutedStr + tU).length < 1000) mutedStr += tU; else mutedArr.push(U);
}
if (mutedArr.length > 0) mutedStr += `and ${mutedArr.length} more...`;
emb.setDescription("**Reason**\n" + reason)
.addField("Muted", mutedStr || "`[NONE]`")
.addField("At", duration.invoked.toFormat(fn.DT_PRINT_FORMAT), true)
.addField("For", duration.duration?.strings.join(" ") || "Indefinite", true)
.addField("Until", duration.until?.toFormat(fn.DT_PRINT_FORMAT) || "Never", true)
.addField("Reason", reason);
return trySend(msg.client, msg, { content: resultMsg, embed: emb });
}
resultMsg += `Result:\`\`\`js\nUsers: ${targetUser.map(r => r?.tag).join(", ")}\nReason: ${reason}\nAt: ${invokedAt.toUTCString()}\nFor: ${timeForMessage.join(" ")}\nUntil: ${typeof untilDate !== "string" ? untilDate.toUTCString() : untilDate}\`\`\``;
return trySend(msg.client, msg, resultMsg);
resultMsg += `Result:\`\`\`js\nUsers: ${targetUsers.map(r => r?.tag).join(", ")}\nReason: ${reason}\nAt: ${duration.invoked.toFormat("DDD',' cccc',' tt")}\nFor: ${duration.duration?.strings?.join(" ")}\nUntil: ${duration.until?.toFormat("DDD',' cccc',' tt")}\`\`\``;
return trySend(this.client, msg, { content: resultMsg + "```js\n" + JSON.stringify(infractionToDoc, null, 2) + "```", split: { maxLength: 2000, append: ",```", prepend: "```js\n", char: "," } });
}
};
/* if (config.mute.role.length === 0) {
return msg.channel.send(`Mute role isn't set! Run \`${this.client.commandPrefix}mute --role <role_[mention, ID]>\`. If you insist i will just give them admin perms <:purifyLife:774102054046007298>`)
}
if (setArgs) {
for(let set of setArgs) {
set = set.toLowerCase();
switch(set) {
case startsWith('role'): {
let role = set.slice('role'.length).trim();
if (role.startsWith('<&')) {
role = role.slice(2,-1);
}
//const foundRole =
}
}
}
}*/
//scheduler.add()
/*const yearDate = dateDur.getFullYear();
const monthDate = dateDur.getMonth();
const dayDate = dateDur.getDay();
const hourDate = dateDur.getHours();
const minuteDate = dateDur.getMinutes();
const secondDate = dateDur.getSeconds();*/
};

View file

@ -0,0 +1,50 @@
'use strict';
const { Message } = require("discord.js");
const { trySend, parseDash, defaultImageEmbed, defaultSplitMessage } = require("../../../resources/functions");
const getColor = require("../../../resources/getColor");
module.exports = async (msg, arg) => {
if (!msg.member.isAdmin) return trySend(msg.client, msg, "<@" + msg.author + "> you're not an Administrator <:nekohmLife:846371737644957786>");
if (!msg.guild.member(msg.guild.client.user).isAdmin) return trySend(msg.client, msg, "<@" + msg.author + "> i am not an Administrator <:pepewhysobLife:853237646666891274>");
const args = parseDash(arg);
if (!args?.[1]) return trySend(msg.client, msg, "Args: `-n role_[name|mention|ID] -c color_[name|number|hex]`");
let data = { name: "Muted" };
for (const ARG of args) {
const U = ARG.slice(2).trim();
if (ARG.startsWith("n ")) if (U.length > 0) data.name = U;
if (ARG.startsWith("c ")) if (U.length > 0) data.color = getColor(U);
}
if (data.name?.length > 100) return trySend(msg.client, msg, "Role name must be less than 100 characters in length!");
let emb = defaultImageEmbed(msg, null, "Create Mute Role");
emb.addField("Name", data.name)
.setDescription("Respond with **'yes'** if you want to proceed. A new role will be created with the following properties:")
.addField("Color", "This embed's color");
if (data.color) emb.setColor(data.color);
await trySend(msg.client, msg, emb);
const RR = await msg.channel.awaitMessages((r) => r.author === msg.author, { max: 1, time: 30000 });
if (RR.first()?.content.toLowerCase() === "yes") return detonate(msg, data); else return trySend(msg.client, msg, "Create Mute Role: **Cancelled**");
}
async function detonate(msg, data) {
const map = msg.guild.channels.cache.map(r => r);
const pleaseWait = await trySend(msg.client, msg, `Setting up for ${map.length} channel${map.length < 2 ? "" : "s"}... This message will be edited when done.`);
data.permissions = 0;
const ROLE = await msg.guild.roles.create({ data: data, reason: "Create Mute Role" }).catch(() => { });
msg.guild.DB.moderation.settings.mute.role = ROLE.id;
let cant = [];
if (ROLE) {
for (const U of map) {
await U.updateOverwrite(ROLE, { SEND_MESSAGES: false, CONNECT: false }, "Create Mute Role").catch(() => cant.push(U.id));
}
} else return pleaseWait.edit("Create Mute Role: Can't create role. Operation cancelled");
if (cant.length > 0) {
const split = defaultSplitMessage,
mes = "**Can't overwrite permissions in:**\n";
split.append = ",";
split.prepend = "";
trySend(msg.client, msg, { content: mes + "<#" + cant.join(">,\n<#") + ">", split: split });
}
msg.guild.setDb(msg.guild.DB);
return pleaseWait.edit(`Create Mute Role: ${ROLE} **Done**`);
}

View file

@ -1,2 +1,93 @@
'use strict';
const { DateTime, Settings, Interval } = require("luxon"),
DURATION_REGEXP = /[\-]?\d+(?![^ymwdhs])[ymwdhs]?o?/gi,
DT_PRINT_FORMAT = "DDD'\n'cccc',' tt";
Settings.defaultZone = "utc";
/**
*
* @param {Interval} interval
* @returns {{ "object": {years: number, months: number,days: number,hours: number,minutes: number,seconds: number}, strings: string[] }}
*/
function intervalToDuration(interval) {
if (!(interval instanceof Interval)) return;
const object = interval.toDuration(["years", "months", "days", "hours", "minutes", "seconds"], { conversionAccuracy: "longterm" }).toObject();
let strings = [];
for (const S in object) {
object[S] = Math.floor(object[S]);
if (object[S] > 0) strings.push(`${object[S]} ${object[S] === 1 ? S.slice(0, -1) : S}`); else continue;
}
if (strings.length > 0) {
if (strings.length > 1) strings[strings.length - 2] += " and";
return { object, strings };
} else console.log(interval, object);
};
/**
* @param {Date} base - Base date
* @param {string} string - To match /[\-]?\d+(?![^ymwdhs])[ymwdhs]?o?/gi
*/
function duration(base, string) {
const DURATION = {
year: base.getFullYear(),
month: base.getMonth(),
day: base.getDate(),
hour: base.getHours(),
minute: base.getMinutes(),
second: base.getSeconds() + 1
},
DT_INVOKED = DateTime.fromJSDate(base),
DURATION_ARGS = string.match(DURATION_REGEXP);
let changed = false;
console.log(DURATION_ARGS, DT_INVOKED.toFormat(DT_PRINT_FORMAT));
for (const value of DURATION_ARGS) {
const val = parseInt(value.match(/[\-]?\d+/)[0], 10);
console.log(val);
if (!val) continue;
if (value.endsWith("h") || value.endsWith("ho")) {
DURATION.hour = DURATION.hour + val;
if (!changed) changed = true;
continue;
}
if (value.endsWith("y")) {
DURATION.year = DURATION.year + val;
if (!changed) changed = true;
continue;
}
if (value.endsWith("mo")) {
DURATION.month = DURATION.month + val;
if (!changed) changed = true;
continue;
}
if (value.endsWith("w")) {
DURATION.day = DURATION.day + 7 * val;
if (!changed) changed = true;
continue;
}
if (value.endsWith("d")) {
DURATION.day = DURATION.day + val;
if (!changed) changed = true;
continue;
}
if (value.endsWith("m") || !/[^\d\-\+]/.test(value)) {
DURATION.minute = DURATION.minute + val;
if (!changed) changed = true;
continue;
}
if (value.endsWith("s")) {
DURATION.second = DURATION.second + val;
if (!changed) changed = true;
continue;
}
}
let DT_END, DT_INTERVAL;
if (changed) DT_END = DateTime.fromJSDate(new Date(DURATION.year, DURATION.month, DURATION.day, DURATION.hour, DURATION.minute, DURATION.second));
if (DT_END) DT_INTERVAL = Interval.fromDateTimes(DT_INVOKED, DT_END)
return { invoked: DT_INVOKED, until: DT_END, interval: DT_INTERVAL, duration: intervalToDuration(DT_INTERVAL) }
}
module.exports = { duration, DT_PRINT_FORMAT, intervalToDuration }

View file

@ -0,0 +1,44 @@
'use strict';
const { parseDash, defaultImageEmbed, trySend, getRole, cleanMentionID } = require("../../../resources/functions"),
fn = require("./duration"),
ARGS_TEXT = "Args:\n`-r` Role: `role_[name|mention|ID]`,\n`-d` Duration: `[duration]` - Format: `number_[y|mo|w|d|h|m|s]`";
module.exports = (msg, arg) => {
if (!msg.member.isAdmin) return trySend(msg.client, msg, msg.author + " you're not an Administrator <:nekohmLife:846371737644957786>");
const args = parseDash(arg);
let setEmb = defaultImageEmbed(msg, null, "Mute Configuration"),
MUTE = msg.guild.DB.moderation.settings.mute || {},
duration,
role,
resultMsg = "";
console.log(args);
if (arg && !args[1]) setEmb.setDescription(ARGS_TEXT); else if (args?.[1]) {
for (const ARG of args) {
if (ARG.startsWith("r ")) {
const key = cleanMentionID(ARG.slice(2));
if (key === "none") {
role = false;
continue;
}
if (key?.length > 0) role = getRole(msg.guild, key)?.id;
if (role === undefined) resultMsg += `No role found for: **${ARG}**\n`; else msg.guild.DB.moderation.settings.mute.role = role;
}
if (ARG.startsWith("d ")) {
const D = ARG.slice(2).trim();
console.log(D);
if (/^[\-\+]?\d{1,16}(?![^ymwdhs])[ymwdhs]?o?/i.test(D)) {
duration = fn.duration(msg.createdAt, D);
msg.guild.DB.moderation.settings.mute.defaultDuration = duration;
} else resultMsg += "Valid duration format: `number_[y|mo|w|d|h|m|s]`. Example: `69y420w5m72s3mo`";
}
}
MUTE = msg.guild.DB.moderation.settings.mute;
msg.guild.setDb(msg.guild.DB);
}
setEmb
.addField("Role", MUTE.role ? "<@&" + MUTE.role + ">" : "Not set")
.addField("Duration", MUTE.defaultDuration?.duration?.strings?.join(" ") || "Not set");
return trySend(msg.client, msg, { content: resultMsg, embed: setEmb });
}

View file

@ -0,0 +1,45 @@
'use strict';
const { Message, User } = require("discord.js");
const { cleanMentionID, findMemberRegEx } = require("../../../resources/functions");
/**
* @param {Message} msg
* @param {string[]} mentions
* @param {User[]} targetUser
* @param {string} resultMsg
* @returns {Promise<{ targetUser: User[], resultMsg: string }>}
*/
module.exports = async (msg, mentions = [], targetUser = [], resultMsg) => {
if (mentions.length === 0) throw new TypeError("Mentions has no length");
for (const usermention of mentions) {
if (usermention.length > 0) {
let found = [],
nameid = cleanMentionID(usermention);
if (/^\d{17,19}$/.test(nameid)) {
const findmem = msg.guild.member(nameid);
if (findmem) {
found.push(findmem.user);
} else {
await msg.client.users.fetch(nameid).then(fetchUser => found.push(fetchUser)).catch(() => { });
}
} else {
found = findMemberRegEx(msg, nameid).map(r => r.user);
}
if (found.length > 0 && found[0] !== null) {
const foundDupli = targetUser.findIndex(r => r === found[0]);
if (foundDupli !== -1) {
resultMsg += `**[WARNING]** Duplicate for user **${targetUser[foundDupli].tag}** with keyword: **${usermention.trim()}**\n`;
} else {
targetUser.push(found[0]);
if (found.length > 1) {
resultMsg += `**[WARNING]** Multiple users found for: **${usermention.trim()}**\n`;
}
}
} else {
resultMsg += `Can't find user: **${usermention.trim()}**\n`;
}
} else continue;
}
return { targetUser, resultMsg };
}

67
cmds/moderation/unmute.js Normal file
View file

@ -0,0 +1,67 @@
'use strict';
const commando = require("@iceprod/discord.js-commando");
const { parseDoubleDash, trySend, defaultImageEmbed, parseComa, defaultEventLogEmbed } = require("../../resources/functions");
const targetUser = require("./src/targetUser");
module.exports = class unmute extends commando.Command {
constructor(client) {
super(client, {
name: "unmute",
memberName: "unmute",
group: "moderation",
description: "Mute.",
details: "Args: `user_[mention|name|ID] -- [reason]`",
guildOnly: true,
userPermissions: ['MANAGE_ROLES'],
clientPermissions: ['MANAGE_ROLES']
});
}
async run(msg, arg) {
msg.channel.startTyping();
if (!arg) return trySend(msg.client, msg, this.details);
const args = parseDoubleDash(arg),
mentions = parseComa(args.shift());
let reason = "No reason provided", targetUsers = [], resultMsg = "";
if (args?.length > 0) {
for (const ARG of args) if (!ARG || ARG === "--" || ARG.trim().length === 0) continue; else reason = ARG.trim();
}
if (mentions?.length > 0) {
const FR = await targetUser(msg, mentions, targetUsers, resultMsg);
console.log(FR);
targetUsers = FR.targetUser;
resultMsg = FR.resultMsg;
}
let notMuted = [],
cant = [], success = [];
for (const USER of targetUsers) {
if (!USER.DB) await USER.dbLoad();
const L = USER.getMutedIn(msg.guild.id);
if (!L.data) { notMuted.push(USER.id); continue } else {
await USER.unmute(msg.guild, msg.member, reason)
.then(() => {
success.push(USER.id);
const emb = defaultEventLogEmbed(msg.guild);
emb.setTitle("You have been unmuted")
.setDescription("**Reason**\n" + reason);
USER.createDM().then(r => trySend(msg.client, r, emb));
})
.catch((e) => {
console.log(e); cant.push(USER.id)
});
}
}
let emb = defaultImageEmbed(msg, null, "Unmute");
if (cant.length > 0) emb.addField("Can't unmute", "<@" + cant.join(">, <@") + ">");
if (notMuted.length > 0) emb.addField("Wasn't muted", "<@" + notMuted.join(">, <@") + ">");
emb.setDescription("**Unmuted**\n" + (success.length > 0 ? "<@" + success.join(">, <@") + ">" : "`[NONE]`"))
.addField("Reason", reason);
return trySend(msg.client, msg, { content: resultMsg, embed: emb });
}
}

View file

@ -63,7 +63,7 @@ module.exports = class EvalCommand extends Command {
this.lastResult = await eval(args.script);
hrDiff = process.hrtime(hrStart);
} catch (err) {
return msg.reply(`Error while evaluating: \`${err}\``);
return msg.reply(`\`\`\`\n${err.stack}\`\`\``);
}
// Prepare for callback time and respond

View file

@ -36,9 +36,7 @@ module.exports = class embmaker extends commando.Command {
}
async run(msg, arg) {
let isAdmin = true;
if (msg.guild && !this.client.owners.includes(msg.author)) {
if (!msg.member.hasPermission("ADMINISTRATOR")) isAdmin = false;
}
if (msg.guild) isAdmin = msg.member.isAdmin;
const args = parseDoubleDash(arg);
let embed = new MessageEmbed();
let autName, footertext, autIcon, autUrl, footericon, content, channel, editSrc, newAttach = [], reportMessage = "";

View file

@ -66,6 +66,7 @@ module.exports = class perms extends commando.Command {
}
const title = `Permissions for: \`${member.user.tag}\``;
mes += `**Default:**\`\`\`js\n`;
if (msg.member.isAdmin) mes += "'ADMINISTRATOR', ";
if (res.length > 0) {
mes += `${res.join(", ")}\`\`\``;
} else {

30
config_copy.json Normal file
View file

@ -0,0 +1,30 @@
{
"invite": "https://discord.com/oauth2/authorize?client_id=788006279837909032&scope=bot&permissions=8",
"token": "",
"errLogChannel": "822877910138224660",
"randomColors": [
12357519,
16711935,
128,
32896,
15277667,
"00ff00",
"ff0000",
"ff94f2",
"f1e40f",
"ff8c00",
"a0522d",
3447003,
"0fffff",
"803c9d",
"faa775",
"000000",
16777214
],
"defaultErrorLogChannel": "822877910138224660",
"mongoServer": "mongodb://localhost:27017",
"chatChannel": "837178237322919966",
"guildLog": "840154722434154496",
"shardChannel": "851361670533218324",
"home": "772073587792281600"
}

View file

@ -1,16 +1,15 @@
{
"dependencies": {
"@iceprod/discord.js-commando": "^0.14.3",
"@iceprod/discord.js-commando": "github:iceproductions/Commando#next",
"axios": "^0.21.1",
"bree": "^6.2.0",
"bufferutil": "^4.0.3",
"cabin": "^9.0.4",
"discord.js": "^12.5.2",
"discord.js-commando": "^0.12.3",
"discord.js": "^12.5.3",
"erlpack": "github:discord/erlpack",
"fs-extra": "^9.1.0",
"lodash": "^4.17.21",
"moment": "^2.29.1",
"luxon": "^2.0.1",
"mongodb": "^3.6.6",
"nekos-best.js": "^2.0.2",
"node": "^15.12.0",
@ -19,5 +18,8 @@
"sqlite3": "^5.0.2",
"utf-8-validate": "^5.0.4",
"zlib-sync": "^0.1.7"
},
"devDependencies": {
"@types/luxon": "^1.27.1"
}
}

View file

@ -11,11 +11,12 @@ function timestampAt(client) {
/**
*
* @param {String} string
* @param {object} object
* @returns {import("discord.js").MessageOptions}
*/
function makeJSONMessage(string) {
return { content: '```js\n' + JSON.stringify(string, (k, v) => v ?? undefined, 2) + '```', split: { maxLength: 2000, char: ",", append: ',```', prepend: '```js\n' } };
function makeJSONMessage(object) {
console.log(typeof object, object);
return { content: '```js\n' + JSON.stringify(object, (k, v) => v ?? undefined, 2) + '```', split: { maxLength: 2000, char: ",", append: ',```', prepend: '```js\n' } };
}
module.exports = { timestampAt, makeJSONMessage }

View file

@ -4,13 +4,13 @@ const { getChannel, defaultEventLogEmbed, trySend } = require("../functions");
const getColor = require("../getColor");
module.exports = async (GUILD, USER) => {
if (GUILD.eventChannels?.ban) {
if (GUILD.DB.settings.eventChannels?.ban) {
if (USER.partial) USER = await USER.fetch();
const log = getChannel(GUILD, GUILD.eventChannels.ban);
const log = getChannel(GUILD, GUILD.DB.settings.eventChannels.ban);
if (!log) return;
const emb = defaultEventLogEmbed(GUILD);
const rea = (await GUILD.fetchBan(USER)).reason;
emb.setDescription(rea ?? "No reason provided.")
emb.setDescription(rea ?? "No reason provided")
.setTitle(`\`${USER.tag}\` banned`)
.setColor(getColor("red"))
.setThumbnail(USER.displayAvatarURL({ size: 4096, format: "png", dynamic: true }))

View file

@ -10,8 +10,8 @@ const getColor = require("../getColor");
* @returns
*/
module.exports = (member) => {
if (member.guild.eventChannels?.join) {
const log = getChannel(member, member.guild.eventChannels.join);
if (member.guild.DB.settings.eventChannels?.join) {
const log = getChannel(member, member.guild.DB.settings.eventChannels.join);
if (!log) return;
const emb = defaultEventLogEmbed(member.guild);
emb

View file

@ -10,8 +10,8 @@ const getColor = require("../getColor");
* @returns
*/
module.exports = (member) => {
if (member.guild.eventChannels?.leave) {
const log = getChannel(member, member.guild.eventChannels.leave);
if (member.guild.DB.settings.eventChannels?.leave) {
const log = getChannel(member, member.guild.DB.settings.eventChannels.leave);
if (!log) return;
const days = Math.floor(new Date(new Date().valueOf() + member.client.matchTimestamp - member.joinedAt.valueOf()).valueOf() / 86400000),
emb = defaultEventLogEmbed(member.guild);

View file

@ -11,19 +11,19 @@ const getColor = require("../getColor");
* @returns
*/
module.exports = (memberold, membernew) => {
if (!membernew.guild.eventChannels?.memberRole && !membernew.guild.eventChannels?.member) {
if (membernew.user.cachedAvatarURL != membernew.user.displayAvatarURL({ format: "png", size: 4096, dynamic: true })) {
membernew.user.cachedAvatarURL = membernew.user.displayAvatarURL({ format: "png", size: 4096, dynamic: true });
if (!membernew.guild.DB.settings.eventChannels?.memberRole && !membernew.guild.DB.settings.eventChannels?.member) {
if (membernew.user.DB.cachedAvatarURL != membernew.user.displayAvatarURL({ format: "png", size: 4096, dynamic: true })) {
membernew.user.DB.cachedAvatarURL = membernew.user.displayAvatarURL({ format: "png", size: 4096, dynamic: true });
};
return;
return membernew.user.setDb(membernew.user.DB);
}
let log;
const emb = defaultEventLogEmbed(membernew.guild);
emb.setTitle("Profile `" + memberold.user.tag + "` updated")
.setThumbnail(membernew.user.cachedAvatarURL ?? memberold.toJSON().displayAvatarURL)
.setThumbnail(membernew.user.DB.cachedAvatarURL ?? memberold.toJSON().displayAvatarURL)
.setColor(getColor("blue"));
if (membernew.guild.eventChannels?.memberRole) {
log = getChannel(membernew, membernew.guild.eventChannels.memberRole);
if (membernew.guild.DB.settings.eventChannels?.memberRole) {
log = getChannel(membernew, membernew.guild.DB.settings.eventChannels.memberRole);
if (membernew.roles.cache.size > memberold.roles.cache.size) {
emb.addField("Role added", ("<@&" + membernew.roles.cache.difference(memberold.roles.cache).sort((a, b) => b.position - a.position).map(r => r.id).join(">, <@&") + ">").slice(0, 2048))
.setDescription("**Old roles**\n" + (memberold.roles.cache.size > 1 ? "<@&" + memberold.roles.cache.sort((a, b) => b.position - a.position).map(r => r.id).slice(0, -1).join(">, <@&") + ">" : "`[NONE]`"));
@ -33,20 +33,18 @@ module.exports = (memberold, membernew) => {
.setDescription("**Current roles**\n" + (membernew.roles.cache.size > 1 ? "<@&" + membernew.roles.cache.sort((a, b) => b.position - a.position).map(r => r.id).slice(0, -1).join(">, <@&") + ">" : "`[NONE]`"));
}
}
if (membernew.guild.eventChannels?.member && membernew.roles.cache.size === memberold.roles.cache.size) {
log = getChannel(membernew, membernew.guild.eventChannels.member);
if (membernew.guild.DB.settings.eventChannels?.member && membernew.roles.cache.size === memberold.roles.cache.size) {
log = getChannel(membernew, membernew.guild.DB.settings.eventChannels.member);
if (membernew.displayName != memberold.displayName) {
emb.addField("Nickname", "Changed from `" + memberold.displayName + "` to `" + membernew.displayName + "`");
}
if (membernew.user.cachedAvatarURL != membernew.user.displayAvatarURL({ format: "png", size: 4096, dynamic: true })) {
if (membernew.user.DB.cachedAvatarURL != membernew.user.displayAvatarURL({ format: "png", size: 4096, dynamic: true })) {
emb
.setImage(membernew.user.displayAvatarURL({ format: "png", size: 4096, dynamic: true }))
.addField("Avatar", (emb.thumbnail ? "This embed's thumbnail is the user's old avatar.\n" : "") + "The image below is the user's new avatar.");
}
}
if (membernew.user.cachedAvatarURL != membernew.user.displayAvatarURL({ format: "png", size: 4096, dynamic: true })) {
membernew.user.cachedAvatarURL = membernew.user.displayAvatarURL({ format: "png", size: 4096, dynamic: true });
};
membernew.user.refreshDb({ cachedAvatarURL: membernew.user.displayAvatarURL({ format: "png", size: "4096", dynamic: true }) });
if (!emb.fields || emb.fields.length === 0) return;
return trySend(membernew.client, log, emb);
}

View file

@ -11,11 +11,11 @@ const getColor = require("../getColor");
*/
module.exports = async (msg) => {
if (msg.partial) return;
const ignored = msg.guild.eventChannels.mesDel?.ignore?.includes(msg.channel.id) ?? false;
const ignored = msg.guild.DB.settings.eventChannels.mesDel?.ignore.includes(msg.channel.id) ?? false;
let check = false;
if (msg.channel.id === msg.guild.eventChannels?.mesDel?.channel && msg.author ? msg.author !== msg.client.user : false && ignored === false) check = true;
if (msg.guild.eventChannels?.mesDel?.channel !== msg.channel.id && ignored === false || check) {
const log = getChannel(msg, msg.guild.eventChannels.mesDel?.channel);
if (msg.channel.id === msg.guild.DB.settings.eventChannels.mesDel?.channel && msg.author ? msg.author !== msg.client.user : false && ignored === false) check = true;
if (msg.guild.DB.settings.eventChannels.mesDel?.channel !== msg.channel.id && ignored === false || check) {
const log = getChannel(msg, msg.guild.DB.settings.eventChannels.mesDel?.channel);
if (!log || !msg.author) return;
const emb = defaultEventLogEmbed(msg.guild);
emb.setColor(getColor("yellow"))

View file

@ -14,11 +14,11 @@ module.exports = async (msgold, msgnew) => {
if (msgnew.partial) msgnew = await msgnew.fetch();
if (msgnew.partial) return;
if (msgnew.content === msgold.content) return;
const ignored = msgnew.guild.eventChannels.mesEd?.ignore?.includes(msgnew.channel.id) || false;
const ignored = msgnew.guild.DB.settings.eventChannels.mesEd?.ignore?.includes(msgnew.channel.id) || false;
let check = false;
if (msgnew.channel.id === msgnew.guild.eventChannels?.mesEd?.channel && msgnew.author ? msgnew.author !== msgnew.client.user : false && ignored === false) check = true;
if (msgnew.guild.eventChannels?.mesEd?.channel !== msgnew.channel.id && ignored === false || check) {
const log = getChannel(msgnew, msgnew.guild.eventChannels.mesEd?.channel);
if (msgnew.channel.id === msgnew.guild.DB.settings.eventChannels.mesEd?.channel && msgnew.author ? msgnew.author !== msgnew.client.user : false && ignored === false) check = true;
if (msgnew.guild.DB.settings.eventChannels.mesEd?.channel !== msgnew.channel.id && ignored === false || check) {
const log = getChannel(msgnew, msgnew.guild.DB.settings.eventChannels.mesEd?.channel);
if (!log || !msgnew.author) return;
const emb = defaultEventLogEmbed(msgnew.guild);
emb

View file

@ -12,9 +12,9 @@ const { CommandoMessage, CommandoClient } = require('@iceprod/discord.js-command
* @param {Error} theError - Catched error (error)
* @param {CommandoMessage} msg - Message object (msg)
* @param {CommandoClient} client - This client (this.client)
* @param {Boolean} sendTheError - Add error content to notify message (true | false)
* @param {String} errorMessage - Error message ("You don't have enough permission to use that command!")
* @param {Boolean} notify - Send error to user who ran the command
* @param {boolean} sendTheError - Add error content to notify message (true | false)
* @param {string} errorMessage - Error message ("You don't have enough permission to use that command!")
* @param {boolean} notify - Send error to user who ran the command
*/
async function errLog(theError, msg, client, sendTheError, errorMessage, notify) {
if (!client && msg) client = msg.client;
@ -22,7 +22,8 @@ async function errLog(theError, msg, client, sendTheError, errorMessage, notify)
let [ret, logThis, inLogChannel, sendErr] = [undefined, '', '', ''];
if (msg instanceof Message) {
// client.emit("commandError", msg.command, theError, msg);
logThis = `\`${msg.command?.name}\` (${msg.id}) ${msg.url} in ${msg.guild ? `**${msg.channel.name}** (${msg.channel.id}) of **${msg.guild.name}** (${msg.guild.id})` : `**DM**`} ran by **${msg.author.tag}** (${msg.author.id}) \n\n`;
logThis = `\`${msg.command?.name}\` (${msg.id}) ${msg.url} in ${msg.guild ? `**${msg.channel.name}**` +
` (${msg.channel.id}) of **${msg.guild.name}** (${msg.guild.id})` : `**DM**`} ran by **${msg.author.tag}** (${msg.author.id}) \n\n`;
if (errorMessage) {
if (errorMessage.length > 0) {
sendErr = sendErr + errorMessage + '\n';
@ -30,13 +31,23 @@ async function errLog(theError, msg, client, sendTheError, errorMessage, notify)
}
}
if (sendTheError) sendErr = sendErr + '```js\n' + theError.stack + '```';
if (notify) ret = await msg.channel.send(sendErr.trim(), { split: true }).catch(noPerm(msg));
if (notify) ret = await msg.channel.send(sendErr.trim(), {
split: {
maxLength: 2000, char: "\n",
append: '```', prepend: '```js\n'
}
}).catch(noPerm(msg).sfskdufsdgsd);
}
if (client) {
inLogChannel = inLogChannel + '```js\n' + theError.stack + '```';
try {
const sendAt = client.channels.cache.get(defaultErrorLogChannel);
sendAt.send(logThis + inLogChannel.trim() + timestampAt(client), { split: { maxLength: 2000, char: "\n", append: '```', prepend: '```js\n' } });
sendAt.send(logThis + inLogChannel.trim() + timestampAt(client), {
split: {
maxLength: 2000, char: "\n",
append: '```', prepend: '```js\n'
}
});
} catch {
return console.error("Can't log to error channel or not configured.", timestampAt() + ":", theError);
}
@ -47,8 +58,8 @@ async function errLog(theError, msg, client, sendTheError, errorMessage, notify)
/**
* Get message object from the message channel or provided channel
* @param {Message} msg - Message object (msg)
* @param {String} MainID - Message ID | Channel_[mention|ID] | Message link
* @param {String} SecondID - Message ID
* @param {string} MainID - Message ID | Channel_[mention|ID] | Message link
* @param {string} SecondID - Message ID
* @returns {Promise<Message>} Message object | undefined
*/
async function getChannelMessage(msg, MainID, SecondID) {
@ -82,7 +93,7 @@ function execCB(error, stdout, stderr) {
/**
* Command usage logger
* @param {CommandoMessage} msg
* @param {String} addition
* @param {string} addition
*/
async function ranLog(msg, addition) {
if (typeof addition != "string") return console.log(`[RANLOG] Not a string:`, addition);
@ -95,8 +106,8 @@ async function ranLog(msg, addition) {
if (addition && addition.length > 0) embed.setDescription(addition.slice(0, ifCode && addSplit[0]?.[0].length > 0 ? 2044 : 2048) + (ifCode && addSplit[0]?.[0].length > 0 ? "```" : ""));
if (addSplit[0]?.[0].length > 0) for (const add of addSplit) embed.addField("", "```js\n" + add.join(",") + (embed.fields.length < (addSplit.length - 1) ? ",```" : ""));
embed.setFooter(timestampAt(msg.client), msg.guild?.iconURL({ format: "png", size: 128, dynamic: true }));
if (msg.guild) embed.addField("Guild", `\`${msg.guild?.name}\`\n(${msg.guild?.id})`, true);
embed.addField("Channel", (msg.guild ? `<#${msg.channel.id}>\n\`${msg.channel?.name}\`` : `**DM**\n\`${msg.channel.recipient.tag}\``) + `\n(${msg.channel.id})`, true)
if (msg.guild) embed.addField("Guild", `\`${msg.guild.name}\`\n(${msg.guild.id})`, true);
embed.addField("Channel", (msg.guild ? `<#${msg.channel.id}>\n\`${msg.channel.name}\`` : `**DM**\n\`${msg.channel.recipient.tag}\``) + `\n(${msg.channel.id})`, true)
.addField("User", `<@!${msg.author.id}>`, true);
trySend(msg.client, channel, { embed: embed });
}
@ -105,10 +116,10 @@ async function ranLog(msg, addition) {
* Notify when more than one member found when looking in the member list
* @param {Message} msg - Message object
* @param {GuildMember[]} arr - Test array
* @param {String} key - Keyword
* @param {Number} max - Max length
* @param {Boolean} withID - Include user_ID
* @returns {String}
* @param {string} key - Keyword
* @param {number} max - Max length
* @param {boolean} withID - Include user_ID
* @returns {string}
*/
function multipleMembersFound(msg, arr, key, max = 4, withID) {
if (msg && arr.length > 1) {
@ -136,7 +147,7 @@ function multipleMembersFound(msg, arr, key, max = 4, withID) {
/**
* Get member object with RegExp
* @param {Message | GuildMember | Guild} base Object of the guild being searched
* @param {String} key Keyword
* @param {string} key Keyword
* @returns {GuildMember[]} Member object found
*/
function findMemberRegEx(base, key) {
@ -161,7 +172,7 @@ async function noPerm(msg) {
* @param {CommandoClient} client - (this.client)
* @param {Message | String | TextChannel | DMChannel} msgOrChannel Message object | channel_ID
* @param {MessageOptions} content - ({content:content,optionblabla})
* @param {Boolean} checkAd - Check source for Discord invite link (true)
* @param {boolean} checkAd - Check source for Discord invite link (true)
* @returns {Promise<Message>} Sent message object
*/
async function trySend(client, msgOrChannel, content, checkAd = true) {
@ -206,7 +217,7 @@ async function tryDelete(msg) {
/**
* React message
* @param {Message} msg - Message to react (msg)
* @param {String} reaction - Emote ("name:ID")
* @param {string} reaction - Emote ("name:ID")
*/
async function tryReact(msg, reaction) {
if (!msg || !reaction || reaction.length === 0) return;
@ -219,7 +230,7 @@ async function tryReact(msg, reaction) {
/**
* Check message's content for ads
* @param {String} content - Content to check
* @param {string} content - Content to check
*/
function adCheck(content) {
if (content.length > 5) {
@ -232,14 +243,14 @@ function adCheck(content) {
/**
* Make default image embed
* @param {Message | GuildMember} msg
* @param {String} image
* @param {string} image
* @param {GuildMember | User} author
* @param {String} title
* @param {String} footerQuote
* @param {string} title
* @param {string} footerQuote
* @returns {MessageEmbed}
*/
function defaultImageEmbed(msg, image, title, footerQuote) {
if (!footerQuote) footerQuote = (msg.guild ?? msg.author).defaultEmbed?.footerQuote || "";
if (!footerQuote) footerQuote = (msg.guild ?? msg.author).DB.defaultEmbed?.footerQuote || "";
const emb = new MessageEmbed()
.setImage(image)
.setColor(msg.guild ? getColor(msg.member?.displayColor) : randomColors[Math.floor(Math.random() * randomColors.length)])
@ -250,8 +261,8 @@ function defaultImageEmbed(msg, image, title, footerQuote) {
/**
* Return clean ID of provided key
* @param {String} key - Mention | Channel Name | Username | Rolename
* @returns {String} Clean ID
* @param {string} key - Mention | Channel Name | Username | Rolename
* @returns {string} Clean ID
*/
function cleanMentionID(key) {
if (!key || (typeof key !== "string")) return;
@ -266,7 +277,7 @@ function cleanMentionID(key) {
/**
* Get channel object wit RegExp
* @param {Message | GuildMember | Guild} msg Object of the guild being searched
* @param {String} name Keyword
* @param {string} name Keyword
* @param {ChannelType[]} exclude Exclude channel type
* @returns {GuildChannel[]} Channels object found
*/
@ -285,7 +296,7 @@ function findChannelRegEx(msg, name, exclude) {
/**
* Get role object with RegExp
* @param {Message | GuildMember | Guild} msg Object of the guild being searched
* @param {String} name Keyword
* @param {string} name Keyword
* @returns {Role[]} Roles object found
*/
function findRoleRegEx(msg, name) {
@ -298,10 +309,10 @@ function findRoleRegEx(msg, name) {
* Notify when more than one channel found when looking in the channel list
* @param {Message} msg - Message object
* @param {GuildChannel[]} arr - Test array
* @param {String} key - Keyword
* @param {Number} max - Max length
* @param {Boolean} withID - Include channel_ID
* @returns {String}
* @param {string} key - Keyword
* @param {number} max - Max length
* @param {boolean} withID - Include channel_ID
* @returns {string}
*/
function multipleChannelsFound(msg, arr, key, max = 4, withID) {
if (msg && arr.length > 1) {
@ -329,10 +340,10 @@ function multipleChannelsFound(msg, arr, key, max = 4, withID) {
* Notify when more than one role found when looking in the role list
* @param {Message} msg - Message object
* @param {Role[]} arr - Test array
* @param {String} key - Keyword
* @param {Number} max - Max length
* @param {Boolean} withID - Include role_ID
* @returns {String}
* @param {string} key - Keyword
* @param {number} max - Max length
* @param {boolean} withID - Include role_ID
* @returns {string}
*/
function multipleRolesFound(msg, arr, key, max = 4, withID) {
if (msg && arr.length > 1) {
@ -359,7 +370,7 @@ function multipleRolesFound(msg, arr, key, max = 4, withID) {
/**
* Standard
* @param {Message | Guild} msg - Message object
* @param {String} key - Channel ID | Mention | Name
* @param {string} key - Channel ID | Mention | Name
* @param {ChannelType[]} exclude - Exclude channel type
* @returns {GuildChannel | Channel} Channel object
*/
@ -380,7 +391,7 @@ function getChannel(msg, key, exclude) {
/**
* Get guild member using name || tag || ID
* @param {Guild} guild
* @param {String} key - name || tag || ID
* @param {string} key - name || tag || ID
* @returns {GuildMember[]}
*/
function getMember(guild, key) {
@ -398,8 +409,8 @@ function getMember(guild, key) {
/**
* Compare 2 different timestamp
* @param {Number} compare - Number to compare
* @returns {Number} Result
* @param {number} compare - Number to compare
* @returns {number} Result
*/
function getUTCComparison(compare) {
return compare - new Date().valueOf();
@ -412,17 +423,20 @@ function getUTCComparison(compare) {
*/
function defaultEventLogEmbed(guild) {
if (!guild) return;
const C = guild.member(guild.client.user);
return new MessageEmbed()
.setColor(getColor(C.displayColor))
.setAuthor(guild.name)
.setFooter((guild.defaultEmbed?.footerQuote ? guild.defaultEmbed.footerQuote : ""), guild.iconURL({ format: "png", size: 128, dynamic: true }))
.setFooter((guild.DB?.settings?.defaultEmbed?.footerQuote ?
guild.DB.settings.defaultEmbed.footerQuote : ""), guild.iconURL({ format: "png", size: 128, dynamic: true }))
.setTimestamp(new Date());
}
/**
* Split on Length
* @param {Array<String>} arr
* @param {Number} maxLength - Max character length per split
* @param {String} joiner
* @param {number} maxLength - Max character length per split
* @param {string} joiner
* @returns {Array<String[]>}
*/
function splitOnLength(arr, maxLength, joiner = "\n") {
@ -442,29 +456,32 @@ function splitOnLength(arr, maxLength, joiner = "\n") {
/**
* Parse string (split ",")
* @param {String} content
* @param {string} content
* @returns {String[]}
*/
function parseComa(content) {
return content.trim().split(/(?<!\\),+(?!\d*})/);
if (!content) return;
return content.split(/(?<!\\),+(?!\d*})/);
}
/**
* Parse string (split "--")
* @param {String} content
* @param {string} content
* @returns {String[]}
*/
function parseDoubleDash(content) {
return content.trim().split(/(?<!https?:\/\/[^\s\n]+)(?<!\\)(--)+/);
if (!content) return;
return content.split(/(?<!https?:\/\/[^\s\n]+)(?<!\\)(--)+/);
}
/**
* Parse string (split "-")
* @param {String} content
* @param {string} content
* @returns {String[]}
*/
function parseDash(content) {
return content.trim().split(/(?<!https?:\/\/[^\s\n]+)(?<!\\)-(?!-)/);
if (!content) return;
return content.split(/(?<!https?:\/\/[^\s\n]+)(?<!\\)-(?!-)/);
}
const reValidURL = /^https?:\/\/[^\s\n]+\.[^\s\n][^\s\n]/;
@ -472,8 +489,8 @@ const reValidURL = /^https?:\/\/[^\s\n]+\.[^\s\n][^\s\n]/;
/**
* Get user
* @param {Message} msg
* @param {String} key
* @param {Boolean} nonID
* @param {string} key
* @param {boolean} nonID
* @returns {User}
*/
function getUser(msg, key, nonID) {
@ -492,6 +509,7 @@ function getRole(guild, key) {
function wait(ms) { return new Promise(r => setTimeout(() => r(), ms)) }
const defaultSplitMessage = { maxLength: 2000, char: ",", append: ',```', prepend: '```js\n' };
module.exports = {
cleanMentionID, defaultEventLogEmbed,
multipleMembersFound, multipleRolesFound, multipleChannelsFound,
@ -501,5 +519,5 @@ module.exports = {
trySend, tryDelete, tryReact,
adCheck, defaultImageEmbed, getChannel,
splitOnLength, parseComa, parseDoubleDash, getMember,
parseDash, reValidURL, getUser, getRole, wait
parseDash, reValidURL, getUser, getRole, wait, defaultSplitMessage
}

View file

@ -29,28 +29,108 @@ module.exports = function getColor(name) {
return '00ff00';
case 'red':
return 'ff0000';
case 'pink':
return 'ff94f2';
case 'yellow':
return 'f1e40f';
case 'orange':
return 'ff8c00';
case 'brown':
return 'a0522d';
case 'blue':
return 3447003;
case 'light blue':
return '0fffff';
case 'cyan':
return '0fffff';
case 'purple':
return '803c9d';
case 'peach':
return 'faa775';
case 'black':
return '000000';
case 'white':
return 16777214;
case 'cyan':
return '0fffff';
case 'Blue':
return '00bfff';
case 'azure':
return '007fff';
case 'sapphire':
return '0f52ba';
case 'ultramarine':
return '120a8f';
case 'wheat':
return 'f5deb3';
case 'tan':
return 'd2b48c';
case 'rosybrown':
return 'bc8f8f';
case 'brown':
return 'a0522d';
case 'umber':
return '826644';
case 'tea green':
return 'd0f0c0';
case 'pale green':
return '98fb98';
case 'erin':
return '00ff40';
case 'mantis':
return '74c365';
case 'dark green':
return '355e3b';
case 'khaki':
return 'c3b091';
case 'peach':
return 'faa775';
case 'coral':
return 'ff7f50';
case 'orange':
return 'ff8c00';
case 'persimmon':
return 'b45e06';
case 'mimi pink':
return 'ffdae9';
case 'amaranth':
return 'f19cbb';
case 'pink purple':
return 'e62aed';
case 'red violet':
return 'c71585';
case 'raspberry':
return 'e30b5c';
case 'thistle':
return 'd8bfd8';
case 'orchid':
return 'da70d6';
case 'amethyst':
return '9966cc';
case 'purple':
return '803c9d';
case 'eminence':
return '6c3082';
case 'misty roses':
return 'ffe4e1';
case 'pink':
return 'ffc0cb';
case 'bright pink':
return 'ff91a4';
case 'crimson':
return 'dc143c';
case 'dark Red':
return '8b0000';
case 'champagne':
return 'f7e7ce';
case 'cream':
return 'fffdd0';
case 'gold':
return 'ffd700';
case 'dark yellow':
return '999900';
case 'olive':
return '808000';
case 'silver':
return 'c0c0c0';
case 'gray':
return 'a9a9a9';
case 'dark gray':
return 808080;
case 'dim gray':
return 696969;
case 'midnight':
return '000001';
default: {
if (/\D/.test(name)) {
if (name.startsWith("#")) name = name.slice(1);

View file

@ -1,41 +1,61 @@
'use strict';
const { Structures } = require("discord.js"),
const { Structures, Guild, GuildMember } = require("discord.js"),
{ database } = require("../database/mongo"),
{ errLog } = require("./functions");
const { DateTime, Duration } = require("luxon");
Structures.extend("Guild", g => {
return class Guild extends g {
Structures.extend("Guild", u => {
return class Guild extends u {
constructor(client, data) {
super(client, data);
this.dbLoaded = false;
}
async dbLoad() {
return database.collection("Guild").findOne({ document: this.id }).then((r, e) => {
if (e) return errLog(e, null, this.client);
this.infractions = r?.moderation?.infractions || [];
this.moderation = r?.moderation?.settings || {};
this.defaultEmbed = r?.settings?.defaultEmbed || {};
this.quoteOTD = r?.settings?.quoteOTD || {};
this.eventChannels = r?.settings?.eventChannels || {};
return this.dbLoaded = true;
r = r?.DB;
if (!r) r = {};
if (!r.settings) r.settings = {};
if (!r.moderation) r.moderation = {};
if (!r.settings.eventChannels) r.settings.eventChannels = {};
if (!r.moderation.settings) r.moderation.settings = {};
if (!r.moderation.infractions) r.moderation.infractions = [];
return this.DB = r;
});
}
async setDb(Db, empty = false) {
if (typeof Db !== "object") throw new TypeError("Expected 'object'; Got '" + typeof Db + "'");
if (Db === {} && !empty) throw new TypeError("Empty!");
return database.collection("Guild").updateOne({ document: this.id }, { $set: { DB: Db }, $setOnInsert: { document: this.id } },
{ upsert: true }).then((r, e) => {
if (e) return errLog(e, null, this.client);
return this.DB = Db;
});
}
/**
* @param {object} data - Data to set
* @returns
*/
async refreshDb(data) {
if (!this.DB) await this.dbLoad();
if (data) for (const D in data) if (this.DB[D]) this.DB[D] = data[D];
return this.setDb(this.DB);
}
/**
* Get user infractions
* @param {String} get - User ID
* @returns {Promise<Object[]>} Infractions object
* @returns {Promise<Object[]>} Array of infractions objects
*/
async getInfractions(get) {
try {
const r = await database.collection("Guild").findOne({ document: this.id });
this.infractions = r?.moderation?.infractions;
if (!this.DB) await this.dbLoad();
let found = [];
if (this.infractions.length > 0) {
for (const inf of this.infractions) {
if (this.DB.moderation.infractions.length > 0) {
for (const inf of this.DB.moderation.infractions) {
for (const user of inf.by) {
if (user.id === get) {
found.push(inf);
@ -50,46 +70,34 @@ Structures.extend("Guild", g => {
async addInfraction(add) {
try {
const r = await database.collection("Guild").findOne({ document: this.id });
this.infractions = r?.moderation?.infractions;
return database.collection("Guild").updateOne({ document: this.id }, { $push: { "moderation.infractions": add } }, (e) => {
if (e) return errLog(e, null, this.client);
this.infractions.push(add);
return true;
});
if (!this.DB) await this.dbLoad();
this.DB.moderation.infractions.push(add);
return this.setDb(this.DB);
} catch (e) { }
}
async setQuoteOTD(set) {
return database.collection("Guild").updateOne({ document: this.id }, { $set: { "settings.quoteOTD": set }, $setOnInsert: { document: this.id } }, { upsert: true }, (e) => {
if (e) return errLog(e, null, this.client);
this.quoteOTD = set;
return true;
});
if (!this.DB) await this.dbLoad();
this.DB.settings.quoteOTD = set;
return this.setDb(this.DB);
}
async setEventChannels(set) {
return database.collection("Guild").updateOne({ document: this.id }, { $set: { "settings.eventChannels": set }, $setOnInsert: { document: this.id } }, { upsert: true }, (e) => {
if (e) return errLog(e, null, this.client);
this.eventChannels = set;
return true;
});
if (!this.DB) await this.dbLoad();
this.DB.settings.eventChannels = set;
return this.setDb(this.DB);
}
async setDefaultEmbed(set) {
return database.collection("Guild").updateOne({ document: this.id }, { $set: { "settings.defaultEmbed": set }, $setOnInsert: { document: this.id } }, { upsert: true }, (e) => {
if (e) return errLog(e, null, this.client);
this.defaultEmbed = set;
return true;
});
if (!this.DB) await this.dbLoad();
this.DB.settings.defaultEmbed = set;
return this.setDb(this.DB);
}
async setModerationSettings(set) {
return database.collection("Guild").updateOne({ document: this.id }, { $set: { "moderation.settings": set }, $setOnInsert: { document: this.id } }, { upsert: true }, (e) => {
if (e) return errLog(e, null, this.client);
this.moderation = set;
return true;
});
if (!this.DB) await this.dbLoad();
this.DB.moderation.settings = set;
return this.setDb(this.DB);
}
}
});
@ -98,59 +106,170 @@ Structures.extend("User", u => {
return class User extends u {
constructor(client, data) {
super(client, data);
this.dbLoaded = false;
this.cutie = true;
this.F = "F";
}
async setF(string) {
return database.collection("User").updateOne({ document: this.id }, { $set: { F: string }, $setOnInsert: { document: this.id } }, { upsert: true }, (e, r) => {
if (e) return errLog(e, null, this.client);
this.F = string;
return true;
});
}
async dbLoad() {
return database.collection("User").findOne({ document: this.id }).then((r, e) => {
if (e) return errLog(e, null, this.client);
this.defaultEmbed = r?.settings?.defaultEmbed || {};
this.cachedAvatarURL = this.displayAvatarURL({ format: "png", size: 4096, dynamic: true });
this.interactions = r?.interactions || {};
this.description = r?.description;
this.F = r?.F;
return this.dbLoaded = true;
r = r?.DB;
if (!r) r = {};
if (!r.F) r.F = "<:pepewhysobLife:853237646666891274>";
if (!r.cachedAvatarURL) r.cachedAvatarURL = this.displayAvatarURL({ format: "png", size: 4096, dynamic: true });
if (!r.mutedIn) r.mutedIn = [];
if (!r.interactions) r.interactions = {};
return this.DB = r;
});
}
async setDb(Db, empty = false) {
if (typeof Db !== "object") throw new TypeError("Expected 'object'; Got '" + typeof Db + "'");
if (Db === {} && !empty) throw new TypeError("Empty!");
return database.collection("User").updateOne({ document: this.id }, { $set: { DB: Db }, $setOnInsert: { document: this.id } },
{ upsert: true }).then((r, e) => {
if (e) return errLog(e, null, this.client);
return this.DB = Db;
});
}
/**
* @param {object} data - Data to set
* @returns
*/
async refreshDb(data) {
if (!this.DB) await this.dbLoad();
if (data) for (const D in data) if (this.DB[D]) this.DB[D] = data[D];
return this.setDb(this.DB);
}
async setF(string) {
if (!this.DB) await this.dbLoad();
this.DB.F = string;
return this.setDb(this.DB);
}
async setInteractions(count) {
return database.collection("User").updateOne({ document: this.id }, { $set: { interactions: count }, $setOnInsert: { document: this.id } }, { upsert: true }, (e, r) => {
if (e) return errLog(e, null, this.client);
this.interactions = count;
return true;
});
if (!this.DB) await this.dbLoad();
this.DB.interactions = count;
return this.setDb(this.DB);
}
async setDescription(set) {
return database.collection("User").updateOne({ document: this.id }, { $set: { description: set }, $setOnInsert: { document: this.id } }, { upsert: true }, (e, r) => {
if (e) return errLog(e, null, this.client);
this.description = set;
return true;
});
if (!this.DB) await this.dbLoad();
this.DB.description = set;
return this.setDb(this.DB);
}
async setDefaultEmbed(set) {
return database.collection("User").updateOne({ document: this.id }, { $set: { "settings.defaultEmbed": set }, $setOnInsert: { document: this.id } }, { upsert: true }, (e) => {
if (e) return errLog(e, null, this.client);
this.defaultEmbed = set;
return true;
});
if (!this.DB) await this.dbLoad();
this.DB.defaultEmbed = set;
return this.setDb(this.DB);
}
/**
* @param {string} guildID
* @param {{state: boolean, duration: object, infraction: number}} state
* @returns {number}
*/
pushMutedIn(guildID, { state: state = true, duration: duration, infraction: infraction }) {
const push = {
guildID: guildID,
state: state,
duration: duration,
infraction: infraction
}
return this.DB.mutedIn.push(push);
}
removeMutedIn(guildID) {
return this.DB.mutedIn = this.DB.mutedIn.filter((r) => r.guildID !== guildID);
}
/**
* @param {string} guildID
* @returns {{data: {state: boolean, duration: duration, infraction: number, guildID: string}, index: number, count: number}}
*/
getMutedIn(guildID) {
let index = -1;
const hmm = this.DB.mutedIn.filter((r, i) => {
if (r.guildID === guildID) {
index = i;
return true;
} else return false;
}),
data = hmm?.[0],
count = hmm?.length || 0;
const D = { data, index, count };
console.log(D);
return D;
}
/**
* @param {string} guildID
* @param {{state: boolean, duration: object, infraction: number}} state
* @returns {{state: boolean, duration: object, infraction: number, guildID: string}}
*/
updateMutedIn(guildID, { state: state = true, duration: duration, infraction: infraction }) {
const I = this.getMutedIn(guildID)?.index;
if (I === -1) return false;
const push = {
guildID: guildID,
state: state,
duration: duration,
infraction: infraction
};
this.DB.mutedIn[I] = push;
return this.DB.mutedIn[I];
}
/**
* @param {Guild} guild
* @param {string} reason
* @param {{duration: object, saveTakenRoles: boolean, infraction: number, moderator: GuildMember}} data
*/
async mute(guild, data, reason) {
if (!guild || !(guild instanceof Guild)) throw new TypeError("Guild is " + typeof guild);
if (!data?.infraction) throw new Error("Missing infraction id");
if (!this.DB) await this.dbLoad();
if (!guild.DB) await guild.dbLoad();
const MEM = guild.member(this);
if (MEM) {
if (data.moderator.roles.highest.position < MEM.roles.highest.position) throw new Error("You can't mute someone with higher position than you <:nekokekLife:852865942530949160>");
return MEM.mute(data, reason)
} else {
const MC = this.getMutedIn(guild.id);
if (MC?.index > -1) {
if (data.duration && MC.data) {
const ret = this.updateMutedIn(guild.id, { state: true, duration: data.duration, infraction: MC.data.infraction });
this.setDb(this.DB);
return ret;
};
throw new Error("This member is already muted. Provide `[duration]` to set new duration.");
}
const ret = this.pushMutedIn(guild.id, { state: true, duration: data.duration, infraction: data.infraction });
this.setDb(this.DB);
return ret;
};
}
async unmute(guild, moderator, reason) {
if (!guild || !(guild instanceof Guild)) throw new TypeError("Guild is " + typeof guild);
if (!this.DB) await this.dbLoad();
const MEM = guild.member(this);
if (MEM) {
if (moderator.roles.highest.position < MEM.roles.highest.position) throw new Error("You can't mute someone with higher position than you <:nekokekLife:852865942530949160>");
return MEM.unmute(reason)
} else {
const ret = this.removeMutedIn(guild.id);
this.setDb(this.DB);
return ret;
}
}
}
});
Structures.extend("TextChannel", e => {
return class TextChannel extends e {
Structures.extend("TextChannel", u => {
return class TextChannel extends u {
constructor(guild, data) {
super(guild, data);
this.lastMessagesID = [];
@ -165,8 +284,8 @@ Structures.extend("TextChannel", e => {
}
});
Structures.extend("DMChannel", e => {
return class DMChannel extends e {
Structures.extend("DMChannel", u => {
return class DMChannel extends u {
constructor(client, data) {
super(client, data);
this.lastMessagesID = [];
@ -194,14 +313,115 @@ Structures.extend("Message", e => {
};
});
Structures.extend("GuildMember", e => {
return class GuildMember extends e {
Structures.extend("GuildMember", u => {
return class GuildMember extends u {
constructor(client, data, guild) {
super(client, data, guild);
}
async dbLoad() {
return database.collection("GuildMember").findOne({ document: this.id }).then((r, e) => {
if (e) return errLog(e, null, this.client);
r = r?.DB;
if (!r) r = {};
return this.DB = r;
});
}
async setDb(Db, empty = false) {
if (typeof Db !== "object") throw new TypeError("Expected 'object'; Got '" + typeof Db + "'");
if (Db === {} && !empty) throw new TypeError("Empty!");
return database.collection("GuildMember").updateOne({ document: this.id }, { $set: { DB: Db }, $setOnInsert: { document: this.id } },
{ upsert: true }).then((r, e) => {
if (e) return errLog(e, null, this.client);
return this.DB = Db;
});
}
/**
* @param {object} data - Data to set
* @returns
*/
async refreshDb(data) {
if (!this.DB) await this.dbLoad();
if (data) for (const D in data) if (this.DB[D]) this.DB[D] = data[D];
return this.setDb(this.DB);
}
async infractions() {
return this.guild.getInfractions(this.id);
}
/**
* @param {{duration: object, saveTakenRoles: boolean, infraction: number}} data
* @param {string} reason
* @returns
*/
async mute(data, reason) {
if (!this.DB) await this.dbLoad();
if (!this.user.DB) await this.user.dbLoad();
if (!this.guild.DB) await this.guild.dbLoad();
if (!data) throw new Error("Missing infraction id");
const MC = this.user.getMutedIn(this.guild.id);
if (!data.infraction && !MC?.data) throw new Error("Missing infraction id");
if (MC?.index > -1) {
if (data.duration && MC.data) {
const ret = this.user.updateMutedIn(this.guild.id, { state: true, duration: data.duration, infraction: MC.data.infraction });
this.user.setDb(this.user.DB);
return ret;
}
throw new Error("This member is already muted. Provide `[duration]` to set new duration.");
}
if (data.saveTakenRoles === undefined) data.saveTakenRoles = true;
const ROLES = this.roles.cache.filter((r) => !r.managed).map(r => r.id);
if (data.saveTakenRoles && ROLES?.length > 0) {
console.log("populating takenRoles M");
this.DB.takenRoles = ROLES;
}
this.DB.muteRole = this.guild.DB.moderation.settings.mute.role;
try {
if (ROLES?.length > 0) await this.roles.remove(ROLES, reason);
await this.roles.add(this.DB.muteRole, reason);
const ret = this.user.pushMutedIn(this.guild.id, {
state: true,
duration: data.duration,
infraction: data.infraction
});
this.setDb(this.DB);
this.user.setDb(this.user.DB);
return ret;
} catch (e) {
if (this.DB.takenRoles?.length > 0) await this.roles.add(this.DB.takenRoles, reason).catch(() => { });
if (this.DB.muteRole) await this.roles.remove(this.DB.muteRole, reason).catch(() => { });
this.user.removeMutedIn(this.guild.id);
console.log("clear takenRoles M");
this.DB.takenRoles = [];
this.DB.muteRole = undefined;
throw e;
}
}
async unmute(reason) {
if (!this.DB) await this.dbLoad();
if (!this.user.DB) await this.user.dbLoad();
try {
if (this.DB.takenRoles.length > 0) await this.roles.add(this.DB.takenRoles, reason);
if (this.DB.muteRole) await this.roles.remove(this.DB.muteRole, reason);
const ret = this.user.removeMutedIn(this.guild.id);
console.log("clear takenRoles UM");
this.DB.takenRoles = [];
this.DB.muteRole = undefined;
this.setDb(this.DB);
this.user.setDb(this.user.DB)
return ret;
} catch (e) {
throw e;
}
}
get isAdmin() { if (!this.client.owners.includes(this.user)) return this.hasPermission("ADMINISTRATOR"); else return true }
}
});