1
0
mirror of https://github.com/toast-ts/Daggerbot-TS.git synced 2024-11-17 04:10:59 -05:00

Bot improvements

This commit is contained in:
toast-ts 2023-05-23 15:14:17 +10:00
parent edaf1373b3
commit 4b9fcfb9a8
32 changed files with 152 additions and 151 deletions

View File

@ -1,6 +1,6 @@
import Discord from 'discord.js';
import TClient from './client';
import fs from 'node:fs';
import {writeFileSync, readFileSync} from 'node:fs';
import {FSPlayer, FSData, FSCareerSavegame} from './typings/interfaces';
export default async(client:TClient,Channel:string,Message:string,ServerName:string)=>{
@ -112,9 +112,9 @@ export default async(client:TClient,Channel:string,Message:string,ServerName:str
if (!isServerOnline){
playerLog();
const Database:Array<number> = JSON.parse(fs.readFileSync('src/database/MPPlayerData.json',{encoding:'utf8',flag:'r+'}));
const Database:Array<number> = JSON.parse(readFileSync('src/database/MPPlayerData.json',{encoding:'utf8',flag:'r+'}));
Database.push(DSS.data.slots?.used);
fs.writeFileSync('src/database/MPPlayerData.json', JSON.stringify(Database));
writeFileSync('src/database/MPPlayerData.json', JSON.stringify(Database));
client.MPServerCache.players = playersOnServer
}
}

View File

@ -1,5 +1,5 @@
import Discord, {Client, WebhookClient, GatewayIntentBits, Partials} from 'discord.js';
import fs from 'node:fs';
import {readFileSync, readdirSync} from 'node:fs';
import {exec} from 'node:child_process';
import mongoose from 'mongoose';
import {formatTimeOpt, Tokens, Config, repeatedMessages, MPServerCache} from './typings/interfaces';
@ -16,10 +16,10 @@ import tokens from './tokens.json' assert { type: 'json'};
let importconfig:Config
try{
importconfig = JSON.parse(fs.readFileSync('src/DB-Beta.config.json', {encoding:'utf8'}));
importconfig = JSON.parse(readFileSync('src/DB-Beta.config.json', {encoding:'utf8'}));
console.log('Using development config :: Daggerbot Beta')
} catch(e){
importconfig = JSON.parse(fs.readFileSync('src/config.json', {encoding:'utf8'}))
importconfig = JSON.parse(readFileSync('src/config.json', {encoding:'utf8'}))
console.log('Using production config')
}
@ -101,11 +101,11 @@ export default class TClient extends Client {
family: 4
}).then(()=>console.log(this.logTime(), 'Successfully connected to MongoDB')).catch(err=>{console.error(this.logTime(), `Failed to connect to MongoDB\n${err.reason}`); exec('pm2 stop Daggerbot')})
this.login(this.tokens.main);
for await (const file of fs.readdirSync('dist/events')){
for await (const file of readdirSync('dist/events')){
const eventFile = await import(`./events/${file}`);
this.on(file.replace('.js',''), async(...args)=>eventFile.default.run(this,...args))
};
for await (const file of fs.readdirSync('dist/commands')){
for await (const file of readdirSync('dist/commands')){
const command = await import(`./commands/${file}`);
this.commands.set(command.default.data.name,{command, uses: 0});
this.registry.push(command.default.data.toJSON())

View File

@ -1,20 +1,20 @@
import Discord,{SlashCommandBuilder} from 'discord.js';
import Discord from 'discord.js';
import TClient from '../client.js';
export default {
run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
client.punish(interaction, 'ban');
},
data: new SlashCommandBuilder()
data: new Discord.SlashCommandBuilder()
.setName('ban')
.setDescription('Ban a member from the server')
.addUserOption(opt=>opt
.addUserOption(x=>x
.setName('member')
.setDescription('Which member to ban?')
.setRequired(true))
.addStringOption(opt=>opt
.addStringOption(x=>x
.setName('time')
.setDescription('How long the ban will be?'))
.addStringOption(opt=>opt
.addStringOption(x=>x
.setName('reason')
.setDescription('Reason for the ban'))
}

View File

@ -1,7 +1,6 @@
import Discord,{SlashCommandBuilder} from 'discord.js';
import Discord from 'discord.js';
import TClient from '../client.js';
import {writeFileSync} from 'node:fs';
import path from 'node:path';
export default {
async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
if (!client.isStaff(interaction.member) && !client.config.whitelist.includes(interaction.member.id)) return client.youNeedRole(interaction, 'admin')
@ -25,23 +24,23 @@ export default {
}
} as any)[interaction.options.getSubcommand()]();
},
data: new SlashCommandBuilder()
data: new Discord.SlashCommandBuilder()
.setName('bannedwords')
.setDescription('description placeholder')
.addSubcommand(opt=>opt
.addSubcommand(x=>x
.setName('view')
.setDescription('View the list of currently banned words'))
.addSubcommand(opt=>opt
.addSubcommand(x=>x
.setName('add')
.setDescription('Add the word to the list')
.addStringOption(optt=>optt
.addStringOption(x=>x
.setName('word')
.setDescription('Add the specific word to automod\'s bannedWords database')
.setRequired(true)))
.addSubcommand(opt=>opt
.addSubcommand(x=>x
.setName('remove')
.setDescription('Remove the word from the list')
.addStringOption(optt=>optt
.addStringOption(x=>x
.setName('word')
.setDescription('Remove the specific word from automod\'s bannedWords list')
.setRequired(true)))

View File

@ -1,4 +1,4 @@
import Discord,{SlashCommandBuilder} from 'discord.js';
import Discord from 'discord.js';
import TClient from '../client.js';
export default {
async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
@ -15,14 +15,14 @@ export default {
.setFooter({text: `Bonk count for ${member.user.tag}: ${await client.bonkCount._content.findById(member.id).then(b=>b.value.toLocaleString('en-US'))}`})
]})
},
data: new SlashCommandBuilder()
data: new Discord.SlashCommandBuilder()
.setName('bonk')
.setDescription('Bonk a member')
.addUserOption(opt=>opt
.addUserOption(x=>x
.setName('member')
.setDescription('Which member to bonk?')
.setRequired(true))
.addStringOption(opt=>opt
.addStringOption(x=>x
.setName('reason')
.setDescription('Reason for the bonk'))
}

View File

@ -1,4 +1,4 @@
import Discord,{SlashCommandBuilder} from "discord.js";
import Discord from "discord.js";
import TClient from '../client.js';
export default {
run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
@ -43,34 +43,34 @@ export default {
}
} as any)[interaction.options.getSubcommand()]();
},
data: new SlashCommandBuilder()
data: new Discord.SlashCommandBuilder()
.setName('case')
.setDescription('Retrieve case information or user\'s punishment history')
.addSubcommand(opt=>opt
.addSubcommand(x=>x
.setName('view')
.setDescription('View a multiple or single case')
.addIntegerOption((optt)=>optt
.addIntegerOption(x=>x
.setName('id')
.setDescription('Case ID')
.setRequired(true)))
.addSubcommand(opt=>opt
.addSubcommand(x=>x
.setName('member')
.setDescription('View member\'s punishment history')
.addUserOption(optt=>optt
.addUserOption(x=>x
.setName('user')
.setDescription('Which user do you want to view their punishment history?')
.setRequired(true))
.addIntegerOption(optt=>optt
.addIntegerOption(x=>x
.setName('page')
.setDescription('Select the page number')))
.addSubcommand(opt=>opt
.addSubcommand(x=>x
.setName('update')
.setDescription('Update the case with new reason')
.addIntegerOption(optt=>optt
.addIntegerOption(x=>x
.setName('id')
.setDescription('Case ID to be updated')
.setRequired(true))
.addStringOption(optt=>optt
.addStringOption(x=>x
.setName('reason')
.setDescription('New reason for the case')
.setRequired(true)))

View File

@ -1,4 +1,4 @@
import Discord,{SlashCommandBuilder} from 'discord.js';
import Discord from 'discord.js';
import TClient from '../client.js';
export default {
run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
@ -7,7 +7,7 @@ export default {
client.config.contribList.map(id=>{const member = interaction.guild.members.cache.get(id); return `${member?.user?.username ?? 'N/A'} <@${id}>`}).join('\n')
].join('\n'))]})
},
data: new SlashCommandBuilder()
data: new Discord.SlashCommandBuilder()
.setName('contributors')
.setDescription('List of people who contributed to the bot')
}

View File

@ -1,4 +1,4 @@
import Discord,{SlashCommandBuilder} from 'discord.js';
import Discord from 'discord.js';
import {Octokit} from '@octokit/rest';
import {createTokenAuth} from '@octokit/auth-token';
import {exec} from 'node:child_process';
@ -130,36 +130,36 @@ export default {
}
} as any)[interaction.options.getSubcommand()]();
},
data: new SlashCommandBuilder()
data: new Discord.SlashCommandBuilder()
.setName('dev')
.setDescription('Developer commands')
.addSubcommand(optt=>optt
.addSubcommand(x=>x
.setName('eval')
.setDescription('Execute the code to the bot')
.addStringOption((opt)=>opt
.addStringOption(x=>x
.setName('code')
.setDescription('Execute your code')
.setRequired(true)))
.addSubcommand(optt=>optt
.addSubcommand(x=>x
.setName('logs')
.setDescription('Retrieve the logs from host and sends it to dev server'))
.addSubcommand(optt=>optt
.addSubcommand(x=>x
.setName('restart')
.setDescription('Restart the bot for technical reasons'))
.addSubcommand(optt=>optt
.addSubcommand(x=>x
.setName('update')
.setDescription('Pull from repository and restart'))
.addSubcommand(optt=>optt
.addSubcommand(x=>x
.setName('statsgraph')
.setDescription('Edit the number of data points to pull')
.addIntegerOption(hiTae=>hiTae
.addIntegerOption(x=>x
.setName('number')
.setDescription('Number of data points to pull')
.setRequired(true)))
.addSubcommand(optt=>optt
.addSubcommand(x=>x
.setName('presence')
.setDescription('Update the bot\'s presence')
.addIntegerOption(hiTae=>hiTae
.addIntegerOption(x=>x
.setName('type')
.setDescription('Set an activity type')
.addChoices(
@ -169,13 +169,13 @@ export default {
{name: 'Watching', value: Discord.ActivityType.Watching},
{name: 'Competing in', value: Discord.ActivityType.Competing}
))
.addStringOption(hiAgain=>hiAgain
.addStringOption(x=>x
.setName('name')
.setDescription('Set a message for the activity status'))
.addStringOption(hiAgainx2=>hiAgainx2
.addStringOption(x=>x
.setName('url')
.setDescription('Set an url for streaming status'))
.addStringOption(hiAgainx3=>hiAgainx3
.addStringOption(x=>x
.setName('status')
.setDescription('Set a status indicator for the bot')
.setChoices(

View File

@ -1,4 +1,4 @@
import Discord,{SlashCommandBuilder} from 'discord.js';
import Discord from 'discord.js';
import TClient from '../client.js';
export default {
run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
@ -12,10 +12,10 @@ export default {
fsDevConsole: ()=>interaction.reply({embeds: [new client.embed().setColor(client.config.embedColor).setTitle('Enabling the development console').setDescription('Head over to `game.xml` in `Documents/My Games/FarmingSimulator2022` and find the section that mentions `<controls>false</controls>` inside development section, change it to `true` then you are good to go!\nFYI: The keybind to open console is \``\u200b\` (backtick).').setImage('https://cdn.discordapp.com/attachments/1015195575693627442/1097273921444790322/image.png')]})
} as any)[interaction.options.getString('question', true)]();
},
data: new SlashCommandBuilder()
data: new Discord.SlashCommandBuilder()
.setName('faq')
.setDescription('List of questions, e.g; log file for FS, YT Scams and etc.')
.addStringOption(opt=>opt
.addStringOption(x=>x
.setName('question')
.setDescription('What question do you want answered?')
.setRequired(true)

View File

@ -1,17 +1,17 @@
import Discord,{SlashCommandBuilder} from 'discord.js';
import Discord from 'discord.js';
import TClient from '../client.js';
export default {
run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
client.punish(interaction, 'kick');
},
data: new SlashCommandBuilder()
data: new Discord.SlashCommandBuilder()
.setName('kick')
.setDescription('Boot a member from the server')
.addUserOption(opt=>opt
.addUserOption(x=>x
.setName('member')
.setDescription('Which member to kick?')
.setRequired(true))
.addStringOption(opt=>opt
.addStringOption(x=>x
.setName('reason')
.setDescription('Reason for the kick'))
}

View File

@ -1,8 +1,8 @@
import Discord,{SlashCommandBuilder} from 'discord.js';
import Discord from 'discord.js';
import TClient from '../client.js';
import path from 'node:path';
import canvas from 'canvas';
import fs from 'node:fs';
import {readFileSync} from 'node:fs';
async function MPdata(client:TClient, interaction:Discord.ChatInputCommandInteraction, embed: Discord.EmbedBuilder) {
let FSserver;
@ -94,7 +94,7 @@ export default {
},
players: async()=>{
const embed1 = new client.embed();
const data = JSON.parse(fs.readFileSync(path.join('src/database/MPPlayerData.json'), {encoding: 'utf8'})).slice(client.statsGraph)
const data = JSON.parse(readFileSync(path.join('src/database/MPPlayerData.json'), {encoding: 'utf8'})).slice(client.statsGraph)
// handle negative days
data.forEach((change: number, i: number) => {
if (change < 0) data[i] = data[i - 1] || data[i + 1] || 0;
@ -259,25 +259,25 @@ export default {
}*/
} as any)[interaction.options.getSubcommand()]();
},
data: new SlashCommandBuilder()
data: new Discord.SlashCommandBuilder()
.setName('mp')
.setDescription('Display MP status and other things')
.addSubcommand(opt=>opt
.addSubcommand(x=>x
.setName('status')
.setDescription('Check server status and details'))
.addSubcommand(opt=>opt
.addSubcommand(x=>x
.setName('players')
.setDescription('Check who\'s playing on the server'))
.addSubcommand(opt=>opt
.addSubcommand(x=>x
.setName('info')
.setDescription('Provides you with server information such as filters and so on'))
.addSubcommand(opt=>opt
.addSubcommand(x=>x
.setName('url')
.setDescription('View the URL for this server\'s FSMP server or update the URL')
.addStringOption(opt=>opt
.addStringOption(x=>x
.setName('address')
.setDescription('Insert a \'dedicated-server-stats\' URL')))/*
.addSubcommand(opt=>opt
.addSubcommand(x=>x
.setName('series')
.setDescription('Step-by-step on joining Daggerwin\'s MP series'))*/
}

View File

@ -1,20 +1,20 @@
import Discord,{SlashCommandBuilder} from 'discord.js';
import Discord from 'discord.js';
import TClient from '../client.js';
export default {
run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
client.punish(interaction, 'mute');
},
data: new SlashCommandBuilder()
data: new Discord.SlashCommandBuilder()
.setName('mute')
.setDescription('Mute a member')
.addUserOption(opt=>opt
.addUserOption(x=>x
.setName('member')
.setDescription('Which member to mute?')
.setRequired(true))
.addStringOption(opt=>opt
.addStringOption(x=>x
.setName('time')
.setDescription('Mute duration'))
.addStringOption(opt=>opt
.addStringOption(x=>x
.setName('reason')
.setDescription('Reason for the mute'))
}

View File

@ -1,4 +1,4 @@
import Discord,{SlashCommandBuilder} from 'discord.js';
import Discord from 'discord.js';
import TClient from '../client.js';
export default {
async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
@ -6,7 +6,7 @@ export default {
const time = msg.createdTimestamp - interaction.createdTimestamp;
msg.edit(`Websocket: \`${client.formatTime(client.ws.ping, 3, {longNames: false, commas: true})}\`\nBot: \`${client.formatTime(time, 3, {longNames: false, commas: true})}\``)
},
data: new SlashCommandBuilder()
data: new Discord.SlashCommandBuilder()
.setName('ping')
.setDescription('Check bot\'s latency')
}

View File

@ -1,8 +1,10 @@
import Discord,{SlashCommandBuilder} from 'discord.js';
import Discord from 'discord.js';
import TClient from '../client.js';
export default {
async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
if (!client.isStaff(interaction.member)) return client.youNeedRole(interaction, 'dcmod');
if (client.config.mainServer.id === interaction.guildId) {
if (!client.isStaff(interaction.member)) return client.youNeedRole(interaction, 'dcmod');
}
const amount = interaction.options.getInteger('amount') as number;
if (amount > 100) return interaction.reply({content: 'Discord API limits purging up to 100 messages.', ephemeral: true})
const user = interaction.options.getUser('user');
@ -22,14 +24,14 @@ export default {
}
await interaction.reply({content: `Successfully purged ${amount} messages.`, ephemeral: true})
},
data: new SlashCommandBuilder()
data: new Discord.SlashCommandBuilder()
.setName('purge')
.setDescription('Purge the amount of messages in this channel')
.addIntegerOption(opt=>opt
.addIntegerOption(x=>x
.setName('amount')
.setDescription('Amount of messages to be obliterated')
.setRequired(true))
.addUserOption(opt=>opt
.addUserOption(x=>x
.setName('user')
.setDescription('Which user to have their messages obliterated?'))
}

View File

@ -1,4 +1,4 @@
import Discord,{SlashCommandBuilder} from 'discord.js';
import Discord from 'discord.js';
import TClient from '../client.js';
export default {
run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
@ -6,7 +6,7 @@ export default {
embed.addFields({name: 'Hex code', value: `#${embed.data.color.toString(16).toUpperCase()}`});
interaction.reply({embeds: [embed]});
},
data: new SlashCommandBuilder()
data: new Discord.SlashCommandBuilder()
.setName('randomcolor')
.setDescription('Generate a random hex code')
}

View File

@ -1,7 +1,7 @@
import Discord,{SlashCommandBuilder} from 'discord.js';
import Discord from 'discord.js';
import TClient from '../client.js';
import path from 'node:path';
import fs from 'node:fs';
import {readFileSync} from 'node:fs';
import canvas from 'canvas';
export default {
async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
@ -11,7 +11,7 @@ export default {
view: async()=>{
// fetch user or user interaction sender
const member = interaction.options.getMember("member") ?? interaction.member as Discord.GuildMember;
if (member.user.bot) return interaction.reply('Bots don\'t level up, try viewing non-bots instead.')
if (member.user.bot) return interaction.reply('Bots don\'t level up, try viewing the rank data from the users instead.');
// information about users progress on level roles
const userData = await client.userLevels._content.findById(member.user.id);
@ -31,7 +31,7 @@ export default {
const timeActive = Math.floor((Date.now() - client.config.LRSstart)/1000/60/60/24);
const dailyMsgsPath = path.join('./src/database/dailyMsgs.json');
const data = JSON.parse(fs.readFileSync(dailyMsgsPath, 'utf8')).map((x: Array<number>, i: number, a: any) => {
const data = JSON.parse(readFileSync(dailyMsgsPath, 'utf8')).map((x: Array<number>, i: number, a: any) => {
const yesterday = a[i - 1] || [];
return x[1] - (yesterday[1] || x[1]);
}).slice(1).slice(-60);
@ -159,16 +159,16 @@ export default {
}
} as any)[interaction.options.getSubcommand()]();
},
data: new SlashCommandBuilder()
data: new Discord.SlashCommandBuilder()
.setName('rank')
.setDescription('Level system')
.addSubcommand(optt=>optt
.addSubcommand(x=>x
.setName('view')
.setDescription('View your rank or someone else\'s rank')
.addUserOption(opt=>opt
.addUserOption(x=>x
.setName('member')
.setDescription('Which member do you want to view?')))
.addSubcommand(optt=>optt
.addSubcommand(x=>x
.setName('leaderboard')
.setDescription('View top 10 users on leaderboard'))
}

View File

@ -1,4 +1,4 @@
import Discord,{SlashCommandBuilder} from 'discord.js';
import Discord from 'discord.js';
import TClient from '../client.js';
export default {
run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
@ -13,10 +13,10 @@ export default {
{name: '🔹 Permissions', value: `${permissions.includes('Administrator') ? ['Administrator'] : permissions.join(', ') || 'None'}`, inline: true}
)]})
},
data: new SlashCommandBuilder()
data: new Discord.SlashCommandBuilder()
.setName('roleinfo')
.setDescription('View information about the selected role')
.addRoleOption(opt=>opt
.addRoleOption(x=>x
.setName('role')
.setDescription('Role name to view information')
.setRequired(true))

View File

@ -1,17 +1,17 @@
import Discord,{SlashCommandBuilder} from 'discord.js';
import Discord from 'discord.js';
import TClient from '../client.js';
export default {
run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
client.punish(interaction, 'softban');
},
data: new SlashCommandBuilder()
data: new Discord.SlashCommandBuilder()
.setName('softban')
.setDescription('Softban a member from the server')
.addUserOption(opt=>opt
.addUserOption(x=>x
.setName('member')
.setDescription('Which member to softban?')
.setRequired(true))
.addStringOption(opt=>opt
.addStringOption(x=>x
.setName('reason')
.setDescription('Reason for the softban'))
}

View File

@ -1,4 +1,4 @@
import Discord,{SlashCommandBuilder,version} from 'discord.js';
import Discord from 'discord.js';
import pkg from 'typescript';
import si from 'systeminformation';
import TClient from '../client.js';
@ -49,7 +49,7 @@ export default {
{name: '> __Dependencies__', value: [
`**TypeScript:** ${pkg.version}`,
`**NodeJS:** ${process.version}`,
`**DiscordJS:** ${version}`,
`**DiscordJS:** ${Discord.version}`,
`**Axios:** ${client.axios.VERSION}`
].join('\n')},
{name: '> __Host__', value: [
@ -63,7 +63,7 @@ export default {
);
interaction.reply({embeds: [embed], fetchReply: true}).then(x=>x.edit({embeds: [new client.embed(x.embeds[0].data).setFooter({text: `Load time: ${client.formatTime(x.createdTimestamp - interaction.createdTimestamp, 2, {longNames: true, commas: true})}`})]}))
},
data: new SlashCommandBuilder()
data: new Discord.SlashCommandBuilder()
.setName('statistics')
.setDescription('See a list of commands ordered by their usage or host stats')
}

View File

@ -1,4 +1,4 @@
import Discord,{SlashCommandBuilder} from 'discord.js';
import Discord from 'discord.js';
import TClient,{WClient} from '../client.js';
export default {
async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
@ -64,39 +64,39 @@ export default {
}
} as any)[interaction.options.getSubcommand()]();
},
data: new SlashCommandBuilder()
data: new Discord.SlashCommandBuilder()
.setName('suggest')
.setDescription('Want to suggest ideas/thoughts to bot techs? Suggest it here')
.addSubcommand(opt=>opt
.addSubcommand(x=>x
.setName('your')
.setDescription('What do you want to suggest?')
.addStringOption(s=>s
.addStringOption(x=>x
.setName('suggestion')
.setDescription('Suggest something to bot techs. (You will be DM\'d by bot if your idea was approved/rejected)')
.setMaxLength(1024)
.setRequired(true))
.addAttachmentOption(i=>i
.addAttachmentOption(x=>x
.setName('image')
.setDescription('If your idea seems complicated or prefer to show what your idea may look like then attach the image.')))
.addSubcommand(opt=>opt
.addSubcommand(x=>x
.setName('approve')
.setDescription('[Bot Tech] Approve the suggestion sent by the user')
.addStringOption(id=>id
.addStringOption(x=>x
.setName('id')
.setDescription('User\'s suggestion ID')
.setRequired(true))
.addStringOption(m=>m
.addStringOption(x=>x
.setName('message')
.setDescription('(Optional) Include a message with your approval')
.setMaxLength(256)))
.addSubcommand(opt=>opt
.addSubcommand(x=>x
.setName('reject')
.setDescription('[Bot Tech] Reject the suggestion sent by the user')
.addStringOption(id=>id
.addStringOption(x=>x
.setName('id')
.setDescription('User\'s suggestion ID')
.setRequired(true))
.addStringOption(m=>m
.addStringOption(x=>x
.setName('message')
.setDescription('(Optional) Include a message with your rejection')
.setMaxLength(256)))

View File

@ -1,4 +1,4 @@
import Discord,{SlashCommandBuilder} from 'discord.js';
import Discord from 'discord.js';
import TClient from '../client.js';
export default {
async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
@ -11,14 +11,14 @@ export default {
console.log(client.logTime(), `[UnpunishmentLog] Case #${interaction.options.getInteger('case_id')} was used in /${interaction.commandName} for ${reason}`);
(client.channels.cache.get(client.config.mainServer.channels.punishment_log) as Discord.TextChannel).send({embeds:[new client.embed().setColor(client.config.embedColor).setTitle('Unpunishment Log').setDescription(`Case #${interaction.options.getInteger('case_id')} was used in \`/${interaction.commandName}\` for \`${reason}\``).setTimestamp()]});
},
data: new SlashCommandBuilder()
data: new Discord.SlashCommandBuilder()
.setName('unpunish')
.setDescription('Remove the active punishment from a member')
.addIntegerOption(opt=>opt
.addIntegerOption(x=>x
.setName('case_id')
.setDescription('Case ID of the punishment to be overwritten')
.setRequired(true))
.addStringOption(opt=>opt
.addStringOption(x=>x
.setName('reason')
.setDescription('Reason for removing the punishment'))
}

View File

@ -1,18 +1,17 @@
import Discord,{SlashCommandBuilder} from 'discord.js';
import Discord from 'discord.js';
import TClient from '../client.js';
export default {
run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
client.punish(interaction, 'warn');
},
data: new SlashCommandBuilder()
data: new Discord.SlashCommandBuilder()
.setName('warn')
.setDescription('Warn a member')
.addUserOption(opt=>opt
.addUserOption(x=>x
.setName('member')
.setDescription('Which member to warn?')
.setRequired(true))
.addStringOption(opt=>opt
.addStringOption(x=>x
.setName('reason')
.setDescription('Reason for the warning')
.setRequired(false))
.setDescription('Reason for the warning'))
}

View File

@ -1,4 +1,4 @@
import Discord,{GuildMember, SlashCommandBuilder} from 'discord.js';
import Discord from 'discord.js';
import TClient from '../client.js';
function convert(status?:Discord.ClientPresenceStatus){
@ -12,8 +12,8 @@ function convert(status?:Discord.ClientPresenceStatus){
export default {
async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
const member = interaction.options.getMember('member') as GuildMember;
if (member == null){
const member = interaction.options.getMember('member') as Discord.GuildMember;
if (member === null){
const user = interaction.options.getUser('member') as Discord.User;
const embed = new client.embed()
.setColor(client.config.embedColor)
@ -44,16 +44,16 @@ export default {
{name: `🔹 Roles: ${member.roles.cache.size - 1}`, value: member.roles.cache.size > 1 ? member.roles.cache.filter(x=>x.id !== interaction.guild.roles.everyone.id).sort((a,b)=>b.position - a.position).map(x=>x).join(member.roles.cache.size > 4 ? ' ' : '\n').slice(0,1024) : 'No roles'}
)
if (member.premiumSinceTimestamp !== null) embed.addFields({name: '🔹 Server Boosting since', value: `<t:${Math.round(member.premiumSinceTimestamp/1000)}>\n<t:${Math.round(member.premiumSinceTimestamp/1000)}:R>`, inline: true})
if (!presence) embed.addFields({name: `🔹 Status: Unavailable to retrieve`, value: '\u200b'})
if (!presence) embed.addFields({name: `🔹 Status: Unavailable to be fetched`, value: '\u200b'})
if (member.presence) embed.addFields({name: `🔹 Status: ${member.presence.status}`, value: `${member.presence.status === 'offline' ? '⚫' : `Desktop: ${convert(presence.desktop)}\nWeb: ${convert(presence.web)}\nMobile: ${convert(presence.mobile)}`}`, inline: true})
embedArray.push(embed)
interaction.reply({embeds: embedArray})
}
},
data: new SlashCommandBuilder()
data: new Discord.SlashCommandBuilder()
.setName('whois')
.setDescription('View your own or someone else\'s information')
.addUserOption(opt=>opt
.addUserOption(x=>x
.setName('member')
.setDescription('Member or user to view their information')
.setRequired(true))

View File

@ -7,8 +7,8 @@ export default {
const banLog = fetchBanlog.entries.first();
if (!banLog) return console.log(`${member.user.tag} was banned from ${member.guild.name} but no audit log for this user.`)
const {executor, target, reason } = banLog;
if (target.id == member.user.id) (client.channels.resolve(client.config.mainServer.channels.logs) as Discord.TextChannel).send({embeds: [
new client.embed().setColor(client.config.embedColorRed).setTimestamp().setThumbnail(member.user.displayAvatarURL({size: 2048})).setTitle(`Member Banned: ${target.tag}`).setDescription(`🔹 **User**\n<@${target.id}>\n\`${target.id}\``).addFields(
if (target.id === member.user.id) (client.channels.resolve(client.config.mainServer.channels.logs) as Discord.TextChannel).send({embeds: [
new client.embed().setColor(client.config.embedColorRed).setTimestamp().setThumbnail(member.user.displayAvatarURL({size: 2048})).setTitle(`Member Banned: ${target.tag}`).setDescription(`🔹 **User**\n<@${target.id}>\n\`${target.id}\``).setFooter({text:'Rank data has been wiped.'}).addFields(
{name: '🔹 Moderator', value: `<@${executor.id}>\n\`${executor.id}\``},
{name: '🔹 Reason', value: `${reason == null ? 'Reason unspecified': reason}`}
)]});

View File

@ -7,7 +7,7 @@ export default {
const unbanLog = fetchUnbanlog.entries.first();
if (!unbanLog) return console.log(`${member.user.tag} was unbanned from ${member.guild.name} but no audit log for this user.`)
const { executor, target, reason } = unbanLog;
if (target.id == member.user.id) (client.channels.resolve(client.config.mainServer.channels.logs) as Discord.TextChannel).send({embeds: [
if (target.id === member.user.id) (client.channels.resolve(client.config.mainServer.channels.logs) as Discord.TextChannel).send({embeds: [
new client.embed().setColor(client.config.embedColorGreen).setTimestamp().setThumbnail(member.user.displayAvatarURL({size: 2048})).setTitle(`Member Unbanned: ${target.tag}`).setDescription(`🔹 **User**\n<@${target.id}>\n\`${target.id}\``).addFields(
{name: '🔹 Moderator', value: `<@${executor.id}>\n\`${executor.id}\``},
{name: '🔹 Reason', value: `${reason == null ? 'Reason unspecified.': reason}`}

View File

@ -4,7 +4,7 @@ export default {
async run(client:TClient, member:Discord.GuildMember){
if (member.partial || member.guild?.id != client.config.mainServer.id) return;
const index = member.guild.memberCount;
const suffix = ((index)=>{
const suffix = (index=>{
const numbers = index.toString().split('').reverse(); // eg 1850 --> [0,5,8,1]
if (numbers[1] === '1') return 'th'; // this is some -teen
else {
@ -17,13 +17,13 @@ export default {
(client.channels.resolve(client.config.mainServer.channels.welcome) as Discord.TextChannel).send({embeds: [new client.embed().setColor(client.config.embedColor).setThumbnail(member.user.displayAvatarURL({size: 2048}) || member.user.defaultAvatarURL).setTitle(`Welcome to Daggerwin, ${member.user.tag}!`).setFooter({text: `${index}${suffix} member`})]})
if (!client.config.botSwitches.logs) return;
const newInvites = await member.guild.invites.fetch();
const usedInvite = newInvites.find((inv:any)=>client.invites.get(inv.code)?.uses < inv.uses);
newInvites.forEach((inv:any)=>client.invites.set(inv.code,{uses: inv.uses, creator: inv.inviter.id}));
const usedInvite = newInvites.find((inv:Discord.Invite)=>client.invites.get(inv.code)?.uses < inv.uses);
newInvites.forEach((inv:Discord.Invite)=>client.invites.set(inv.code,{uses: inv.uses, creator: inv.inviterId, channel: inv.channel.name}));
(client.channels.resolve(client.config.mainServer.channels.logs) as Discord.TextChannel).send({embeds: [
new client.embed().setColor(client.config.embedColorGreen).setTimestamp().setThumbnail(member.user.displayAvatarURL({size: 2048})).setTitle(`Member Joined: ${member.user.tag}`).setDescription(`<@${member.user.id}>\n\`${member.user.id}\``).setFooter({text: `Total members: ${index}${suffix}`}).addFields(
{name: '🔹 Account Creation Date', value: `<t:${Math.round(member.user.createdTimestamp/1000)}>\n<t:${Math.round(member.user.createdTimestamp/1000)}:R>`},
{name: '🔹 Invite Data:', value: usedInvite ? `Invite: \`${usedInvite.code}\`\nCreated by: **${usedInvite.inviter?.tag}**` : 'No invite data could be found.'}
{name: '🔹 Invite Data:', value: usedInvite ? `Invite: \`${usedInvite.code}\`\nCreated by: **${usedInvite.inviter?.tag}**\nChannel: **#${usedInvite.channel.name}**` : 'No invite data could be fetched.'}
)]})
}
}

View File

@ -4,6 +4,7 @@ export default {
async run(client:TClient, member:Discord.GuildMember){
if (!client.config.botSwitches.logs) return;
if (!member.joinedTimestamp || member.guild?.id != client.config.mainServer.id) return;
if (client.guilds.cache.get(client.config.mainServer.id).bans.cache.has(member.id)) return await client.userLevels._content.findByIdAndDelete(member.id);
const levelData = await client.userLevels._content.findById(member.id);
const embed = new client.embed().setColor(client.config.embedColorRed).setTimestamp().setThumbnail(member.user.displayAvatarURL({size: 2048}) as string).setTitle(`Member Left: ${member.user.tag}`).setDescription(`<@${member.user.id}>\n\`${member.user.id}\``).addFields(
{name: '🔹 Account Creation Date', value: `<t:${Math.round(member.user.createdTimestamp/1000)}>\n<t:${Math.round(member.user.createdTimestamp/1000)}:R>`},

View File

@ -4,7 +4,7 @@ export default {
run(client:TClient, oldMember:Discord.GuildMember, newMember:Discord.GuildMember){
if (oldMember.guild.id != client.config.mainServer.id) return;
if (!client.config.botSwitches.logs) return;
const channel = (client.channels.resolve(client.config.mainServer.channels.logs) as Discord.TextChannel)
const channel = (client.channels.resolve(client.config.mainServer.channels.logs) as Discord.TextChannel);
if (oldMember.nickname != newMember.nickname){
const embed = new client.embed().setColor(client.config.embedColor).setTimestamp().setThumbnail(newMember.user.displayAvatarURL({size: 2048})).setTitle(`Nickname updated: ${newMember.user.tag}`).setDescription(`<@${newMember.user.id}>\n\`${newMember.user.id}\``)
oldMember.nickname == null ? '' : embed.addFields({name: '🔹 Old nickname', value: `\`\`\`${oldMember.nickname}\`\`\``})
@ -16,8 +16,8 @@ export default {
const oldRoles = oldMember.roles.cache.map((x,i)=>i).filter(x=>!newMember.roles.cache.map((x,i)=>i).some(y=>y==x));
if (newRoles.length == 0 && oldRoles.length == 0) return;
const embed = new client.embed().setColor(client.config.embedColor).setThumbnail(newMember.user.displayAvatarURL({size: 2048})).setTitle(`Role updated: ${newMember.user.tag}`).setDescription(`<@${newMember.user.id}>\n\`${newMember.user.id}\``)
if (newRoles.length != 0) embed.addFields({name: '🔹 Role added', value: newRoles.map((x)=>`<@&${x}>`).join(' ')});
if (oldRoles.length != 0) embed.addFields({name: '🔹 Role removed', value: oldRoles.map((x)=>`<@&${x}>`).join(' ')});
if (newRoles.length != 0) embed.addFields({name: newRoles.length > 1 ? '🔹 Roles added' : '🔹 Role added', value: newRoles.map(x=>`<@&${x}>`).join(' ')});
if (oldRoles.length != 0) embed.addFields({name: oldRoles.length > 1 ? '🔹 Roles removed' : '🔹 Role removed', value: oldRoles.map(x=>`<@&${x}>`).join(' ')});
channel.send({embeds: [embed]})
}
}

View File

@ -4,6 +4,6 @@ export default {
async run(client:TClient, invite: Discord.Invite){
if (!invite.guild) return;
const newInvites = await (invite.guild as Discord.Guild).invites.fetch();
newInvites.forEach(inv=>client.invites.set(inv.code,{uses: inv.code, creator: inv.inviterId}))
newInvites.forEach(inv=>client.invites.set(inv.code,{uses: inv.code, creator: inv.inviterId, channel: inv.channel.name}))
}
}

View File

@ -14,7 +14,7 @@ export default {
{ name: 'Sent at', value: `<t:${Math.round(msg.createdTimestamp/1000)}>\n<t:${Math.round(msg.createdTimestamp/1000)}:R>` }
)
const attachments: Array<string> = [];
msg.attachments.forEach((x) => attachments.push(x.url));
msg.attachments.forEach(x=>attachments.push(x.url));
channel.send({embeds: [embed], files: attachments})
}
}

View File

@ -1,10 +1,8 @@
import Discord from 'discord.js';
import TClient from '../client.js';
export default {
run(client:TClient, messages:Discord.Collection<string, Discord.Message<boolean>>){
if (!client.config.botSwitches.logs) return;
if (client.config.mainServer.id != '468835415093411861') return;
const channel = client.channels.resolve(client.config.mainServer.channels.logs) as Discord.TextChannel;
channel.send({embeds: [new client.embed().setColor(client.config.embedColorRed).setTimestamp().setTitle(`${messages.size} messages were purged`).setDescription(`\`\`\`${messages.map((msgs)=>`${msgs.author?.username}: ${msgs.content}`).reverse().join('\n').slice(0,3900)}\`\`\``).addFields({name: 'Channel', value: `<#${messages.first().channel.id}>`})]})
run(client:TClient, messages:Discord.Collection<string, Discord.Message<boolean>>, channel:Discord.GuildTextBasedChannel){
if (!client.config.botSwitches.logs || channel.guildId != client.config.mainServer.id) return;
(client.channels.resolve(client.config.mainServer.channels.logs) as Discord.TextChannel).send({embeds: [new client.embed().setColor(client.config.embedColorRed).setTimestamp().setTitle(`${messages.size} messages were purged`).setDescription(`\`\`\`${messages.map(msgs=>`${msgs.author?.username}: ${msgs.content}`).reverse().join('\n').slice(0,3900)}\`\`\``).addFields({name: 'Channel', value: `<#${messages.first().channel.id}>`})]})
}
}

View File

@ -3,13 +3,15 @@ import TClient from './client.js';
const client = new TClient;
client.init();
import MPLoop from './MPLoop.js';
import fs from 'node:fs';
import {writeFileSync, readFileSync} from 'node:fs';
client.on('ready', async()=>{
setInterval(()=>client.user.setPresence(client.config.botPresence), 300000);
await client.guilds.fetch(client.config.mainServer.id).then(async guild=>{
await guild.members.fetch();
setInterval(()=>guild.invites.fetch().then(invites=>invites.forEach(inv=>client.invites.set(inv.code, {uses: inv.uses, creator: inv.inviterId}))),300000)
setInterval(()=>{
client.user.setPresence(client.config.botPresence);
guild.invites.fetch().then(invites=>invites.forEach(inv=>client.invites.set(inv.code, {uses: inv.uses, creator: inv.inviterId, channel: inv.channel.name})))
},300000)
});
if (client.config.botSwitches.registerCommands){
client.config.whitelistedServers.forEach(guildId=>(client.guilds.cache.get(guildId) as Discord.Guild).commands.set(client.registry).catch((e:Error)=>{
@ -46,22 +48,22 @@ setInterval(async()=>{
setInterval(async()=>{
const now = Date.now();
const lrsStart = client.config.LRSstart;
const punishments = await client.punishments._content.find({});
punishments.filter(x=>x.endTime && x.endTime<= now && !x.expired).forEach(async punishment=>{
console.log(client.logTime(), `${punishment.member}\'s ${punishment.type} should expire now`);
const unpunishResult = await client.punishments.removePunishment(punishment._id, client.user.id, 'Time\'s up!');
console.log(client.logTime(), unpunishResult);
});
const formattedDate = Math.floor((now - lrsStart)/1000/60/60/24);
const dailyMsgs = JSON.parse(fs.readFileSync('./src/database/dailyMsgs.json', {encoding: 'utf8'}))
const dailyMsgs = JSON.parse(readFileSync('./src/database/dailyMsgs.json', {encoding: 'utf8'}))
if (!dailyMsgs.some((x:Array<number>)=>x[0] === formattedDate)){
let total = (await client.userLevels._content.find({})).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) total = yesterday // messages went down.
dailyMsgs.push([formattedDate, total]);
fs.writeFileSync('./src/database/dailyMsgs.json', JSON.stringify(dailyMsgs))
writeFileSync('./src/database/dailyMsgs.json', JSON.stringify(dailyMsgs))
console.log(client.logTime(), `Pushed [${formattedDate}, ${total}] to dailyMsgs`);
client.guilds.cache.get(client.config.mainServer.id).commands.fetch().then((commands)=>(client.channels.resolve(client.config.mainServer.channels.logs) as Discord.TextChannel).send(`:pencil: Pushed \`[${formattedDate}, ${total}]\` to </rank leaderboard:${commands.find(x=>x.name == 'rank').id}>`))
}