Plan: Move user punishments to guild

This commit is contained in:
Neko-Life 2021-07-23 14:30:10 +07:00
parent bf43f30da9
commit 2bd1774e4f
13 changed files with 135 additions and 66 deletions

63
cmds/moderation/ban.js Normal file
View file

@ -0,0 +1,63 @@
'use strict';
const commando = require("@iceprod/discord.js-commando");
const { Message } = require("discord.js");
const { DateTime } = require("luxon");
const { parseDoubleDash, trySend } = require("../../resources/functions");
const { duration, CHECK_FOR_DURATION_REGEXP } = require("./src/duration");
const targetUser = require("./src/targetUser");
module.exports = class ban extends commando.Command {
constructor(client) {
super(client, {
name: "ban",
memberName: "ban",
group: "moderation",
description: "Ban pesky troll and toxic members",
guildOnly: true,
userPermissions: ["BAN_MEMBERS"],
clientPermissions: ["BAN_MEMBERS"],
details: "Args: `user_[name|mention|ID] -- [reason] -- [duration] [--d [number of days to delete messages of the user to ban]]`",
examples: ["some user name, some user tag -- 10d76y8m99mo6h70w -- sending unsolicited cakes in DM --d 5"]
});
}
/**
*
* @param {Message} msg
* @param {*} arg
* @returns
*/
async run(msg, arg) {
const args = parseDoubleDash(arg),
target = args?.shift();
let reason = "No reason provided", pDuration = {}, execTarget = [], resultMsg = "", daysToDeleteMessage = 0;
if (!target || target.length < 1) return trySend(msg.client, msg, this.description); else {
const ET = await targetUser(msg, target);
execTarget = ET.targetUser;
resultMsg = ET.resultMsg;
}
if (args?.[1]) {
for (const ARG of args) {
if (ARG === "--" || ARG.trim().length < 1) continue;
if (ARG.startsWith("d ")) {
const U = ARG.slice(2).trim();
if (U.length > 0 && !/\D/.test(U)) daysToDeleteMessage = parseInt(U, 10); else return trySend(msg.client, msg, "Invalid number of days to delete messages!");
continue;
}
else if (CHECK_FOR_DURATION_REGEXP.test(ARG.trim()))
pDuration = duration(msg.editedAt || msg.createdAt, ARG.trim()); else reason = ARG.trim();
}
}
if (!pDuration.invoked) pDuration.invoked = DateTime.fromJSDate(msg.editedAt || msg.createdAt);
if (execTarget.length > 0) {
for (const U of execTarget) {
}
}
}
}

View file

@ -13,6 +13,7 @@ const durationFn = fn.duration;
const targetUser = require("./src/targetUser");
const configureMuteRole = require("./src/configureMuteRole");
const { makeJSONMessage } = require("../../resources/debug");
const createInfraction = require("./src/createInfraction");
Settings.defaultZone = "utc";
/*{
@ -82,12 +83,13 @@ module.exports = class mute extends commando.Command {
if (args?.[1]) {
for (const ARG of args) {
if (ARG === "--" || ARG.trim().length < 1) continue;
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())) {
if (fn.CHECK_FOR_DURATION_REGEXP.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 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` +
@ -110,19 +112,8 @@ module.exports = class mute extends commando.Command {
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 (targetUsers.length > 0) {
let infractionCase = msg.guild.DB.moderation.infractions?.length,
muted = [], cant = [], already = [], infractionN = [];
infractionToDoc = {
infraction: infractionCase ? infractionCase++ : 1,
by: targetUsers,
moderator: msg.author,
punishment: "mute",
reason: reason,
msg: msg.toJSON()
}
let muted = [], cant = [], already = [], infractionN = [];
for (const EXEC of targetUsers) {
try {
@ -142,12 +133,13 @@ module.exports = class mute extends commando.Command {
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);
}
let infractionToDoc = createInfraction(msg, targetUsers, "mute", reason);
infractionToDoc.executed = muted;
infractionToDoc.aborted = already;
infractionToDoc.failed = cant;
if (muted.length > 0) msg.guild.addInfraction(infractionToDoc);
const NAME = msg.guild.id + "/" + infractionToDoc.infraction,
newUnmuteSchedule = {

View file

@ -0,0 +1,21 @@
'use strict';
const { Message, User } = require("discord.js");
/**
* @param {Message} msg
* @param {User[]} targetUsers
* @param {["ban"|"mute"|"kick"|"strike"]} punishment
* @param {string} reason
*/
module.exports = (msg, targetUsers, punishment, reason) => {
let infractionCase = msg.guild.DB.moderation.infractions?.length;
return {
infraction: infractionCase ? infractionCase++ : 1,
by: targetUsers,
moderator: msg.author,
punishment: punishment,
reason: reason,
msg: msg.toJSON()
}
}

