add rank commands

merge-requests/15/head
Matthew 2020-07-06 03:15:06 -04:00
parent e39ebfd140
commit cd4805dbae
No known key found for this signature in database
GPG Key ID: 210AF32ADE3B5C4B
35 changed files with 1888 additions and 1730 deletions

View File

@ -1,5 +1,5 @@
import locsh from './loc.sh/main';
export default {
'loc.sh': locsh,
};
import locsh from './loc.sh/main';
export default {
'loc.sh': locsh,
};

View File

@ -1,6 +1,6 @@
import { Server, ServerManagement } from '../../class';
export default (management: ServerManagement) => {
const server = new Server(management, 3890, `${__dirname}/routes`);
return server;
};
import { Server, ServerManagement } from '../../class';
export default (management: ServerManagement) => {
const server = new Server(management, 3890, `${__dirname}/routes`);
return server;
};

View File

@ -1 +1 @@
export { default as root } from './root';
export { default as root } from './root';

View File

@ -1,27 +1,27 @@
import { Route, Server } from '../../../class';
import { RedirectRaw } from '../../../models';
export default class Root extends Route {
constructor(server: Server) {
super(server);
this.conf = {
path: '/',
};
}
public bind() {
this.router.get('/', (_req, res) => res.redirect('https://www.libraryofcode.org/'));
this.router.get('/:key', async (req, res) => {
try {
const link: RedirectRaw = await this.server.client.db.Redirect.findOne({ key: req.params.key }).lean().exec();
if (!link) return res.status(404).json({ code: this.constants.codes.NOT_FOUND, message: this.constants.messages.NOT_FOUND });
res.redirect(link.to);
return await this.server.client.db.Redirect.updateOne({ key: req.params.key }, { $inc: { visitedCount: 1 } });
} catch (err) {
this.server.client.util.handleError(err);
return res.status(500).json({ code: this.constants.codes.SERVER_ERROR, message: this.constants.messages.SERVER_ERROR });
}
});
}
}
import { Route, Server } from '../../../class';
import { RedirectRaw } from '../../../models';
export default class Root extends Route {
constructor(server: Server) {
super(server);
this.conf = {
path: '/',
};
}
public bind() {
this.router.get('/', (_req, res) => res.redirect('https://www.libraryofcode.org/'));
this.router.get('/:key', async (req, res) => {
try {
const link: RedirectRaw = await this.server.client.db.Redirect.findOne({ key: req.params.key }).lean().exec();
if (!link) return res.status(404).json({ code: this.constants.codes.NOT_FOUND, message: this.constants.messages.NOT_FOUND });
res.redirect(link.to);
return await this.server.client.db.Redirect.updateOne({ key: req.params.key }, { $inc: { visitedCount: 1 } });
} catch (err) {
this.server.client.util.handleError(err);
return res.status(500).json({ code: this.constants.codes.SERVER_ERROR, message: this.constants.messages.SERVER_ERROR });
}
});
}
}

View File

@ -1,69 +1,69 @@
import eris from 'eris';
import mongoose from 'mongoose';
import { promises as fs } from 'fs';
import { Collection, Command, Util, ServerManagement, Event } from '.';
import { Member, MemberInterface, Moderation, ModerationInterface, PagerNumber, PagerNumberInterface, Redirect, RedirectInterface } from '../models';
export default class Client extends eris.Client {
public config: { token: string, prefix: string, guildID: string, mongoDB: string, emailPass: string, };
public commands: Collection<Command>;
public events: Collection<Event>;
public intervals: Collection<NodeJS.Timeout>;
public util: Util;
public serverManagement: ServerManagement;
public db: { Member: mongoose.Model<MemberInterface>, Moderation: mongoose.Model<ModerationInterface>, PagerNumber: mongoose.Model<PagerNumberInterface>, Redirect: mongoose.Model<RedirectInterface> };
constructor(token: string, options?: eris.ClientOptions) {
super(token, options);
this.commands = new Collection<Command>();
this.events = new Collection<Event>();
this.intervals = new Collection<NodeJS.Timeout>();
this.db = { Member, Moderation, PagerNumber, Redirect };
}
public async loadDatabase() {
await mongoose.connect(this.config.mongoDB, { useNewUrlParser: true, useUnifiedTopology: true, poolSize: 50 });
}
public loadPlugins() {
this.util = new Util(this);
this.serverManagement = new ServerManagement(this);
}
public async loadIntervals() {
const intervalFiles = await fs.readdir(`${__dirname}/../intervals`);
intervalFiles.forEach((file) => {
const intervalName = file.split('.')[0];
if (file === 'index.js') return;
const interval: NodeJS.Timeout = (require(`${__dirname}/../intervals/${file}`).default)(this);
this.intervals.add(intervalName, interval);
this.util.signale.success(`Successfully loaded interval: ${intervalName}`);
});
}
public async loadEvents(eventFiles: { [s: string]: typeof Event; } | ArrayLike<typeof Event>) {
const evtFiles = Object.entries<typeof Event>(eventFiles);
for (const [name, Ev] of evtFiles) {
const event = new Ev(this);
this.events.add(event.event, event);
this.on(event.event, event.run);
this.util.signale.success(`Successfully loaded event: ${name}`);
delete require.cache[require.resolve(`${__dirname}/../events/${name}`)];
}
}
public async loadCommands(commandFiles: { [s: string]: typeof Command; } | ArrayLike<typeof Command>) {
const cmdFiles = Object.values<typeof Command>(commandFiles);
for (const Cmd of cmdFiles) {
const command = new Cmd(this);
this.commands.add(command.name, command);
this.util.signale.success(`Successfully loaded command: ${command.name}`);
}
}
}
import eris from 'eris';
import mongoose from 'mongoose';
import { promises as fs } from 'fs';
import { Collection, Command, Util, ServerManagement, Event } from '.';
import { Member, MemberInterface, Moderation, ModerationInterface, PagerNumber, PagerNumberInterface, Rank, RankInterface, Redirect, RedirectInterface } from '../models';
export default class Client extends eris.Client {
public config: { token: string, prefix: string, guildID: string, mongoDB: string, emailPass: string, };
public commands: Collection<Command>;
public events: Collection<Event>;
public intervals: Collection<NodeJS.Timeout>;
public util: Util;
public serverManagement: ServerManagement;
public db: { Member: mongoose.Model<MemberInterface>, Moderation: mongoose.Model<ModerationInterface>, PagerNumber: mongoose.Model<PagerNumberInterface>, Rank: mongoose.Model<RankInterface>, Redirect: mongoose.Model<RedirectInterface> };
constructor(token: string, options?: eris.ClientOptions) {
super(token, options);
this.commands = new Collection<Command>();
this.events = new Collection<Event>();
this.intervals = new Collection<NodeJS.Timeout>();
this.db = { Member, Moderation, PagerNumber, Rank, Redirect };
}
public async loadDatabase() {
await mongoose.connect(this.config.mongoDB, { useNewUrlParser: true, useUnifiedTopology: true, poolSize: 50 });
}
public loadPlugins() {
this.util = new Util(this);
this.serverManagement = new ServerManagement(this);
}
public async loadIntervals() {
const intervalFiles = await fs.readdir(`${__dirname}/../intervals`);
intervalFiles.forEach((file) => {
const intervalName = file.split('.')[0];
if (file === 'index.js') return;
const interval: NodeJS.Timeout = (require(`${__dirname}/../intervals/${file}`).default)(this);
this.intervals.add(intervalName, interval);
this.util.signale.success(`Successfully loaded interval: ${intervalName}`);
});
}
public async loadEvents(eventFiles: { [s: string]: typeof Event; } | ArrayLike<typeof Event>) {
const evtFiles = Object.entries<typeof Event>(eventFiles);
for (const [name, Ev] of evtFiles) {
const event = new Ev(this);
this.events.add(event.event, event);
this.on(event.event, event.run);
this.util.signale.success(`Successfully loaded event: ${name}`);
delete require.cache[require.resolve(`${__dirname}/../events/${name}`)];
}
}
public async loadCommands(commandFiles: { [s: string]: typeof Command; } | ArrayLike<typeof Command>) {
const cmdFiles = Object.values<typeof Command>(commandFiles);
for (const Cmd of cmdFiles) {
const command = new Cmd(this);
this.commands.add(command.name, command);
this.util.signale.success(`Successfully loaded command: ${command.name}`);
}
}
}

View File

@ -1,153 +1,153 @@
/**
* Hold a bunch of something
*/
export default class Collection<V> extends Map<string, V> {
baseObject: new (...args: any[]) => V;
/**
* Creates an instance of Collection
*/
constructor(iterable: Iterable<[string, V]>|object = null) {
if (iterable && iterable instanceof Array) {
super(iterable);
} else if (iterable && iterable instanceof Object) {
super(Object.entries(iterable));
} else {
super();
}
}
/**
* Map to array
* ```js
* [value, value, value]
* ```
*/
toArray(): V[] {
return [...this.values()];
}
/**
* Map to object
* ```js
* { key: value, key: value, key: value }
* ```
*/
toObject(): { [key: string]: V } {
const obj: { [key: string]: V } = {};
for (const [key, value] of this.entries()) {
obj[key] = value;
}
return obj;
}
/**
* Add an object
*
* If baseObject, add only if instance of baseObject
*
* If no baseObject, add
* @param key The key of the object
* @param value The object data
* @param replace Whether to replace an existing object with the same key
* @return The existing or newly created object
*/
add(key: string, value: V, replace: boolean = false): V {
if (this.has(key) && !replace) {
return this.get(key);
}
if (this.baseObject && !(value instanceof this.baseObject)) return null;
this.set(key, value);
return value;
}
/**
* Return the first object to make the function evaluate true
* @param func A function that takes an object and returns something
* @return The first matching object, or `null` if no match
*/
find(func: Function): V {
for (const item of this.values()) {
if (func(item)) return item;
}
return null;
}
/**
* Return an array with the results of applying the given function to each element
* @param callbackfn A function that takes an object and returns something
*/
map<U>(callbackfn: (value?: V, index?: number, array?: V[]) => U): U[] {
const arr = [];
for (const item of this.values()) {
arr.push(callbackfn(item));
}
return arr;
}
/**
* Return all the objects that make the function evaluate true
* @param func A function that takes an object and returns true if it matches
*/
filter(func: (value: V) => boolean): V[] {
const arr = [];
for (const item of this.values()) {
if (func(item)) {
arr.push(item);
}
}
return arr;
}
/**
* Test if at least one element passes the test implemented by the provided function. Returns true if yes, or false if not.
* @param func A function that takes an object and returns true if it matches
*/
some(func: (value: V) => boolean) {
for (const item of this.values()) {
if (func(item)) {
return true;
}
}
return false;
}
/**
* Update an object
* @param key The key of the object
* @param value The updated object data
*/
update(key: string, value: V) {
return this.add(key, value, true);
}
/**
* Remove an object
* @param key The key of the object
* @returns The removed object, or `null` if nothing was removed
*/
remove(key: string): V {
const item = this.get(key);
if (!item) {
return null;
}
this.delete(key);
return item;
}
/**
* Get a random object from the Collection
* @returns The random object or `null` if empty
*/
random(): V {
if (!this.size) {
return null;
}
return Array.from(this.values())[Math.floor(Math.random() * this.size)];
}
toString() {
return `[Collection<${this.baseObject.name}>]`;
}
}
/**
* Hold a bunch of something
*/
export default class Collection<V> extends Map<string, V> {
baseObject: new (...args: any[]) => V;
/**
* Creates an instance of Collection
*/
constructor(iterable: Iterable<[string, V]>|object = null) {
if (iterable && iterable instanceof Array) {
super(iterable);
} else if (iterable && iterable instanceof Object) {
super(Object.entries(iterable));
} else {
super();
}
}
/**
* Map to array
* ```js
* [value, value, value]
* ```
*/
toArray(): V[] {
return [...this.values()];
}
/**
* Map to object
* ```js
* { key: value, key: value, key: value }
* ```
*/
toObject(): { [key: string]: V } {
const obj: { [key: string]: V } = {};
for (const [key, value] of this.entries()) {
obj[key] = value;
}
return obj;
}
/**
* Add an object
*
* If baseObject, add only if instance of baseObject
*
* If no baseObject, add
* @param key The key of the object
* @param value The object data
* @param replace Whether to replace an existing object with the same key
* @return The existing or newly created object
*/
add(key: string, value: V, replace: boolean = false): V {
if (this.has(key) && !replace) {
return this.get(key);
}
if (this.baseObject && !(value instanceof this.baseObject)) return null;
this.set(key, value);
return value;
}
/**
* Return the first object to make the function evaluate true
* @param func A function that takes an object and returns something
* @return The first matching object, or `null` if no match
*/
find(func: Function): V {
for (const item of this.values()) {
if (func(item)) return item;
}
return null;
}
/**
* Return an array with the results of applying the given function to each element
* @param callbackfn A function that takes an object and returns something
*/
map<U>(callbackfn: (value?: V, index?: number, array?: V[]) => U): U[] {
const arr = [];
for (const item of this.values()) {
arr.push(callbackfn(item));
}
return arr;
}
/**
* Return all the objects that make the function evaluate true
* @param func A function that takes an object and returns true if it matches
*/
filter(func: (value: V) => boolean): V[] {
const arr = [];
for (const item of this.values()) {
if (func(item)) {
arr.push(item);
}
}
return arr;
}
/**
* Test if at least one element passes the test implemented by the provided function. Returns true if yes, or false if not.
* @param func A function that takes an object and returns true if it matches
*/
some(func: (value: V) => boolean) {
for (const item of this.values()) {
if (func(item)) {
return true;
}
}
return false;
}
/**
* Update an object
* @param key The key of the object
* @param value The updated object data
*/
update(key: string, value: V) {
return this.add(key, value, true);
}
/**
* Remove an object
* @param key The key of the object
* @returns The removed object, or `null` if nothing was removed
*/
remove(key: string): V {
const item = this.get(key);
if (!item) {
return null;
}
this.delete(key);
return item;
}
/**
* Get a random object from the Collection
* @returns The random object or `null` if empty
*/
random(): V {
if (!this.size) {
return null;
}
return Array.from(this.values())[Math.floor(Math.random() * this.size)];
}
toString() {
return `[Collection<${this.baseObject.name}>]`;
}
}

View File

