mirror of
https://github.com/toast-ts/Daggerbot-TS.git
synced 2024-11-17 04:10:59 -05:00
Push part 2
This commit is contained in:
parent
3abfdf3c31
commit
f5aa7a33fa
308
src/client.ts
308
src/client.ts
@ -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();
|
||||
}
|
||||
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))
|
||||
}
|
||||
module.exports = TClient;
|
||||
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
65
src/commands/eval.ts
Normal 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
12
src/commands/ping.ts
Normal 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'
|
||||
}
|
@ -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
69
src/database.ts
Normal 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
@ -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"]
|
@ -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}
|
@ -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]]
|
@ -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
132
src/events/messageCreate.ts
Normal 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}`)
|
||||
}
|
||||
}
|
||||
}
|
263
src/index.ts
263
src/index.ts
@ -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)
|
||||
|
||||
@ -170,3 +187,213 @@ while (client.commands.some(command=>!command.hidden && !command.page)){
|
||||
}
|
||||
client.categoryNames = Object.keys(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}`
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
Loading…
Reference in New Issue
Block a user