1
0
mirror of https://github.com/toast-ts/Daggerbot-TS.git synced 2024-12-27 20:35:38 -05:00

Push part 2

This commit is contained in:
AnxietyisReal 2022-11-14 00:46:50 +11:00
parent c943158538
commit d2ebea40aa
13 changed files with 3593 additions and 124 deletions

View File

@ -1,9 +1,34 @@
import { Client, GatewayIntentBits, Partials } from 'discord.js';
import Discord = require('discord.js');
import fs = require('node:fs');
import database from './database';
interface createTableOpt {
columnAlign: any,
columnSeparator: any,
columnEmptyChar: any
}
interface formatTimeOpt {
longNames: boolean,
commas: boolean
}
interface Punishment {
id: number;
type: string;
member: string;
moderator: string;
expired?: boolean;
time?: number;
reason: string;
endTime?: number;
cancels?: number;
duration?: number;
}
interface CommandInfoOpt {
insertNewline: boolean,
parts: string[], //idfk
titles: string[]
}
import Discord, { Client, GatewayIntentBits, Partials } from 'discord.js';
import fs from 'node:fs';
import { Database } from './database';
import timeNames from './timeNames.js';
class TClient extends Client {
export class TClient extends Client {
invites: any;
commands: any;
config: any;
@ -17,11 +42,13 @@ class TClient extends Client {
messageCollector: any;
attachmentBuilder: any;
moment: any;
xjs: any;
axios: any;
memberCount_LastGuildFetchTimestamp: any;
userLevels: any;
punishments: any;
bonkCount: any;
bannedWords: any;
userLevels: Database;
punishments: Database;
bonkCount: Database;
bannedWords: Database;
repeatedMessages: any;
setMaxListeners: any;
@ -38,7 +65,7 @@ class TClient extends Client {
Partials.Reaction,
Partials.Message
],
allowedMentions: { repliedUser: false }
allowedMentions: { repliedUser: false, parse: ['roles', 'users'] }
})
this.invites = new Map();
this.commands = new Discord.Collection();
@ -58,14 +85,16 @@ class TClient extends Client {
this.collection = Discord.Collection;
this.messageCollector = Discord.MessageCollector;
this.attachmentBuilder = Discord.AttachmentBuilder;
this.moment = require('moment');
this.moment = import('moment');
this.xjs = import('xml-js');
this.axios = import('axios');
this.memberCount_LastGuildFetchTimestamp = 0;
this.userLevels = new database('./database/userLevels.json', 'object');
this.bonkCount = new database('./database/bonkCount.json', 'object');
this.punishments = new database('./database/punishments.json', 'array');
this.bannedWords = new database('./database/bannedWords.json', 'array');
this.userLevels = new Database('./database/userLevels.json', 'object');
this.bonkCount = new Database('./database/bonkCount.json', 'object');
this.punishments = new Database('./database/punishments.json', 'array');
this.bannedWords = new Database('./database/bannedWords.json', 'array');
this.repeatedMessages = {};
this.setMaxListeners(20)
this.setMaxListeners(80)
}
async init(){
this.login(this.tokens.token_toast);
@ -74,13 +103,72 @@ class TClient extends Client {
this.bonkCount.initLoad();
this.userLevels.initLoad().intervalSave(15000).disableSaveNotifs();
}
formatPunishmentType(punishment: any, client: any, cancels: any){
commandInfo(client: TClient, command: any, options?: CommandInfoOpt){
let text = ':small_orange_diamond: ';
if (!options.titles) options.titles = [];
function e(){
text += '\n';
if (options.insertNewline){
text += '\n';
} return;
}
if (options.parts.includes('name') && command.name){
if (options.titles.includes('name') && options.titles.includes('usage')){
text += 'Name & Usage: ';
} else if (options.titles.includes('name')){
text += 'Name: ';
}
text += '`' + client.config.prefix + command.name;
if (options.parts.includes('usage') && command.usage){
text += ' ' + command.usage.map((x:string)=>x.startsWith('?') ? '?['+x.slice(1)+']' : '['+x+']').join(' ');
}
text += '`';
e();
} else if (options.parts.includes('usage') && command.usage){
if (options.titles.includes('usage')) text += 'Usage: ';
text += '`'+command.usage.map((x:string)=>x.startsWith('?') ? '?['+x+']' : '['+x+']').join(' ') + '`';
e();
}
if (options.parts.includes('description') && command.description){
if (options.titles.includes('description')) text += 'Description: ';
text += command.description;
e();
}
if (options.parts.includes('shortDescription')){
if (command.shortDescription){
if (options.titles.includes('shortDescription')) text += 'Shorter description: ';
text += command.shortDescription;
e();
} else if (!options.titles.includes('shortDescription') && command.description){
text += command.description;
e();
}
}
if (options.parts.includes('alias') && command.alias){
if (options.titles.includes('alias')) text += 'Aliases: ';
text += command.alias.map((x:any)=>'`'+x+'`').join(', ');
e();
}
if (options.parts.includes('category') && command.category){
if (options.titles.includes('category')) text += 'Category: ';
text += command.category;
e();
}
if (options.parts.includes('autores') && command.autores){
if (options.titles.includes('autores')) text += 'AutoResponse:tm: Requirements: ';
text += '`['+command.autores.join('] [')+']`';
e();
}
e();
return text;
}
formatPunishmentType(punishment: Punishment, client: TClient, cancels: Punishment){
if (punishment.type == 'removeOtherPunishment'){
cancels ||= this.punishments._content.find(x=>x.id === punishment.cancels)
cancels ||= this.punishments._content.find((x: Punishment)=>x.id === punishment.cancels)
return cancels.type[0].toUpperCase()+cancels.type.slice(1)+' Removed';
} else return punishment.type[0].toUpperCase()+punishment.type.slice(1);
}
formatTime(integer: number, accuracy = 1, options = {}){
formatTime(integer: number, accuracy = 1, options?: formatTimeOpt){
let achievedAccuracy = 0;
let text = '';
const { longNames, commas } = options
@ -95,19 +183,189 @@ class TClient extends Client {
break;
}
}
if (text.length == 0) text = integer + (longNames ? ' milliseconds' : 'ms') + (commas ? ', ' : '');
if (commas){
if (text.length == 0) text = integer + (options?.longNames ? ' milliseconds' : 'ms') + (options?.commas ? ', ' : '');
if (options?.commas){
text = text.slice(0, -2);
if (longNames){
if (options?.longNames){
text = text.split('');
text[text.lastIndexOf(',')] = ' and';
text = text.join('');
}
} return text.trim();
}
}
module.exports = TClient;
isStaff(guildMember: Discord.GuildMember){
return this.config.mainServer.staffRoles.map((x: string)=>this.config.mainServer.roles[x]).some((x: string)=>guildMember.roles.cache.has(x))
}
alignText(text: string, length: number, alignment: string, emptyChar = ' '){
if (alignment == 'right'){
text = emptyChar.repeat(length - text.length)+text;
} else if (alignment == 'middle'){
const emptyCharsPerSide = (length - text.length)/2;
text = emptyChar.repeat(Math.floor(emptyCharsPerSide))+text+emptyChar.repeat(Math.floor(emptyCharsPerSide));
} else {
text = text + emptyChar.repeat(length - text.length);
} return text;
}
createTable(columnTitles = [], rowsData = [], options: createTableOpt, client: TClient){
const rows: any = [];
let { columnAlign = [], columnSeparator = [], columnEmptyChar = [] } = options;
if (columnSeparator.length < 1) columnSeparator.push('|');
columnSeparator = columnSeparator.map((x: string)=>`${x}`);
// col widths
const columnWidths = columnTitles.map((title: any, i)=>Math.max(title.length, ...rowsData.map((x: any)=>x[i].length)));
// first row
rows.push(columnTitles.map((title, i)=>{
let text = client.alignText(title, columnWidths[i], columnAlign[i], columnEmptyChar[i]);
if (columnSeparator[i]){
text += ' '.repeat(columnSeparator[i].length);
}
return text;
}).join(''))
// big line
rows.push('━'.repeat(rows[0].length));
//data
// remove unicode
rowsData.map((row: any)=>{
return row.map((element: string)=>{
return element.split('').map((char: string)=>{
if (char.charCodeAt(0)>128) return '□';
}).join('')
})
})
rows.push(rowsData.map((row: any)=>row.map((element: string, i: number)=>{
return client.alignText(element, columnWidths[i], columnEmptyChar[i])+(i === columnTitles.length - 1 ? '' : columnSeparator[i]);
}).join('')
).join('\n'))
export function init() {
throw new Error('Function not implemented.');
}
return rows.join('\n');
}
makeModlogEntry(data: Punishment, client: TClient){
const cancels = data.cancels ? client.punishments._content.find((x: Punishment)=>x.id === data.cancels) : null;
// turn data into embed
const embed = new this.embed().setColor(this.config.embedColor).setTimestamp(data.time)
.setTitle(`${this.formatPunishmentType(data, client, cancels)} | Case #${data.id}`).addFields(
{name: '🔹 User', value: `<@${data.member}> \`${data.member}\``, inline: true},
{name: '🔹 Moderator', value: `<@${data.moderator}> \`${data.moderator}\``, inline: true},
{name: '\u200b', value: `\u200b`, inline: true},
{name: '🔹 Reason', value: `\`${data.reason || 'Unspecified'}\``, inline: true},
)
if (data.duration) {
embed.addFields(
{name: '🔹 Duration', value: client.formatTime(data.duration, 100), inline: true},
{name: '\u200b', value: '\u200b', inline: true}
)
}
if (data.cancels) embed.addFields({name: '🔹 Overwrites', value: `This case overwrites Case #${cancels.id} \`${cancels.reason}\``})
// send embed to log channel
(client.channels.cache.get(client.config.mainServer.channels.logs) as Discord.TextChannel).send({embeds: [embed]})
}
async punish(client: TClient, message: Discord.Message, args: string, type: string){
let member: any;
if (message.guildId !== client.config.mainServer.id) return message.channel.send('This command doesn\'t work in this server');
if (!message.member.roles.cache.has(client.config.mainServer.roles.dcmod)) return message.reply(`You need the <@&${client.config.mainServer.roles.dcmod}> role to use this command.`)
if (type == 'ban' && args[1]){
member = message.mentions.users?.first() || (await client.users.fetch(args[1]).catch(()=>undefined));
} else if (args[1]){
member = message.mentions.members?.first() || (await message.guild.members.fetch(args[1]).catch(()=>undefined));
}
let memberAsked = false;
if (!member){
memberAsked = true;
await message.channel.send(`Which member would you like to ${type}?\nSend another message with a mention or a user ID. (30s)`).then(async (x:any)=>{
const filter = m=>m.author.id == message.author.id;
member = await message.channel.awaitMessages({filter, time: 30000, errors: ['time'], max: 1}).then(async (z:any)=>{
if (z.first().content.startsWith(client.config.prefix)) return 'timedout';
if (type == 'ban'){
return z.first().mentions.users?.first() || (await client.users.fetch(z.first().content).catch(()=>undefined));
} else {
return z.first().mentions.members?.first() || (await message.guild.members.fetch(z.first().content).catch(()=>undefined))
}
}).catch(async()=>{
message.channel.send('Command cancelled after 30 seconds of inactivity.');
return 'timedout';
});
})
}
if (member === 'timedout') return;
else if (!member) return message.channel.send('You failed to mention a member.');
let time;
let reason;
let col1; // idfk if this should be included here but just wanted to get rid of red underline.
let result: any;
if (args[2] && !memberAsked){
// if the first character of args 2 is a number, args 2 is the time. otherwise its the reason.
time = (args[2][0].match(/[0-9]/) && !['softban', 'kick', 'warn'].includes(type)) ? args[2] : undefined;
// if time is in args 2, reason starts at args 3. if no time was provided, reason starts at args 2
reason = args.slice(time ? 3 : 2).join(' '); // "Property 'join' does not exist on type 'string'." :linus: x99
} else {
if (!['softban', 'kick', 'warn'].includes(type)){
await message.channel.send(`How long do you want to ${type} this user for?\nSend another message with a time name, or 'forever' to ${type} this user forever. (30s)`);
const filter = m=>m.author.id === message.author.id;
col1 = await message.channel.awaitMessages({filter, time: 30000, errors: ['time'], max: 1}).then(collected=>{
if (collected.first()?.content.startsWith(client.config.prefix)) return 'timedout';
return collected.first()?.content.toLowerCase() === 'forever' ? 'inf' : collected.first()?.content;
}).catch(()=>{
message.channel.send('Command cancelled after 30 seconds of inactivity.');
return 'timedout';
});
if (time === 'timedout') return;
}
await message.channel.send(`Send another message with a reason for this ${type}.\nSend another message with "-" to leave the reason unspecified. (30s)`);
const filter = m=>m.author.id === message.author.id;
reason = await message.channel.awaitMessages({filter, time: 30000, errors: ['time'], max: 1}).then(collected=>{
if (collected.first()?.content.startsWith(client.config)) return 0;
return collected.first()?.content == '-' ? undefined : collected.first()?.content;
}).catch(()=>{
message.channel.send('Command cancelled after 30 seconds of inactivity.');
return 0;
})
if (reason === 0) return;
}
const punishmentResult = await client.punishments.addPunishment(type, member, {time, reason}, message.author.id, message);
(typeof result == 'string' ? message.reply(punishmentResult) : message.reply({embeds: [punishmentResult]}))
};
async unPunish(client: TClient, message: Discord.Message, args: string){
if (message.guildId !== client.config.mainServer.id) return message.channel.send('This command doesn\'t work in this server');
if (!message.member.roles.cache.has(client.config.mainServer.roles.dcmod)) return message.reply(`You need the <@&${client.config.mainServer.roles.dcmod}> role to use this command.`)
let punishment;
if (args[1]) punishment = client.punishments._content.find((x:any)=>x.id == args[1])
if (!punishment){
await message.channel.send(`Which punishment would you like to remove?\nSend another message with a Case # (30s)`).then(async (x:any)=>{
const filter = m=>m.author.id === message.author.id;
punishment = await message.channel.awaitMessages({filter, time: 30000, errors: ['time'], max: 1}).then(async (z:any)=>{
return client.punishments._content.find((x:any)=>x.id == z.first()?.content);
}).catch(async()=>{
message.channel.send('Command cancelled after 30 seconds of inactivity.');
return 'timedout';
});
})
}
if (punishment === 'timedout') return;
else if (!punishment) return message.channel.send('You failed to mention a Case #');
//if (punishment.type !== 'warn' && message.member.roles.cache.has(client.config.mainServer.roles.trialmoderator)) return message.channel.send('Trial moderators can only remove warnings.');
let reason;
if (args[2]){
reason = args.slice(2).join(' '); // "Property 'join' does not exist on type 'string'." :linus: x50
}else{
await message.channel.send(`Send another message with a reason for this ${punishment.type} removal. (30s)\n*Send \`-\` to leave the reason unspecified.*`);
const filter = m=>m.author.id === message.author.id;
reason = await message.channel.awaitMessages({filter, time: 30000, errors: ['time'], max: 1}).then(collected=>collected.first()?.content === '-' ? undefined : collected.first()?.content).catch(()=>0);
if (reason === 0) return message.channel.send('Invalid reason.');
}
const unpunishResult = await client.punishments.removePunishment(punishment.id, message.author.id, reason);
message.channel.send(unpunishResult);
}
async YTLoop(YTChannelID: string, YTChannelName: string, DCChannelID: string){
const Data = this.xjs.xml2js((await this.axios.get(`https://www.youtube.com/feeds/videos.xml?channel_id=${YTChannelID}`, {timeout: 5000})), {compact: true, spaces: 2}).catch(()=>{return null});
if (!Data) return;
if (this.YTCache[YTChannelID] == undefined){
this.YTCache[YTChannelID] = Data.feed.entry[0]['yt:videoId']._text;
return;
}
if (Data.feed.entry[1]['yt:videoId']._text == this.YTCache[YTChannelID]){
this.YTCache[YTChannelID] = Data.feed.entry[0]['yt:videoId']._text
(this.channels.resolve(DCChannelID) as Discord.TextChannel).send(`**${YTChannelName}** just uploaded a video!\n${Data.feed.entry[0].link._attributes.href}`)
}
}
}

65
src/commands/eval.ts Normal file
View File

@ -0,0 +1,65 @@
import Discord from 'discord.js';
import { TClient } from 'src/client';
import * as util from 'node:util';
const removeUsername = (text: string)=>{
let matchesLeft = true;
const array = text.split('\/');
while (matchesLeft){
let usersIndex = array.indexOf('home');
if (usersIndex<1) matchesLeft = false;
else {
let usernameIndex = usersIndex+1;
if(array[usernameIndex].length == 0) usernameIndex += 1;
array[usernameIndex] = '*'.repeat(array[usernameIndex].length);
array[usersIndex] = 'ho\u200bme';
}
} return array.join('\/');
};
export default {
async run(client: TClient, message: Discord.Message, args: any) {
if (!client.config.eval.allowed) return message.channel.send('Eval is disabled.');
if (!client.config.eval.whitelist.includes(message.author.id)) return message.reply('You\'re not allowed to use this command.');
const code = message.content.slice(client.config.prefix.length+args[0].length+1);
let output = 'error';
let error = false;
try {
output = await eval(code)
} catch (err: any) {
error = true
const embed = new client.embed().setColor('ff0000').setTitle('__Eval__').addFields(
{name: 'Input', value: `\`\`\`js\n${code.slice(0, 1010)}\n\`\`\``},
{name: 'Output', value: `\`\`\`\n${err}\`\`\``}
)
message.channel.send({embeds: [embed]}).then(errorEmbedMessage=>{
const filter = x=>x.content === 'stack' && x.author.id === message.author.id
const messagecollector = message.channel.createMessageCollector({filter, max: 1, time: 60000});
messagecollector.on('collect',collected=>{
collected.channel.send(`\`\`\`\n${removeUsername(err.stack)}\n\`\`\``);
});
});
}
if (error) return;
if (typeof output !== 'string') {
output = 'js\n'+util.formatWithOptions({depth: 1}, '%O', output)
} else {
output = '\n' + String(output);
}
if (typeof output == 'object') {
output = 'js\n'+util.formatWithOptions({depth: 1}, '%O', output)
} else {
output = '\n' + String(output);
}
[client.tokens.token_main,client.tokens.token_beta,client.tokens.token_toast,client.tokens.token_tae].forEach((x)=>{
const regexp = new RegExp(x,'g');
output = output.replace(regexp, 'TOKEN_LEAK');
})
const embed = new client.embed().setColor(client.config.embedColor).setTitle('__Eval__').addFields(
{name: 'Input', value: `\`\`\`js\n${code.slice(0,1010)}\n\`\`\``},
{name: 'Output', value: `\`\`\`${removeUsername(output).slice(0,1016)}\n\`\`\``}
);
message.channel.send({embeds: [embed]})
},
name: 'eval',
description: 'Run code for debugging purposes',
category: 'bot'
}

12
src/commands/ping.ts Normal file
View File

@ -0,0 +1,12 @@
import { TClient } from "src/client";
import Discord from 'discord.js';
export default {
async run(client: TClient, message: Discord.Message, args: any){
const msg = await message.reply(`Pinging...`)
const time = msg.createdTimestamp - message.createdTimestamp;
msg.edit(`Websocket: \`${client.ws.ping}\`ms\nBot: \`${time}\``)
},
name: 'ping',
description: 'Check bot\'s latency',
category: 'bot'
}

View File

@ -1,72 +0,0 @@
import { resolve } from 'path';
import { readFileSync, writeFileSync } from 'fs';
class Database {
/**
* @param {string} dir
* @param {string} dataType
*/
constructor(dir, dataType) {
this._dataType = dataType;
this._content = dataType === 'array' ? [] : dataType === 'object' ? {} : undefined;
this._path = resolve(dir);
this._interval = undefined;
this._saveNotifs = true;
}
/**
* @param {string | number} data
* @param {any} data1
*/
addData(data, data1) {
if (this._dataType === 'array') {
this._content.push(data);
} else if (this._dataType === 'object') {
this._content[data] = data1;
}
return this;
}
/**
* @param {string | number} key
*/
removeData(key) {
if (this._dataType === 'array') {
this._content.splice(key, 1);
} else if (this._dataType === 'object') {
delete this._content[key];
}
return this;
}
initLoad() {
const json = readFileSync(this._path);
// @ts-ignore
const array = JSON.parse(json);
this._content = array;
console.log(this._path + ' Database Loaded');
return this;
}
forceSave(db = this, force = false) {
const oldJson = readFileSync(db._path, { encoding: 'utf8' });
const newJson = JSON.stringify(db._content);
if (oldJson !== newJson || force) {
writeFileSync(db._path, newJson);
if (this._saveNotifs) console.log(this._path + ' Database Saved');
}
return db;
}
/**
* @param {any} milliseconds
*/
intervalSave(milliseconds) {
this._interval = setInterval(() => this.forceSave(this), milliseconds || 60000);
return this;
}
stopInterval() {
if (this._interval) clearInterval(this._interval);
return this;
}
disableSaveNotifs() {
this._saveNotifs = false;
console.log(this._path + ' "Database Saved" Notifications Disabled');
return this;
}
}
export default Database;

69
src/database.ts Normal file
View File

@ -0,0 +1,69 @@
import path from 'node:path';
import { readFileSync, writeFileSync } from 'node:fs';
import moment from 'moment';
export class Database {
public _dataType: string;
public _path: string;
public _interval?: NodeJS.Timer;
public _saveNotifs: boolean;
public _content: any;
constructor(dir: string, dataType: string){
this._dataType = dataType;
this._path = path.resolve(dir);
this._interval = undefined;
this._saveNotifs = true;
this._content = dataType === 'array' ? [] : {};
}
addData(data: any, data1?: any){
if (Array.isArray(this._content)){
this._content.push(data);
} else if (typeof this._content === 'object'){
this._content[data] = data1;
}
return this;
}
removeData(key: any, type: number, element: any){
if (this._dataType === 'array'){
switch (type){
case 0:
this._content = this._content.filter((x:any)=>x != key);
break;
case 1:
this._content = this._content.filter((x:any)=>x[element] != key);
break;
default:
return 'Type must be properly specified';
}
} else if (this._dataType === 'object'){
delete this._content[key];
}
return this;
}
initLoad(){
this._content = JSON.parse(readFileSync(this._path, {encoding: 'utf8'}));
console.log(this._path + ' Database loaded');
return this;
}
forceSave(db=this, force=false){
const oldJson = readFileSync(db._path, {encoding: 'utf8'});
const newJson = JSON.stringify(db._content);
if (oldJson !== newJson || force){
writeFileSync(this._path, JSON.stringify(this._content, null, 2));
if (this._saveNotifs) console.log(`\x1b[36m[${moment().format('DD/MM/YY HH:mm:ss')}] \x1b[33m` + this._path + ' Database saved');
}
return db;
}
intervalSave(milliseconds?: number){
this._interval = setInterval(()=>this.forceSave(this), milliseconds || 60000);
return this;
}
stopInterval(){
if (this._interval) clearInterval(this._interval);
return this;
}
disableSaveNotifs(){
this._saveNotifs = false;
console.log(this._path + ' "Database saved" Notifications disabled');
return this;
}
} // Nice.

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
[]
["fuck","fck","fů","fuk","fúck","fùck","fûck","fück","fūck","fůck","fűck","fùçk","fûćk","fucking","fųck","shit","shite","sht","shìt","shít","shît","shït","shīt","shįt","shıt","shlt","whore","pelotudo","boludo","nigger","nigga","nigs","niggas@","cunt","cnut","bitch","dick","pussy","asshole","b1tch","b!tch","blowjob","cock","c0ck","retard","fag","faggot","tits","boobs","dick","sex","porn","bjob","stfu","","­","͏","͏","؜","","","","","","","","stfu","ass","kkk","<@1011334031478100099>","<@468835415093411861>","asf","af","wtf","piss","pissed","pissing"]

View File

@ -1 +1 @@
{}
{"696085982201643090":3,"532662366354276352":2849,"178941218510602240":9,"615761944154210305":7,"141304507249197057":14,"190407856527376384":7,"711527768185372742":1,"716355511552966737":5,"593696856165449749":14,"824043915539513406":20,"771892617599516674":10,"889665445915926588":1,"488683638310043677":1027,"475037861725339649":1,"389237487094071337":1,"859313171964887140":1,"301350210926280704":2,"695323013813633076":2,"458688902102908928":2,"606595407769894995":1,"734703851558535188":2,"544215307972247553":2,"506022868157595648":1,"468837263577579524":3,"743212818467258468":1,"954092707213619221":1}

View File

@ -1 +1 @@
[]
[[0,674965],[1,675885],[2,676639],[3,677245],[4,677609],[5,678188],[6,678916],[7,679465],[8,679938],[9,680540],[10,681614],[11,682079],[12,682780],[13,683187],[14,683547],[15,683900],[16,684592],[17,685466],[18,686078],[19,686481],[20,676748],[21,676968],[22,677427],[23,677592],[24,677894],[25,678116],[26,676785],[27,677570],[28,678491],[29,679137],[30,679818],[31,680094],[32,680417],[33,680783],[34,681563],[35,682070],[36,682670],[37,683504],[38,684078],[39,684383],[40,684692],[41,685448],[42,685664],[43,685994],[44,686366],[45,687118],[46,687626],[47,688008],[48,688754],[49,688942],[50,689107],[51,689472],[52,690143],[53,690644],[54,691124],[55,692196],[56,692624],[57,692906],[58,693456],[59,693952],[60,694586],[61,695070],[62,696163],[63,696564],[64,697315],[65,698548],[66,699138],[67,699558],[68,700307],[69,701063],[70,701394],[71,701868],[72,702453],[73,702917],[76,705187],[77,705243],[78,705488],[79,705961],[80,706585],[81,707467],[82,708212]]

View File

@ -1 +1,98 @@
{}
[
{
"type": "kick",
"id": 1,
"member": "1009270415241252864",
"moderator": "141304507249197057",
"time": 1662289354828,
"reason": "failing to change inappropriate \"about me\" section on multiple occasions"
},
{
"type": "ban",
"id": 2,
"member": "991510617997443152",
"moderator": "190407856527376384",
"time": 1662485667322,
"reason": "compromised acc"
},
{
"type": "warn",
"id": 3,
"member": "598995859388104784",
"moderator": "532662366354276352",
"time": 1662900975329,
"reason": "being rude to a moderator"
},
{
"type": "ban",
"id": 4,
"member": "542134892327338035",
"moderator": "301350210926280704",
"time": 1663485351678,
"reason": "trying to post a discord link in multiple channels"
},
{
"type": "warn",
"id": 5,
"member": "870330666187907132",
"moderator": "141304507249197057",
"time": 1663594515726,
"reason": "inappropriate reactions"
},
{
"type": "ban",
"id": 6,
"member": "1030414094265761802",
"moderator": "141304507249197057",
"time": 1665779240168,
"reason": "cryptoscammer"
},
{
"type": "warn",
"id": 7,
"member": "934366726282416168",
"moderator": "593696856165449749",
"time": 1667146446817,
"reason": "Trying to put DC invite links everywhere (PG Server)"
},
{
"type": "kick",
"id": 8,
"member": "248226483967885312",
"moderator": "532662366354276352",
"time": 1667505431215,
"reason": "innapropiate pfp"
},
{
"type": "kick",
"id": 9,
"member": "872074877039947778",
"moderator": "301350210926280704",
"time": 1667505683756,
"reason": "inappropriate name and pfp"
},
{
"type": "ban",
"id": 10,
"member": "138377490132500480",
"moderator": "532662366354276352",
"time": 1668120578282,
"reason": "very innapropiate pfp"
},
{
"type": "kick",
"id": 11,
"member": "502208091002109953",
"moderator": "301350210926280704",
"time": 1668123798741,
"reason": "inappropriate status and about me"
},
{
"type": "kick",
"id": 12,
"member": "846431793715871749",
"moderator": "532662366354276352",
"time": 1668331244780,
"reason": "innapropiate profile picture"
}
]

File diff suppressed because it is too large Load Diff

132
src/events/messageCreate.ts Normal file
View File

@ -0,0 +1,132 @@
import Discord, { Channel, ChannelType, TextChannel } from 'discord.js';
import { TClient } from '../client';
export default {
name: 'messageCreate',
execute: async (client: TClient, message: Discord.Message)=>{
if (!client.config.botSwitches.commands && !client.config.eval.whitelist.includes(message.author.id)) return
if (message.author.bot) return;
if (message.channel.type === ChannelType.DM) return;
const msgarr = message.content.toLowerCase().split(' ');
let automodded: any;
// Command handler
if (message.content.startsWith(client.config.prefix)){
const args = message.content.slice(client.config.prefix.length).replace(/\n/g, " ").split(" ");
const commandFile = client.commands.find((x: any)=>x.name === args[0].toLowerCase() || x.alias?.includes(args[0].toLowerCase()));
if (commandFile){
console.log(`[${client.moment().format('DD/MM/YY HH:mm:ss')}] ${message.author.tag} used ${client.config.prefix}${commandFile.name} in #${message.channelId}`);
// do the cmd
try {
commandFile.run(client, message, args);
commandFile.uses ? commandFile.uses++ : commandFile.uses = 1;
return
} catch (error){
console.log(error)
client.channels.fetch(client.config.mainServer.channels.errors).then((channel: TextChannel)=>{
channel.send({embeds: [new client.embed().setColor('#420420').setTitle('Error caught!').setDescription(`**Error:** \`${error.message}\`\n\n**Stack:** \`${`${error.stack}`.slice(0, 2500)}\``)]})
})
return message.reply('An error occured while executing that command.')
}
}
}
function onTimeout(){
delete client.repeatedMessages[message.author.id]
}
const Whitelist = [
// Arrary of channel ids for automod to be disabled in
]
if (client.bannedWords._content.some((x: any)=>msgarr.includes(x)) && !message.member.roles.cache.has(client.config.mainServer.roles.dcmod) && message.guildId == client.config.mainServer.id && !Whitelist.includes(message.channelId) && client.config.botSwitches.automod){
automodded = true;
message.delete();
message.channel.send('That word is banned here.').then((x: any)=>setTimeout(()=>x.delete(), 5000));
if (client.repeatedMessages[message.author.id]){
// add this message to the list
client.repeatedMessages[message.author.id].set(message.createdTimestamp, {cont: 0, ch: message.channelId});
// reset timeout
clearTimeout(client.repeatedMessages[message.author.id].to);
client.repeatedMessages[message.author.id].to = setTimeout(onTimeout, 30000);
// this is the time in which 4 messages have to be sent, in milliseconds (ms)
const threshold = 30000;
// message mustve been sent after (now - threshold), so purge those that were sent earlier
client.repeatedMessages[message.author.id] = client.repeatedMessages[message.author.id].filter((x: any, i: any)=>i >= Date.now() - threshold)
// a spammed message is one that has been sent atleast 4 times in the last threshold milliseconds
const spammedMessage = client.repeatedMessages[message.author.id]?.find((x:any)=>{
return client.repeatedMessages[message.author.id].filter((y:any)=>x.cont === y.cont).size >= 4;
});
// if a spammed message exists;
if (spammedMessage){
// mute
const muteResult = await client.punishments.addPunishment('mute', message.member, {reason: 'Automod; banned words', time: '30m'}, client.user.id);
// and clear their list of long messages
delete client.repeatedMessages[message.author.id];
}
} else {
client.repeatedMessages[message.author.id] = new client.collection();
client.repeatedMessages[message.author.id].set(message.createdTimestamp, {cont: 0, ch: message.channelId});
// autodelete after 30 secs
client.repeatedMessages[message.author.id].to = setTimeout(onTimeout, 30000);
}
}
if (message.content.toLowerCase().includes('discord.gg/') && !message.member.roles.cache.has(client.config.mainServer.roles.dcmod)) {
automodded = true;
message.delete();
}
if (message.guildId == client.config.mainServer.id && !automodded){
client.userLevels.incrementUser(message.author.id); // Ranking incrementation
}
// Mop gifs from banned channels without Monster having to mop them.
const bannedChannels = [
'516344221452599306', // #mp-moderators
'742324777934520350', // #discord-moderators
]
if (message.content.toLowerCase().includes('tenor.com/view') || message.content.toLowerCase().includes('giphy.com/gifs/') || message.content.toLowerCase().includes('giphy.com/media/') && bannedChannels.includes(message.channelId)) {
message.reply('Gifs are disabled in this channel.').then((msg: any)=>message.delete())
}
// Autoresponse:tm:
if (message.mentions.members.has('309373272594579456') && !client.isStaff(message.member) && message.type != 19){
message.reply('Please don\'t tag Daggerwin, read rule 14 in <#468846117405196289>')
}
if (message.mentions.members.has('215497515934416896') && !client.isStaff(message.member) && message.type != 19){
message.reply('Please don\'t tag Monster unless it\'s important!')
}
if (message.content.toLowerCase().startsWith(`${client.config.prefix}players`) || message.content.toLowerCase().startsWith(`${client.config.prefix}status`)){
message.reply('Commands for the MP server have been moved to `*mp players` and `*mp status`.')
}
if (message.content.toLowerCase().includes('whats the password') || message.content.toLowerCase().includes('what\'s the password') || message.content.toLowerCase().includes('password pls')){
message.reply('Password and other details can be found in <#543494084363288637>')
}
if (message.content.toLowerCase().includes('i cant read') || message.content.toLowerCase().includes('i can\'t read')){
message.reply('https://tenor.com/view/aristocats-george-pen-cap-meticulous-gif-5330931')
}
if (message.content.toLowerCase().includes('is daggerbot working')){
message.reply('https://tenor.com/view/i-still-feel-alive-living-existing-active-singing-gif-14630579')
}
if (message.content.toLowerCase().includes('dead chat') || message.content.toLowerCase().includes('chat is dead')){
message.reply('https://cdn.discordapp.com/attachments/925589318276382720/1011333656167579849/F57G5ZS.png')
}
if (message.content.toLowerCase().includes('nawdic') && (message.content.toLowerCase().includes('break') || message.content.toLowerCase().includes('broke') || message.content.toLowerCase().includes('broken'))){
const embed = new client.embed().setTitle('*Nawdic done an oopsie*').setImage('https://c.tenor.com/JSj9ie_MD9kAAAAC/kopfsch%C3%BCtteln-an-kopf-fassen-oh-no.gif').setColor(client.config.embedColor)
message.reply({embeds: [embed]})
}
if (message.content.toLowerCase().startsWith('good morning') || message.content.toLowerCase().startsWith('morning all') || message.content.toLowerCase().startsWith('morning everyone')){
message.reply(`Good morning ${message.author.username}!`)
}
if (message.content.toLowerCase().startsWith('good afternoon') || message.content.toLowerCase().startsWith('afternoon all') || message.content.toLowerCase().startsWith('good evening') || message.content.toLowerCase().startsWith('evening all')){
message.reply(`Good afternoon/evening ${message.author.username}!`)
}
if (message.content.toLowerCase().startsWith('night all') || message.content.toLowerCase().startsWith('night everyone')){
message.reply(`Night ${message.author.username}`)
}
}
}

View File

@ -4,8 +4,6 @@ const client = new TClient;
client.init();
import fs = require('node:fs');
import ServerDB from './models/MPServer';
import axios from 'axios';
import xjs = require('xml-js');
client.on('ready', async()=>{
client.guilds.cache.forEach(async(e: { members: { fetch: () => any; }; })=>{await e.members.fetch()});
@ -33,15 +31,15 @@ client.on('ready', async()=>{
})
// Handle errors
process.on('unhandledRejection', async(error)=>{
process.on('unhandledRejection', async(error: Error)=>{
console.log(error)
client.channels.resolve(client.config.mainServer.channels.errors).send({embeds: [new client.embed().setColor('#420420').setTitle('Error caught!').setDescription(`**Error:** \`${error.message}\`\n\n**Stack:** \`${`${error.stack}`.slice(0, 2500)}\``)]})
});
process.on('uncaughtException', async(error)=>{
process.on('uncaughtException', async(error: Error)=>{
console.log(error)
client.channels.resolve(client.config.mainServer.channels.errors).send({embeds: [new client.embed().setColor('#420420').setTitle('Error caught!').setDescription(`**Error:** \`${error.message}\`\n\n**Stack:** \`${`${error.stack}`.slice(0, 2500)}\``)]})
});
process.on('error', async(error)=>{
process.on('error', async(error: Error)=>{
console.log(error)
client.channels.resolve(client.config.mainServer.channels.errors).send({embeds: [new client.embed().setColor('#420420').setTitle('Error caught!').setDescription(`**Error:** \`${error.message}\`\n\n**Stack:** \`${`${error.stack}`.slice(0, 2500)}\``)]})
});
@ -61,7 +59,7 @@ setInterval(async()=>{
const embed = new client.embed();
let Players = [];
let Server: any;
let CSG: any;
let CSG: void;
let xmlData = undefined;
// Connect to DB to retrieve the Gameserver info to fetch data.
@ -74,22 +72,22 @@ setInterval(async()=>{
const completedURL_CSG = DBURL + '/feed/dedicated-server-savegame.html?code=' + DBCode + '&file=careerSavegame'
try {
Server = await axios.get(completedURL_DSS, {timeout: 4000})
Server = await client.axios.get(completedURL_DSS, {timeout: 4000})
} catch (err){
console.log(`[${client.moment().format('HH:mm:ss')}] dag mp dss fail`)
console.log(`[${client.moment().format('DD/MM/YY HH:mm:ss')}] dag mp dss fail`)
embed.setTitle('Data could not be retrieved, the host may not be responding.').setColor(client.config.embedColorRed)
msg.edit({embeds: [embed]})
return;
}
try {
CSG = await axios.get(completedURL_CSG, {timeout: 4100}).then((xml)=>{
xmlData = xjs.xml2js(xml.data, {compact: true, spaces: 2}).careerSavegame;
CSG = await client.axios.get(completedURL_CSG, {timeout: 4100}).then((xml: any)=>{
xmlData = client.xjs.xml2js(xml.data, {compact: true, spaces: 2}).careerSavegame;
})
} catch (err){
console.log(`[${client.moment().format('HH:mm:ss')}] dag mp csg fail`)
console.log(`[${client.moment().format('DD/MM/YY HH:mm:ss')}] dag mp csg fail`)
}
if (xmlData == undefined){
console.log(`[${client.moment().format('HH:mm:ss')}] dag mp csg failed to convert`)
console.log(`[${client.moment().format('DD/MM/YY HH:mm:ss')}] dag mp csg failed to convert`)
embed.setFooter({text: 'XML Data retrieve failed. Retrying in next minute.'})
msg.edit({embeds: [embed]})
}
@ -133,23 +131,42 @@ setInterval(async()=>{
// Event loop for punishments and daily msgs
setInterval(async()=>{
interface Punishment {
id: number;
type: string;
member: string;
moderator: string;
expired?: boolean;
time?: number;
reason: string;
endTime?: number;
cancels?: number;
duration?: number;
}
const now = Date.now()
const lrsStart = client.config.LRSstart;
client.punishments._content.filter(x=>x.endTime<=now && !x.expired).forEach(async punishment=>{
console.log(`${punishment.member}'s ${punishment.type} should expire now`);
const unpunishResult = await client.punishments.removePunishment(punishment.id, client.user.id, 'Time\'s up!')
console.log(unpunishResult);
client.punishments._content.filter((x: Punishment)=>x.endTime<= now && !x.expired).forEach(async (punishment: Punishment)=>{
console.log(`\x1b[36m[${client.moment().format('DD/MM/YY HH:mm:ss')}]`, '\x1b[32m' + `${punishment.member}\'s ${punishment.type} should expire now`);
const unpunishResult = await client.punishments.removePunishment(punishment.id, client.user.id, 'Time\'s up!');
console.log(`\x1b[36m[${client.moment().format('DD/MM/YY HH:mm:ss')}]`, '\x1b[32m' + unpunishResult);
});
const formattedDate = Math.floor((now - lrsStart)/1000/60/60/24);
const dailyMsgs = require('./database/dailyMsgs.json');
interface UserLevels {
messages: number,
level: number
}
if (!dailyMsgs.some(x=>x[0] === formattedDate)){
let total = Object.values(client.userLevels._content).reduce((a,b)=>a + b.messages, 0); // sum of all users
const yesterday = dailyMsgs.find(x=>x[0] === formattedDate - 1);
let total = Object.values<UserLevels>(client.userLevels._content).reduce((a,b)=>a + b.messages, 0); // sum of all users
const yesterday = dailyMsgs.find((x: Array<number>)=>x[0] === formattedDate - 1);
if (total < yesterday){ // messages went down.
total = yesterday
}
dailyMsgs.push([formattedDate, total]);
fs.writeFileSync(__dirname + './database/dailyMsgs.json', JSON.stringify(dailyMsgs))
console.log(`\x1b[36m[${client.moment().format('DD/MM/YY HH:mm:ss')}] \x1b[33m`, `Pushed [${formattedDate}, ${total}] to dailyMsgs`)
}
}, 5000)
@ -169,4 +186,214 @@ while (client.commands.some(command=>!command.hidden && !command.page)){
command.page = categories[command.category].currentPage;
}
client.categoryNames = Object.keys(categories);
delete categories;
delete categories;
// create pages without contents
client.commands.filter(command=>!command.hidden).forEach(command=>{
if (!client.commandPages.some((x:any)=>x.category === command.category && x.pages === command.pages)){
client.commandPages.push({
name: `${command.category} - Page ${command.page}/${Math.max(...client.commands.filter((x:any)=>x.category === command.category).map((x:any)=>x.page))}`,
category: command.category,
page: command.page
});
}
});
client.commandPages.sort((a: any, b: any)=>{
if (a.name<b.name){
return -1;
} else if (a.name>b.name){
return 1;
} else {
return 0;
}
});
// Punishments
interface punOpt {
time: number,
reason: string,
message: any
}
interface punData {
id: number;
type: string;
member: string;
moderator: string;
expired?: boolean;
time?: number;
reason?: string;
endTime?: number;
cancels?: number;
duration?: number;
}
Object.assign(client.punishments,{
createId(){
return Math.max(...client.punishments._content.map((x: punData)=>x.id), 0) + 1;
},
async addPunishment(type: string, member: Discord.GuildMember, options: punOpt, moderator: string){
const now = Date.now();
const { time, reason, message } = options;
const ms = import('ms');
let timeInMillis;
if (type !== 'mute'){
timeInMillis = time ? ms(time) : null;
} else {
timeInMillis = time ? ms(time) : 2419200000;
}
switch (type) {
case 'ban':
const banData: punData = {type, id: this.createId(), member: member.id, moderator, time: now};
let dm1;
try {
dm1 = await member.send(`You've been banned from ${message.guild.name} ${timeInMillis ? `for ${client.formatTime(timeInMillis, 4, {longNames: true, commas: true})} (${timeInMillis}ms)` : 'forever'} for reason \`${reason || 'Unspecified'}\` (Case #${banData.id})`)
} catch (err) {
setTimeout(()=>message.channel.send('Failed to DM user.'), 500)
}
const banResult = await message.guild.bans.create(member.id, {reason: `${reason || 'Unspecified'} | Case #${banData.id}`}).catch((err: Error)=>err.message);
if (typeof banResult === 'string'){
dm1.delete();
return `Ban was unsuccessful: ${banResult}`;
} else {
if (timeInMillis){
banData.endTime = now + timeInMillis;
banData.duration = timeInMillis;
}
if (reason) banData.reason = reason;
client.makeModlogEntry(banData, client);
this.addData(banData);
this.forceSave();
return new client.embed().setColor(client.config.embedColor).setTitle(`Case #${banData.id}: Ban`).setDescription(`${member.tag}\n<@${member.id}>\n(\`${member.id}\`)`).addFields(
{name: 'Reason', value: `\`${reason || 'Unspecified'}\``},
{name: 'Duration', value: `${timeInMillis ? `for ${client.formatTime(timeInMillis, 4, {longNames: true, commas: true})} (${timeInMillis}ms)` : 'forever'}`}
)
}
case 'softban':
const guild = member.guild;
const softbanData: punData = {type, id: this.createId(), member: member.user.id, moderator, time: now};
const dm2 = await member.send(`You've been softbanned from ${member.guild.name} for reason \`${reason || 'Unspecified'}\` (Case #${softbanData.id})`).catch(err=>setTimeout(()=>message.channel.send(`Failed to DM <@${member.user.id}>.`), 500));
const softbanResult = await member.ban({deleteMessageDays: 7, reason: `${reason || 'Unspecified'} | Case #${softbanData.id}`}).catch((err: Error)=>err.message);
if (typeof softbanResult === 'string'){
dm2.delete();
return `Softban was unsuccessful: ${softbanResult}`;
} else {
const unbanResult = guild.members.unban(softbanData.member, `${reason || 'Unspecified'} | Case #${softbanData.id}`).catch((err: Error)=>err.message);
if (typeof unbanResult === 'string'){
return `Softban (unban) was unsuccessful: ${softbanResult}`
} else {
if (reason) softbanData.reason = reason;
client.makeModlogEntry(softbanData, client);
this.addData(softbanData)
this.forceSave();
return new client.embed().setColor(client.config.embedColor).setTitle(`Case #${softbanData.id}: Softban`).setDescription(`${member.user.tag}\n<@${member.user.id}>\n(\`${member.user.id}\`)`).addFields(
{name: 'Reason', value: `\`${reason || 'Unspecified'}\``}
)
}
}
case 'kick':
const kickData: punData = {type, id: this.createId(), member: member.user.id, moderator, time: now};
const dm3 = await member.send(`You've been kicked from ${member.guild.name} for reason \`${reason || 'Unspecified'}\` (Case #${kickData.id})`).catch((err:Error)=>setTimeout(()=>message.channel.send(`Failed to DM <@${member.user.id}>.`), 500));
const kickResult = await member.kick(`${reason || 'Unspecified'} | Case #${kickData.id}`).catch((err:Error)=>err.message);
if (typeof kickResult === 'string'){
dm3.delete();
return `Kick was unsuccessful: ${kickResult}`;
} else {
if (reason) kickData.reason = reason;
client.makeModlogEntry(kickData, client);
this.addData(kickData);
this.forceSave();
return new client.embed().setColor(client.config.embedColor).setTitle(`Case #${kickData.id}: Kick`).setDescription(`${member.user.tag}\n<@${member.user.id}>\n(\`${member.user.id}\`)`).addFields(
{name: 'Reason', value: `\`${reason || 'Unspecified'}\``}
)
}
case 'mute':
const muteData: punData = {type, id: this.createId(), member: member.user.id, moderator, time: now};
let muteResult;
const dm4 = await member.send(`You've been muted in ${member.guild.name} ${timeInMillis ? `for ${client.formatTime(timeInMillis, 4, {longNames: true, commas: true})} (${timeInMillis}ms)` : 'forever'} for reason \`${reason || 'Unspecified'}\` (Case #${muteData.id})`).catch((err:Error)=>setTimeout(()=>message.channel.send('Failed to DM user.'), 500));
if (timeInMillis){
muteResult = await member.timeout(timeInMillis, `${reason || 'Unspecified'} | Case #${muteData.id}`).catch((err: Error)=>err.message);
} else {
muteResult = await member.timeout(2419200000, `${reason || 'Unspecified'} | Case #${muteData.id}`).catch((err: Error)=>err.message);
}
if (typeof muteResult === 'string') {
dm4.delete();
return `Mute was unsuccessful: ${muteResult}`;
} else {
if (timeInMillis){
muteData.endTime = now + timeInMillis;
muteData.duration = timeInMillis
}
if (reason) muteData.reason = reason;
client.makeModlogEntry(muteData, client);
this.addData(muteData);
this.forceSave();
const embedm = new client.embed().setColor().setTitle(`Case #${muteData.id}: Mute`).setDescription(`${member.user.tag}\n<@${member.user.id}>\n(\`${member.user.id}\`)`).addFields(
{name: 'Reason', value: `\`${reason || 'Unspecified'}\``},
{name: 'Duration', value: `${client.formatTime(timeInMillis, 4, {longNames: true, commas: true})} (${timeInMillis}ms)`}
)
if (moderator !== '795443537356521502') {return embedm};
}
case 'warn':
const warnData: punData = {type, id: this.createId(), member: member.user.id, moderator, time: now};
const warnResult = await member.send(`You've been warned in ${member.guild.name} for reason \`${reason || 'Unspecified'}\` (Case #${warnData.id})`).catch((err:Error)=>setTimeout(()=>message.channel.send(`Failed to DM <@${member.user.id}>.`), 500));
if (typeof warnResult === 'string'){
return `Warn was unsuccessful: ${warnResult}`;
} else {
if (reason) warnData.reason = reason;
client.makeModlogEntry(warnData, client);
this.addData(warnData);
this.forceSave();
const embedw = new client.embed().setColor(client.config.embedColor).setTitle(`Case #${warnData.id}: Warn`).setDescription(`${member.user.tag}\n<@${member.user.id}>\n(\`${member.user.id}\`)`).addFields(
{name: 'Reason', value: `\`${reason || 'Unspecified'}\``}
)
if (moderator !== '795443537356521502') {return embedw};
}
}
},
async removePunishment(caseId: number, moderator: any, reason: string){
const now = Date.now();
const punishment = this._content.find((x:any)=>x.id === caseId);
const id = this.createId();
if (!punishment) return 'Punishment not found.';
if (['ban', 'mute'].includes(punishment.type)){
const guild = client.guilds.cache.get(client.config.mainServer.id) as Discord.Guild;
let removePunishmentResult;
if(punishment.type === 'ban'){
// unban
removePunishmentResult = await guild.members.unban(punishment.member, `${reason || 'Unspecified'} | Case #${id}`).catch((err: TypeError)=>err.message);
}else if (punishment.type === 'mute') {
//remove role
const member = await guild.members.fetch(punishment.member).catch(err=>undefined);
if (member){
removePunishmentResult = await member
if (typeof removePunishmentResult !== 'string'){
member.timeout(null, `${reason || 'Unspecified'} | Case #${id}`)
removePunishmentResult.send(`You've been unmuted in ${removePunishmentResult.guild.name}.`)
removePunishmentResult = removePunishmentResult.user; //removing a role returns a guildmember
}
}else{
// user probably left, lets quietly nuke the punishment.
const removePunishmentData = {type: `un${punishment.type}`, id, cancels: punishment.id, member: punishment.member, reason, moderator, time: now};
this._content[this._content.findIndex(x=>x.id === punishment.id)].expired = true;
this.addData(removePunishmentData).forceSave();
}
}
if (typeof removePunishmentResult === 'string') return `Un${punishment.type} was unsuccessful: ${removePunishmentResult}`;
else{
const removePunishmentData = {type: `un${punishment.type}`, id, cancels: punishment.id, member: punishment.member, reason, moderator, time: now};
client.makeModlogEntry(removePunishmentData, client);
this._content[this._content.findIndex(x=>x.id === punishment.id)].expired = true;
this.addData(removePunishmentData).forceSave();
return `Successfully ${punishment.type === 'ban' ? 'unbanned' : 'unmuted'} ${removePunishmentResult?.tag} (\`${removePunishmentResult?.id}\`) for reason \`${reason || 'Unspecified'}\``;
}
} else {
try {
const removePunishmentData = {type: 'removeOtherPunishment', id, cancels: punishment.id, member: punishment.member, reason, moderator, time: now};
client.makeModlogEntry(removePunishmentData, client);
this._content[this._content.findIndex(x=>x.id === punishment.id)].expired = true;
this.addData(removePunishmentData).forceSave();
return `Successfully removed Case #${punishment.id} (type: ${punishment.type}, user: ${punishment.member}).`;
} catch(error: Error){
return `${punishment.type[0].toUpperCase()+punishment.type.slice(1)} removal was unsuccessful: ${error.message}`
}
}
}
})