@ -1,92 +1,92 @@
import { Member, Message, TextableChannel } from 'eris';
import { Client } from '.';
export default class Command {
public client: Client;
/**
* The name of the command
*/
public name: string;
/**
* The description for the command.
*/
public description: string;
/**
* Usage for the command.
*/
public usage: string;
/**
* The aliases for the command.
*/
public aliases: string[];
/**
* - **0:** Everyone
* - **1:** Associates+
* - **2:** Core Team+
* - **3:** Moderators, Supervisor, & Board of Directors
* - **4:** Technicians, Supervisor, & Board of Directors
* - **5:** Moderators, Technicians, Supervisor, & Board of Directors
* - **6:** Supervisor+
* - **7:** Board of Directors
*/
public permissions: number;
/**
* Determines if the command is only available in server.
*/
public guildOnly: boolean;
/**
* Determines if the command is enabled or not.
*/
public enabled: boolean;
public run(message: Message, args: string[]): Promise<any> { return Promise.resolve(); }
constructor(client: Client) {
this.client = client;
this.aliases = [];
}
public checkPermissions(member: Member): boolean {
if (member.id === '278620217221971968' || member.id === '253600545972027394') return true;
switch (this.permissions) {
case 0:
return true;
case 1:
return member.roles.some((r) => ['701481967149121627', '453689940140883988', '455972169449734144', '701454780828221450', '701454855952138300', '662163685439045632'].includes(r));
case 2:
return member.roles.some((r) => ['453689940140883988', '455972169449734144', '701454780828221450', '701454855952138300', '662163685439045632'].includes(r));
case 3:
return member.roles.some((r) => ['455972169449734144', '701454855952138300', '662163685439045632'].includes(r));
case 4:
return member.roles.some((r) => ['701454780828221450', '701454855952138300', '662163685439045632'].includes(r));
case 5:
return member.roles.some((r) => ['455972169449734144', '701454780828221450', '701454855952138300', '662163685439045632'].includes(r));
case 6:
return member.roles.some((r) => ['701454855952138300', '662163685439045632'].includes(r));
case 7:
return member.roles.includes('662163685439045632');
default:
return false;
}
}
public error(channel: TextableChannel, text: string): Promise<Message> {
return channel.createMessage(`***${this.client.util.emojis.ERROR} ${text}***`);
}
public success(channel: TextableChannel, text: string): Promise<Message> {
return channel.createMessage(`***${this.client.util.emojis.SUCCESS} ${text}***`);
}
public loading(channel: TextableChannel, text: string): Promise<Message> {
return channel.createMessage(`***${this.client.util.emojis.LOADING} ${text}***`);
}
}
import { Member, Message, TextableChannel } from 'eris';
import { Client } from '.';
export default class Command {
public client: Client;
/**
* The name of the command
*/
public name: string;
/**
* The description for the command.
*/
public description: string;
/**
* Usage for the command.
*/
public usage: string;
/**
* The aliases for the command.
*/
public aliases: string[];
/**
* - **0:** Everyone
* - **1:** Associates+
* - **2:** Core Team+
* - **3:** Moderators, Supervisor, & Board of Directors
* - **4:** Technicians, Supervisor, & Board of Directors
* - **5:** Moderators, Technicians, Supervisor, & Board of Directors
* - **6:** Supervisor+
* - **7:** Board of Directors
*/
public permissions: number;
/**
* Determines if the command is only available in server.
*/
public guildOnly: boolean;
/**
* Determines if the command is enabled or not.
*/
public enabled: boolean;
public run(message: Message, args: string[]): Promise<any> { return Promise.resolve(); }
constructor(client: Client) {
this.client = client;
this.aliases = [];
}
public checkPermissions(member: Member): boolean {
if (member.id === '278620217221971968' || member.id === '253600545972027394') return true;
switch (this.permissions) {
case 0:
return true;
case 1:
return member.roles.some((r) => ['701481967149121627', '453689940140883988', '455972169449734144', '701454780828221450', '701454855952138300', '662163685439045632'].includes(r));
case 2:
return member.roles.some((r) => ['453689940140883988', '455972169449734144', '701454780828221450', '701454855952138300', '662163685439045632'].includes(r));
case 3:
return member.roles.some((r) => ['455972169449734144', '701454855952138300', '662163685439045632'].includes(r));
case 4:
return member.roles.some((r) => ['701454780828221450', '701454855952138300', '662163685439045632'].includes(r));
case 5:
return member.roles.some((r) => ['455972169449734144', '701454780828221450', '701454855952138300', '662163685439045632'].includes(r));
case 6:
return member.roles.some((r) => ['701454855952138300', '662163685439045632'].includes(r));
case 7:
return member.roles.includes('662163685439045632');
default:
return false;
}
}
public error(channel: TextableChannel, text: string): Promise<Message> {
return channel.createMessage(`***${this.client.util.emojis.ERROR} ${text}***`);
}
public success(channel: TextableChannel, text: string): Promise<Message> {
return channel.createMessage(`***${this.client.util.emojis.SUCCESS} ${text}***`);
}
public loading(channel: TextableChannel, text: string): Promise<Message> {
return channel.createMessage(`***${this.client.util.emojis.LOADING} ${text}***`);
}
}

View File

@ -1,15 +1,15 @@
import { Client } from '.';
export default class Event {
public client: Client
public event: string;
constructor(client: Client) {
this.client = client;
this.event = '';
this.run = this.run.bind(this);
}
public async run(...args: any[]): Promise<void> { return Promise.resolve(); }
}
import { Client } from '.';
export default class Event {
public client: Client
public event: string;
constructor(client: Client) {
this.client = client;
this.event = '';
this.run = this.run.bind(this);
}
public async run(...args: any[]): Promise<void> { return Promise.resolve(); }
}

View File

@ -1,142 +1,142 @@
/* eslint-disable no-bitwise */
import { Member, User } from 'eris';
import { randomBytes } from 'crypto';
import moment, { unitOfTime } from 'moment';
import { Client, RichEmbed } from '.';
import { Moderation as ModerationModel, ModerationInterface } from '../models';
import { moderation as channels } from '../configs/channels.json';
export default class Moderation {
public client: Client;
public logChannels: {
modlogs: string
};
constructor(client: Client) {
this.client = client;
this.logChannels = {
modlogs: channels.modlogs,
};
}
public checkPermissions(member: Member, moderator: Member): boolean {
if (member.id === moderator.id) return false;
if (member.roles.some((r) => ['662163685439045632', '455972169449734144', '453689940140883988'].includes(r))) return false;
const bit = member.permission.allow;
if ((bit | 8) === bit) return false;
if ((bit | 20) === bit) return false;
return true;
}
/**
* Converts some sort of time based duration to milliseconds based on length.
* @param time The time, examples: 2h, 1m, 1w
*/
public convertTimeDurationToMilliseconds(time: string): number {
const lockLength = time.match(/[a-z]+|[^a-z]+/gi);
const length = Number(lockLength[0]);
const unit = lockLength[1] as unitOfTime.Base;
return moment.duration(length, unit).asMilliseconds();
}
public async ban(user: User, moderator: Member, duration: number, reason?: string): Promise<ModerationInterface> {
if (reason && reason.length > 512) throw new Error('Ban reason cannot be longer than 512 characters');
await this.client.guilds.get(this.client.config.guildID).banMember(user.id, 7, reason);
const logID = randomBytes(2).toString('hex');
const mod = new ModerationModel({
userID: user.id,
logID,
moderatorID: moderator.id,
reason: reason || null,
type: 5,
date: new Date(),
});
const now: number = Date.now();
let date: Date;
let processed = true;
if (duration > 0) {
date = new Date(now + duration);
processed = false;
} else date = null;
const expiration = { date, processed };
mod.expiration = expiration;
const embed = new RichEmbed();
embed.setTitle(`Case ${logID} | Ban`);
embed.setColor('#e74c3c');
embed.setAuthor(user.username, user.avatarURL);
embed.setThumbnail(user.avatarURL);
embed.addField('User', `<@${user.id}>`, true);
embed.addField('Moderator', `<@${moderator.id}>`, true);
if (reason) {
embed.addField('Reason', reason, true);
}
if (date) {
embed.addField('Expiration', moment(date).calendar(), true);
}
embed.setFooter(this.client.user.username, this.client.user.avatarURL);
embed.setTimestamp();
this.client.createMessage(this.logChannels.modlogs, { embed });
return mod.save();
}
public async unban(userID: string, moderator: Member, reason?: string): Promise<ModerationInterface> {
this.client.unbanGuildMember(this.client.config.guildID, userID, reason);
const user = await this.client.getRESTUser(userID);
if (!user) throw new Error('Cannot get user.');
const logID = randomBytes(2).toString('hex');
const mod = new ModerationModel({
userID,
logID,
moderatorID: moderator.id,
reason: reason || null,
type: 4,
date: new Date(),
});
const embed = new RichEmbed();
embed.setTitle(`Case ${logID} | Unban`);
embed.setColor('#1abc9c');
embed.setAuthor(user.username, user.avatarURL);
embed.setThumbnail(user.avatarURL);
embed.addField('User', `<@${user.id}>`, true);
embed.addField('Moderator', `<@${moderator.id}>`, true);
if (reason) {
embed.addField('Reason', reason, true);
}
embed.setFooter(this.client.user.username, this.client.user.avatarURL);
embed.setTimestamp();
this.client.createMessage(this.logChannels.modlogs, { embed });
return mod.save();
}
public async kick(user: Member|User, moderator: Member, reason?: string): Promise<ModerationInterface> {
if (reason && reason.length > 512) throw new Error('Kick reason cannot be longer than 512 characters');
await this.client.guilds.get(this.client.config.guildID).kickMember(user.id, reason);
const logID = randomBytes(2).toString('hex');
const mod = new ModerationModel({
userID: user.id,
logID,
moderatorID: moderator.id,
reason: reason || null,
type: 5,
date: new Date(),
});
const embed = new RichEmbed();
embed.setTitle(`Case ${logID} | Kick`);
embed.setColor('#e74c3c');
embed.setAuthor(user.username, user.avatarURL);
embed.setThumbnail(user.avatarURL);
embed.addField('User', `<@${user.id}>`, true);
embed.addField('Moderator', `<@${moderator.id}>`, true);
if (reason) {
embed.addField('Reason', reason, true);
}
embed.setFooter(this.client.user.username, this.client.user.avatarURL);
embed.setTimestamp();
this.client.createMessage(this.logChannels.modlogs, { embed });
return mod.save();
}
}
/* eslint-disable no-bitwise */
import { Member, User } from 'eris';
import { randomBytes } from 'crypto';
import moment, { unitOfTime } from 'moment';
import { Client, RichEmbed } from '.';
import { Moderation as ModerationModel, ModerationInterface } from '../models';
import { moderation as channels } from '../configs/channels.json';
export default class Moderation {
public client: Client;
public logChannels: {
modlogs: string
};
constructor(client: Client) {
this.client = client;
this.logChannels = {
modlogs: channels.modlogs,
};
}
public checkPermissions(member: Member, moderator: Member): boolean {
if (member.id === moderator.id) return false;
if (member.roles.some((r) => ['662163685439045632', '455972169449734144', '453689940140883988'].includes(r))) return false;
const bit = member.permission.allow;
if ((bit | 8) === bit) return false;
if ((bit | 20) === bit) return false;
return true;
}
/**
* Converts some sort of time based duration to milliseconds based on length.
* @param time The time, examples: 2h, 1m, 1w
*/
public convertTimeDurationToMilliseconds(time: string): number {
const lockLength = time.match(/[a-z]+|[^a-z]+/gi);
const length = Number(lockLength[0]);
const unit = lockLength[1] as unitOfTime.Base;
return moment.duration(length, unit).asMilliseconds();
}
public async ban(user: User, moderator: Member, duration: number, reason?: string): Promise<ModerationInterface> {
if (reason && reason.length > 512) throw new Error('Ban reason cannot be longer than 512 characters');
await this.client.guilds.get(this.client.config.guildID).banMember(user.id, 7, reason);
const logID = randomBytes(2).toString('hex');
const mod = new ModerationModel({
userID: user.id,
logID,
moderatorID: moderator.id,
reason: reason || null,
type: 5,
date: new Date(),
});
const now: number = Date.now();
let date: Date;
let processed = true;
if (duration > 0) {
date = new Date(now + duration);
processed = false;
} else date = null;
const expiration = { date, processed };
mod.expiration = expiration;
const embed = new RichEmbed();
embed.setTitle(`Case ${logID} | Ban`);
embed.setColor('#e74c3c');
embed.setAuthor(user.username, user.avatarURL);
embed.setThumbnail(user.avatarURL);
embed.addField('User', `<@${user.id}>`, true);
embed.addField('Moderator', `<@${moderator.id}>`, true);
if (reason) {
embed.addField('Reason', reason, true);
}
if (date) {
embed.addField('Expiration', moment(date).calendar(), true);
}
embed.setFooter(this.client.user.username, this.client.user.avatarURL);
embed.setTimestamp();
this.client.createMessage(this.logChannels.modlogs, { embed });
return mod.save();
}
public async unban(userID: string, moderator: Member, reason?: string): Promise<ModerationInterface> {
this.client.unbanGuildMember(this.client.config.guildID, userID, reason);
const user = await this.client.getRESTUser(userID);
if (!user) throw new Error('Cannot get user.');
const logID = randomBytes(2).toString('hex');
const mod = new ModerationModel({
userID,
logID,
moderatorID: moderator.id,
reason: reason || null,
type: 4,
date: new Date(),
});
const embed = new RichEmbed();
embed.setTitle(`Case ${logID} | Unban`);
embed.setColor('#1abc9c');
embed.setAuthor(user.username, user.avatarURL);
embed.setThumbnail(user.avatarURL);
embed.addField('User', `<@${user.id}>`, true);
embed.addField('Moderator', `<@${moderator.id}>`, true);
if (reason) {
embed.addField('Reason', reason, true);
}
embed.setFooter(this.client.user.username, this.client.user.avatarURL);
embed.setTimestamp();
this.client.createMessage(this.logChannels.modlogs, { embed });
return mod.save();
}
public async kick(user: Member|User, moderator: Member, reason?: string): Promise<ModerationInterface> {
if (reason && reason.length > 512) throw new Error('Kick reason cannot be longer than 512 characters');
await this.client.guilds.get(this.client.config.guildID).kickMember(user.id, reason);
const logID = randomBytes(2).toString('hex');
const mod = new ModerationModel({
userID: user.id,
logID,
moderatorID: moderator.id,
reason: reason || null,
type: 5,
date: new Date(),
});
const embed = new RichEmbed();
embed.setTitle(`Case ${logID} | Kick`);
embed.setColor('#e74c3c');
embed.setAuthor(user.username, user.avatarURL);
embed.setThumbnail(user.avatarURL);
embed.addField('User', `<@${user.id}>`, true);
embed.addField('Moderator', `<@${moderator.id}>`, true);
if (reason) {
embed.addField('Reason', reason, true);
}
embed.setFooter(this.client.user.username, this.client.user.avatarURL);
embed.setTimestamp();
this.client.createMessage(this.logChannels.modlogs, { embed });
return mod.save();
}
}

View File