View file

@ -2,7 +2,8 @@
const { DateTime, Settings, Interval } = require("luxon"),
DURATION_REGEXP = /[\-]?\d+(?![^ymwdhs])[ymwdhs]?o?/gi,
DT_PRINT_FORMAT = "DDD'\n'cccc',' tt";
DT_PRINT_FORMAT = "DDD'\n'cccc',' tt",
CHECK_FOR_DURATION_REGEXP = /^[\-\+]?\d{1,16}(?![^ymwdhs])[ymwdhs]?o?/i;
Settings.defaultZone = "utc";
/**
@ -90,4 +91,4 @@ function duration(base, string) {
return { invoked: DT_INVOKED, until: DT_END, interval: DT_INTERVAL, duration: intervalToDuration(DT_INTERVAL) }
}
module.exports = { duration, DT_PRINT_FORMAT, intervalToDuration }
module.exports = { duration, DT_PRINT_FORMAT, intervalToDuration, DURATION_REGEXP, CHECK_FOR_DURATION_REGEXP }

View file

@ -10,7 +10,7 @@ const { cleanMentionID, findMemberRegEx } = require("../../../resources/function
* @param {string} resultMsg
* @returns {Promise<{ targetUser: User[], resultMsg: string }>}
*/
module.exports = async (msg, mentions = [], targetUser = [], resultMsg) => {
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) {

View file

@ -18,7 +18,7 @@ module.exports = class UnknownCommandCommand extends Command {
// eslint-disable-next-line
async run(msg) {
if (msg.guild && !msg.member.hasPermission("MANAGE_MESSAGES")) return;
if (new RegExp("^<@\!?" + msg.client.user.id + ">\s").test(msg.content)) {
if (new RegExp("^<@\!?" + msg.client.user.id + ">.").test(msg.content)) {
msg.channel.startTyping();
const s = msg.cleanContent.slice((msg.guild ? msg.guild.member(msg.client.user).displayName.length : msg.client.user.username.length) + 2).trim();
return trySend(msg.client, msg, await chatAnswer(s));

View file

@ -16,7 +16,7 @@ module.exports = class avatar extends commando.Command {
});
}
async run(msg, arg) {
const doc = msg.guild ?? msg.author;
const doc = msg.guild.DB.settings || msg.author.DB;
const footerQuote = doc.defaultEmbed?.footerQuote;
const option = "";// || arg.match(/(?<!\\)--s +\d+/)?.[0];
let user, avatar, member, show, notFound = "";

View file

@ -2,10 +2,10 @@
const commando = require("@iceprod/discord.js-commando");
const { MessageEmbed, User, Message } = require("discord.js");
const { DateTime } = require("luxon");
const { DateTime, Interval } = require("luxon");
const { errLog, trySend, getUser, defaultImageEmbed, splitOnLength } = require("../../resources/functions");
const getColor = require("../../resources/getColor");
const { DT_PRINT_FORMAT } = require("../moderation/src/duration");
const { DT_PRINT_FORMAT, intervalToDuration } = require("../moderation/src/duration");
module.exports = class profile extends commando.Command {
constructor(client) {
@ -31,13 +31,13 @@ module.exports = class profile extends commando.Command {
emb = defaultImageEmbed(msg, null, `\`${TM.tag}\`'s Profile`);
emb
.setThumbnail(TM.displayAvatarURL({ format: "png", size: 4096, dynamic: true }))
.addField("Registered", DateTime.fromJSDate(TM.createdAt).toFormat(DT_PRINT_FORMAT), true)
.addField("ID", TM.id, true);
.addField("ID", TM.id)
.addField("Registered", "<t:" + (Math.floor(TM.createdAt.valueOf() / 1000)) + ":F>");
if (TM.description) emb.setDescription(TM.description);
if (MEM) {
const RI = MEM.roles.cache.sort((a, b) => b.position - a.position).map(r => r.id).slice(0, -1),
RFS = splitOnLength(RI, 1010, ">, <@&");
emb.addField("Joined", DateTime.fromJSDate(MEM.joinedAt).toFormat(DT_PRINT_FORMAT))
RFS = splitOnLength(RI, 1010, ">, <@&"), INT = Interval.fromDateTimes(DateTime.fromJSDate(MEM.joinedAt), DateTime.now());
emb.addField("Joined", "<t:" + (Math.floor(MEM.joinedAt.valueOf() / 1000)) + `:F>\n(${intervalToDuration(INT).strings.join(" ")} ago)`)
.addField("Nick", `\`${MEM.displayName}\``);
if (RFS[0]?.length > 0) {
for (const p of RFS) {

View file

@ -9,8 +9,8 @@ const getColor = require("../../resources/getColor");
module.exports = class servav extends commando.Command {
constructor(client) {
super(client, {
name: "serv-av",
memberName: "serv-av",
name: "servav",
memberName: "servav",
aliases: ["server-avatar", "serv-avatar", "server-av"],
group: "profile",
description: "Show server avatar."
@ -20,7 +20,7 @@ module.exports = class servav extends commando.Command {
const server_ID = arg.split(/ +/)[0];
const doc = msg.guild?.id ?? msg.author.id;
const col = database.collection(msg.guild ? "Guild" : "User");
col.findOne({document: doc}, (err, res) => {
col.findOne({ document: doc }, (err, res) => {
if (err) {
errLog(err, msg, this.client);
}
@ -36,15 +36,15 @@ module.exports = class servav extends commando.Command {
target = msg.guild;
}
if (target) {
icon = target.iconURL({size:4096, dynamic:true});
icon = target.iconURL({ size: 4096, dynamic: true });
} else {
return trySend(this.client, msg, "I'm not in that server...");
}
if (icon) {
let embed = new MessageEmbed()
.setImage(icon)
.setTitle(target.name)
.setFooter(footerQuote ?? "");
.setImage(icon)
.setTitle(target.name)
.setFooter(footerQuote ?? "");
if (target.owner.displayColor) {
const color = getColor(target.owner.displayColor)
embed.setColor(color);

View file

@ -8,22 +8,17 @@ module.exports = class setfootq extends commando.Command {
constructor(client) {
super(client, {
name: "setfootq",
aliases:["setfooterquote"],
aliases: ["setfooterquote"],
memberName: "setfootq",
group: "utility",
description: "Set server embed footer text.",
userPermissions: ["ADMINISTRATOR"]
userPermissions: ["MANAGE_GUILD"]
});
}
async run(msg, args) {
try {
if (msg.guild ? !msg.guild.member(msg.author).hasPermission("MANAGE_GUILD") : false && !this.client.owners.includes(msg.author)) {
return trySend(this.client, msg, 'No lol');
}
let oldQ = msg.guild?.defaultEmbed ?? msg.author.defaultEmbed;
if (!oldQ) {
oldQ = {};
}
let oldQ = msg.guild ? msg.guild.DB.settings.defaultEmbed : msg.author.DB.defaultEmbed;
if (!oldQ) oldQ = {};
const newQ = oldQ?.footerQuote;
oldQ.footerQuote = args.trim();
const r = msg.guild ? msg.guild.setDefaultEmbed(oldQ) : msg.author.setDefaultEmbed(oldQ);

View file

@ -20,7 +20,7 @@ module.exports = (member) => {
.setTitle("`" + member.user.tag + "` joined")
.setThumbnail(member.user.displayAvatarURL({ format: "png", size: 4096, dynamic: true }))
.setColor(getColor("cyan"))
.addField("Registered", DateTime.fromJSDate(member.user.createdAt).toFormat(DT_PRINT_FORMAT), true)
.addField("Registered", "<t:" + (Math.floor(member.user.createdAt.valueOf() / 1000)) + ":F>", true)
.setDescription(`<@!${member.id}> (${member.id}) just joined.\nWe have ${member.guild.memberCount} total members now.`);
return trySend(member.client, log, emb);
}

View file

@ -18,15 +18,14 @@ module.exports = (member) => {
const emb = defaultEventLogEmbed(member.guild),
RO = member.roles.cache.sort((a, b) => b.position - a.position).map(r => r.id).slice(0, -1),
RU = splitOnLength(RO, 1010, ">, <@&"),
JO = DateTime.fromJSDate(member.user.createdAt),
LE = DateTime.fromJSDate(member.joinedAt),
INT = Interval.fromDateTimes(LE, DateTime.now());
emb
.setTitle("`" + member.user.tag + "` left")
.setThumbnail(member.user.displayAvatarURL({ format: "png", size: 4096, dynamic: true }))
.setColor(getColor("yellow"))
.addField("Registered", JO.toFormat(DT_PRINT_FORMAT), true)
.addField("Joined", LE.toFormat(DT_PRINT_FORMAT) + `\n(${intervalToDuration(INT).strings.join(" ")} ago)`, true)
.addField("Registered", "<t:" + (Math.floor(member.user.createdAt.valueOf() / 1000)) + ":F>", true)
.addField("Joined", "<t:" + (Math.floor(member.joinedAt.valueOf() / 1000)) + `:F>\n(${intervalToDuration(INT).strings.join(" ")} ago)`, true)
.addField("Nick", "`" + member.displayName + "`")
.setDescription(`<@!${member.id}> (${member.id}) just left.\nWe have ${member.guild.memberCount} total members now.`);
for (const U of RU) {

View file

@ -1,6 +1,6 @@
'use strict';
const { Structures, Guild, GuildMember } = require("discord.js"),
const { Structures, Guild, GuildMember, BanOptions } = require("discord.js"),
{ database } = require("../database/mongo"),
{ errLog } = require("./functions");
const { DateTime, Duration } = require("luxon");
@ -20,7 +20,8 @@ Structures.extend("Guild", u => {
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 = [];
if (!r.moderation.infractions) r.moderation.infractions = new Map();
if (!r.moderation.timedPunishments) r.moderation.timedPunishments = new Map();
return this.DB = r;
});
}
@ -48,23 +49,12 @@ Structures.extend("Guild", u => {
/**
* Get user infractions
* @param {String} get - User ID
* @returns {Promise<Object[]>} Array of infractions objects
* @returns {Promise<Map>} Array of infractions objects
*/
async getInfractions(get) {
try {
if (!this.DB) await this.dbLoad();
let found = [];
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);
break;
}
}
}
}
return found;
return this.DB.moderation.infractions.filter(r => r.map(u => u.id).includes(get));
} catch (e) { }
}
@ -265,6 +255,14 @@ Structures.extend("User", u => {
return ret;
}
}
/**
* @param {Guild} guild
* @param {BanOptions} option
*/
async ban(guild, option) {
guild.members.ban(this, option);
}
}
});