dexare
Version:
Modular and extendable Discord bot framework
160 lines (138 loc) • 5.22 kB
text/typescript
import Collection from '@discordjs/collection';
import Eris from 'eris';
import { PermissionObject } from '../types';
import LoggerHandler from '../util/logger';
import { ClientEvent } from './events';
import DexareClient from './index';
/** The function for a permission. */
export type PermissionFunction<T extends DexareClient<any>> = (
object: PermissionObject,
client: T,
event?: ClientEvent
) => boolean;
export const DirectMessagePermissions = [
'addReactions',
'readMessages',
'sendMessages',
'embedLinks',
'attachFiles',
'readMessageHistory',
'externalEmojis'
];
export const CorePermissions = [
...Object.keys(Eris.Constants.Permissions).map((permission) => 'discord.' + permission.toLowerCase()),
'dexare.elevated',
'dexare.inguild',
'dexare.nsfwchannel'
];
/** The registry for permissions in Dexare. */
export default class PermissionRegistry<T extends DexareClient<any>> {
readonly permissions = new Collection<string, PermissionFunction<T>>();
private readonly logger: LoggerHandler<T>;
private readonly client: T;
constructor(client: T) {
this.client = client;
this.logger = new LoggerHandler<T>(this.client, 'dexare/permissions');
for (const permission in Eris.Constants.Permissions) {
this.permissions.set('discord.' + permission.toLowerCase(), (object) => {
if (object.message)
if ('guild' in object.message.channel && object.member)
return object.message.channel
.permissionsOf(object.member)
.has(permission as keyof Eris.Constants['Permissions']);
else return DirectMessagePermissions.includes(permission);
else if (object.member)
return object.member.guild
.permissionsOf(object.member)
.has(permission as keyof Eris.Constants['Permissions']);
return DirectMessagePermissions.includes(permission);
});
}
this.permissions.set('dexare.elevated', (object, client) => {
if (!client.config.elevated) return false;
if (Array.isArray(client.config.elevated)) return client.config.elevated.includes(object.user.id);
return client.config.elevated === object.user.id;
});
this.permissions.set('dexare.inguild', (object) => {
if (object.member) return true;
if (object.message) return 'guild' in object.message.channel;
return false;
});
this.permissions.set('dexare.nsfwchannel', (object) => {
// False for users, why would anyone use a channel perm on users
if (!object.message) return false;
return 'nsfw' in object.message.channel ? object.message.channel.nsfw : true;
});
}
/**
* Registers a new permission.
* @param key The permission key to register
* @param permission The permission function to use
*/
register(key: string, permission: PermissionFunction<T>): void {
key = key.toLowerCase();
if (CorePermissions.includes(key)) throw new Error(`Cannot register to core permissions. (${key})`);
this.logger.log(`Registering permission '${key}'`);
this.permissions.set(key, permission);
}
/**
* Unregisters a permission.
* @param key The permission to unregister
*/
unregister(key: string): boolean {
key = key.toLowerCase();
if (CorePermissions.includes(key)) throw new Error(`Cannot unregister core permissions. (${key})`);
this.logger.log(`Unregistering permission '${key}'`);
return this.permissions.delete(key);
}
/**
* Check a permission.
* @param object The object to check with
* @param permission The permission to check
* @param event The client event to associate the function
*/
has(object: PermissionObject, permission: string, event?: ClientEvent) {
permission = permission.toLowerCase();
if (!permission || !this.permissions.has(permission)) return false;
return this.permissions.get(permission)!(object, this.client, event);
}
/**
* Maps permissions into an object with true/false values and permission keys.
* @param object The object to check with
* @param permissions The permissions to map
* @param prevMap The previous map, if any
* @param event The client event to associate
*/
map(
object: PermissionObject,
permissions: string[],
prevMap: { [permission: string]: boolean } = {},
event?: ClientEvent
) {
for (const permission of permissions) {
if (permission in prevMap) continue;
prevMap[permission] = this.has(object, permission, event);
}
return prevMap;
}
/**
* Convert something into a permission object.
* @param object The object to convert
*/
toObject(
object: Eris.Message<Eris.PossiblyUncachedTextableChannel> | Eris.User | Eris.Member
): PermissionObject {
const result: any = {};
let user: Eris.User;
if (object instanceof Eris.Message) user = object.author;
else if (object instanceof Eris.Member) user = object.user;
else user = object;
result.user = user;
if (object instanceof Eris.Member) result.member = object;
if (object instanceof Eris.Message) {
result.message = object;
if (object.member) result.member = object.member;
}
return result;
}
}