@ -1,164 +1,164 @@
/* eslint-disable no-param-reassign */
import { EmbedOptions } from 'eris';
export default class RichEmbed implements EmbedOptions {
title?: string
type?: string
description?: string
url?: string
timestamp?: string | Date
color?: number
footer?: { text: string, icon_url?: string, proxy_icon_url?: string}
image?: { url?: string, proxy_url?: string, height?: number, width?: number }
thumbnail?: { url?: string, proxy_url?: string, height?: number, width?: number }
video?: { url: string, height?: number, width?: number }
provider?: { name: string, url?: string}
author?: { name: string, url?: string, proxy_icon_url?: string, icon_url?: string}
fields?: {name: string, value: string, inline?: boolean}[]
constructor(data: EmbedOptions = {}) {
this.title = data.title;
this.description = data.description;
this.url = data.url;
this.color = data.color;
this.author = data.author;
this.timestamp = data.timestamp;
this.fields = data.fields || [];
this.thumbnail = data.thumbnail;
this.image = data.image;
this.footer = data.footer;
}
/**
* Sets the title of this embed.
*/
setTitle(title: string) {
if (typeof title !== 'string') throw new TypeError('RichEmbed titles must be a string.');
if (title.length > 256) throw new RangeError('RichEmbed titles may not exceed 256 characters.');
this.title = title;
return this;
}
/**
* Sets the description of this embed.
*/
setDescription(description: string) {
if (typeof description !== 'string') throw new TypeError('RichEmbed descriptions must be a string.');
if (description.length > 2048) throw new RangeError('RichEmbed descriptions may not exceed 2048 characters.');
this.description = description;
return this;
}
/**
* Sets the URL of this embed.
*/
setURL(url: string) {
if (typeof url !== 'string') throw new TypeError('RichEmbed URLs must be a string.');
if (!url.startsWith('http://') && !url.startsWith('https://')) url = `https://${url}`;
this.url = encodeURI(url);
return this;
}
/**
* Sets the color of this embed.
*/
setColor(color: string | number) {
if (typeof color === 'string' || typeof color === 'number') {
if (typeof color === 'string') {
const regex = /[^a-f0-9]/gi;
color = color.replace(/#/g, '');
if (regex.test(color)) throw new RangeError('Hexadecimal colours must not contain characters other than 0-9 and a-f.');
color = parseInt(color, 16);
} else if (color < 0 || color > 16777215) throw new RangeError('Base 10 colours must not be less than 0 or greater than 16777215.');
this.color = color;
return this;
}
throw new TypeError('RichEmbed colours must be hexadecimal as string or number.');
}
/**
* Sets the author of this embed.
*/
setAuthor(name: string, icon_url?: string, url?: string) {
if (typeof name !== 'string') throw new TypeError('RichEmbed Author names must be a string.');
if (url && typeof url !== 'string') throw new TypeError('RichEmbed Author URLs must be a string.');
if (icon_url && typeof icon_url !== 'string') throw new TypeError('RichEmbed Author icons must be a string.');
this.author = { name, icon_url, url };
return this;
}
/**
* Sets the timestamp of this embed.
*/
setTimestamp(timestamp = new Date()) {
if (Number.isNaN(timestamp.getTime())) throw new TypeError('Expecting ISO8601 (Date constructor)');
this.timestamp = timestamp;
return this;
}
/**
* Adds a field to the embed (max 25).
*/
addField(name: string, value: string, inline = false) {
if (typeof name !== 'string') throw new TypeError('RichEmbed Field names must be a string.');
if (typeof value !== 'string') throw new TypeError('RichEmbed Field values must be a string.');
if (typeof inline !== 'boolean') throw new TypeError('RichEmbed Field inlines must be a boolean.');
if (this.fields.length >= 25) throw new RangeError('RichEmbeds may not exceed 25 fields.');
if (name.length > 256) throw new RangeError('RichEmbed field names may not exceed 256 characters.');
if (!/\S/.test(name)) throw new RangeError('RichEmbed field names may not be empty.');
if (value.length > 1024) throw new RangeError('RichEmbed field values may not exceed 1024 characters.');
if (!/\S/.test(value)) throw new RangeError('RichEmbed field values may not be empty.');
this.fields.push({ name, value, inline });
return this;
}
/**
* Convenience function for `<RichEmbed>.addField('\u200B', '\u200B', inline)`.
*/
addBlankField(inline = false) {
return this.addField('\u200B', '\u200B', inline);
}
/**
* Set the thumbnail of this embed.
*/
setThumbnail(url: string) {
if (typeof url !== 'string') throw new TypeError('RichEmbed Thumbnail URLs must be a string.');
this.thumbnail = { url };
return this;
}
/**
* Set the image of this embed.
*/
setImage(url: string) {
if (typeof url !== 'string') throw new TypeError('RichEmbed Image URLs must be a string.');
if (!url.startsWith('http://') || !url.startsWith('https://')) url = `https://${url}`;
this.image = { url };
return this;
}
/**
* Sets the footer of this embed.
*/
setFooter(text: string, icon_url?: string) {
if (typeof text !== 'string') throw new TypeError('RichEmbed Footers must be a string.');
if (icon_url && typeof icon_url !== 'string') throw new TypeError('RichEmbed Footer icon URLs must be a string.');
if (text.length > 2048) throw new RangeError('RichEmbed footer text may not exceed 2048 characters.');
this.footer = { text, icon_url };
return this;
}
}
/* eslint-disable no-param-reassign */
import { EmbedOptions } from 'eris';
export default class RichEmbed implements EmbedOptions {
title?: string
type?: string
description?: string
url?: string
timestamp?: string | Date
color?: number
footer?: { text: string, icon_url?: string, proxy_icon_url?: string}
image?: { url?: string, proxy_url?: string, height?: number, width?: number }
thumbnail?: { url?: string, proxy_url?: string, height?: number, width?: number }
video?: { url: string, height?: number, width?: number }
provider?: { name: string, url?: string}
author?: { name: string, url?: string, proxy_icon_url?: string, icon_url?: string}
fields?: {name: string, value: string, inline?: boolean}[]
constructor(data: EmbedOptions = {}) {
this.title = data.title;
this.description = data.description;
this.url = data.url;
this.color = data.color;
this.author = data.author;
this.timestamp = data.timestamp;
this.fields = data.fields || [];
this.thumbnail = data.thumbnail;
this.image = data.image;
this.footer = data.footer;
}
/**
* Sets the title of this embed.
*/
setTitle(title: string) {
if (typeof title !== 'string') throw new TypeError('RichEmbed titles must be a string.');
if (title.length > 256) throw new RangeError('RichEmbed titles may not exceed 256 characters.');
this.title = title;
return this;
}
/**
* Sets the description of this embed.
*/
setDescription(description: string) {
if (typeof description !== 'string') throw new TypeError('RichEmbed descriptions must be a string.');
if (description.length > 2048) throw new RangeError('RichEmbed descriptions may not exceed 2048 characters.');
this.description = description;
return this;
}
/**
* Sets the URL of this embed.
*/
setURL(url: string) {
if (typeof url !== 'string') throw new TypeError('RichEmbed URLs must be a string.');
if (!url.startsWith('http://') && !url.startsWith('https://')) url = `https://${url}`;
this.url = encodeURI(url);
return this;
}
/**
* Sets the color of this embed.
*/
setColor(color: string | number) {
if (typeof color === 'string' || typeof color === 'number') {
if (typeof color === 'string') {
const regex = /[^a-f0-9]/gi;
color = color.replace(/#/g, '');
if (regex.test(color)) throw new RangeError('Hexadecimal colours must not contain characters other than 0-9 and a-f.');
color = parseInt(color, 16);
} else if (color < 0 || color > 16777215) throw new RangeError('Base 10 colours must not be less than 0 or greater than 16777215.');
this.color = color;
return this;
}
throw new TypeError('RichEmbed colours must be hexadecimal as string or number.');
}
/**
* Sets the author of this embed.
*/
setAuthor(name: string, icon_url?: string, url?: string) {
if (typeof name !== 'string') throw new TypeError('RichEmbed Author names must be a string.');
if (url && typeof url !== 'string') throw new TypeError('RichEmbed Author URLs must be a string.');
if (icon_url && typeof icon_url !== 'string') throw new TypeError('RichEmbed Author icons must be a string.');
this.author = { name, icon_url, url };
return this;
}
/**
* Sets the timestamp of this embed.
*/
setTimestamp(timestamp = new Date()) {
if (Number.isNaN(timestamp.getTime())) throw new TypeError('Expecting ISO8601 (Date constructor)');
this.timestamp = timestamp;
return this;
}
/**
* Adds a field to the embed (max 25).
*/
addField(name: string, value: string, inline = false) {
if (typeof name !== 'string') throw new TypeError('RichEmbed Field names must be a string.');
if (typeof value !== 'string') throw new TypeError('RichEmbed Field values must be a string.');
if (typeof inline !== 'boolean') throw new TypeError('RichEmbed Field inlines must be a boolean.');
if (this.fields.length >= 25) throw new RangeError('RichEmbeds may not exceed 25 fields.');
if (name.length > 256) throw new RangeError('RichEmbed field names may not exceed 256 characters.');
if (!/\S/.test(name)) throw new RangeError('RichEmbed field names may not be empty.');
if (value.length > 1024) throw new RangeError('RichEmbed field values may not exceed 1024 characters.');
if (!/\S/.test(value)) throw new RangeError('RichEmbed field values may not be empty.');
this.fields.push({ name, value, inline });
return this;
}
/**
* Convenience function for `<RichEmbed>.addField('\u200B', '\u200B', inline)`.
*/
addBlankField(inline = false) {
return this.addField('\u200B', '\u200B', inline);
}
/**
* Set the thumbnail of this embed.
*/
setThumbnail(url: string) {
if (typeof url !== 'string') throw new TypeError('RichEmbed Thumbnail URLs must be a string.');
this.thumbnail = { url };
return this;
}
/**
* Set the image of this embed.
*/
setImage(url: string) {
if (typeof url !== 'string') throw new TypeError('RichEmbed Image URLs must be a string.');
if (!url.startsWith('http://') || !url.startsWith('https://')) url = `https://${url}`;
this.image = { url };
return this;
}
/**
* Sets the footer of this embed.
*/
setFooter(text: string, icon_url?: string) {
if (typeof text !== 'string') throw new TypeError('RichEmbed Footers must be a string.');
if (icon_url && typeof icon_url !== 'string') throw new TypeError('RichEmbed Footer icon URLs must be a string.');
if (text.length > 2048) throw new RangeError('RichEmbed footer text may not exceed 2048 characters.');
this.footer = { text, icon_url };
return this;
}
}

View File

@ -1,75 +1,75 @@
/* eslint-disable consistent-return */
import { Router, Request, Response } from 'express';
import { Server } from '.';
export default class Route {
public server: Server;
public conf: { path: string; deprecated?: boolean; maintenance?: boolean; };
public router: Router;
constructor(server: Server) {
this.server = server;
this.conf = { path: '' };
this.router = Router();
}
public bind() {}
public init() {
this.router.all('*', (req, res, next) => {
this.server.client.util.signale.log(`'${req.method}' request from '${req.ip}' to '${req.hostname}${req.path}'.`);
if (this.conf.maintenance === true) res.status(503).json({ code: this.constants.codes.MAINTENANCE_OR_UNAVAILABLE, message: this.constants.messages.MAINTENANCE_OR_UNAVAILABLE });
else if (this.conf.deprecated === true) res.status(501).json({ code: this.constants.codes.DEPRECATED, message: this.constants.messages.DEPRECATED });
else next();
});
}
public deprecated(): void {
this.router.all('*', (_req, res) => {
res.status(501).json({ code: this.constants.codes.DEPRECATED, message: this.constants.messages.DEPRECATED });
});
}
public maintenance(): void {
this.router.all('*', (_req, res) => {
res.status(503).json({ code: this.constants.codes.MAINTENANCE_OR_UNAVAILABLE, message: this.constants.messages.MAINTENANCE_OR_UNAVAILABLE });
});
}
public handleError(error: Error, res: Response) {
res.status(500).json({ code: this.constants.codes.SERVER_ERROR, message: this.constants.messages.SERVER_ERROR });
this.server.parent.client.util.handleError(error);
}
get constants() {
return {
codes: {
SUCCESS: 100,
UNAUTHORIZED: 101,
PERMISSION_DENIED: 104,
ENDPOINT_NOT_FOUND: 104,
NOT_FOUND: 1041,
ACCOUNT_NOT_FOUND: 1041,
CLIENT_ERROR: 1044,
SERVER_ERROR: 105,
DEPRECATED: 1051,
MAINTENANCE_OR_UNAVAILABLE: 1053,
},
messages: {
UNAUTHORIZED: ['CREDENTIALS_INVALID', 'The credentials you supplied are invalid.'],
BEARER_TOKEN_INVALID: ['BEARER_TOKEN_INVALID', 'The Bearer token you supplied is invalid.'],
PERMISSION_DENIED: ['PERMISSION_DENIED', 'You do not have valid credentials to access this resource.'],
NOT_FOUND: ['NOT_FOUND', 'The resource you requested cannot be located.'],
ENDPOINT_NOT_FOUND: ['ENDPOINT_NOT_FOUND', 'The endpoint you requested does not exist or cannot be located.'],
SERVER_ERROR: ['INTERNAL_ERROR', 'An internal error has occurred, Engineers have been notified.'],
DEPRECATED: ['ENDPOINT_OR_RESOURCE_DEPRECATED', 'The endpoint or resource you\'re trying to access has been deprecated.'],
MAINTENANCE_OR_UNAVAILABLE: ['SERVICE_UNAVAILABLE', 'The endpoint or resource you\'re trying to access is either in maintenance or is not available.'],
},
discord: {
SERVER_ID: '446067825673633794',
},
};
}
}
/* eslint-disable consistent-return */
import { Router, Request, Response } from 'express';
import { Server } from '.';
export default class Route {
public server: Server;
public conf: { path: string; deprecated?: boolean; maintenance?: boolean; };
public router: Router;
constructor(server: Server) {
this.server = server;
this.conf = { path: '' };
this.router = Router();
}
public bind() {}
public init() {
this.router.all('*', (req, res, next) => {
this.server.client.util.signale.log(`'${req.method}' request from '${req.ip}' to '${req.hostname}${req.path}'.`);
if (this.conf.maintenance === true) res.status(503).json({ code: this.constants.codes.MAINTENANCE_OR_UNAVAILABLE, message: this.constants.messages.MAINTENANCE_OR_UNAVAILABLE });
else if (this.conf.deprecated === true) res.status(501).json({ code: this.constants.codes.DEPRECATED, message: this.constants.messages.DEPRECATED });
else next();
});
}
public deprecated(): void {
this.router.all('*', (_req, res) => {
res.status(501).json({ code: this.constants.codes.DEPRECATED, message: this.constants.messages.DEPRECATED });
});
}
public maintenance(): void {
this.router.all('*', (_req, res) => {
res.status(503).json({ code: this.constants.codes.MAINTENANCE_OR_UNAVAILABLE, message: this.constants.messages.MAINTENANCE_OR_UNAVAILABLE });
});
}
public handleError(error: Error, res: Response) {
res.status(500).json({ code: this.constants.codes.SERVER_ERROR, message: this.constants.messages.SERVER_ERROR });
this.server.parent.client.util.handleError(error);
}
get constants() {
return {
codes: {
SUCCESS: 100,
UNAUTHORIZED: 101,
PERMISSION_DENIED: 104,
ENDPOINT_NOT_FOUND: 104,
NOT_FOUND: 1041,
ACCOUNT_NOT_FOUND: 1041,
CLIENT_ERROR: 1044,
SERVER_ERROR: 105,
DEPRECATED: 1051,
MAINTENANCE_OR_UNAVAILABLE: 1053,
},
messages: {
UNAUTHORIZED: ['CREDENTIALS_INVALID', 'The credentials you supplied are invalid.'],
BEARER_TOKEN_INVALID: ['BEARER_TOKEN_INVALID', 'The Bearer token you supplied is invalid.'],
PERMISSION_DENIED: ['PERMISSION_DENIED', 'You do not have valid credentials to access this resource.'],
NOT_FOUND: ['NOT_FOUND', 'The resource you requested cannot be located.'],
ENDPOINT_NOT_FOUND: ['ENDPOINT_NOT_FOUND', 'The endpoint you requested does not exist or cannot be located.'],
SERVER_ERROR: ['INTERNAL_ERROR', 'An internal error has occurred, Engineers have been notified.'],
DEPRECATED: ['ENDPOINT_OR_RESOURCE_DEPRECATED', 'The endpoint or resource you\'re trying to access has been deprecated.'],
MAINTENANCE_OR_UNAVAILABLE: ['SERVICE_UNAVAILABLE', 'The endpoint or resource you\'re trying to access is either in maintenance or is not available.'],
},
discord: {
SERVER_ID: '446067825673633794',
},
};
}
}

View File

@ -1,68 +1,68 @@
import express from 'express';
import helmet from 'helmet';
import { promises as fs } from 'fs';
import { Server as HTTPServer } from 'http';
import { Collection, ServerManagement, Route } from '.';
export default class Server {
public app: express.Application;
public routes: Collection<Route>;
public parent: ServerManagement;
public port: number;
private root: string;
constructor(parent: ServerManagement, port: number, routeRoot: string) {
this.parent = parent;
this.app = express();
this.routes = new Collection<Route>();
this.port = port;
this.root = routeRoot;
this.loadRoutes();
this.init();
}
get client() {
return this.parent.client;
}
public async loadRoutes() {
const routes = Object.values<typeof Route>(require(this.root));
for (const RouteFile of routes) {
const route = new RouteFile(this);
if (route.conf.deprecated) {
route.deprecated();
} else if (route.conf.maintenance) {
route.maintenance();
} else {
route.init();
route.bind();
}
this.parent.client.util.signale.success(`Successfully loaded route 'http://localhost:${this.port}/${route.conf.path}'.`);
this.routes.add(route.conf.path, route);
this.app.use(route.conf.path, route.router);
}
this.app.listen(this.port);
}
public init() {
this.app.set('trust proxy', 'loopback');
this.app.use(helmet({
hsts: false,
hidePoweredBy: false,
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
},
},
}));
}
public listen(port: number): HTTPServer {
return this.app.listen(port);
}
}
import express from 'express';
import helmet from 'helmet';
import { promises as fs } from 'fs';
import { Server as HTTPServer } from 'http';
import { Collection, ServerManagement, Route } from '.';
export default class Server {
public app: express.Application;
public routes: Collection<Route>;
public parent: ServerManagement;
public port: number;
private root: string;
constructor(parent: ServerManagement, port: number, routeRoot: string) {
this.parent = parent;
this.app = express();
this.routes = new Collection<Route>();
this.port = port;
this.root = routeRoot;
this.loadRoutes();
this.init();
}
get client() {
return this.parent.client;
}
public async loadRoutes() {
const routes = Object.values<typeof Route>(require(this.root));
for (const RouteFile of routes) {
const route = new RouteFile(this);
if (route.conf.deprecated) {
route.deprecated();
} else if (route.conf.maintenance) {
route.maintenance();
} else {
route.init();
route.bind();
}
this.parent.client.util.signale.success(`Successfully loaded route 'http://localhost:${this.port}/${route.conf.path}'.`);
this.routes.add(route.conf.path, route);
this.app.use(route.conf.path, route.router);
}
this.app.listen(this.port);
}
public init() {
this.app.set('trust proxy', 'loopback');
this.app.use(helmet({
hsts: false,
hidePoweredBy: false,
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
},
},
}));
}
public listen(port: number): HTTPServer {
return this.app.listen(port);
}
}

