diff --git a/src/client.ts b/src/client.ts index fcafabd..6412671 100644 --- a/src/client.ts +++ b/src/client.ts @@ -95,7 +95,7 @@ export default class TClient extends Discord.Client { } async init(){ console.time('Startup'); - DatabaseServer.connect(this); + DatabaseServer.init(); this.login(this.tokens.main); for (const file of readdirSync('dist/events')){ const eventFile = await import(`./events/${file}`); @@ -116,5 +116,4 @@ export default class TClient extends Discord.Client { } isStaff = (guildMember:Discord.GuildMember)=>this.config.mainServer.staffRoles.map((x: string)=>this.config.mainServer.roles[x]).some((x: string)=>guildMember.roles.cache.has(x)); youNeedRole = (interaction:Discord.CommandInteraction, role:string)=>interaction.reply(`This command is restricted to <@&${this.config.mainServer.roles[role]}>`); - logTime = ()=>`[${this.moment().format('DD/MM/YY HH:mm:ss')}]`; } diff --git a/src/commands/calculator.ts b/src/commands/calculator.ts index c04a961..82bacd5 100644 --- a/src/commands/calculator.ts +++ b/src/commands/calculator.ts @@ -35,16 +35,3 @@ export default { .setDescription('The expression to be calculated') .setRequired(true)) } - -// Copilot conversation: - -//Q: Why do we need to replace the string? -//A: Because eval() is dangerous and can run any code -// So we need to make sure that the string is a math expression -// and nothing else - -//Q: If we receive a string like "1+1; console.log('Hello World')" -// will it run the console.log()? -//A: No, because we are replacing all characters that are not -// numbers, operators, parenthesis, etc. So it will only run -// the math expression \ No newline at end of file diff --git a/src/commands/mp.ts b/src/commands/mp.ts index c872266..3f445a8 100644 --- a/src/commands/mp.ts +++ b/src/commands/mp.ts @@ -4,7 +4,7 @@ import path from 'node:path'; import canvas from 'canvas'; import FormatPlayer from '../helpers/FormatPlayer.js'; import MessageTool from '../helpers/MessageTool.js'; -import LogPrefix from '../helpers/LogPrefix.js'; +import Logger from '../helpers/Logger.js'; import {readFileSync} from 'node:fs'; import {FSData} from '../typings/interfaces'; @@ -197,18 +197,18 @@ export default { const Url = await client.MPServer._content.findById(interaction.guildId); if (Url[serverSelector].ip && Url[serverSelector].code) return interaction.reply(Url[serverSelector].ip+'/feed/dedicated-server-stats.json?code='+Url[serverSelector].code) } catch(err){ - console.log(client.logTime(), LogPrefix('MPDB'), err); + Logger.forwardToConsole('error', 'MPDB', err); interaction.reply(`\`\`\`${err}\`\`\``) } } else { if (!address.match(/dedicated-server-stats/)) return interaction.reply('The URL does not match `dedicated-server-stats.xml`'); const newURL = address.replace('xml','json').split('/feed/dedicated-server-stats.json?code='); try { - console.log(client.logTime(), LogPrefix('MPDB'), `${serverSelector}\'s URL for ${interaction.guild.name} has been updated by ${interaction.member.displayName} (${interaction.member.id})`); + Logger.forwardToConsole('log', 'MPDB', `${serverSelector}\'s URL for ${interaction.guild.name} has been updated by ${interaction.member.displayName} (${interaction.member.id})`); const affected = await client.MPServer._content.findByIdAndUpdate({_id: interaction.guildId}, {$set: {[serverSelector]: {ip: newURL[0], code: newURL[1]}}}) if (affected) return interaction.reply('URL successfully updated.') } catch (err) { - console.log(client.logTime(), LogPrefix('MPDB'), `${serverSelector}\'s URL for ${interaction.guild.name} has been created by ${interaction.member.displayName} (${interaction.member.id})`); + Logger.forwardToConsole('log', 'MPDB', `${serverSelector}\'s URL for ${interaction.guild.name} has been created by ${interaction.member.displayName} (${interaction.member.id})`); await client.MPServer._content.create({_id: interaction.guildId, [serverSelector]: { ip: newURL[0], code: newURL[1] }}) .then(()=>interaction.reply('This server doesn\'t have any data in the database, therefore I have created it for you.')) .catch((err:Error)=>interaction.reply(`I got hit by a flying brick while trying to populate the server data:\n\`\`\`${err.message}\`\`\``)) diff --git a/src/commands/unpunish.ts b/src/commands/unpunish.ts index 39599dc..772c52b 100644 --- a/src/commands/unpunish.ts +++ b/src/commands/unpunish.ts @@ -1,6 +1,6 @@ import Discord from 'discord.js'; import TClient from '../client.js'; -import LogPrefix from '../helpers/LogPrefix.js'; +import Logger from '../helpers/Logger.js'; export default { async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){ @@ -10,7 +10,7 @@ export default { if (punishment.expired) return interaction.reply('This case has been overwritten by another case.'); const reason = interaction.options.getString('reason') ?? 'Reason unspecified'; await client.punishments.removePunishment(punishment.id, interaction.user.id, reason, interaction); - console.log(client.logTime(), LogPrefix('UnpunishmentLog'), `Case #${interaction.options.getInteger('case_id')} was used in /${interaction.commandName} for ${reason}`); + Logger.forwardToConsole('log', '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 Discord.SlashCommandBuilder() diff --git a/src/events/interactionCreate.ts b/src/events/interactionCreate.ts index afdd58e..9beb1a9 100644 --- a/src/events/interactionCreate.ts +++ b/src/events/interactionCreate.ts @@ -1,11 +1,13 @@ import Discord from 'discord.js'; import TClient from '../client.js'; +import Logger from '../helpers/Logger.js'; + export default { async run(client:TClient, interaction:Discord.BaseInteraction){ if (!interaction.inGuild() || !interaction.inCachedGuild()) return; if (interaction.isChatInputCommand()){ const commandFile = client.commands.get(interaction.commandName); - console.log(client.logTime(), `${interaction.user.username} used /${interaction.commandName} ${interaction.options.getSubcommandGroup(false) ?? ''} ${interaction.options.getSubcommand(false) ?? ''} in #${interaction.channel.name}`); + Logger.forwardToConsole('log', 'InteractionLog', `${interaction.user.username} used /${interaction.commandName} ${interaction.options.getSubcommandGroup(false) ?? ''} ${interaction.options.getSubcommand(false) ?? ''} in #${interaction.channel.name}`); if (!client.config.botSwitches.commands && !client.config.whitelist.includes(interaction.user.id)) return interaction.reply({content: `I am currently operating in development mode.\nPlease notify <@${client.config.whitelist[0]}> if this is a mistake.`, ephemeral: true}); if (commandFile){ try{ @@ -43,7 +45,7 @@ export default { interaction.member.roles.add(RoleID, 'Button Role'); interaction.reply({content: `You have been added to <@&${RoleID}>`, ephemeral: true}) } - } else console.log(client.logTime(), `Button pressed at ${interaction.message.url}`); + } else Logger.forwardToConsole('log', 'InteractionLog', `Button has been pressed at ${interaction.message.url}`); } } } diff --git a/src/events/messageCreate.ts b/src/events/messageCreate.ts index 8e8cf41..1c7f49f 100644 --- a/src/events/messageCreate.ts +++ b/src/events/messageCreate.ts @@ -2,7 +2,7 @@ import Discord from 'discord.js'; import TClient from '../client.js'; import Response from '../funcs/ResponseModule.js'; import CmdTrigger from '../funcs/CmdModule.js'; -import LogPrefix from '../helpers/LogPrefix.js'; +import Logger from '../helpers/Logger.js'; import Automoderator from '../funcs/Automod.js'; export default { @@ -15,7 +15,7 @@ export default { const automodFailReason = 'msg got possibly deleted by another bot.'; if (await client.bannedWords._content.findById(Automoderator.scanMsg(message))/* && !Whitelist.includes(message.channelId) */){ automodded = true; - message.delete().catch(()=>console.log(LogPrefix('AUTOMOD-BANNEDWORDS'), automodFailReason)); + message.delete().catch(()=>Logger.forwardToConsole('log', 'AUTOMOD-BANNEDWORDS', automodFailReason)); message.channel.send('That word isn\'t allowed here.').then(x=>setTimeout(()=>x.delete(), 10000)); await Automoderator.repeatedMessages(client, message, 30000, 3, 'bw', '30m', 'Constant swearing'); } else if (message.content.toLowerCase().includes('discord.gg/') && !client.isStaff(message.member as Discord.GuildMember)){ @@ -23,7 +23,7 @@ export default { const validInvite = await client.fetchInvite(url).catch(()=>undefined); if (validInvite && validInvite.guild?.id !== client.config.mainServer.id){ automodded = true; - message.delete().catch(()=>console.log(LogPrefix('AUTOMOD-ADVERT'), automodFailReason)); + message.delete().catch(()=>Logger.forwardToConsole('log', 'AUTOMOD-ADVERT', automodFailReason)); message.channel.send('Please don\'t advertise other Discord servers.').then(x=>setTimeout(()=>x.delete(), 15000)); await Automoderator.repeatedMessages(client, message, 60000, 2, 'adv', '1h', 'Discord advertisement'); } diff --git a/src/events/messageDelete.ts b/src/events/messageDelete.ts index e569377..604ecd9 100644 --- a/src/events/messageDelete.ts +++ b/src/events/messageDelete.ts @@ -1,13 +1,13 @@ import Discord from 'discord.js'; import TClient from '../client.js'; -import LogPrefix from '../helpers/LogPrefix.js'; +import Logger from '../helpers/Logger.js'; export default { run(client:TClient, msg:Discord.Message){ if (!client.config.botSwitches.logs) return; const disabledChannels = ['548032776830582794', '541677709487505408', '949380187668242483'] if (msg.guild?.id != client.config.mainServer.id || msg.partial || msg.author.bot || disabledChannels.includes(msg.channelId)) return; - if (Discord.DiscordAPIError.name === '10008') return console.log(client.logTime(), LogPrefix('MsgDelete'), 'Caught an unexpected error returned by Discord API. (Unknown Message)'); + if (Discord.DiscordAPIError.name === '10008') return Logger.forwardToConsole('log', 'MsgDelete', 'Caught an unexpected error returned by Discord API. (Unknown Message)'); const embed = new client.embed().setColor(client.config.embedColorRed).setTimestamp().setAuthor({name: `Author: ${msg.author.username} (${msg.author.id})`, iconURL: `${msg.author.displayAvatarURL()}`}).setTitle('Message deleted').setDescription(`<@${msg.author.id}>\n\`${msg.author.id}\``); if (msg.content.length != 0) embed.addFields({name: 'Content', value: `\`\`\`\n${msg.content.slice(0,1000)}\n\`\`\``}); embed.addFields( diff --git a/src/funcs/DatabaseServer.ts b/src/funcs/DatabaseServer.ts index 17d284a..e131aa7 100644 --- a/src/funcs/DatabaseServer.ts +++ b/src/funcs/DatabaseServer.ts @@ -1,14 +1,24 @@ -import TClient from '../client'; import mongoose from 'mongoose'; -import LogPrefix from '../helpers/LogPrefix.js'; +import Logger from '../helpers/Logger.js'; +import {readFileSync} from 'node:fs'; +import {Tokens} from '../typings/interfaces'; +const tokens:Tokens = JSON.parse(readFileSync('src/tokens.json', 'utf-8')); const connection:mongoose.Connection = mongoose.connection; export default class DatabaseServer { - static connect(client: TClient) { - const Logger = (logType:'log'|'error', msg:string)=>console[logType](client.logTime(), LogPrefix('DATABASE'), msg); - + protected static eventManager() { + let dbPrefix = 'Database'; + connection + .on('connected', ()=>Logger.forwardToConsole('log', dbPrefix, 'Connection to MongoDB has been established')) + .on('disconnected', ()=>Logger.forwardToConsole('log', dbPrefix, 'Connection to MongoDB has been lost')) + .on('close', ()=>Logger.forwardToConsole('log', dbPrefix, 'MongoDB has closed the connection')) + .on('all', ()=>Logger.forwardToConsole('log', dbPrefix, 'Successfully established a connection to all members')) + .on('fullsetup', ()=>Logger.forwardToConsole('log', dbPrefix, 'Successfully established a connection to Primary server & atleast one member')) + .on('error', (err:mongoose.Error)=>Logger.forwardToConsole('error', dbPrefix, `Encountered an error in MongoDB: ${err.message}`)) + } + protected static connect() { connection.set('strictQuery', true); - connection.openUri(client.tokens.mongodb_uri, { + connection.openUri(tokens.mongodb_uri, { replicaSet: 'toastyy', autoIndex: true, authMechanism: 'SCRAM-SHA-256', @@ -18,16 +28,10 @@ export default class DatabaseServer { socketTimeoutMS: 30000, tls: false, family: 4 - }); - - connection - .on('connecting', ()=>Logger('log','Establishing connection to MongoDB')) - .on('connected', ()=>Logger('log','Connection to MongoDB has been established')) - .on('disconnecting', ()=>Logger('log','Disconnecting from MongoDB')) - .on('disconnected', ()=>Logger('log','Disconnected from MongoDB')) - .on('close', ()=>Logger('log','MongoDB has closed the connection')) - .on('all', ()=>Logger('log','Successfully established a connection to all members')) - .on('fullsetup', ()=>Logger('log','Successfully established a connection to Primary server & atleast one member')) - .on('error', (err:mongoose.Error)=>Logger('error',`Encountered an error in MongoDB: ${err.message}`)); + }) + } + static init() { + this.connect(); + this.eventManager(); } } diff --git a/src/funcs/MPModule.ts b/src/funcs/MPModule.ts index 0b92a95..7a280db 100644 --- a/src/funcs/MPModule.ts +++ b/src/funcs/MPModule.ts @@ -5,7 +5,7 @@ interface TServer { import Discord from 'discord.js'; import TClient from '../client.js'; import FormatPlayer from '../helpers/FormatPlayer.js'; -import LogPrefix from '../helpers/LogPrefix.js'; +import Logger from '../helpers/Logger.js'; import {writeFileSync, readFileSync} from 'node:fs'; import {FSPlayer, FSData, FSCareerSavegame} from '../typings/interfaces'; @@ -23,7 +23,7 @@ export default async(client:TClient, Channel:string, Message:string, Server:TSer const hitCSG = await fetch(Server.ip+'/feed/dedicated-server-savegame.html?code='+Server.code+'&file=careerSavegame', sessionInit).then(async r=>(client.xjs.xml2js(await r.text(), {compact: true}) as any).careerSavegame as FSCareerSavegame); if (!hitDSS ?? !hitCSG){ - if (hitDSS && !hitDSS.slots) return console.log(LogPrefix('MPModule'), `DSS failed with unknown slots table for ${client.MPServerCache[ServerName].name}`); + if (hitDSS && !hitDSS.slots) return Logger.forwardToConsole('log', 'MPModule', `DSS failed with unknown slots table for ${client.MPServerCache[ServerName].name}`); else return msg.edit({embeds: [serverErrorEmbed]}); } @@ -51,7 +51,7 @@ export default async(client:TClient, Channel:string, Message:string, Server:TSer const serverLog = client.channels.resolve(client.config.mainServer.channels.fs_server_log) as Discord.TextChannel; const playersOnServer = hitDSS.slots?.players.filter(x=>x.isUsed); const playersInCache = client.MPServerCache[ServerName].players; - if (!playersOnServer ?? playersOnServer === undefined) return console.log(LogPrefix('MPModule'), 'Empty array, ignoring...'); // For the love of god, stop throwing errors everytime. + if (!playersOnServer ?? playersOnServer === undefined) return Logger.forwardToConsole('log', 'MPModule', 'Array is empty, ignoring...'); // For the love of god, stop throwing errors everytime. playersOnServer.forEach(player=>playerData.push(`**${player.name}${FormatPlayer.decoratePlayerIcons(player)}**\nFarming for ${FormatPlayer.uptimeFormat(player.uptime)}`)); // Player leaving @@ -88,7 +88,7 @@ export default async(client:TClient, Channel:string, Message:string, Server:TSer } } catch(err) { msg.edit({content: err.message, embeds: [serverErrorEmbed]}); - console.log(client.logTime(), LogPrefix('MPModule'),`Failed to make a request for ${ServerName}:`, err.message) + Logger.forwardToConsole('log', 'MPModule', `Failed to make a request for ${ServerName}: ${err.message}`); } } HITALL(); diff --git a/src/funcs/Punish.ts b/src/funcs/Punish.ts index bfb5985..0e3e6d0 100644 --- a/src/funcs/Punish.ts +++ b/src/funcs/Punish.ts @@ -1,6 +1,6 @@ import Discord from 'discord.js'; import TClient from '../client.js'; -import LogPrefix from '../helpers/LogPrefix.js'; +import Logger from '../helpers/Logger.js'; export default async(client:TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>, type: string)=>{ if (!client.isStaff(interaction.member as Discord.GuildMember)) return client.youNeedRole(interaction, 'dcmod'); @@ -10,7 +10,7 @@ export default async(client:TClient, interaction: Discord.ChatInputCommandIntera const GuildMember = interaction.options.getMember('member') ?? undefined; const User = interaction.options.getUser('member', true); - console.log(client.logTime(), LogPrefix('PunishmentLog'), `${GuildMember?.user?.username ?? User?.username ?? 'No user data'} ${time ? ['warn', 'kick'].includes(type) ? 'and no duration set' : `and ${time} (duration)` : ''} was used in /${interaction.commandName} for ${reason}`); + Logger.forwardToConsole('log', 'PunishmentLog', `${GuildMember?.user?.username ?? User?.username ?? 'No user data'} ${time ? ['warn', 'kick'].includes(type) ? 'and no duration set' : `and ${time} (duration)` : ''} 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).setAuthor({name: interaction?.user?.username, iconURL: interaction?.user?.displayAvatarURL({size:2048})}).setTitle('Punishment Log').setDescription(`${GuildMember?.user?.username ?? User?.username ?? 'No user data'} ${time ? ['warn', 'kick'].includes(client.punishments.type) ? 'and no duration set' : `and ${time} (duration)` : ''} was used in \`/${interaction.commandName}\` for \`${reason}\``).setTimestamp()]}); if (interaction.user.id === User.id) return interaction.reply(`You cannot ${type} yourself.`); if (!GuildMember && type != 'unban') return interaction.reply(`You cannot ${type} someone who is not in the server.`); diff --git a/src/funcs/YTModule.ts b/src/funcs/YTModule.ts index 022d48e..668cac0 100644 --- a/src/funcs/YTModule.ts +++ b/src/funcs/YTModule.ts @@ -1,6 +1,6 @@ import {TextChannel} from 'discord.js'; import TClient from '../client.js'; -import LogPrefix from '../helpers/LogPrefix.js'; +import Logger from '../helpers/Logger.js'; import MessageTool from '../helpers/MessageTool.js'; export default async(client: TClient, YTChannelID: string, YTChannelName: string, DiscordChannelID: string, DiscordRoleID: string)=>{ @@ -8,7 +8,7 @@ export default async(client: TClient, YTChannelID: string, YTChannelName: string try { await fetch(`https://www.youtube.com/feeds/videos.xml?channel_id=${YTChannelID}`, {signal: AbortSignal.timeout(8000), headers: {'User-Agent': 'Daggerbot - Notification/undici'}}).then(async xml=>Data = client.xjs.xml2js(await xml.text(), {compact: true})) } catch(err){ - console.log(client.logTime(), LogPrefix('YTModule'), `Failed to fetch "${YTChannelName}" from YouTube`) + Logger.forwardToConsole('log', 'YTModule', `Failed to fetch "${YTChannelName}" from YouTube`) } if (!Data) return; diff --git a/src/helpers/LogPrefix.ts b/src/helpers/LogPrefix.ts deleted file mode 100644 index 5319190..0000000 --- a/src/helpers/LogPrefix.ts +++ /dev/null @@ -1 +0,0 @@ -export default (prefix:string)=>{ return `[${prefix}]` }; \ No newline at end of file diff --git a/src/helpers/Logger.ts b/src/helpers/Logger.ts new file mode 100644 index 0000000..b340877 --- /dev/null +++ b/src/helpers/Logger.ts @@ -0,0 +1,13 @@ +import moment from 'moment'; + +export default class Logger { + static logTime() { + return `[${moment().format('DD/MM/YY HH:mm:ss')}]`; + } + static logPrefix(prefix:string) { + return `[${prefix}]`; + } + static forwardToConsole(logType:'log'|'error', prefix:string, message:string|any) { + console[logType](this.logTime(), this.logPrefix(prefix), message); + } +} diff --git a/src/index.ts b/src/index.ts index 271f52f..3553cac 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,6 +2,7 @@ import Discord from 'discord.js'; import TClient from './client.js'; const client = new TClient; client.init(); +import Logger from './helpers/Logger.js'; import YTModule from './funcs/YTModule.js'; import MPModule from './funcs/MPModule.js'; import {Player} from 'discord-player'; @@ -49,8 +50,8 @@ setInterval(async()=>{ 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`); - console.log(client.logTime(), await client.punishments.removePunishment(punishment._id, client.user.id, 'Time\'s up!')); + Logger.forwardToConsole('log', 'Punishment', `${punishment.member}\'s ${punishment.type} should expire now`); + Logger.forwardToConsole('log', 'Punishment', await client.punishments.removePunishment(punishment._id, client.user.id, 'Time\'s up!')); }); const formattedDate = Math.floor((now - client.config.LRSstart)/1000/60/60/24); @@ -61,7 +62,7 @@ setInterval(async()=>{ if (total < yesterday) total = yesterday // messages went down. dailyMsgs.push([formattedDate, total]); writeFileSync('./src/database/dailyMsgs.json', JSON.stringify(dailyMsgs)) - console.log(client.logTime(), `Pushed [${formattedDate}, ${total}] to dailyMsgs`); + Logger.forwardToConsole('log', 'DailyMsgs', `Pushed [${formattedDate}, ${total}]`) 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 x.name === 'rank').id}>`)); (client.channels.resolve(client.config.mainServer.channels.thismeanswar) as Discord.TextChannel).send({files:['./src/database/dailyMsgs.json']}).catch(fileErr=>console.log(fileErr)) } diff --git a/src/models/userLevels.ts b/src/models/userLevels.ts index f674391..6a0d683 100644 --- a/src/models/userLevels.ts +++ b/src/models/userLevels.ts @@ -1,7 +1,7 @@ import Discord from 'discord.js'; import TClient from '../client.js'; import mongoose from 'mongoose'; -import LogPrefix from '../helpers/LogPrefix.js'; +import Logger from '../helpers/Logger.js'; const Schema = mongoose.model('userLevels', new mongoose.Schema({ _id: {type: String}, @@ -25,7 +25,7 @@ export default class userLevels extends Schema { if (userData.messages >= this.algorithm(userData.level+2)){ while (userData.messages > this.algorithm(userData.level+1)){ const newData = await this._content.findByIdAndUpdate(userid, {level:userData.level++}, {new: true}); - console.log(this.client.logTime(), LogPrefix('LevelSystem'), `${userid} extended to level ${newData.level}`); + Logger.forwardToConsole('log', 'LevelSystem', `${userid} extended to level ${newData.level}`); } } else if (userData.messages >= this.algorithm(userData.level+1)) { const newData = await this._content.findByIdAndUpdate(userid, {level:userData.level+1}, {new: true});