2020-04-19 12:12:10 +02:00
const escapeRegex = require ( 'escape-string-regexp' ) ;
2020-04-08 18:08:46 +02:00
const { Structures } = require ( 'discord.js' ) ;
2020-06-19 20:28:49 +02:00
const { Collection , Emojis } = require ( '../../util' ) ;
2020-04-08 18:08:46 +02:00
2020-07-28 22:40:15 +02:00
const safeCommands = [ 'command:settings' , 'command:grant' , 'command:revoke' ] ;
2020-04-08 18:08:46 +02:00
const Guild = Structures . extend ( 'Guild' , ( Guild ) => {
class ExtendedGuild extends Guild {
constructor ( ... args ) {
super ( ... args ) ;
this . _settings = null ; //internal cache of current guild's settings; should ALWAYS stay the same as database.
2020-05-07 01:26:16 +02:00
this . _permissions = null ; //internal cache, should always match database.
2020-06-04 19:59:09 +02:00
2020-05-24 23:43:47 +02:00
this . callbacks = [ ] ;
2020-06-18 16:07:39 +02:00
this . webhooks = new Collection ( ) ;
2020-04-08 18:08:46 +02:00
}
2020-05-07 17:08:07 +02:00
//Fetch and cache settings
2020-04-19 10:27:13 +02:00
async settings ( ) {
2020-05-08 08:50:54 +02:00
if ( ! this . _settings ) this . _settings = this . client . transactionHandler . send ( { provider : 'mongodb' , request : { collection : 'guilds' , type : 'findOne' , query : { guildId : this . id } } } ) ;
if ( this . _settings instanceof Promise ) this . _settings = await this . _settings || null ;
2020-07-28 05:00:24 +02:00
if ( ! this . _settings ) this . _settings = { guildId : this . id , ... this . defaultConfig } ;
// else this._settings = Object.assign({}, { ...this.defaultConfig, ...this._settings }); //eslint-disable-line prefer-object-spread
else this . _settings = { ... this . defaultConfig , ... this . _settings } ; //eslint-disable-line prefer-object-spread
2020-04-19 10:27:13 +02:00
return this . _settings ;
2020-05-07 01:26:16 +02:00
}
2020-04-19 10:27:13 +02:00
2020-05-07 17:08:07 +02:00
//Fetch and cache perms
2020-05-08 08:50:54 +02:00
async permissions ( ) {
if ( ! this . _permissions ) this . _permissions = this . client . transactionHandler . send ( { provider : 'mongodb' , request : { collection : 'permissions' , type : 'findOne' , query : { guildId : this . id } } } ) ;
if ( this . _permissions instanceof Promise ) this . _permissions = await this . _permissions || null ;
if ( ! this . _permissions ) this . _permissions = { guildId : this . id } ;
2020-05-07 01:26:16 +02:00
return this . _permissions ;
2020-04-19 10:27:13 +02:00
}
2020-04-19 12:12:10 +02:00
2020-06-04 19:59:09 +02:00
async caseId ( ) {
if ( ! this . _settings ) await this . settings ( ) ;
return this . _caseId = this . _settings . caseId ; //eslint-disable-line no-return-assign
}
2020-05-07 01:26:16 +02:00
/* Settings Wrapper */
2020-05-06 01:40:46 +02:00
2020-05-17 15:27:35 +02:00
async _deleteSettings ( ) { //Delete whole entry - remove
2020-05-06 01:40:46 +02:00
try {
await this . client . transactionHandler . send ( {
provider : 'mongodb' ,
request : {
2020-07-23 22:40:20 +02:00
type : 'delete' ,
2020-05-17 15:27:35 +02:00
collection : 'guilds' ,
2020-05-06 01:40:46 +02:00
query : {
guildId : this . id
}
}
} ) ;
2020-07-28 05:00:24 +02:00
this . _settings = { ... { } , ... this . defaultConfig } ; //Create a new object so settings that change the _settings value won't replicate it towards the defaultConfig.
2020-05-06 01:40:46 +02:00
this . _storageLog ( ` Database Delete (guild: ${ this . id } ). ` ) ;
} catch ( error ) {
this . _storageError ( error ) ;
}
2020-05-21 12:47:58 +02:00
return true ;
2020-05-06 01:40:46 +02:00
}
2020-07-20 00:42:21 +02:00
async _resetSettings ( ) {
if ( ! this . _settings ) await this . settings ( ) ;
try {
await this . client . transactionHandler . send ( {
provider : 'mongodb' ,
request : {
type : 'updateOne' ,
collection : 'guilds' ,
query : {
guildId : this . id
} ,
data : {
caseId : this . _settings . caseId ,
guildId : this . id
} ,
upsert : false
}
} ) ;
this . _settings = {
2020-07-28 05:00:24 +02:00
... this . defaultConfig ,
... { caseId : this . _settings . caseId }
2020-07-20 00:42:21 +02:00
} ;
this . _storageLog ( ` Database Reset (guild: ${ this . id } ). ` ) ;
} catch ( error ) {
this . _storageError ( error ) ;
}
}
2020-05-17 15:27:35 +02:00
async _updateSettings ( data ) { //Update property (upsert true) - updateOne
2020-07-04 12:23:10 +02:00
if ( ! this . _settings ) await this . settings ( ) ;
2020-05-06 01:40:46 +02:00
try {
await this . client . transactionHandler . send ( {
provider : 'mongodb' ,
request : {
type : 'updateOne' ,
2020-05-17 15:27:35 +02:00
collection : 'guilds' ,
2020-05-06 01:40:46 +02:00
query : {
guildId : this . id
} ,
data
}
} ) ;
2020-05-17 15:27:35 +02:00
this . _settings = {
... this . _settings ,
2020-05-06 01:40:46 +02:00
... data
} ;
this . _storageLog ( ` Database Update (guild: ${ this . id } ). ` ) ;
} catch ( error ) {
this . _storageError ( error ) ;
}
2020-05-21 12:47:58 +02:00
return true ;
2020-05-06 01:40:46 +02:00
}
2020-05-21 12:47:58 +02:00
async _removeSettings ( value ) { //Remove property
2020-07-04 12:23:10 +02:00
if ( ! this . _settings ) await this . settings ( ) ;
2020-07-28 05:00:24 +02:00
if ( this . defaultConfig [ value ] ) {
await this . _updateSettings ( { [ value ] : this . defaultConfig [ value ] } ) ;
2020-05-06 01:40:46 +02:00
return undefined ;
}
try {
await this . client . transactionHandler . send ( {
provider : 'mongodb' ,
request : {
type : 'removeProperty' ,
2020-05-17 15:27:35 +02:00
collection : 'guilds' ,
2020-05-06 01:40:46 +02:00
query : {
guildId : this . id
} ,
data : [
value
]
}
} ) ;
this . _storageLog ( ` Database Remove (guild: ${ this . id } ). ` ) ;
2020-05-21 12:47:58 +02:00
delete this . _settings [ value ] ;
2020-05-06 01:40:46 +02:00
} catch ( error ) {
this . _storageError ( error ) ;
}
2020-05-21 12:47:58 +02:00
return true ;
2020-07-28 22:40:15 +02:00
}
/* Permission Checking */
async _checkPermissions ( message , command ) {
if ( typeof command === 'string' ) command = this . client . registry . components . get ( command ) ;
const { permissionType } = await this . settings ( ) ;
const discordCheck = ( member , permissions ) => {
return member . permissions . missing ( permissions ) ;
} ;
const grantCheck = async ( message , permission ) => {
const _permissions = await this . permissions ( ) ;
const roles = message . member . roles . cache . keyArray ( ) ;
const channelId = message . channel . id ;
const userId = message . member . id ;
let allowed = false ;
for ( const [ id , permissions ] of Object . entries ( _permissions ) ) {
if ( id === userId || roles . includes ( id ) ) {
if ( permissions . global . includes ( permission ) ) {
allowed = true ; break ;
}
const channel = permissions . channels [ channelId ] ;
if ( channel ) {
if ( channel . includes ( permission ) ) {
allowed = true ; break ;
}
}
}
}
return allowed ? [ ] : [ permission ] ;
} ;
let missing = [ ] ;
if ( permissionType === 'discord' ) {
missing = discordCheck ( message . member , command . memberPermissions ) ;
} else if ( permissionType === 'grant' ) {
if ( ! safeCommands . includes ( command . resolveable ) && ( discordCheck ( message . member , [ 'ADMINISTRATOR' ] ) . length > 0 || discordCheck ( message . member , [ 'MANAGE_GUILD' ] ) . length > 0 ) ) {
missing = await grantCheck ( message , command . resolveable ) ;
}
} else {
missing = [ ... discordCheck ( message . member , command . memberPermissions ) , ... await grantCheck ( message , command . resolveable ) ] ;
}
return missing ;
}
2020-05-06 01:40:46 +02:00
/* Language Formatting */
2020-05-24 23:43:47 +02:00
format ( index , parameters = { } , code = false ) {
2020-04-19 21:54:50 +02:00
2020-05-24 23:43:47 +02:00
let language = 'en_us' ;
if ( this . _settings . locale ) language = this . _settings . locale ;
2020-04-19 12:12:10 +02:00
2020-05-24 23:43:47 +02:00
parameters . prefix = this . prefix ;
2020-07-04 12:23:10 +02:00
let template = this . client . localeLoader . template ( language , index ) ; //.languages[language][index];
2020-05-24 23:43:47 +02:00
2020-06-19 20:28:49 +02:00
for ( const emoji of Object . keys ( Emojis ) ) {
parameters [ ` emoji_ ${ emoji } ` ] = Emojis [ emoji ] ;
}
2020-07-04 12:23:10 +02:00
if ( ! template ) {
2020-05-24 23:43:47 +02:00
return ` **Missing language index \` ${ language } [ ${ index } ] \` in languages. Contact a bot developer about this.** ` ;
}
for ( const [ param , val ] of Object . entries ( parameters ) ) {
2020-06-19 20:28:49 +02:00
template = template . replace ( new RegExp ( ` { ${ escapeRegex ( param . toLowerCase ( ) ) } } ` , 'gi' ) , val ) ;
2020-04-19 12:12:10 +02:00
}
2020-05-24 23:43:47 +02:00
2020-07-04 12:23:10 +02:00
if ( code ) {
2020-05-24 23:43:47 +02:00
try {
2020-07-04 12:23:10 +02:00
template = eval ( template ) ; //eslint-disable-line no-eval
} catch ( error ) {
this . command . client . logger . error ( ` Error in locale ${ language } : ${ index } while executing code. \n ${ error . stack || error } ` ) ;
2020-05-24 23:43:47 +02:00
}
}
return template ;
2020-04-19 21:54:50 +02:00
2020-04-19 12:12:10 +02:00
}
2020-05-06 01:40:46 +02:00
/* Resolver Shortcuts */
2020-06-02 12:09:28 +02:00
async resolveMembers ( members , strict ) {
2020-04-11 10:06:39 +02:00
2020-06-02 12:09:28 +02:00
return this . client . resolver . resolveMembers ( members , strict , this ) ;
2020-04-17 17:23:13 +02:00
}
async resolveMember ( member , strict ) {
2020-06-02 12:09:28 +02:00
return this . client . resolver . resolveMembers ( member , strict , this ) ;
2020-04-17 17:23:13 +02:00
2020-04-11 10:06:39 +02:00
}
2020-06-19 15:38:56 +02:00
async resolveChannels ( channels , strict ) {
2020-04-11 10:06:39 +02:00
2020-06-02 12:09:28 +02:00
return this . client . resolver . resolveChannels ( channels , strict , this ) ;
2020-04-11 10:06:39 +02:00
}
2020-06-19 15:38:56 +02:00
async resolveChannel ( channel , strict ) {
2020-04-17 17:23:13 +02:00
2020-06-02 12:09:28 +02:00
return this . client . resolver . resolveChannel ( channel , strict , this ) ;
2020-04-17 17:23:13 +02:00
}
2020-06-02 12:09:28 +02:00
async resolveRoles ( roles , strict ) {
2020-04-11 10:06:39 +02:00
2020-06-02 12:09:28 +02:00
return this . client . resolver . resolveRoles ( roles , strict , this ) ;
2020-04-11 10:06:39 +02:00
}
2020-04-17 17:23:13 +02:00
async resolveRole ( role , strict ) {
2020-05-22 22:13:47 +02:00
2020-06-02 12:09:28 +02:00
return this . client . resolver . resolveRole ( role , strict , this ) ;
2020-04-17 17:23:13 +02:00
}
2020-05-06 01:40:46 +02:00
/* Logging */
_storageLog ( log ) {
2020-05-07 17:08:07 +02:00
this . client . logger . debug ( log ) ;
2020-05-06 01:40:46 +02:00
}
_storageError ( error ) {
2020-05-07 17:08:07 +02:00
this . client . logger . error ( ` Database Error (guild: ${ this . id } ) : \n ${ error . stack || error } ` ) ;
2020-05-06 01:40:46 +02:00
}
2020-07-04 12:23:10 +02:00
_debugLog ( log ) {
this . client . logger . debug ( ` [ ${ this . name } ]( ${ this . id } ): ${ log } ` ) ;
}
/* Lazy Developer Getters */
2020-07-28 05:00:24 +02:00
get defaultConfig ( ) {
return JSON . parse ( JSON . stringify ( this . client . defaultConfig ) ) ;
}
2020-05-06 01:40:46 +02:00
get prefix ( ) {
2020-05-24 05:50:35 +02:00
return this . _settings . prefix
|| this . client . _options . bot . prefix ;
2020-05-06 01:40:46 +02:00
}
2020-05-25 13:13:34 +02:00
get premium ( ) { //GUILD SETTINGS MUST BE FETCHED
return this . _settings . premium ;
}
2020-05-06 01:40:46 +02:00
2020-07-04 12:23:10 +02:00
get debug ( ) { //GUILD SETTINGS MUST BE FETCHED
return this . _settings . debug ;
}
2020-04-08 18:08:46 +02:00
}
return ExtendedGuild ;
} ) ;
module . exports = Guild ;