View File

@ -1,22 +1,22 @@
import { Client, Collection, Server } from '.';
import serverSetup from '../api';
export default class ServerManagement {
public client: Client;
public servers: Collection<Server>;
constructor(client: Client) {
this.client = client;
this.servers = new Collection<Server>();
this.loadServers();
}
public async loadServers() {
const apiRoot = Object.entries<(management: ServerManagement) => Server>(serverSetup);
for (const [api, server] of apiRoot) {
this.servers.add(api, server(this));
this.client.util.signale.success(`Successfully loaded server '${api}'.`);
}
}
}
import { Client, Collection, Server } from '.';
import serverSetup from '../api';
export default class ServerManagement {
public client: Client;
public servers: Collection<Server>;
constructor(client: Client) {
this.client = client;
this.servers = new Collection<Server>();
this.loadServers();
}
public async loadServers() {
const apiRoot = Object.entries<(management: ServerManagement) => Server>(serverSetup);
for (const [api, server] of apiRoot) {
this.servers.add(api, server(this));
this.client.util.signale.success(`Successfully loaded server '${api}'.`);
}
}
}

View File

@ -1,138 +1,138 @@
/* eslint-disable no-bitwise */
import nodemailer from 'nodemailer';
import signale from 'signale';
import { Member, Message, Guild, PrivateChannel, GroupChannel, Role, AnyGuildChannel } from 'eris';
import { Client, Command, Moderation, RichEmbed } from '.';
import { statusMessages as emotes } from '../configs/emotes.json';
export default class Util {
public client: Client;
public moderation: Moderation;
public signale: signale.Signale;
public transporter: nodemailer.Transporter;
constructor(client: Client) {
this.client = client;
this.moderation = new Moderation(this.client);
this.signale = signale;
this.signale.config({
displayDate: true,
displayTimestamp: true,
displayFilename: true,
});
this.transporter = nodemailer.createTransport({
host: 'staff.libraryofcode.org',
port: 587,
auth: { user: 'internal', pass: this.client.config.emailPass },
});
}
get emojis() {
return {
SUCCESS: emotes.success,
LOADING: emotes.loading,
ERROR: emotes.error,
};
}
/**
* Resolves a command
* @param query Command input
* @param message Only used to check for errors
*/
public resolveCommand(query: string | string[]): Promise<{cmd: Command, args: string[] }> {
try {
if (typeof query === 'string') query = query.split(' ');
const commands = this.client.commands.toArray();
const resolvedCommand = commands.find((c) => c.name === query[0].toLowerCase() || c.aliases.includes(query[0].toLowerCase()));
if (!resolvedCommand) return Promise.resolve(null);
query.shift();
return Promise.resolve({ cmd: resolvedCommand, args: query });
} catch (error) {
return Promise.reject(error);
}
}
public resolveGuildChannel(query: string, { channels }: Guild, categories = false): AnyGuildChannel | undefined {
const ch: AnyGuildChannel[] = channels.filter((c) => (!categories ? c.type !== 4 : true));
return ch.find((c) => c.id === query.replace(/[<#>]/g, '') || c.name === query)
|| ch.find((c) => c.name.toLowerCase() === query.toLowerCase())
|| ch.find((c) => c.name.toLowerCase().startsWith(query.toLowerCase()));
}
public resolveRole(query: string, { roles }: Guild): Role | undefined {
return roles.find((r) => r.id === query.replace(/[<@&>]/g, '') || r.name === query)
|| roles.find((r) => r.name.toLowerCase() === query.toLowerCase())
|| roles.find((r) => r.name.toLowerCase().startsWith(query.toLowerCase()));
}
public resolveMember(query: string, { members }: Guild): Member | undefined {
return members.find((m) => `${m.username}#${m.discriminator}` === query || m.username === query || m.id === query.replace(/[<@!>]/g, '') || m.nick === query) // Exact match for mention, username+discrim, username and user ID
|| members.find((m) => `${m.username.toLowerCase()}#${m.discriminator}` === query.toLowerCase() || m.username.toLowerCase() === query.toLowerCase() || (m.nick && m.nick.toLowerCase() === query.toLowerCase())) // Case insensitive match for username+discrim, username
|| members.find((m) => m.username.toLowerCase().startsWith(query.toLowerCase()) || (m.nick && m.nick.toLowerCase().startsWith(query.toLowerCase())));
}
public async handleError(error: Error, message?: Message, command?: Command, disable = true): Promise<void> {
try {
this.signale.error(error);
const info = { content: `\`\`\`js\n${error.stack || error}\n\`\`\``, embed: null };
if (message) {
const embed = new RichEmbed();
embed.setColor('FF0000');
embed.setAuthor(`Error caused by ${message.author.username}#${message.author.discriminator}`, message.author.avatarURL);
embed.setTitle('Message content');
embed.setDescription(message.content);
embed.addField('User', `${message.author.mention} (\`${message.author.id}\`)`, true);
embed.addField('Channel', message.channel.mention, true);
let guild: string;
if (message.channel instanceof PrivateChannel || message.channel instanceof GroupChannel) guild = '@me';
else guild = message.channel.guild.id;
embed.addField('Message link', `[Click here](https://discordapp.com/channels/${guild}/${message.channel.id}/${message.id})`, true);
embed.setTimestamp(new Date(message.timestamp));
info.embed = embed;
}
await this.client.createMessage('595788220764127272', info);
const msg = message ? message.content.slice(this.client.config.prefix.length).trim().split(/ +/g) : [];
if (command && disable) this.resolveCommand(msg).then((c) => { c.cmd.enabled = false; });
if (message) message.channel.createMessage(`***${this.emojis.ERROR} An unexpected error has occured - please contact a Staff member.${command && disable ? ' This command has been disabled.' : ''}***`);
} catch (err) {
this.signale.error(err);
}
}
public splitString(string: string, length: number): string[] {
if (!string) return [];
if (Array.isArray(string)) string = string.join('\n');
if (string.length <= length) return [string];
const arrayString: string[] = [];
let str: string = '';
let pos: number;
while (string.length > 0) {
pos = string.length > length ? string.lastIndexOf('\n', length) : string.length;
if (pos > length) pos = length;
str = string.substr(0, pos);
string = string.substr(pos);
arrayString.push(str);
}
return arrayString;
}
public splitFields(fields: { name: string, value: string, inline?: boolean }[]): { name: string, value: string, inline?: boolean }[][] {
let index = 0;
const array: {name: string, value: string, inline?: boolean}[][] = [[]];
while (fields.length) {
if (array[index].length >= 25) { index += 1; array[index] = []; }
array[index].push(fields[0]); fields.shift();
}
return array;
}
public decimalToHex(int: number): string {
const hex = int.toString(16);
return '#000000'.substring(0, 7 - hex.length) + hex;
}
}
/* eslint-disable no-bitwise */
import nodemailer from 'nodemailer';
import signale from 'signale';
import { Member, Message, Guild, PrivateChannel, GroupChannel, Role, AnyGuildChannel } from 'eris';
import { Client, Command, Moderation, RichEmbed } from '.';
import { statusMessages as emotes } from '../configs/emotes.json';
export default class Util {
public client: Client;
public moderation: Moderation;
public signale: signale.Signale;
public transporter: nodemailer.Transporter;
constructor(client: Client) {
this.client = client;
this.moderation = new Moderation(this.client);
this.signale = signale;
this.signale.config({
displayDate: true,
displayTimestamp: true,
displayFilename: true,
});
this.transporter = nodemailer.createTransport({
host: 'staff.libraryofcode.org',
port: 587,
auth: { user: 'internal', pass: this.client.config.emailPass },
});
}
get emojis() {
return {
SUCCESS: emotes.success,
LOADING: emotes.loading,
ERROR: emotes.error,
};
}
/**
* Resolves a command
* @param query Command input
* @param message Only used to check for errors
*/
public resolveCommand(query: string | string[]): Promise<{cmd: Command, args: string[] }> {
try {
if (typeof query === 'string') query = query.split(' ');
const commands = this.client.commands.toArray();
const resolvedCommand = commands.find((c) => c.name === query[0].toLowerCase() || c.aliases.includes(query[0].toLowerCase()));
if (!resolvedCommand) return Promise.resolve(null);
query.shift();
return Promise.resolve({ cmd: resolvedCommand, args: query });
} catch (error) {
return Promise.reject(error);
}
}
public resolveGuildChannel(query: string, { channels }: Guild, categories = false): AnyGuildChannel | undefined {
const ch: AnyGuildChannel[] = channels.filter((c) => (!categories ? c.type !== 4 : true));
return ch.find((c) => c.id === query.replace(/[<#>]/g, '') || c.name === query)
|| ch.find((c) => c.name.toLowerCase() === query.toLowerCase())
|| ch.find((c) => c.name.toLowerCase().startsWith(query.toLowerCase()));
}
public resolveRole(query: string, { roles }: Guild): Role | undefined {
return roles.find((r) => r.id === query.replace(/[<@&>]/g, '') || r.name === query)
|| roles.find((r) => r.name.toLowerCase() === query.toLowerCase())
|| roles.find((r) => r.name.toLowerCase().startsWith(query.toLowerCase()));
}
public resolveMember(query: string, { members }: Guild): Member | undefined {
return members.find((m) => `${m.username}#${m.discriminator}` === query || m.username === query || m.id === query.replace(/[<@!>]/g, '') || m.nick === query) // Exact match for mention, username+discrim, username and user ID
|| members.find((m) => `${m.username.toLowerCase()}#${m.discriminator}` === query.toLowerCase() || m.username.toLowerCase() === query.toLowerCase() || (m.nick && m.nick.toLowerCase() === query.toLowerCase())) // Case insensitive match for username+discrim, username
|| members.find((m) => m.username.toLowerCase().startsWith(query.toLowerCase()) || (m.nick && m.nick.toLowerCase().startsWith(query.toLowerCase())));
}
public async handleError(error: Error, message?: Message, command?: Command, disable = true): Promise<void> {
try {
this.signale.error(error);
const info = { content: `\`\`\`js\n${error.stack || error}\n\`\`\``, embed: null };
if (message) {
const embed = new RichEmbed();
embed.setColor('FF0000');
embed.setAuthor(`Error caused by ${message.author.username}#${message.author.discriminator}`, message.author.avatarURL);
embed.setTitle('Message content');
embed.setDescription(message.content);
embed.addField('User', `${message.author.mention} (\`${message.author.id}\`)`, true);
embed.addField('Channel', message.channel.mention, true);
let guild: string;
if (message.channel instanceof PrivateChannel || message.channel instanceof GroupChannel) guild = '@me';
else guild = message.channel.guild.id;
embed.addField('Message link', `[Click here](https://discordapp.com/channels/${guild}/${message.channel.id}/${message.id})`, true);
embed.setTimestamp(new Date(message.timestamp));
info.embed = embed;
}
await this.client.createMessage('595788220764127272', info);
const msg = message ? message.content.slice(this.client.config.prefix.length).trim().split(/ +/g) : [];
if (command && disable) this.resolveCommand(msg).then((c) => { c.cmd.enabled = false; });
if (message) message.channel.createMessage(`***${this.emojis.ERROR} An unexpected error has occured - please contact a Staff member.${command && disable ? ' This command has been disabled.' : ''}***`);
} catch (err) {
this.signale.error(err);
}
}
public splitString(string: string, length: number): string[] {
if (!string) return [];
if (Array.isArray(string)) string = string.join('\n');
if (string.length <= length) return [string];
const arrayString: string[] = [];
let str: string = '';
let pos: number;
while (string.length > 0) {
pos = string.length > length ? string.lastIndexOf('\n', length) : string.length;
if (pos > length) pos = length;
str = string.substr(0, pos);
string = string.substr(pos);
arrayString.push(str);
}
return arrayString;
}
public splitFields(fields: { name: string, value: string, inline?: boolean }[]): { name: string, value: string, inline?: boolean }[][] {
let index = 0;
const array: {name: string, value: string, inline?: boolean}[][] = [[]];
while (fields.length) {
if (array[index].length >= 25) { index += 1; array[index] = []; }
array[index].push(fields[0]); fields.shift();
}
return array;
}
public decimalToHex(int: number): string {
const hex = int.toString(16);
return '#000000'.substring(0, 7 - hex.length) + hex;
}
}

View File

@ -1,10 +1,10 @@
export { default as Client } from './Client';
export { default as Collection } from './Collection';
export { default as Command } from './Command';
export { default as Event } from './Event';
export { default as Moderation } from './Moderation';
export { default as RichEmbed } from './RichEmbed';
export { default as Route } from './Route';
export { default as Server } from './Server';
export { default as ServerManagement } from './ServerManagement';
export { default as Util } from './Util';
export { default as Client } from './Client';
export { default as Collection } from './Collection';
export { default as Command } from './Command';
export { default as Event } from './Event';
export { default as Moderation } from './Moderation';
export { default as RichEmbed } from './RichEmbed';
export { default as Route } from './Route';
export { default as Server } from './Server';
export { default as ServerManagement } from './ServerManagement';
export { default as Util } from './Util';

45
src/commands/addrank.ts Normal file
View File

@ -0,0 +1,45 @@
import { Message } from 'eris';
import { Client, Command } from '../class';
export default class AddRank extends Command {
constructor(client: Client) {
super(client);
this.name = 'addrank';
this.description = 'Makes a role self-assignable.';
this.usage = `${this.client.config.prefix}addrank <role> <permissions, pass 0 for everyone. separate role IDs with ':'> <description>`;
this.permissions = 6;
this.guildOnly = true;
this.enabled = true;
}
public async run(message: Message, args: string[]) {
try {
if (!args[0]) return this.client.commands.get('help').run(message, [this.name]);
if (!args[1]) return this.error(message.channel, 'Permissions are required.');
if (!args[2]) return this.error(message.channel, 'A description is required');
const role = this.client.util.resolveRole(args[0], this.client.guilds.get(this.client.config.guildID));
if (!role) return this.error(message.channel, 'The role you specified doesn\'t appear to exist.');
const check = await this.client.db.Rank.findOne({ roleID: role.id });
if (check) return this.error(message.channel, 'This role is already self-assignable.');
let permissions: string[];
if (args[1] === '0') {
permissions = ['0'];
} else {
permissions = args[1].split(':');
}
const entry = new this.client.db.Rank({
name: role.name,
roleID: role.id,
permissions,
description: args.slice(2).join(' '),
});
await entry.save();
return this.success(message.channel, `Role ${role.name} is now self-assignable.`);
} catch (err) {
return this.client.util.handleError(err, message, this);
}
}
}

30
src/commands/delrank.ts Normal file
View File

@ -0,0 +1,30 @@
import { Message } from 'eris';
import { Client, Command } from '../class';
export default class DelRank extends Command {
constructor(client: Client) {
super(client);
this.name = 'delrank';
this.description = 'Deletes an existing self-assignable role. This doesn\'t delete the role itself.';
this.usage = `${this.client.config.prefix}delrank <role>`;
this.permissions = 6;
this.guildOnly = true;
this.enabled = true;
}
public async run(message: Message, args: string[]) {
try {
if (!args[0]) return this.client.commands.get('help').run(message, [this.name]);
const role = this.client.util.resolveRole(args[0], this.client.guilds.get(this.client.config.guildID));
if (!role) return this.error(message.channel, 'The role you specified doesn\'t appear to exist.');
const check = await this.client.db.Rank.findOne({ roleID: role.id });
if (!check) return this.error(message.channel, 'The entry doesn\'t appear to exist.');
await this.client.db.Rank.deleteOne({ roleID: role.id });
return this.success(message.channel, `Role ${role.name} is no longer self-assignable.`);
} catch (err) {
return this.client.util.handleError(err, message, this);
}
}
}

View File

@ -1,7 +1,9 @@
export { default as additem } from './additem';
export { default as addrank } from './addrank';
export { default as addredirect } from './addredirect';
export { default as ban } from './ban';
export { default as delitem } from './delitem';
export { default as delrank } from './delrank';
export { default as delredirect } from './delredirect';
export { default as djs } from './djs';
export { default as eval } from './eval';
@ -13,6 +15,7 @@ export { default as listredirects } from './listredirects';
export { default as npm } from './npm';
export { default as page } from './page';
export { default as ping } from './ping';
export { default as rank } from './rank';
export { default as roleinfo } from './roleinfo';
export { default as unban } from './unban';
export { default as whois } from './whois';

62
src/commands/rank.ts Normal file
View File

@ -0,0 +1,62 @@
import { Message, Role } from 'eris';
import { Client, Command, RichEmbed } from '../class';
export default class Rank extends Command {
constructor(client: Client) {
super(client);
this.name = 'rank';
this.description = 'Joins/leaves a self-assignable rank. Run this command without arguments to get a list of self-assignable roles.';
this.usage = `${this.client.config.prefix}rank <rank>`;
this.permissions = 0;
this.guildOnly = true;
this.enabled = true;
}
public async run(message: Message, args: string[]) {
try {
if (!args[0]) {
const roles = await this.client.db.Rank.find();
const embed = new RichEmbed();
embed.setTitle('Ranks');
embed.setDescription(`Use \`${this.client.config.prefix}rank <rank name> to join/leave the rank.\``);
for (const rank of roles.sort((a, b) => a.name.localeCompare(b.name))) {
let perms: string;
if (rank.permissions.includes('0')) {
perms = 'Everyone';
} else {
const rolesArray: Role[] = [];
rank.permissions.forEach((r) => {
rolesArray.push(this.client.guilds.get(this.client.config.guildID).roles.get(r));
});
perms = rolesArray.map((r) => message.guild.roles.get(r.id)).sort((a, b) => b.position - a.position).map((r) => `<@&${r.id}>`).join(', ');
}
embed.addField(rank.name, `__Description:__ ${rank.description}\n__Permissions:__ ${perms}`);
}
embed.setFooter(this.client.user.username, this.client.user.avatarURL);
embed.setTimestamp();
return message.channel.createMessage({ embed });
}
const role = this.client.util.resolveRole(args[0], this.client.guilds.get(this.client.config.guildID));
if (!role) return this.error(message.channel, 'The role you specified doesn\'t exist.');
const entry = await this.client.db.Rank.findOne({ roleID: role.id }).lean().exec();
if (!entry) return this.error(message.channel, 'The rank you specified doesn\'t exist.');
if (!message.member.roles.includes(entry.roleID)) {
let permCheck: boolean;
if (entry.permissions.includes('0')) {
permCheck = true;
} else {
permCheck = entry.permissions.some((item) => message.member.roles.includes(item));
}
if (!permCheck) return this.error(message.channel, 'Permission denied.');
await message.member.addRole(entry.roleID, `User ${message.author.username}#${message.author.discriminator} self-assigned this role.`);
this.success(message.channel, `You have self-assigned ${entry.name}.`);
} else if (message.member.roles.includes(entry.roleID)) {
await message.member.removeRole(entry.roleID, `User ${message.author.username}#${message.author.discriminator} has removed a self-assignable role.`);
this.success(message.channel, `You have removed ${entry.name}.`);
}
return null;
} catch (err) {
return this.client.util.handleError(err, message, this);
}
}
}

View File

@ -1,142 +1,142 @@
[
{
"name": "Matthew",
"id": "278620217221971968",
"title": "Chief Director of Engineering",
"dept": "Board of Directors",
"emailAddress": "matthew@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/matthew",
"github": "https://github.com/matthew119427",
"bio": "so baby come light me up, and maybe ill let you on it. a little bit dangerous, but baby thats how i want it. a little less conversation and a little more touch my body. cuz im so into you... ~ Ariana Grande, Into You - Dangerous Woman",
"acknowledgements": ["Maintainer & Lead Developer"]
},
{
"name": "Joe",
"id": "556969659531001858",
"dept": "Board of Directors",
"emailAddress": "joe@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/Joe",
"github": "https://github.com/sirdroolio",
"bio": "new Error(\"Proper Bio not found\");",
"acknowledgements": ["Developer"]
},
{
"name": "Bsian",
"id": "253600545972027394",
"title": "Director of Engineering",
"dept": "Board of Directors",
"emailAddress": "bsian@staff.libraryofcode.org",
"bio": "I also like trains",
"acknowledgements": ["Maintainer & Assistant Lead Developer"]
},
{
"name": "NightRaven",
"id": "239261547959025665",
"title": "Director of Information Security",
"dept": "Board of Directors",
"emailAddress": "nightraven@staff.libraryofcode.org",
"bio": "I like trains"
},
{
"name": "Unknown",
"id": "143414786913206272",
"title": "Director of Operations",
"dept": "Board of Directors",
"emailAddress": "unknown@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/unknown",
"bio": "im not a proffesional developer or anything, i just enjoy it as a hobby."
},
{
"name": "TheSkele27",
"id": "213632190557192192",
"title": "Director of Community Engagement",
"dept": "Board of Directors",
"emailAddress": "theskele27@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/TheSkele27",
"github": "https://github.com/TheSkele27",
"bio": "Is water wet?"
},
{
"name": "Catbirby",
"id": "131953641371205632",
"dept": "Supervisor",
"emailAddress": "catbirby@staff.libraryofcode.org",
"github": "https://github.com/catbirby",
"bio": "Computer Tech/Networking Nerd/Sysadmin/Graphic Designer/Audiophile. I don't do much coding but know my way around most languages."
},
{
"name": "D3XTER",
"id": "468009964263178262",
"dept": "Core Team",
"emailAddress": "dexter@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/D3XTER",
"bio": "Hi I'm D3XTER how are ya?"
},
{
"name": "DedShotTM",
"id": "402154763363418142",
"dept": "Technician & Moderator",
"emailAddress": "dedshot@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/DedShotTM",
"github": "https://github.com/DedShotTM",
"bio": "Imagine having a bio",
"acknowledgements": ["Contributor"]
},
{
"name": "EdgyBoi2414",
"id": "397432516010835970",
"dept": "Core Team",
"emailAddress": "edgyboi2414@gmail.com",
"gitlab": "https://gitlab.libraryofcode.org/EdgyBoi2414",
"github": "https://github.com/EdgyBoi2414",
"bio": "\"If teardrops could be bottled, there'd be swimming pools, built by models...\" - Some Philosopher"
},
{
"name": "Hector",
"id": "377781496292835339",
"dept": "Core Team",
"emailAddress": "hector@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/Hector",
"github": "https://github.com/Hector6704",
"bio": "Hi there, I'm the developer of Delta, the Discord bot. I'm a free-time French JavaScript developer. I hope you'll enjoy LOC!"
},
{
"name": "KhaaZ",
"id": "179908288337412096",
"dept": "Core Team",
"emailAddress": "khaaz@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/KhaaZ",
"github": "https://github.com/Khaazz",
"bio": "I baguette for a living and eat code for breakfast."
},
{
"name": "Ryan",
"id": "186679073764802560",
"dept": "Associate",
"emailAddress": "wbdvryan@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/plainRyan",
"bio": "Experiment, learn, share, repeat.",
"acknowledgements": ["Contributor"]
},
{
"name": "Zloth",
"id": "382368885267234816",
"dept": "Associate",
"emailAddress": "zloth@staff.libraryofcode.org",
"github": "https://github.com/gavintjhxx",
"bio": "Wake up. Eat. Code. Sleep. Loop()"
},
{
"name": "PlayerVMachine",
"id": "273999507174195203",
"dept": "Instructor & Associate",
"emailAddress": "nicolas@staff.libraryofcode.org",
"bio": "I write C++ to pay off my student loans"
},
{
"name": "Null",
"id": "323673862971588609",
"gitlab": "https://gitlab.libraryofcode.org/null",
"acknowledgements": ["Contributor"]
}
]
[
{
"name": "Matthew",
"id": "278620217221971968",
"title": "Chief Director of Engineering",
"dept": "Board of Directors",
"emailAddress": "matthew@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/matthew",
"github": "https://github.com/matthew119427",
"bio": "so baby come light me up, and maybe ill let you on it. a little bit dangerous, but baby thats how i want it. a little less conversation and a little more touch my body. cuz im so into you... ~ Ariana Grande, Into You - Dangerous Woman",
"acknowledgements": ["Maintainer & Lead Developer"]
},
{
"name": "Joe",
"id": "556969659531001858",
"dept": "Board of Directors",
"emailAddress": "joe@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/Joe",
"github": "https://github.com/sirdroolio",
"bio": "new Error(\"Proper Bio not found\");",
"acknowledgements": ["Developer"]
},
{
"name": "Bsian",
"id": "253600545972027394",
"title": "Director of Engineering",
"dept": "Board of Directors",
"emailAddress": "bsian@staff.libraryofcode.org",
"bio": "I also like trains",
"acknowledgements": ["Maintainer & Assistant Lead Developer"]
},
{
"name": "NightRaven",
"id": "239261547959025665",
"title": "Director of Information Security",
"dept": "Board of Directors",
"emailAddress": "nightraven@staff.libraryofcode.org",
"bio": "I like trains"
},
{
"name": "Unknown",
"id": "143414786913206272",
"title": "Director of Operations",
"dept": "Board of Directors",
"emailAddress": "unknown@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/unknown",
"bio": "im not a proffesional developer or anything, i just enjoy it as a hobby."
},
{
"name": "TheSkele27",
"id": "213632190557192192",
"title": "Director of Community Engagement",
"dept": "Board of Directors",
"emailAddress": "theskele27@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/TheSkele27",
"github": "https://github.com/TheSkele27",
"bio": "Is water wet?"
},
{
"name": "Catbirby",
"id": "131953641371205632",
"dept": "Supervisor",
"emailAddress": "catbirby@staff.libraryofcode.org",
"github": "https://github.com/catbirby",
"bio": "Computer Tech/Networking Nerd/Sysadmin/Graphic Designer/Audiophile. I don't do much coding but know my way around most languages."
},
{
"name": "D3XTER",
"id": "468009964263178262",
"dept": "Core Team",
"emailAddress": "dexter@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/D3XTER",
"bio": "Hi I'm D3XTER how are ya?"
},
{
"name": "DedShotTM",
"id": "402154763363418142",
"dept": "Technician & Moderator",
"emailAddress": "dedshot@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/DedShotTM",
"github": "https://github.com/DedShotTM",
"bio": "Imagine having a bio",
"acknowledgements": ["Contributor"]
},
{
"name": "EdgyBoi2414",
"id": "397432516010835970",
"dept": "Core Team",
"emailAddress": "edgyboi2414@gmail.com",
"gitlab": "https://gitlab.libraryofcode.org/EdgyBoi2414",
"github": "https://github.com/EdgyBoi2414",
"bio": "\"If teardrops could be bottled, there'd be swimming pools, built by models...\" - Some Philosopher"
},
{
"name": "Hector",
"id": "377781496292835339",
"dept": "Core Team",
"emailAddress": "hector@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/Hector",
"github": "https://github.com/Hector6704",
"bio": "Hi there, I'm the developer of Delta, the Discord bot. I'm a free-time French JavaScript developer. I hope you'll enjoy LOC!"
},
{
"name": "KhaaZ",
"id": "179908288337412096",
"dept": "Core Team",
"emailAddress": "khaaz@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/KhaaZ",
"github": "https://github.com/Khaazz",
"bio": "I baguette for a living and eat code for breakfast."
},
{
"name": "Ryan",
"id": "186679073764802560",
"dept": "Associate",
"emailAddress": "wbdvryan@staff.libraryofcode.org",
"gitlab": "https://gitlab.libraryofcode.org/plainRyan",
"bio": "Experiment, learn, share, repeat.",
"acknowledgements": ["Contributor"]
},
{
"name": "Zloth",
"id": "382368885267234816",
"dept": "Associate",
"emailAddress": "zloth@staff.libraryofcode.org",
"github": "https://github.com/gavintjhxx",
"bio": "Wake up. Eat. Code. Sleep. Loop()"
},
{
"name": "PlayerVMachine",
"id": "273999507174195203",
"dept": "Instructor & Associate",
"emailAddress": "nicolas@staff.libraryofcode.org",
"bio": "I write C++ to pay off my student loans"
},
{
"name": "Null",
"id": "323673862971588609",
"gitlab": "https://gitlab.libraryofcode.org/null",
"acknowledgements": ["Contributor"]
}
]

View File

@ -1,6 +1,6 @@
{
"moderation": {
"modlogs": "446080867065135115",
"automod": ""
}
}
{
"moderation": {
"modlogs": "446080867065135115",
"automod": ""
}
}

View File

@ -1,14 +1,14 @@
{
"whois": {
"titleAndDepartment": "<:loc:607695848612167700>",
"email": "<:email:699786452267040878>",
"gitlab": "<:gitlab:699788655748841492>",
"github": "<:github:699786469404835939>",
"bio": "<:bio:699786408193294416>"
},
"statusMessages": {
"success": "<:modSuccess:578750988907970567>",
"loading": "<a:modloading:588607353935364106>",
"error": "<:modError:578750737920688128>"
}
}
{
"whois": {
"titleAndDepartment": "<:loc:607695848612167700>",
"email": "<:email:699786452267040878>",
"gitlab": "<:gitlab:699788655748841492>",
"github": "<:github:699786469404835939>",
"bio": "<:bio:699786408193294416>"
},
"statusMessages": {
"success": "<:modSuccess:578750988907970567>",
"loading": "<a:modloading:588607353935364106>",
"error": "<:modError:578750737920688128>"
}
}

View File

@ -1,32 +1,32 @@
/* eslint-disable no-useless-return */
import { Message, TextChannel, NewsChannel } from 'eris';
import { Client, Event } from '../class';
export default class CommandHandler extends Event {
public client: Client;
constructor(client: Client) {
super(client);
this.event = 'messageCreate';
}
public async run(message: Message) {
try {
if (message.author.bot) return;
if (message.content.indexOf(this.client.config.prefix) !== 0) return;
const noPrefix: string[] = message.content.slice(this.client.config.prefix.length).trim().split(/ +/g);
const resolved = await this.client.util.resolveCommand(noPrefix);
if (!resolved) return;
if (resolved.cmd.guildOnly && !(message.channel instanceof TextChannel || message.channel instanceof NewsChannel)) return;
if (!resolved.cmd.enabled) { message.channel.createMessage(`***${this.client.util.emojis.ERROR} This command has been disabled***`); return; }
if (!resolved.cmd.checkPermissions(message.member)) return;
if ((message.channel.type === 0) && !message.channel.guild.members.get(message.author.id)) {
message.channel.guild.members.add(await message.channel.guild.getRESTMember(message.author.id));
}
this.client.util.signale.log(`User '${message.author.username}#${message.author.discriminator}' ran command '${resolved.cmd.name}' in '${message.channel.id}'.`);
await resolved.cmd.run(message, resolved.args);
} catch (err) {
this.client.util.handleError(err, message);
}
}
}
/* eslint-disable no-useless-return */
import { Message, TextChannel, NewsChannel } from 'eris';
import { Client, Event } from '../class';
export default class CommandHandler extends Event {
public client: Client;
constructor(client: Client) {
super(client);
this.event = 'messageCreate';
}
public async run(message: Message) {
try {
if (message.author.bot) return;
if (message.content.indexOf(this.client.config.prefix) !== 0) return;
const noPrefix: string[] = message.content.slice(this.client.config.prefix.length).trim().split(/ +/g);
const resolved = await this.client.util.resolveCommand(noPrefix);
if (!resolved) return;
if (resolved.cmd.guildOnly && !(message.channel instanceof TextChannel || message.channel instanceof NewsChannel)) return;
if (!resolved.cmd.enabled) { message.channel.createMessage(`***${this.client.util.emojis.ERROR} This command has been disabled***`); return; }
if (!resolved.cmd.checkPermissions(message.member)) return;
if ((message.channel.type === 0) && !message.channel.guild.members.get(message.author.id)) {
message.channel.guild.members.add(await message.channel.guild.getRESTMember(message.author.id));
}
this.client.util.signale.log(`User '${message.author.username}#${message.author.discriminator}' ran command '${resolved.cmd.name}' in '${message.channel.id}'.`);
await resolved.cmd.run(message, resolved.args);
} catch (err) {
this.client.util.handleError(err, message);
}
}
}

View File

@ -1,2 +1,2 @@
export { default as CommandHandler } from './CommandHandler';
export { default as ready } from './ready';
export { default as CommandHandler } from './CommandHandler';
export { default as ready } from './ready';

View File

@ -1,24 +1,24 @@
import { Client, Event } from '../class';
export default class Ready extends Event {
public client: Client;
constructor(client: Client) {
super(client);
this.event = 'ready';
}
public async run() {
this.client.util.signale.start(`${this.client.user.username} is now ready!\nServers: ${this.client.guilds.size}\nUsers: ${this.client.users.size}\n\nhttps://gitlab.libraryofcode.org/engineering/communityrelations`);
this.client.on('error', (err) => {
this.client.util.handleError(err);
});
process.on('uncaughtException', (err) => {
this.client.util.handleError(err);
process.exit(1);
});
process.on('unhandledRejection', (err: Error) => {
this.client.util.handleError(err);
});
}
}
import { Client, Event } from '../class';
export default class Ready extends Event {
public client: Client;
constructor(client: Client) {
super(client);
this.event = 'ready';
}
public async run() {
this.client.util.signale.start(`${this.client.user.username} is now ready!\nServers: ${this.client.guilds.size}\nUsers: ${this.client.users.size}\n\nhttps://gitlab.libraryofcode.org/engineering/communityrelations`);
this.client.on('error', (err) => {
this.client.util.handleError(err);
});
process.on('uncaughtException', (err) => {
this.client.util.handleError(err);
process.exit(1);
});
process.on('unhandledRejection', (err: Error) => {
this.client.util.handleError(err);
});
}
}

View File

@ -1,24 +1,24 @@
import { Client } from '../class';
let interval: NodeJS.Timeout;
export default function checkLock(client: Client): NodeJS.Timeout {
interval = setInterval(async () => {
try {
const moderations = await client.db.Moderation.find();
moderations.forEach(async (moderation) => {
if (!moderation.expiration) return;
if (moderation.expiration.processed) return;
if (new Date() > moderation.expiration.date) {
await moderation.updateOne({ 'expiration.processed': true });
const moderator = client.guilds.get(client.config.guildID).members.get(moderation.moderatorID);
await client.util.moderation.unban(moderation.userID, moderator);
client.util.signale.complete(`Released member ${moderation.userID} | Queue date at ${moderation.expiration.date.toLocaleString('en-us')}`);
}
});
} catch (error) {
await client.util.handleError(error);
}
}, 10000);
return interval;
}
import { Client } from '../class';
let interval: NodeJS.Timeout;
export default function checkLock(client: Client): NodeJS.Timeout {
interval = setInterval(async () => {
try {
const moderations = await client.db.Moderation.find();
moderations.forEach(async (moderation) => {
if (!moderation.expiration) return;
if (moderation.expiration.processed) return;
if (new Date() > moderation.expiration.date) {
await moderation.updateOne({ 'expiration.processed': true });
const moderator = client.guilds.get(client.config.guildID).members.get(moderation.moderatorID);
await client.util.moderation.unban(moderation.userID, moderator);
client.util.signale.complete(`Released member ${moderation.userID} | Queue date at ${moderation.expiration.date.toLocaleString('en-us')}`);
}
});
} catch (error) {
await client.util.handleError(error);
}
}, 10000);
return interval;
}

View File

@ -1,358 +1,358 @@
/* eslint-disable no-continue */
/* eslint-disable no-await-in-loop */
import { Member, TextableChannel } from 'eris';
import { Client } from '../class';
let interval: NodeJS.Timeout;
async function setupDepartmentCodes(client: Client): Promise<void> {
const directorPagers = await client.db.PagerNumber.findOne({ num: '00' }).lean().exec();
const supervisorPagers = await client.db.PagerNumber.findOne({ num: '01' }).lean().exec();
const technicianPagers = await client.db.PagerNumber.findOne({ num: '10' }).lean().exec();
const moderatorPagers = await client.db.PagerNumber.findOne({ num: '20' }).lean().exec();
const coreTeamPagers = await client.db.PagerNumber.findOne({ num: '21' }).lean().exec();
const associatePagers = await client.db.PagerNumber.findOne({ num: '22' }).lean().exec();
if (!directorPagers) {
const setup = new client.db.PagerNumber({
num: '00',
individualAssignID: '',
emailAddresses: [],
discordIDs: [],
});
await setup.save();
}
if (!supervisorPagers) {
const setup = new client.db.PagerNumber({
num: '01',
individualAssignID: '',
emailAddresses: [],
discordIDs: [],
});
await setup.save();
}
if (!technicianPagers) {
const setup = new client.db.PagerNumber({
num: '10',
individualAssignID: '',
emailAddresses: [],
discordIDs: [],
});
setup.save();
}
if (!moderatorPagers) {
const setup = new client.db.PagerNumber({
num: '20',
individualAssignID: '',
emailAddresses: [],
discordIDs: [],
});
await setup.save();
}
if (!coreTeamPagers) {
const setup = new client.db.PagerNumber({
num: '21',
individualAssignID: '',
emailAddresses: [],
discordIDs: [],
});
await setup.save();
}
if (!associatePagers) {
const setup = new client.db.PagerNumber({
num: '22',
individualAssignID: '',
emailAddresses: [],
discordIDs: [],
});
await setup.save();
}
}
function logNewPager(client: Client, num: string, member: Member): void {
const channel = <TextableChannel> client.guilds.get(client.config.guildID).channels.get('722636436716781619');
channel.createMessage(`__**'${member.user.username}#${member.user.discriminator}' assigned to pager number '${num}'.**__`);
}
export default function departmentPager(client: Client): NodeJS.Timeout {
setupDepartmentCodes(client);
interval = setInterval(async () => {
const acknowledgements = require(`${__dirname}/../configs/acknowledgements.json`);
function resolveStaffInformation(id: string) {
return acknowledgements.find((m) => m.id === id);
}
// await client.guilds.get(client.config.guildID).fetchAllMembers();
const { members } = client.guilds.get(client.config.guildID);
for (const member of members.values()) {
const pager = await client.db.PagerNumber.findOne({ individualAssignID: member.id }).lean().exec();
if (!pager) continue;
if (pager.num.startsWith('00') && !member.roles.includes('662163685439045632')) {
client.db.PagerNumber.deleteOne({ num: pager.num });
client.util.signale.log(`Pager Number '${pager.num}' has been deleted.`);
} else if (pager.num.startsWith('01') && !member.roles.includes('701454855952138300')) {
client.db.PagerNumber.deleteOne({ num: pager.num });
client.util.signale.log(`Pager Number '${pager.num}' has been deleted.`);
} else if (pager.num.startsWith('10') && !member.roles.includes('701454780828221450')) {
client.db.PagerNumber.deleteOne({ num: pager.num });
client.util.signale.log(`Pager Number '${pager.num}' has been deleted.`);
} else if (pager.num.startsWith('20') && !member.roles.includes('455972169449734144')) {
client.db.PagerNumber.deleteOne({ num: pager.num });
client.util.signale.log(`Pager Number '${pager.num}' has been deleted.`);
} else if (pager.num.startsWith('21') && !member.roles.includes('453689940140883988')) {
client.db.PagerNumber.deleteOne({ num: pager.num });
client.util.signale.log(`Pager Number '${pager.num}' has been deleted.`);
} else if (pager.num.startsWith('22') && !member.roles.includes('701481967149121627')) {
client.db.PagerNumber.deleteOne({ num: pager.num });
client.util.signale.log(`Pager Number '${pager.num}' has been deleted.`);
}
}
// const takenPagers = new Set<string>();
for (const member of members.values()) {
let pager = await client.db.PagerNumber.findOne({ individualAssignID: member.id }).lean().exec();
// Directors
if (!pager && member.roles.includes('662163685439045632')) {
let randomPagerNumber: string;
let status = true;
// eslint-disable-next-line no-constant-condition
while (status) {
randomPagerNumber = `00${String(Math.floor(Math.random() * 9) + 1)}`;
const check = await client.db.PagerNumber.findOne({ num: randomPagerNumber });
if (check) status = false;
if (check?.num !== randomPagerNumber) status = false;
}
const acknowledgement = resolveStaffInformation(member.id);
if (!acknowledgement || !acknowledgement.emailAddress) return;
const newNumber = new client.db.PagerNumber({
num: randomPagerNumber,
individualAssignID: member.id,
emailAddresses: [acknowledgement.emailAddress],
discordIDs: [member.id],
});
if (await client.db.PagerNumber.findOne({ num: randomPagerNumber })) return;
pager = await newNumber.save();
logNewPager(client, randomPagerNumber, member);
client.getDMChannel(member.id).then((chan) => {
chan.createMessage(`__**Pager Number Creation**__\nYour individual pager number has been automatically created. Your number (PN) is ${randomPagerNumber}.`);
});
} else if (!pager && member.roles.includes('701454855952138300')) {
// Supervisors
let randomPagerNumber: string;
let status = true;
// eslint-disable-next-line no-constant-condition
while (status) {
randomPagerNumber = `01${String(Math.floor(Math.random() * 9) + 1)}`;
const check = await client.db.PagerNumber.findOne({ num: randomPagerNumber });
if (check) status = false;
if (check?.num !== randomPagerNumber) status = false;
}
const acknowledgement = resolveStaffInformation(member.id);
if (!acknowledgement || !acknowledgement.emailAddress) return;
const newNumber = new client.db.PagerNumber({
num: randomPagerNumber,
individualAssignID: member.id,
emailAddresses: [acknowledgement.emailAddress],
discordIDs: [member.id],
});
if (await client.db.PagerNumber.findOne({ num: randomPagerNumber })) return;
logNewPager(client, randomPagerNumber, member);
pager = await newNumber.save();
client.getDMChannel(member.id).then((chan) => {
chan.createMessage(`__**Pager Number Creation**__\nYour individual pager number has been automatically created. Your number (PN) is ${randomPagerNumber}.`);
});
} else if (!pager && member.roles.includes('701454780828221450')) {
// Technicians
let randomPagerNumber: string;
let status = true;
// eslint-disable-next-line no-constant-condition
while (status) {
randomPagerNumber = `10${String(Math.floor(Math.random() * 99) + 1)}`;
if (randomPagerNumber.length === 3) randomPagerNumber = `${randomPagerNumber}0`;
const check = await client.db.PagerNumber.findOne({ num: randomPagerNumber });
if (check) status = false;
if (check?.num !== randomPagerNumber) status = false;
}
const acknowledgement = resolveStaffInformation(member.id);
if (!acknowledgement || !acknowledgement.emailAddress) return;
const newNumber = new client.db.PagerNumber({
num: randomPagerNumber,
individualAssignID: member.id,
emailAddresses: [acknowledgement.emailAddress],
discordIDs: [member.id],
});
if (await client.db.PagerNumber.findOne({ num: randomPagerNumber })) return;
logNewPager(client, randomPagerNumber, member);
pager = await newNumber.save();
client.getDMChannel(member.id).then((chan) => {
chan.createMessage(`__**Pager Number Creation**__\nYour individual pager number has been automatically created. Your number (PN) is ${randomPagerNumber}.`);
});
} else if (!pager && member.roles.includes('455972169449734144')) {
// Moderators
let randomPagerNumber: string;
let status = true;
// eslint-disable-next-line no-constant-condition
while (status) {
randomPagerNumber = `20${String(Math.floor(Math.random() * 99) + 1)}`;
if (randomPagerNumber.length === 3) randomPagerNumber = `${randomPagerNumber}0`;
const check = await client.db.PagerNumber.findOne({ num: randomPagerNumber });
if (check) status = false;
if (check?.num !== randomPagerNumber) status = false;
}
const acknowledgement = resolveStaffInformation(member.id);
if (!acknowledgement || !acknowledgement.emailAddress) return;
const newNumber = new client.db.PagerNumber({
num: randomPagerNumber,
individualAssignID: member.id,
emailAddresses: [acknowledgement.emailAddress],
discordIDs: [member.id],
});
if (await client.db.PagerNumber.findOne({ num: randomPagerNumber })) return;
logNewPager(client, randomPagerNumber, member);
pager = await newNumber.save();
client.getDMChannel(member.id).then((chan) => {
chan.createMessage(`__**Pager Number Creation**__\nYour individual pager number has been automatically created. Your number (PN) is ${randomPagerNumber}.`);
});
} else if (!pager && member.roles.includes('453689940140883988')) {
// Core Team
let randomPagerNumber: string;
let status = true;
// eslint-disable-next-line no-constant-condition
while (status) {
randomPagerNumber = `21${String(Math.floor(Math.random() * 999) + 1)}`;
if (randomPagerNumber.length === 4) randomPagerNumber = `${randomPagerNumber}0`;
const check = await client.db.PagerNumber.findOne({ num: randomPagerNumber });
if (check) status = false;
if (check?.num !== randomPagerNumber) status = false;
}
const acknowledgement = resolveStaffInformation(member.id);
if (!acknowledgement || !acknowledgement.emailAddress) return;
const newNumber = new client.db.PagerNumber({
num: randomPagerNumber,
individualAssignID: member.id,
emailAddresses: [acknowledgement.emailAddress],
discordIDs: [member.id],
});
if (await client.db.PagerNumber.findOne({ num: randomPagerNumber })) return;
logNewPager(client, randomPagerNumber, member);
pager = await newNumber.save();
client.getDMChannel(member.id).then((chan) => {
chan.createMessage(`__**Pager Number Creation**__\nYour individual pager number has been automatically created. Your number (PN) is ${randomPagerNumber}.`);
});
} else if (!pager && member.roles.includes('701481967149121627')) {
// Associates
let randomPagerNumber: string;
let status = true;
// eslint-disable-next-line no-constant-condition
while (status) {
randomPagerNumber = `22${String(Math.floor(Math.random() * 999) + 1)}`;
if (randomPagerNumber.length === 4) randomPagerNumber = `${randomPagerNumber}0`;
const check = await client.db.PagerNumber.findOne({ num: randomPagerNumber });
if (check) status = false;
if (check?.num !== randomPagerNumber) status = false;
}
const acknowledgement = resolveStaffInformation(member.id);
if (!acknowledgement || !acknowledgement.emailAddress) return;
const newNumber = new client.db.PagerNumber({
num: randomPagerNumber,
individualAssignID: member.id,
emailAddresses: [acknowledgement.emailAddress],
discordIDs: [member.id],
});
if (await client.db.PagerNumber.findOne({ num: randomPagerNumber })) return;
logNewPager(client, randomPagerNumber, member);
pager = await newNumber.save();
client.getDMChannel(member.id).then((chan) => {
chan.createMessage(`__**Pager Number Creation**__\nYour individual pager number has been automatically created. Your number (PN) is ${randomPagerNumber}.`);
});
}
}
// Associates
const associatePagers = await client.db.PagerNumber.findOne({ num: '22' });
for (const member of members.values()) {
if (member.roles.includes('701481967149121627') && !associatePagers.discordIDs.includes(member.id)) {
await associatePagers.updateOne({ $addToSet: { discordIDs: member.id } });
const acknowledgement = resolveStaffInformation(member.id);
if (acknowledgement?.emailAddress) await associatePagers.updateOne({ $addToSet: { emailAddresses: acknowledgement.emailAddress } });
}
if (!member.roles.includes('701481967149121627') && associatePagers.discordIDs.includes(member.id)) {
await associatePagers.updateOne({ $pull: { discordIDs: member.id } });
const acknowledgement = resolveStaffInformation(member.id);
if (acknowledgement?.emailAddress) await associatePagers.updateOne({ $pull: { emailAddresses: acknowledgement.emailAddress } });
}
}
// Core Team
const coreTeamPagers = await client.db.PagerNumber.findOne({ num: '21' });
for (const member of members.values()) {
if (member.roles.includes('453689940140883988') && !coreTeamPagers.discordIDs.includes(member.id)) {
await coreTeamPagers.updateOne({ $addToSet: { discordIDs: member.id } });
const acknowledgement = resolveStaffInformation(member.id);
if (acknowledgement?.emailAddress) await coreTeamPagers.updateOne({ $addToSet: { emailAddresses: acknowledgement.emailAddress } });
}
if (!member.roles.includes('453689940140883988') && coreTeamPagers.discordIDs.includes(member.id)) {
await coreTeamPagers.updateOne({ $pull: { discordIDs: member.id } });
const acknowledgement = resolveStaffInformation(member.id);
if (acknowledgement?.emailAddress) await coreTeamPagers.updateOne({ $pull: { emailAddresses: acknowledgement.emailAddress } });
}
}
// Moderator
const moderatorPagers = await client.db.PagerNumber.findOne({ num: '20' });
for (const member of members.values()) {
if (member.roles.includes('455972169449734144') && !moderatorPagers.discordIDs.includes(member.id)) {
await moderatorPagers.updateOne({ $addToSet: { discordIDs: member.id } });
const acknowledgement = resolveStaffInformation(member.id);
if (acknowledgement?.emailAddress) await moderatorPagers.updateOne({ $addToSet: { emailAddresses: acknowledgement.emailAddress } });
}
if (!member.roles.includes('455972169449734144') && moderatorPagers.discordIDs.includes(member.id)) {
await moderatorPagers.updateOne({ $pull: { discordIDs: member.id } });
const acknowledgement = resolveStaffInformation(member.id);
if (acknowledgement?.emailAddress) await moderatorPagers.updateOne({ $pull: { emailAddresses: acknowledgement.emailAddress } });
}
}
// Technician
const technicianPagers = await client.db.PagerNumber.findOne({ num: '10' });
for (const member of members.values()) {
if (member.roles.includes('701454780828221450') && !technicianPagers.discordIDs.includes(member.id)) {
await technicianPagers.updateOne({ $addToSet: { discordIDs: member.id } });
const acknowledgement = resolveStaffInformation(member.id);
if (acknowledgement?.emailAddress) await technicianPagers.updateOne({ $addToSet: { emailAddresses: acknowledgement.emailAddress } });
}
if (!member.roles.includes('701454780828221450') && technicianPagers.discordIDs.includes(member.id)) {
await technicianPagers.updateOne({ $pull: { discordIDs: member.id } });
const acknowledgement = resolveStaffInformation(member.id);
if (acknowledgement?.emailAddress) await technicianPagers.updateOne({ $pull: { emailAddresses: acknowledgement.emailAddress } });
}
}
// Supervisor
const supervisorPagers = await client.db.PagerNumber.findOne({ num: '01' });
for (const member of members.values()) {
if (member.roles.includes('701454855952138300') && !supervisorPagers.discordIDs.includes(member.id)) {
await supervisorPagers.updateOne({ $addToSet: { discordIDs: member.id } });
const acknowledgement = resolveStaffInformation(member.id);
if (acknowledgement?.emailAddress) await supervisorPagers.updateOne({ $addToSet: { emailAddresses: acknowledgement.emailAddress } });
}
if (!member.roles.includes('701454855952138300') && supervisorPagers.discordIDs.includes(member.id)) {
await supervisorPagers.updateOne({ $pull: { discordIDs: member.id } });
const acknowledgement = resolveStaffInformation(member.id);
if (acknowledgement?.emailAddress) await supervisorPagers.updateOne({ $pull: { emailAddresses: acknowledgement.emailAddress } });
}
}
// Board of Directors
const directorPagers = await client.db.PagerNumber.findOne({ num: '00' });
for (const member of members.values()) {
if (member.roles.includes('662163685439045632') && !directorPagers.discordIDs.includes(member.id)) {
await directorPagers.updateOne({ $addToSet: { discordIDs: member.id } });
const acknowledgement = resolveStaffInformation(member.id);
if (acknowledgement?.emailAddress) await directorPagers.updateOne({ $addToSet: { emailAddresses: acknowledgement.emailAddress } });
}
if (!member.roles.includes('662163685439045632') && directorPagers.discordIDs.includes(member.id)) {
await directorPagers.updateOne({ $pull: { discordIDs: member.id } });
const acknowledgement = resolveStaffInformation(member.id);
if (acknowledgement?.emailAddress) await directorPagers.updateOne({ $pull: { emailAddresses: acknowledgement.emailAddress } });
}
}
}, 300000);
return interval;
}
/* eslint-disable no-continue */
/* eslint-disable no-await-in-loop */
import { Member, TextableChannel } from 'eris';
import { Client } from '../class';
let interval: NodeJS.Timeout;
async function setupDepartmentCodes(client: Client): Promise<void> {
const directorPagers = await client.db.PagerNumber.findOne({ num: '00' }).lean().exec();
const supervisorPagers = await client.db.PagerNumber.findOne({ num: '01' }).lean().exec();
const technicianPagers = await client.db.PagerNumber.findOne({ num: '10' }).lean().exec();
const moderatorPagers = await client.db.PagerNumber.findOne({ num: '20' }).lean().exec();
const coreTeamPagers = await client.db.PagerNumber.findOne({ num: '21' }).lean().exec();
const associatePagers = await client.db.PagerNumber.findOne({ num: '22' }).lean().exec();
if (!directorPagers) {
const setup = new client.db.PagerNumber({
num: '00',
individualAssignID: '',
emailAddresses: [],
discordIDs: [],
});
await setup.save();
}
if (!supervisorPagers) {
const setup = new client.db.PagerNumber({
num: '01',
individualAssignID: '',
emailAddresses: [],
discordIDs: [],
});
await setup.save();
}
if (!technicianPagers) {
const setup = new client.db.PagerNumber({
num: '10',
individualAssignID: '',
emailAddresses: [],
discordIDs: [],
});
setup.save();
}
if (!moderatorPagers) {
const setup = new client.db.PagerNumber({
num: '20',
individualAssignID: '',
emailAddresses: [],
discordIDs: [],
});
await setup.save();
}
if (!coreTeamPagers) {
const setup = new client.db.PagerNumber({
num: '21',
individualAssignID: '',
emailAddresses: [],
discordIDs: [],
});
await setup.save();
}
if (!associatePagers) {
const setup = new client.db.PagerNumber({
num: '22',
individualAssignID: '',
emailAddresses: [],
discordIDs: [],
});
await setup.save();
}
}
function logNewPager(client: Client, num: string, member: Member): void {
const channel = <TextableChannel> client.guilds.get(client.config.guildID).channels.get('722636436716781619');
channel.createMessage(`__**'${member.user.username}#${member.user.discriminator}' assigned to pager number '${num}'.**__`);
}
export default function departmentPager(client: Client): NodeJS.Timeout {
setupDepartmentCodes(client);
interval = setInterval(async () => {
const acknowledgements = require(`${__dirname}/../configs/acknowledgements.json`);
function resolveStaffInformation(id: string) {
return acknowledgements.find((m) => m.id === id);
}
// await client.guilds.get(client.config.guildID).fetchAllMembers();
const { members } = client.guilds.get(client.config.guildID);
for (const member of members.values()) {
const pager = await client.db.PagerNumber.findOne({ individualAssignID: member.id }).lean().exec();
if (!pager) continue;
if (pager.num.startsWith('00') && !member.roles.includes('662163685439045632')) {
client.db.PagerNumber.deleteOne({ num: pager.num });
client.util.signale.log(`Pager Number '${pager.num}' has been deleted.`);
} else if (pager.num.startsWith('01') && !member.roles.includes('701454855952138300')) {
client.db.PagerNumber.deleteOne({ num: pager.num });
client.util.signale.log(`Pager Number '${pager.num}' has been deleted.`);
} else if (pager.num.startsWith('10') && !member.roles.includes('701454780828221450')) {
client.db.PagerNumber.deleteOne({ num: pager.num });
client.util.signale.log(`Pager Number '${pager.num}' has been deleted.`);
} else if (pager.num.startsWith('20') && !member.roles.includes('455972169449734144')) {
client.db.PagerNumber.deleteOne({ num: pager.num });
client.util.signale.log(`Pager Number '${pager.num}' has been deleted.`);
} else if (pager.num.startsWith('21') && !member.roles.includes('453689940140883988')) {
client.db.PagerNumber.deleteOne({ num: pager.num });
client.util.signale.log(`Pager Number '${pager.num}' has been deleted.`);
} else if (pager.num.startsWith('22') && !member.roles.includes('701481967149121627')) {
client.db.PagerNumber.deleteOne({ num: pager.num });
client.util.signale.log(`Pager Number '${pager.num}' has been deleted.`);
}
}
// const takenPagers = new Set<string>();
for (const member of members.values()) {
let pager = await client.db.PagerNumber.findOne({ individualAssignID: member.id }).lean().exec();
// Directors
if (!pager && member.roles.includes('662163685439045632')) {
let randomPagerNumber: string;
let status = true;
// eslint-disable-next-line no-constant-condition
while (status) {
randomPagerNumber = `00${String(Math.floor(Math.random() * 9) + 1)}`;
const check = await client.db.PagerNumber.findOne({ num: randomPagerNumber });
if (check) status = false;
if (check?.num !== randomPagerNumber) status = false;
}
const acknowledgement = resolveStaffInformation(member.id);
if (!acknowledgement || !acknowledgement.emailAddress) return;
const newNumber = new client.db.PagerNumber({
num: randomPagerNumber,
individualAssignID: member.id,
emailAddresses: [acknowledgement.emailAddress],
discordIDs: [member.id],
});
if (await client.db.PagerNumber.findOne({ num: randomPagerNumber })) return;
pager = await newNumber.save();
logNewPager(client, randomPagerNumber, member);
client.getDMChannel(member.id).then((chan) => {
chan.createMessage(`__**Pager Number Creation**__\nYour individual pager number has been automatically created. Your number (PN) is ${randomPagerNumber}.`);
});
} else if (!pager && member.roles.includes('701454855952138300')) {
// Supervisors
let randomPagerNumber: string;
let status = true;
// eslint-disable-next-line no-constant-condition
while (status) {
randomPagerNumber = `01${String(Math.floor(Math.random() * 9) + 1)}`;
const check = await client.db.PagerNumber.findOne({ num: randomPagerNumber });
if (check) status = false;
if (check?.num !== randomPagerNumber) status = false;
}
const acknowledgement = resolveStaffInformation(member.id);
if (!acknowledgement || !acknowledgement.emailAddress) return;
const newNumber = new client.db.PagerNumber({
num: randomPagerNumber,
individualAssignID: member.id,
emailAddresses: [acknowledgement.emailAddress],
discordIDs: [member.id],
});
if (await client.db.PagerNumber.findOne({ num: randomPagerNumber })) return;
logNewPager(client, randomPagerNumber, member);
pager = await newNumber.save();
client.getDMChannel(member.id).then((chan) => {
chan.createMessage(`__**Pager Number Creation**__\nYour individual pager number has been automatically created. Your number (PN) is ${randomPagerNumber}.`);
});
} else if (!pager && member.roles.includes('701454780828221450')) {
// Technicians
let randomPagerNumber: string;
let status = true;
// eslint-disable-next-line no-constant-condition
while (status) {
randomPagerNumber = `10${String(Math.floor(Math.random() * 99) + 1)}`;
if (randomPagerNumber.length === 3) randomPagerNumber = `${randomPagerNumber}0`;
const check = await client.db.PagerNumber.findOne({ num: randomPagerNumber });
if (check) status = false;
if (check?.num !== randomPagerNumber) status = false;
}
const acknowledgement = resolveStaffInformation(member.id);
if (!acknowledgement || !acknowledgement.emailAddress) return;
const newNumber = new client.db.PagerNumber({
num: randomPagerNumber,
individualAssignID: member.id,
emailAddresses: [acknowledgement.emailAddress],
discordIDs: [member.id],
});
if (await client.db.PagerNumber.findOne({ num: randomPagerNumber })) return;
logNewPager(client, randomPagerNumber, member);
pager = await newNumber.save();
client.getDMChannel(member.id).then((chan) => {
chan.createMessage(`__**Pager Number Creation**__\nYour individual pager number has been automatically created. Your number (PN) is ${randomPagerNumber}.`);
});
} else if (!pager && member.roles.includes('455972169449734144')) {
// Moderators
let randomPagerNumber: string;
let status = true;
// eslint-disable-next-line no-constant-condition
while (status) {
randomPagerNumber = `20${String(Math.floor(Math.random() * 99) + 1)}`;
if (randomPagerNumber.length === 3) randomPagerNumber = `${randomPagerNumber}0`;
const check = await client.db.PagerNumber.findOne({ num: randomPagerNumber });
if (check) status = false;
if (check?.num !== randomPagerNumber) status = false;
}
const acknowledgement = resolveStaffInformation(member.id);
if (!acknowledgement || !acknowledgement.emailAddress) return;
const newNumber = new client.db.PagerNumber({
num: randomPagerNumber,
individualAssignID: member.id,
emailAddresses: [acknowledgement.emailAddress],
discordIDs: [member.id],
});
if (await client.db.PagerNumber.findOne({ num: randomPagerNumber })) return;
logNewPager(client, randomPagerNumber, member);
pager = await newNumber.save();
client.getDMChannel(member.id).then((chan) => {
chan.createMessage(`__**Pager Number Creation**__\nYour individual pager number has been automatically created. Your number (PN) is ${randomPagerNumber}.`);
});
} else if (!pager && member.roles.includes('453689940140883988')) {
// Core Team
let randomPagerNumber: string;
let status = true;
// eslint-disable-next-line no-constant-condition
while (status) {
randomPagerNumber = `21${String(Math.floor(Math.random() * 999) + 1)}`;
if (randomPagerNumber.length === 4) randomPagerNumber = `${randomPagerNumber}0`;
const check = await client.db.PagerNumber.findOne({ num: randomPagerNumber });
if (check) status = false;
if (check?.num !== randomPagerNumber) status = false;
}
const acknowledgement = resolveStaffInformation(member.id);
if (!acknowledgement || !acknowledgement.emailAddress) return;
const newNumber = new client.db.PagerNumber({
num: randomPagerNumber,
individualAssignID: member.id,
emailAddresses: [acknowledgement.emailAddress],
discordIDs: [member.id],
});
if (await client.db.PagerNumber.findOne({ num: randomPagerNumber })) return;
logNewPager(client, randomPagerNumber, member);
pager = await newNumber.save();
client.getDMChannel(member.id).then((chan) => {
chan.createMessage(`__**Pager Number Creation**__\nYour individual pager number has been automatically created. Your number (PN) is ${randomPagerNumber}.`);
});
} else if (!pager && member.roles.includes('701481967149121627')) {
// Associates
let randomPagerNumber: string;
let status = true;
// eslint-disable-next-line no-constant-condition
while (status) {
randomPagerNumber = `22${String(Math.floor(Math.random() * 999) + 1)}`;
if (randomPagerNumber.length === 4) randomPagerNumber = `${randomPagerNumber}0`;
const check = await client.db.PagerNumber.findOne({ num: randomPagerNumber });
if (check) status = false;
if (check?.num !== randomPagerNumber) status = false;
}
const acknowledgement = resolveStaffInformation(member.id);
if (!acknowledgement || !acknowledgement.emailAddress) return;
const newNumber = new client.db.PagerNumber({
num: randomPagerNumber,
individualAssignID: member.id,
emailAddresses: [acknowledgement.emailAddress],
discordIDs: [member.id],
});
if (await client.db.PagerNumber.findOne({ num: randomPagerNumber })) return;
logNewPager(client, randomPagerNumber, member);
pager = await newNumber.save();
client.getDMChannel(member.id).then((chan) => {
chan.createMessage(`__**Pager Number Creation**__\nYour individual pager number has been automatically created. Your number (PN) is ${randomPagerNumber}.`);
});
}
}
// Associates
const associatePagers = await client.db.PagerNumber.findOne({ num: '22' });
for (const member of members.values()) {
if (member.roles.includes('701481967149121627') && !associatePagers.discordIDs.includes(member.id)) {
await associatePagers.updateOne({ $addToSet: { discordIDs: member.id } });
const acknowledgement = resolveStaffInformation(member.id);
if (acknowledgement?.emailAddress) await associatePagers.updateOne({ $addToSet: { emailAddresses: acknowledgement.emailAddress } });
}
if (!member.roles.includes('701481967149121627') && associatePagers.discordIDs.includes(member.id)) {
await associatePagers.updateOne({ $pull: { discordIDs: member.id } });
const acknowledgement = resolveStaffInformation(member.id);
if (acknowledgement?.emailAddress) await associatePagers.updateOne({ $pull: { emailAddresses: acknowledgement.emailAddress } });
}
}
// Core Team
const coreTeamPagers = await client.db.PagerNumber.findOne({ num: '21' });
for (const member of members.values()) {
if (member.roles.includes('453689940140883988') && !coreTeamPagers.discordIDs.includes(member.id)) {
await coreTeamPagers.updateOne({ $addToSet: { discordIDs: member.id } });
const acknowledgement = resolveStaffInformation(member.id);
if (acknowledgement?.emailAddress) await coreTeamPagers.updateOne({ $addToSet: { emailAddresses: acknowledgement.emailAddress } });
}
if (!member.roles.includes('453689940140883988') && coreTeamPagers.discordIDs.includes(member.id)) {
await coreTeamPagers.updateOne({ $pull: { discordIDs: member.id } });
const acknowledgement = resolveStaffInformation(member.id);
if (acknowledgement?.emailAddress) await coreTeamPagers.updateOne({ $pull: { emailAddresses: acknowledgement.emailAddress } });
}
}
// Moderator
const moderatorPagers = await client.db.PagerNumber.findOne({ num: '20' });
for (const member of members.values()) {
if (member.roles.includes('455972169449734144') && !moderatorPagers.discordIDs.includes(member.id)) {
await moderatorPagers.updateOne({ $addToSet: { discordIDs: member.id } });
const acknowledgement = resolveStaffInformation(member.id);
if (acknowledgement?.emailAddress) await moderatorPagers.updateOne({ $addToSet: { emailAddresses: acknowledgement.emailAddress } });
}
if (!member.roles.includes('455972169449734144') && moderatorPagers.discordIDs.includes(member.id)) {
await moderatorPagers.updateOne({ $pull: { discordIDs: member.id } });
const acknowledgement = resolveStaffInformation(member.id);
if (acknowledgement?.emailAddress) await moderatorPagers.updateOne({ $pull: { emailAddresses: acknowledgement.emailAddress } });
}
}
// Technician
const technicianPagers = await client.db.PagerNumber.findOne({ num: '10' });
for (const member of members.values()) {
if (member.roles.includes('701454780828221450') && !technicianPagers.discordIDs.includes(member.id)) {
await technicianPagers.updateOne({ $addToSet: { discordIDs: member.id } });
const acknowledgement = resolveStaffInformation(member.id);
if (acknowledgement?.emailAddress) await technicianPagers.updateOne({ $addToSet: { emailAddresses: acknowledgement.emailAddress } });
}
if (!member.roles.includes('701454780828221450') && technicianPagers.discordIDs.includes(member.id)) {
await technicianPagers.updateOne({ $pull: { discordIDs: member.id } });
const acknowledgement = resolveStaffInformation(member.id);
if (acknowledgement?.emailAddress) await technicianPagers.updateOne({ $pull: { emailAddresses: acknowledgement.emailAddress } });
}
}
// Supervisor
const supervisorPagers = await client.db.PagerNumber.findOne({ num: '01' });
for (const member of members.values()) {
if (member.roles.includes('701454855952138300') && !supervisorPagers.discordIDs.includes(member.id)) {
await supervisorPagers.updateOne({ $addToSet: { discordIDs: member.id } });
const acknowledgement = resolveStaffInformation(member.id);
if (acknowledgement?.emailAddress) await supervisorPagers.updateOne({ $addToSet: { emailAddresses: acknowledgement.emailAddress } });
}
if (!member.roles.includes('701454855952138300') && supervisorPagers.discordIDs.includes(member.id)) {
await supervisorPagers.updateOne({ $pull: { discordIDs: member.id } });
const acknowledgement = resolveStaffInformation(member.id);
if (acknowledgement?.emailAddress) await supervisorPagers.updateOne({ $pull: { emailAddresses: acknowledgement.emailAddress } });
}
}
// Board of Directors
const directorPagers = await client.db.PagerNumber.findOne({ num: '00' });
for (const member of members.values()) {
if (member.roles.includes('662163685439045632') && !directorPagers.discordIDs.includes(member.id)) {
await directorPagers.updateOne({ $addToSet: { discordIDs: member.id } });
const acknowledgement = resolveStaffInformation(member.id);
if (acknowledgement?.emailAddress) await directorPagers.updateOne({ $addToSet: { emailAddresses: acknowledgement.emailAddress } });
}
if (!member.roles.includes('662163685439045632') && directorPagers.discordIDs.includes(member.id)) {
await directorPagers.updateOne({ $pull: { discordIDs: member.id } });
const acknowledgement = resolveStaffInformation(member.id);
if (acknowledgement?.emailAddress) await directorPagers.updateOne({ $pull: { emailAddresses: acknowledgement.emailAddress } });
}
}
}, 300000);
return interval;
}

View File

@ -1,11 +1,11 @@
import { Client } from '../class';
let interval: NodeJS.Timeout;
export default async function fetchMembers(client: Client): Promise<NodeJS.Timeout> {
await client.guilds.get(client.config.guildID)?.fetchAllMembers();
interval = setInterval(async () => {
// await client.guilds.get(client.config.guildID).fetchAllMembers();
}, 1800000);
return interval;
}
import { Client } from '../class';
let interval: NodeJS.Timeout;
export default async function fetchMembers(client: Client): Promise<NodeJS.Timeout> {
await client.guilds.get(client.config.guildID)?.fetchAllMembers();
interval = setInterval(async () => {
// await client.guilds.get(client.config.guildID).fetchAllMembers();
}, 1800000);
return interval;
}

View File

@ -1,23 +1,23 @@
/* DM Ramirez with the code below to claim 500 free Rubies!
d2c3d8e14b
*/
import { parse } from 'yaml';
import { promises as fs } from 'fs';
import { Client } from './class';
import * as eventFiles from './events';
import * as commandFiles from './commands';
async function main(): Promise<void> {
const read = await fs.readFile('../config.yaml', 'utf8');
const config: { token: string, prefix: string, guildID: string, mongoDB: string, emailPass: string } = parse(read);
const client = new Client(config.token, { defaultImageFormat: 'png', restMode: true });
client.config = config;
await client.loadDatabase();
client.loadPlugins();
await client.loadIntervals();
await client.loadEvents(eventFiles);
await client.loadCommands(commandFiles);
client.connect();
}
main();
/* DM Ramirez with the code below to claim 500 free Rubies!
d2c3d8e14b
*/
import { parse } from 'yaml';
import { promises as fs } from 'fs';
import { Client } from './class';
import * as eventFiles from './events';
import * as commandFiles from './commands';
async function main(): Promise<void> {
const read = await fs.readFile('../config.yaml', 'utf8');
const config: { token: string, prefix: string, guildID: string, mongoDB: string, emailPass: string } = parse(read);
const client = new Client(config.token, { defaultImageFormat: 'png', restMode: true });
client.config = config;
await client.loadDatabase();
client.loadPlugins();
await client.loadIntervals();
await client.loadEvents(eventFiles);
await client.loadCommands(commandFiles);
client.connect();
}
main();

View File

@ -1,19 +1,19 @@
import { Document, Schema, model } from 'mongoose';
export interface MemberInterface extends Document {
userID: string
additional: {
langs: ['js', 'py', 'rb', 'ts', 'rs', 'go', 'cfam', 'csharp', 'swift', 'java', 'kt', 'asm'],
operatingSystems: ['arch', 'deb', 'cent', 'fedora', 'manjaro', 'mdarwin', 'redhat', 'ubuntu', 'win'],
},
}
const Member: Schema = new Schema({
userID: String,
additional: {
langs: Array,
operatingSystems: Array,
},
});
export default model<MemberInterface>('Member', Member);
import { Document, Schema, model } from 'mongoose';
export interface MemberInterface extends Document {
userID: string
additional: {
langs: ['js', 'py', 'rb', 'ts', 'rs', 'go', 'cfam', 'csharp', 'swift', 'java', 'kt', 'asm'],
operatingSystems: ['arch', 'deb', 'cent', 'fedora', 'manjaro', 'mdarwin', 'redhat', 'ubuntu', 'win'],
},
}
const Member: Schema = new Schema({
userID: String,
additional: {
langs: Array,
operatingSystems: Array,
},
});
export default model<MemberInterface>('Member', Member);

View File

@ -1,37 +1,37 @@
import { Document, Schema, model } from 'mongoose';
export interface ModerationInterface extends Document {
userID: string,
logID: string,
moderatorID: string,
reason: string,
/**
* @field 0 - Warn
* @field 1 - Unmute
* @field 2 - Mute
* @field 3 - Kick
* @field 4 - Unban
* @field 5 - Ban
*/
type: 0 | 1 | 2 | 3 | 4 | 5
date: Date,
expiration: {
date: Date,
processed: boolean
}
}
const Moderation: Schema = new Schema({
userID: String,
logID: String,
moderatorID: String,
reason: String,
type: Number,
date: Date,
expiration: {
date: Date,
processed: Boolean,
},
});
export default model<ModerationInterface>('Moderation', Moderation);
import { Document, Schema, model } from 'mongoose';
export interface ModerationInterface extends Document {
userID: string,
logID: string,
moderatorID: string,
reason: string,
/**
* @field 0 - Warn
* @field 1 - Unmute
* @field 2 - Mute
* @field 3 - Kick
* @field 4 - Unban
* @field 5 - Ban
*/
type: 0 | 1 | 2 | 3 | 4 | 5
date: Date,
expiration: {
date: Date,
processed: boolean
}
}
const Moderation: Schema = new Schema({
userID: String,
logID: String,
moderatorID: String,
reason: String,
type: Number,
date: Date,
expiration: {
date: Date,
processed: Boolean,
},
});
export default model<ModerationInterface>('Moderation', Moderation);

View File

@ -1,26 +1,26 @@
import { Document, Schema, model } from 'mongoose';
export interface PagerNumberRaw {
num: string,
// This field will be "" if the pager number doesn't belong to an individual user
individualAssignID: string,
emailAddresses: string[],
discordIDs: string[],
}
export interface PagerNumberInterface extends Document {
num: string,
// This field will be "" if the pager number doesn't belong to an individual user
individualAssignID: string,
emailAddresses: string[],
discordIDs: string[],
}
const PagerNumber: Schema = new Schema({
num: String,
individualAssignID: String,
emailAddresses: Array,
discordIDs: Array,
});
export default model<PagerNumberInterface>('PagerNumber', PagerNumber);
import { Document, Schema, model } from 'mongoose';
export interface PagerNumberRaw {
num: string,
// This field will be "" if the pager number doesn't belong to an individual user
individualAssignID: string,
emailAddresses: string[],
discordIDs: string[],
}
export interface PagerNumberInterface extends Document {
num: string,
// This field will be "" if the pager number doesn't belong to an individual user
individualAssignID: string,
emailAddresses: string[],
discordIDs: string[],
}
const PagerNumber: Schema = new Schema({
num: String,
individualAssignID: String,
emailAddresses: Array,
discordIDs: Array,
});
export default model<PagerNumberInterface>('PagerNumber', PagerNumber);

17
src/models/Rank.ts Normal file
View File

@ -0,0 +1,17 @@
import { Document, Schema, model } from 'mongoose';
export interface RankInterface extends Document {
name: string,
roleID: string,
permissions: string[],
description: string,
}
const Rank: Schema = new Schema({
name: String,
roleID: String,
permissions: Array,
description: String,
});
export default model<RankInterface>('Rank', Rank);

View File

@ -1,21 +1,21 @@
import { Document, Schema, model } from 'mongoose';
export interface RedirectInterface extends Document {
key: string,
to: string,
visitedCount: number,
}
export interface RedirectRaw {
key: string,
to: string,
visitedCount: number,
}
const Redirect: Schema = new Schema({
key: String,
to: String,
visitedCount: Number,
});
export default model<RedirectInterface>('Redirect', Redirect);
import { Document, Schema, model } from 'mongoose';
export interface RedirectInterface extends Document {
key: string,
to: string,
visitedCount: number,
}
export interface RedirectRaw {
key: string,
to: string,
visitedCount: number,
}
const Redirect: Schema = new Schema({
key: String,
to: String,
visitedCount: Number,
});
export default model<RedirectInterface>('Redirect', Redirect);

View File

@ -1,4 +1,5 @@
export { default as Member, MemberInterface } from './Member';
export { default as Moderation, ModerationInterface } from './Moderation';
export { default as PagerNumber, PagerNumberInterface, PagerNumberRaw } from './PagerNumber';
export { default as Redirect, RedirectInterface, RedirectRaw } from './Redirect';
export { default as Member, MemberInterface } from './Member';
export { default as Moderation, ModerationInterface } from './Moderation';
export { default as PagerNumber, PagerNumberInterface, PagerNumberRaw } from './PagerNumber';
export { default as Rank, RankInterface } from './Rank';
export { default as Redirect, RedirectInterface, RedirectRaw } from './Redirect';