2017-09-30 01:21:48 +02:00
// Check for environmental variables.
require ( 'checkenv' ) . check ( ) ;
2017-08-03 03:48:16 +02:00
const discord = require ( 'discord.js' ) ;
const path = require ( 'path' ) ;
const schedule = require ( 'node-schedule' ) ;
2017-10-05 04:21:36 +02:00
const fs = require ( 'fs' ) ;
2016-12-08 04:52:37 +01:00
2017-08-03 03:48:16 +02:00
const logger = require ( './logging.js' ) ;
2017-10-05 04:21:36 +02:00
const state = require ( './state.js' ) ;
2018-04-04 01:28:33 +02:00
const data = require ( './data.js' ) ;
2016-12-08 04:52:37 +01:00
2018-04-04 01:28:33 +02:00
state . responses = require ( './responses.json' ) ;
2017-09-30 01:21:48 +02:00
2016-12-08 04:52:37 +01:00
var cachedModules = [ ] ;
2016-12-31 06:49:12 +01:00
var cachedTriggers = [ ] ;
2016-12-08 04:52:37 +01:00
var client = new discord . Client ( ) ;
2018-04-04 01:28:33 +02:00
logger . info ( 'Application startup. Configuring environment.' ) ;
2018-01-20 06:11:52 +01:00
process . on ( 'unhandledRejection' , ( error , promise ) => {
logger . error ( ` Unhandled promise rejection: ${ error . message } . ` , error ) ;
} ) ;
process . on ( 'uncaughtException' , error => {
logger . error ( ` Unhandled exception: ${ error . message } . ` , error ) ;
2017-09-24 21:44:49 +02:00
} ) ;
2018-02-28 01:19:14 +01:00
function findArray ( haystack , arr ) {
2017-09-30 01:38:00 +02:00
return arr . some ( function ( v ) {
return haystack . indexOf ( v ) >= 0 ;
} ) ;
}
2016-12-08 04:52:37 +01:00
client . on ( 'ready' , ( ) => {
// Initalize app channels.
2017-10-05 04:21:36 +02:00
state . logChannel = client . channels . get ( process . env . DISCORD _LOG _CHANNEL ) ;
state . guild = state . logChannel . guild ;
2016-12-08 04:52:37 +01:00
2017-03-31 03:17:21 +02:00
logger . info ( 'Bot is now online and connected to server.' ) ;
2016-12-08 04:52:37 +01:00
} ) ;
2017-09-30 01:38:00 +02:00
client . on ( 'guildMemberAdd' , ( member ) => {
2018-02-28 01:19:14 +01:00
member . addRole ( process . env . DISCORD _RULES _ROLE ) ;
2017-10-05 04:21:36 +02:00
state . stats . joins += 1 ;
2017-07-20 03:45:58 +02:00
} ) ;
2017-09-30 01:38:00 +02:00
client . on ( 'guildMemberRemove' , ( member ) => {
2017-10-05 04:21:36 +02:00
state . stats . leaves += 1 ;
2017-07-20 03:45:58 +02:00
} ) ;
2017-10-05 04:21:36 +02:00
// Output the stats for state.stats every 24 hours.
2017-07-20 04:05:02 +02:00
// Server is in UTC mode, 11:30 EST would be 03:30 UTC.
2017-09-30 01:38:00 +02:00
schedule . scheduleJob ( { hour : 3 , minute : 30 } , function ( ) {
2018-04-04 01:28:33 +02:00
logger . info ( ` Here are today's stats for ${ ( new Date ( ) ) . toLocaleDateString ( ) } ! ${ state . stats . joins } users have joined, ${ state . stats . ruleAccepts } users have accepted the rules, ${ state . stats . leaves } users have left, ${ state . stats . warnings } warnings have been issued. ` ) ;
2018-04-04 01:50:20 +02:00
state . logChannel . send ( ` Here are today's stats for ${ ( new Date ( ) ) . toLocaleDateString ( ) } ! ${ state . stats . joins } users have joined, ${ state . stats . ruleAccepts } users have accepted the rules, ${ state . stats . leaves } users have left, ${ state . stats . warnings } warnings have been issued. ` ) ;
2017-07-20 03:45:58 +02:00
// Clear the stats for the day.
2017-10-05 04:21:36 +02:00
state . stats . joins = 0 ;
2018-02-28 01:19:14 +01:00
state . stats . ruleAccepts = 0 ;
2017-10-05 04:21:36 +02:00
state . stats . leaves = 0 ;
2018-04-04 01:28:33 +02:00
state . stats . warnings = 0 ;
2017-07-20 03:45:58 +02:00
} ) ;
2016-12-08 04:52:37 +01:00
client . on ( 'message' , message => {
2017-09-30 01:38:00 +02:00
if ( message . author . bot && message . content . startsWith ( '.ban' ) === false ) { return ; }
2016-12-08 04:52:37 +01:00
2018-01-20 05:29:33 +01:00
if ( message . guild == null && state . responses . pmReply ) {
2016-12-08 04:52:37 +01:00
// We want to log PM attempts.
logger . info ( ` ${ message . author . username } ${ message . author } [PM]: ${ message . content } ` ) ;
2018-04-04 01:50:20 +02:00
state . logChannel . send ( ` ${ message . author } [PM]: ${ message . content } ` ) ;
2018-01-20 05:29:33 +01:00
message . reply ( state . responses . pmReply ) ;
2016-12-08 04:52:37 +01:00
return ;
}
2017-07-09 05:53:01 +02:00
logger . verbose ( ` ${ message . author . username } ${ message . author } [Channel: ${ message . channel . name } ${ message . channel } ]: ${ message . content } ` ) ;
2016-12-08 04:52:37 +01:00
2018-02-28 01:19:14 +01:00
// Check if the channel is #rules, if so we want to follow a different logic flow.
if ( message . channel . id === process . env . DISCORD _RULES _CHANNEL ) {
if ( message . content . includes ( process . env . DISCORD _RULES _TRIGGER ) ) {
// We want to remove the 'Unauthorized' role from them once they agree to the rules.
logger . verbose ( ` ${ message . author . username } ${ message . author } has accepted the rules, removing role ${ process . env . DISCORD _RULES _ROLE } . ` ) ;
state . stats . ruleAccepts += 1 ;
message . member . removeRole ( process . env . DISCORD _RULES _ROLE , 'Accepted the rules.' ) ;
}
// Delete the message in the channel to force a cleanup.
message . delete ( ) ;
return ;
} else if ( message . content . startsWith ( '.' ) && message . content . startsWith ( '..' ) === false ) {
// We want to make sure it's an actual command, not someone '...'-ing.
2016-12-08 04:52:37 +01:00
let cmd = message . content . split ( ' ' ) [ 0 ] . slice ( 1 ) ;
// Check by the name of the command.
let cachedModule = cachedModules [ ` ${ cmd } .js ` ] ;
let cachedModuleType = 'Command' ;
// Check by the quotes in the configuration.
2018-01-20 05:29:33 +01:00
if ( cachedModule == null ) { cachedModule = state . responses . quotes [ cmd ] ; cachedModuleType = 'Quote' ; }
2016-12-08 04:52:37 +01:00
if ( cachedModule ) {
// Check access permissions.
2017-09-30 01:38:00 +02:00
if ( cachedModule . roles !== undefined && findArray ( message . member . roles . map ( function ( x ) { return x . name ; } ) , cachedModule . roles ) === false ) {
2018-04-04 01:50:20 +02:00
state . logChannel . send ( ` ${ message . author } attempted to use admin command: ${ message . content } ` ) ;
2017-08-03 01:11:05 +02:00
logger . info ( ` ${ message . author . username } ${ message . author } attempted to use admin command: ${ message . content } ` ) ;
2016-12-08 04:52:37 +01:00
return false ;
}
2017-03-31 03:29:52 +02:00
logger . info ( ` ${ message . author . username } ${ message . author } [Channel: ${ message . channel } ] executed command: ${ message . content } ` ) ;
2016-12-08 04:52:37 +01:00
message . delete ( ) ;
2017-01-15 18:37:43 +01:00
try {
2017-09-30 01:38:00 +02:00
if ( cachedModuleType === 'Command' ) {
2017-01-15 18:37:43 +01:00
cachedModule . command ( message ) ;
2017-09-30 01:38:00 +02:00
} else if ( cachedModuleType === 'Quote' ) {
2017-01-15 18:37:43 +01:00
cachedModules [ 'quote.js' ] . command ( message , cachedModule . reply ) ;
}
} catch ( err ) { logger . error ( err ) ; }
2018-04-04 01:28:33 +02:00
// Warn after running command?
try {
// Check if the command requires a warning.
if ( cmd !== 'warn' && cachedModule . warn === true ) {
// Access check to see if the user has privilages to warn.
let warnCommand = cachedModules [ 'warn.js' ] ;
if ( findArray ( message . member . roles . map ( function ( x ) { return x . name ; } ) , warnCommand . roles ) ) {
// They are allowed to warn because they are in warn's roles.
warnCommand . command ( message ) ;
}
}
} catch ( err ) { logger . error ( err ) ; }
} else {
// Not a valid command.
2016-12-08 04:52:37 +01:00
}
2017-09-30 01:38:00 +02:00
} else if ( message . author . bot === false ) {
2016-12-31 06:49:12 +01:00
// This is a normal channel message.
2017-09-30 01:38:00 +02:00
cachedTriggers . forEach ( function ( trigger ) {
if ( trigger . roles === undefined || findArray ( message . member . roles . map ( function ( x ) { return x . name ; } ) , trigger . roles ) ) {
if ( trigger . trigger ( message ) === true ) {
logger . debug ( ` ${ message . author . username } ${ message . author } [Channel: ${ message . channel } ] triggered: ${ message . content } ` ) ;
try {
trigger . execute ( message ) ;
} catch ( err ) { logger . error ( err ) ; }
2016-12-31 06:49:12 +01:00
}
2017-09-30 01:38:00 +02:00
}
2016-12-31 06:49:12 +01:00
} ) ;
2016-12-08 04:52:37 +01:00
}
2017-03-31 03:17:21 +02:00
} ) ;
2016-12-08 04:52:37 +01:00
2017-03-31 03:17:21 +02:00
// Cache all command modules.
2017-03-31 03:18:23 +02:00
cachedModules = [ ] ;
2017-10-05 04:21:36 +02:00
fs . readdirSync ( './src/commands/' ) . forEach ( function ( file ) {
2017-03-31 03:17:21 +02:00
// Load the module if it's a script.
2017-09-30 01:38:00 +02:00
if ( path . extname ( file ) === '.js' ) {
2017-04-08 01:36:45 +02:00
if ( file . includes ( '.disabled' ) ) {
logger . info ( ` Did not load disabled module: ${ file } ` ) ;
} else {
logger . info ( ` Loaded module: ${ file } ` ) ;
cachedModules [ file ] = require ( ` ./commands/ ${ file } ` ) ;
}
2017-03-31 03:17:21 +02:00
}
2016-12-08 04:52:37 +01:00
} ) ;
2017-03-31 03:17:21 +02:00
// Cache all triggers.
2017-03-31 03:18:23 +02:00
cachedTriggers = [ ] ;
2017-10-05 04:21:36 +02:00
fs . readdirSync ( './src/triggers/' ) . forEach ( function ( file ) {
2017-03-31 03:17:21 +02:00
// Load the trigger if it's a script.
2017-09-30 01:38:00 +02:00
if ( path . extname ( file ) === '.js' ) {
2017-04-08 01:36:45 +02:00
if ( file . includes ( '.disabled' ) ) {
logger . info ( ` Did not load disabled trigger: ${ file } ` ) ;
} else {
logger . info ( ` Loaded trigger: ${ file } ` ) ;
cachedTriggers . push ( require ( ` ./triggers/ ${ file } ` ) ) ;
}
2017-03-31 03:17:21 +02:00
}
} ) ;
2018-04-04 01:28:33 +02:00
data . readWarnings ( ) ;
data . readBans ( ) ;
// Load custom responses
if ( process . env . DATA _CUSTOM _RESPONSES ) {
data . readCustomResponses ( ) ;
}
2017-09-30 01:21:48 +02:00
client . login ( process . env . DISCORD _LOGIN _TOKEN ) ;
2017-09-30 01:38:00 +02:00
logger . info ( 'Startup completed. Established connection to Discord.' ) ;