galactic-bot/structure/moderation/infractions/Prune.js

176 lines
7.6 KiB
JavaScript

const { Infraction } = require('../interfaces/');
const { Collection } = require('../../../util/');
const Arguments = ['users', 'bots', 'text', 'startswith', 'endswith', 'emojis', 'reactions', 'emojis', 'reactions', 'images', 'attachments'];
class Prune extends Infraction {
constructor(client, opts = {}) {
super(client, {
type: 'PRUNE',
targetType: 'channel',
message: opts.message,
arguments: opts.arguments,
executor: opts.executor.user,
target: opts.target,
reason: opts.reason || 'N/A',
guild: opts.guild,
channel: opts.channel,
silent: opts.silent,
color: 0xdb36fc,
dictionary: {
past: 'pruned',
present: 'prune'
},
data: opts.data
});
this.client = client;
this.channel = opts.target;
}
async execute() {
const { amount, message } = this.data;
let messages = await this.fetchMessages(message, amount); //Collection, not array.
if(messages.size === 0) return this._fail('C_PRUNE_NOTFETCHED');
const hasOld = messages.some((m) => m.createdTimestamp >= Date.now()+1209600000); //I hope Node.js can handle these large of numbers.. e_e (2 weeks)
const hasUndeletable = messages.some((m) => m.deletable);
messages = messages.filter((m) => m.deletable);
if(messages.size === 0) return this._fail('C_PRUNE_NOTDELETABLE');
const filtered = await this.filterMessages(messages);
if(filtered.size === 0) return this._fail('C_PRUNE_NOFILTERRESULTS');
const deleted = await this.deleteMessages(filtered);
if(deleted === 0) return this._fail('C_PRUNE_NODELETE');
await this.handle();
return this._succeed('C_PRUNE_AMOUNT', {
hasOld: deleted > amount ? hasOld : false,
hasUndeletable: deleted > amount ? hasUndeletable : false,
amount: deleted
});
}
async deleteMessages(messages) {
let amount = 0;
const bulkDelete = async(messages) => {
try {
const deleteThese = messages.splice(0, 100);
const result = await this.target.bulkDelete(deleteThese, true); //Filtering old just incase, d.js uses Snowflake times instead of our Client's timestamp.
if(result && result.size > 0) amount += result.size;
} catch(error) {} //eslint-disable-line no-empty
if(messages.length > 0) {
await bulkDelete(messages);
}
};
await bulkDelete(messages.array());
return amount;
}
async filterMessages(messages) {
const a = this.arguments;
const filters = {
AND: (m) => {
return (a.users ? a.users.value.map((u) => u.id).includes(m.author.id) : true)
&& (a.bots ? m.author.bot : true)
&& (a.text ? m.content.toLowerCase().includes(a.text.value.toLowerCase()) : true)
&& (a.startswith ? m.content.toLowerCase().startsWith(a.startswith.value.toLowerCase()) : true)
&& (a.endswith ? m.content.toLowerCase().endsWith(a.endswith.value.toLowerCase()) : true)
&& (a.emojis ? (/<?(a)?:?(\w{2,32}):(\d{17,19})>?/u).match(m.content) : true) //does not support unicode emojis... might want to support? idk
&& (a.reactions ? m.reactions.cache.size > 0 : true)
&& (a.images ? m.attachments.some((a) => a.height && a.width) : true)
&& (a.attachments ? m.attachments.size > 0 : true);
},
OR: (m) => {
return (a.users ? a.users.value.map((u) => u.id).includes(m.author.id) : false)
|| (a.bots ? m.author.bot : false)
|| (a.text ? m.content.toLowerCase().includes(a.text.value.toLowerCase()) : false)
|| (a.startswith ? m.content.toLowerCase().startsWith(a.startswith.value.toLowerCase()) : false)
|| (a.endswith ? m.content.toLowerCase().endsWith(a.endswith.value.toLowerCase()) : false)
|| (a.emojis ? (/<?(a)?:?(\w{2,32}):(\d{17,19})>?/u).match(m.content) : false) //does not support unicode emojis... might want to support? idk
|| (a.reactions ? m.reactions.cache.size > 0 : false)
|| (a.images ? m.attachments.some((a) => a.height && a.width) : false)
|| (a.attachments ? m.attachments.size > 0 : false);
},
NAND: (m) => {
return (a.users ? !a.users.value.map((u) => u.id).includes(m.author.id) : true)
&& (a.bots ? !m.author.bot : true)
&& (a.text ? !m.content.toLowerCase().includes(a.text.value.toLowerCase()) : true)
&& (a.startswith ? !m.content.toLowerCase().startsWith(a.startswith.value.toLowerCase()) : true)
&& (a.endswith ? !m.content.toLowerCase().endsWith(a.endswith.value.toLowerCase()) : true)
&& (a.emojis ? !(/<?(a)?:?(\w{2,32}):(\d{17,19})>?/u).match(m.content) : true) //does not support unicode emojis... might want to support? idk
&& (a.reactions ? m.reactions.cache.size === 0 : true)
&& (a.images ? !m.attachments.some((a) => a.height && a.width) : true)
&& (a.attachments ? m.attachments.size === 0 : true);
},
NOR: (m) => {
return (a.users ? !a.users.value.map((u) => u.id).includes(m.author.id) : false)
|| (a.bots ? !m.author.bot : false)
|| (a.text ? !m.content.toLowerCase().includes(a.text.value.toLowerCase()) : false)
|| (a.startswith ? !m.content.toLowerCase().startsWith(a.startswith.value.toLowerCase()) : false)
|| (a.endswith ? !m.content.toLowerCase().endsWith(a.endswith.value.toLowerCase()) : false)
|| (a.emojis ? !(/<?(a)?:?(\w{2,32}):(\d{17,19})>?/u).match(m.content) : false) //does not support unicode emojis... might want to support? idk
|| (a.reactions ? m.reactions.cache.size === 0 : false)
|| (a.images ? !m.attachments.some((a) => a.height && a.width) : false)
|| (a.attachments ? m.attachments.size === 0 : false);
}
};
const type = a.and ? 'AND' : 'OR';
const method = a.not ? `N${type}` : type;
let found = false;
for(const arg of Object.keys(a)) {
if(Arguments.includes(arg)) found = true;
}
if(!found) return messages;
return messages.filter((m) => {
return filters[method](m);
});
}
async fetchMessages(message, amount) {
let fetched = new Collection();
const fetch = async (lastMessage, amount) => {
const messages = await this.target.messages.fetch({
limit: amount > 100 ? 100 : amount,
before: lastMessage,
after: this.arguments.after ? this.arguments.after.value : null
});
fetched = fetched.concat(messages);
const remaining = amount - 100;
if(remaining > 0) {
await fetch(messages.lastKey(), remaining);
}
};
await fetch(this.arguments.before ? this.arguments.before.value : message, amount);
return fetched;
}
description() {
return `\n${this.guild.format('INFRACTION_DESCRIPTIONAMOUNT', { amount: this.data.amount })}`;
}
}
module.exports = Prune;