2020-08-13 01:02:33 +03:00
/ * *
2021-03-15 23:12:58 +02:00
* Discord Tickets
2021-02-15 20:34:59 +02:00
* Copyright ( C ) 2021 Isaac Saunders
2021-05-22 02:04:18 +03:00
*
2021-02-15 20:34:59 +02:00
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
2021-05-22 02:04:18 +03:00
*
2021-02-15 20:34:59 +02:00
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2021-05-22 02:04:18 +03:00
*
2021-02-15 20:34:59 +02:00
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < https : //www.gnu.org/licenses/>.
2021-05-22 02:04:18 +03:00
*
2021-09-25 02:05:39 +03:00
* @ name @ discord - tickets / bot
2021-02-20 19:09:08 +02:00
* @ description An open - source Discord bot for ticket management
2021-02-15 20:34:59 +02:00
* @ copyright 2021 Isaac Saunders
* @ license GNU - GPLv3
2021-02-16 02:02:44 +02:00
* /
2021-09-25 02:05:39 +03:00
/* eslint-disable no-console */
2021-04-07 15:33:49 +03:00
process . title = 'Discord Tickets' ;
2021-04-24 22:34:09 +03:00
2021-08-16 17:04:13 +03:00
const min _node _version = '16.6.0' ;
const semver = require ( 'semver' ) ;
if ( semver . lt ( process . versions . node , min _node _version ) ) return console . log ( ` \x 07Error: Discord Tickets does not work on Node v ${ process . versions . node } ; please upgrade to v ${ min _node _version } or above. ` ) ;
2021-02-16 02:02:44 +02:00
2021-04-24 22:34:09 +03:00
const leeks = require ( 'leeks.js' ) ;
2021-02-16 02:02:44 +02:00
const fs = require ( 'fs' ) ;
const { path } = require ( './utils/fs' ) ;
2021-02-17 15:24:33 +02:00
2021-02-18 00:01:44 +02:00
const checkFile = ( file , example ) => {
2021-04-07 02:02:07 +03:00
if ( fs . existsSync ( path ( file ) ) ) return true ;
if ( ! fs . existsSync ( path ( example ) ) ) {
2021-04-07 15:33:49 +03:00
console . log ( ` \x 07Error: " ${ file } " not found, and unable to create it due to " ${ example } " being missing. ` ) ;
2021-02-17 22:51:03 +02:00
return process . exit ( ) ;
}
2021-04-07 02:02:07 +03:00
console . log ( ` Copying " ${ example } " to " ${ file } "... ` ) ;
fs . copyFileSync ( path ( example ) , path ( file ) ) ;
2021-02-18 00:01:44 +02:00
return false ;
} ;
2021-04-07 02:02:07 +03:00
checkFile ( './user/config.js' , './user/example.config.js' ) ;
2021-02-18 00:01:44 +02:00
if ( ! checkFile ( './.env' , './example.env' ) ) {
2021-04-07 02:02:07 +03:00
console . log ( 'Generating database encryption key...' ) ;
const file = path ( './.env' ) ;
const crypto = require ( 'crypto' ) ;
2021-05-18 20:12:07 +03:00
const key = 'DB_ENCRYPTION_KEY=' ;
const value = crypto
2021-04-07 02:02:07 +03:00
. randomBytes ( 24 )
. toString ( 'hex' ) ;
2021-05-22 02:04:18 +03:00
let data = fs . readFileSync ( file , { encoding : 'utf-8' } ) ;
2021-04-07 02:02:07 +03:00
data = data . replace ( key , key + value ) ;
fs . writeFileSync ( file , data ) ;
console . log ( 'Saved.' ) ;
2021-04-24 22:34:09 +03:00
console . log ( leeks . colours . yellow ( 'Warning: do not lose your ENV file or encryption key; you will lose access to data in the database.' ) ) ;
2021-04-07 15:33:49 +03:00
console . log ( '\x07Please set your bot\'s "DISCORD_TOKEN" in "./.env".' ) ;
2021-04-07 02:02:07 +03:00
2021-02-17 22:51:03 +02:00
process . exit ( ) ;
}
2021-02-18 00:01:44 +02:00
2021-05-22 02:04:18 +03:00
require ( 'dotenv' ) . config ( { path : path ( './.env' ) } ) ;
2021-02-16 02:02:44 +02:00
2021-02-17 00:34:20 +02:00
require ( './banner' ) ( ) ;
2021-02-27 23:13:46 +02:00
const log = require ( './logger' ) ;
2021-02-16 02:02:44 +02:00
2021-04-07 02:02:07 +03:00
const { version } = require ( '../package.json' ) ;
process . on ( 'unhandledRejection' , error => {
log . notice ( 'PLEASE INCLUDE THIS INFORMATION IF YOU ASK FOR HELP ABOUT THE FOLLOWING ERROR:' ) ;
log . notice ( ` Discord Tickets v ${ version } , Node v ${ process . versions . node } on ${ process . platform } ` ) ;
log . warn ( 'An error was not caught' ) ;
if ( error instanceof Error ) log . warn ( ` Uncaught ${ error . name } ` ) ;
log . error ( error ) ;
} ) ;
2021-08-16 23:05:20 +03:00
const DiscordUtils = require ( './utils/discord' ) ;
2021-04-07 02:02:07 +03:00
const Cryptr = require ( 'cryptr' ) ;
2021-02-16 16:48:04 +02:00
const I18n = require ( '@eartharoid/i18n' ) ;
2021-05-12 23:14:02 +03:00
const ListenerLoader = require ( './modules/listeners/loader' ) ;
2021-03-03 19:20:33 +02:00
const CommandManager = require ( './modules/commands/manager' ) ;
const PluginManager = require ( './modules/plugins/manager' ) ;
2021-04-01 23:33:08 +03:00
const TicketManager = require ( './modules/tickets/manager' ) ;
2021-02-17 00:34:20 +02:00
2021-04-07 02:02:07 +03:00
const fetch = require ( 'node-fetch' ) ;
2021-02-17 00:34:20 +02:00
const {
Client ,
Intents
} = require ( 'discord.js' ) ;
2021-05-18 22:35:39 +03:00
// eslint-disable-next-line no-unused-vars
2021-08-16 23:05:20 +03:00
const Logger = require ( 'leekslazylogger' ) ;
2021-02-16 16:48:04 +02:00
2021-02-18 20:41:35 +02:00
/ * *
2021-05-17 20:13:55 +03:00
* The Discord client
* @ typedef { Bot } Bot
2021-02-18 20:41:35 +02:00
* @ extends { Client }
* /
2021-02-16 02:02:44 +02:00
class Bot extends Client {
constructor ( ) {
super ( {
2021-08-16 23:05:20 +03:00
intents : [
Intents . FLAGS . GUILDS ,
Intents . FLAGS . GUILD _MEMBERS ,
Intents . FLAGS . GUILD _MESSAGES ,
Intents . FLAGS . GUILD _MESSAGE _REACTIONS
] ,
2021-02-17 00:34:20 +02:00
partials : [
'CHANNEL' ,
2021-05-13 18:01:09 +03:00
'MESSAGE' ,
2021-02-17 00:34:20 +02:00
'REACTION'
] ,
2021-08-16 23:05:20 +03:00
presence : DiscordUtils . selectPresence ( )
2021-02-16 02:02:44 +02:00
} ) ;
2021-05-22 02:04:18 +03:00
2021-02-18 00:01:44 +02:00
( async ( ) => {
2021-08-17 02:09:41 +03:00
this . version = version ;
2021-02-18 00:01:44 +02:00
/** The global bot configuration */
2021-04-07 02:02:07 +03:00
this . config = require ( '../user/config' ) ;
2021-02-18 00:01:44 +02:00
2021-05-18 22:35:39 +03:00
/ * *
* A [ leekslazylogger ] ( https : //logger.eartharoid.me) instance
2021-08-16 23:05:20 +03:00
* @ type { Logger }
2021-05-18 22:35:39 +03:00
* /
2021-02-18 00:01:44 +02:00
this . log = log ;
2021-05-18 22:35:39 +03:00
/ * *
* A [ Cryptr ] ( https : //www.npmjs.com/package/cryptr) instance
* @ type { Cryptr }
* /
2021-04-07 02:02:07 +03:00
this . cryptr = new Cryptr ( process . env . DB _ENCRYPTION _KEY ) ;
2021-05-18 20:12:07 +03:00
const locales = { } ;
2021-04-27 13:34:34 +03:00
fs . readdirSync ( path ( './src/locales' ) )
. filter ( file => file . endsWith ( '.json' ) )
. forEach ( file => {
2021-05-22 02:04:18 +03:00
const data = fs . readFileSync ( path ( ` ./src/locales/ ${ file } ` ) , { encoding : 'utf8' } ) ;
2021-05-18 20:12:07 +03:00
const name = file . slice ( 0 , file . length - 5 ) ;
2021-04-27 13:34:34 +03:00
locales [ name ] = JSON . parse ( data ) ;
} ) ;
2021-05-18 22:35:39 +03:00
/ * *
* An [ @ eartharoid / i18n ] ( https : //github.com/eartharoid/i18n) instance
* @ type { I18n }
* /
2021-04-27 13:34:34 +03:00
this . i18n = new I18n ( 'en-GB' , locales ) ;
2021-02-18 00:01:44 +02:00
2021-04-05 20:38:00 +03:00
/** A sequelize instance */
this . db = await require ( './database' ) ( this ) , // this.db.models.Ticket...
2021-02-18 00:01:44 +02:00
this . setMaxListeners ( this . config . max _listeners ) ; // set the max listeners for each event
2021-05-22 02:04:18 +03:00
2021-09-24 21:39:58 +03:00
require ( './update/notifier' ) ( this ) ; // check for updates
2021-05-22 02:04:18 +03:00
2021-05-12 23:14:02 +03:00
const listeners = new ListenerLoader ( this ) ;
2021-05-18 22:35:39 +03:00
listeners . load ( ) ; // load listeners
2021-02-17 15:24:33 +02:00
2021-02-25 11:58:19 +02:00
/** The ticket manager */
this . tickets = new TicketManager ( this ) ;
2021-02-18 00:01:44 +02:00
/** The command manager, used by internal and plugin commands */
this . commands = new CommandManager ( this ) ;
2021-02-17 22:17:35 +02:00
2021-02-18 00:01:44 +02:00
/** The plugin manager */
this . plugins = new PluginManager ( this ) ;
this . plugins . load ( ) ; // load plugins
2021-02-16 02:02:44 +02:00
2021-08-16 23:05:20 +03:00
/** Some utility methods */
this . utils = new DiscordUtils ( this ) ;
2021-02-18 00:01:44 +02:00
this . log . info ( 'Connecting to Discord API...' ) ;
2021-02-17 01:35:31 +02:00
2021-02-18 00:01:44 +02:00
this . login ( ) ;
} ) ( ) ;
2021-02-16 02:02:44 +02:00
}
2021-02-17 00:34:20 +02:00
2021-03-04 12:18:48 +02:00
async postStats ( ) {
2021-03-03 23:19:51 +02:00
/ * *
* OH NO , TELEMETRY ! ?
2021-03-15 23:12:58 +02:00
* Relax , it just counts how many people are using Discord Tickets .
2021-03-04 12:18:48 +02:00
* You can see the source here : https : //github.com/discord-tickets/stats
2021-03-03 23:19:51 +02:00
* /
if ( this . config . super _secret _setting ) { // you can disable it if you really want
2021-08-17 02:09:41 +03:00
const data = {
client : this . user . id ,
guilds : this . guilds . cache . size ,
members : await this . guilds . cache . reduce ( async ( acc , guild ) => await acc + ( await guild . fetch ( ) ) . approximateMemberCount , 0 ) ,
tickets : await this . db . models . Ticket . count ( ) ,
version : this . version
} ;
this . log . debug ( 'Sending statistics' , data ) ;
await fetch ( 'https://stats.discordtickets.app/v2' , {
body : JSON . stringify ( data ) ,
headers : { 'Content-Type' : 'application/json' } ,
method : 'POST'
} )
. catch ( error => {
this . log . warn ( 'Failed to send statistics' ) ;
this . log . debug ( error ) ;
2021-03-04 12:18:48 +02:00
} ) ;
2021-03-03 23:19:51 +02:00
}
}
2021-02-16 02:02:44 +02:00
}
2021-04-07 02:02:07 +03:00
new Bot ( ) ;