Merge branch 'dev'

merge-requests/13/head
Matthew 2020-05-22 01:51:59 -04:00
commit 7c0c777ad3
No known key found for this signature in database
GPG Key ID: D499B75C1390E321
38 changed files with 179 additions and 169 deletions

View File

@ -39,6 +39,7 @@
"import/prefer-default-export": "off",
"no-useless-constructor": "off",
"@typescript-eslint/no-useless-constructor": 2,
"import/extensions": "off"
"import/extensions": "off",
"no-param-reassign": "off"
}
}

23
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,23 @@
stages:
- lint
- build
lint:
stage: lint
script: |
yarn install
yarn lint
only:
- pushes
- merge_requests
- web
tsc:
stage: build
script: |
yarn install
tsc -p tsconfig.json -noEmit
only:
- pushes
- merge_requests
- web

View File

@ -4,7 +4,7 @@ clean:
@-rm -rf build
build:
-tsc -p ./tsconfig.json
-npx tsc -p ./tsconfig.json
run:
cd build && node main

5
src/api/index.ts Normal file
View File

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

View File

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

View File

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

View File

@ -1,16 +1,18 @@
import { Route, Server } from '../../../class';
import { RedirectInterface } from '../../../models';
import { RedirectRaw } from '../../../models';
export default class Root extends Route {
constructor(server: Server) {
super(server, { path: '/' });
super(server);
this.conf = {
path: '/',
};
}
public bind() {
this.router.get('/:key', async (req, res) => {
try {
// @ts-ignore
const link: RedirectInterface = await this.server.client.db.redirect.findOne({ key: req.params.key }).lean().exec();
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 });
return res.redirect(link.to);
} catch (err) {

View File

@ -1 +0,0 @@

View File

@ -1,7 +1,7 @@
import eris from 'eris';
import mongoose from 'mongoose';
import { promises as fs } from 'fs';
import { Collection, Command, Util, ServerManagement } from '.';
import { Collection, Command, Util, ServerManagement, Event } from '.';
import { Member, MemberInterface, Moderation, ModerationInterface, Redirect, RedirectInterface } from '../models';
export default class Client extends eris.Client {
@ -9,7 +9,7 @@ export default class Client extends eris.Client {
public commands: Collection<Command>;
public events: Collection<Function>;
public events: Collection<Event>;
public intervals: Collection<NodeJS.Timeout>;
@ -17,15 +17,14 @@ export default class Client extends eris.Client {
public serverManagement: ServerManagement;
public db: { member: mongoose.Model<MemberInterface>, moderation: mongoose.Model<ModerationInterface>, redirect: mongoose.Model<RedirectInterface> };
public db: { Member: mongoose.Model<MemberInterface>, Moderation: mongoose.Model<ModerationInterface>, Redirect: mongoose.Model<RedirectInterface> };
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
constructor(token: string, options?: eris.ClientOptions) {
super(token, options);
this.commands = new Collection<Command>();
this.events = new Collection<Function>();
this.events = new Collection<Event>();
this.intervals = new Collection<NodeJS.Timeout>();
this.db = { member: Member, moderation: Moderation, redirect: Redirect };
this.db = { Member, Moderation, Redirect };
}
public async loadDatabase() {
@ -48,27 +47,23 @@ export default class Client extends eris.Client {
});
}
public async loadEvents() {
const evtFiles = await fs.readdir(`${__dirname}/../events`);
evtFiles.forEach((file) => {
const eventName = file.split('.')[0];
if (file === 'index.js') return;
// eslint-disable-next-line
const event = new (require(`${__dirname}/../events/${file}`).default)(this);
this.events.add(eventName, event);
this.on(eventName, (...args) => event.run(...args));
this.util.signale.success(`Successfully loaded event: ${eventName}`);
delete require.cache[require.resolve(`${__dirname}/../events/${file}`)];
});
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() {
const commandFiles = await fs.readdir(`${__dirname}/../commands`);
commandFiles.forEach((file) => {
// eslint-disable-next-line new-cap
const command: Command = new (require(`${__dirname}/../commands/${file}`).default)(this);
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}`);
});
}
}
}

15
src/class/Event.ts Normal file
View File

@ -0,0 +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(); }
}

View File

@ -111,7 +111,7 @@ export default class Moderation {
return mod.save();
}
public async kick(user: User, moderator: Member, reason?: string): Promise<ModerationInterface> {
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');

View File

@ -1,20 +1,8 @@
/* eslint-disable no-param-reassign */
export interface EmbedData {
title?: string
description?: string
url?: string
timestamp?: 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 }
author?: { name: string, url?: string, proxy_icon_url?: string, icon_url?: string}
fields?: {name: string, value: string, inline?: boolean}[]
}
import { EmbedOptions } from 'eris';
export default class RichEmbed implements EmbedData {
export default class RichEmbed implements EmbedOptions {
title?: string
type?: string
@ -23,15 +11,15 @@ export default class RichEmbed implements EmbedData {
url?: string
timestamp?: Date
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 }
image?: { url?: string, proxy_url?: string, height?: number, width?: number }
thumbnail?: { 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 }
@ -41,7 +29,7 @@ export default class RichEmbed implements EmbedData {
fields?: {name: string, value: string, inline?: boolean}[]
constructor(data: EmbedData = {}) {
constructor(data: EmbedOptions = {}) {
/*
let types: {
title?: string, type?: string, description?: string, url?: string, timestamp?: Date, color?: number, fields?: {name: string, value: string, inline?: boolean}[]
@ -124,8 +112,7 @@ export default class RichEmbed implements EmbedData {
* Sets the timestamp of this embed.
*/
setTimestamp(timestamp = new Date()) {
// eslint-disable-next-line no-restricted-globals
if (isNaN(timestamp.getTime())) throw new TypeError('Expecting ISO8601 (Date constructor)');
if (Number.isNaN(timestamp.getTime())) throw new TypeError('Expecting ISO8601 (Date constructor)');
this.timestamp = timestamp;
return this;
}

View File

@ -9,9 +9,9 @@ export default class Route {
public router: Router;
constructor(server: Server, options: { path: string, deprecated?: boolean, maintenance?: boolean }) {
constructor(server: Server) {
this.server = server;
this.conf = options;
this.conf = { path: '' };
this.router = Router();
}

View File

@ -31,10 +31,9 @@ export default class Server {
}
public async loadRoutes() {
const routes = await fs.readdir(`${this.root}`);
for (const routeFile of routes) {
// eslint-disable-next-line new-cap
const route: Route = new (require(`${this.root}/${routeFile}`).default)(this);
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) {

View File

@ -1,7 +1,5 @@
import express from 'express';
import { promises as fs } from 'fs';
import { Client, Collection, Server } from '.';
// import serverSetup from '../api/server';
import serverSetup from '../api';
export default class ServerManagement {
public client: Client;
@ -15,12 +13,9 @@ export default class ServerManagement {
}
public async loadServers() {
const apiRoot = await fs.readdir(`${__dirname}/../api`);
for (const api of apiRoot) {
// eslint-disable-next-line no-continue
if (api === 'server.js') continue;
const server: Server = require(`${__dirname}/../api/${api}/main.js`).default(this);
this.servers.add(api, server);
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

@ -37,8 +37,6 @@ export default class Util {
*/
public resolveCommand(query: string | string[]): Promise<{cmd: Command, args: string[] }> {
try {
// let resolvedCommand: Command;
// eslint-disable-next-line no-param-reassign
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()));
@ -91,7 +89,6 @@ export default class Util {
}
await this.client.createMessage('595788220764127272', info);
const msg = message ? message.content.slice(this.client.config.prefix.length).trim().split(/ +/g) : [];
// eslint-disable-next-line no-param-reassign
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) {
@ -101,7 +98,6 @@ export default class Util {
public splitString(string: string, length: number): string[] {
if (!string) return [];
// eslint-disable-next-line no-param-reassign
if (Array.isArray(string)) string = string.join('\n');
if (string.length <= length) return [string];
const arrayString: string[] = [];
@ -111,7 +107,6 @@ export default class Util {
pos = string.length > length ? string.lastIndexOf('\n', length) : string.length;
if (pos > length) pos = length;
str = string.substr(0, pos);
// eslint-disable-next-line no-param-reassign
string = string.substr(pos);
arrayString.push(str);
}

View File

@ -1,6 +1,7 @@
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';

View File

@ -23,10 +23,9 @@ export default class AddItem extends Command {
return message.channel.createMessage({ embed });
}
if (args[0].split('-')[0] === 'os' && ['arch', 'deb', 'cent', 'fedora', 'manjaro', 'mdarwin', 'redhat', 'ubuntu', 'win'].includes(args[0].split('-')[1])) {
const account = await this.client.db.member.findOne({ userID: message.member.id });
const account = await this.client.db.Member.findOne({ userID: message.member.id });
if (!account) {
// eslint-disable-next-line new-cap
const newAccount = new this.client.db.member({
const newAccount = new this.client.db.Member({
userID: message.member.id,
additional: {
operatingSystems: [args[0].split('-')[1]],
@ -39,10 +38,9 @@ export default class AddItem extends Command {
return message.channel.createMessage(`***${this.client.util.emojis.SUCCESS} Added OS code ${args[0]} to profile.***`);
}
if (args[0].split('-')[0] === 'lang' && ['js', 'py', 'rb', 'ts', 'rs', 'go', 'cfam', 'csharp', 'swift', 'java', 'kt', 'asm'].includes(args[0].split('-')[1])) {
const account = await this.client.db.member.findOne({ userID: message.member.id });
const account = await this.client.db.Member.findOne({ userID: message.member.id });
if (!account) {
// eslint-disable-next-line new-cap
const newAccount = new this.client.db.member({
const newAccount = new this.client.db.Member({
userID: message.member.id,
additional: {
langs: [args[0].split('-')[1]],

View File

@ -15,7 +15,7 @@ export default class AddRedirect extends Command {
public async run(message: Message, args: string[]) {
try {
if (!args[0]) return this.client.commands.get('help').run(message, [this.name]);
const check = await this.client.db.redirect.findOne({ key: args[1].toLowerCase() });
const check = await this.client.db.Redirect.findOne({ key: args[1].toLowerCase() });
if (check) return this.error(message.channel, `Redirect key ${args[1].toLowerCase()} already exists. Linked to: ${check.to}`);
try {
const test = new URL(args[0]);
@ -24,8 +24,7 @@ export default class AddRedirect extends Command {
return this.error(message.channel, 'This doesn\'t appear to be a valid URL.');
}
if ((/^[a-zA-Z0-9]+$/gi.test(args[1].toLowerCase().replace('-', '').trim()) === false) || args[1].toLowerCase().length > 15) return this.error(message.channel, 'Invalid key. The key must be alphanumeric and less than 16 characters.');
// eslint-disable-next-line new-cap
const redirect = new this.client.db.redirect({
const redirect = new this.client.db.Redirect({
key: args[1].toLowerCase(),
to: args[0],
});

View File

@ -23,16 +23,16 @@ export default class DelItem extends Command {
return message.channel.createMessage({ embed });
}
if (args[0].split('-')[0] === 'os' && ['arch', 'deb', 'cent', 'fedora', 'manjaro', 'mdarwin', 'redhat', 'ubuntu', 'win'].includes(args[0].split('-')[1])) {
const account = await this.client.db.member.findOne({ userID: message.member.id });
if (!account || !account?.additional.operatingSystems || account?.additional.operatingSystems.length < 1) {
const account = await this.client.db.Member.findOne({ userID: message.member.id });
if (account?.additional.operatingSystems.length < 1) {
return message.channel.createMessage(`***${this.client.util.emojis.ERROR} You don't have any operating systems to remove.***`);
}
await account.updateOne({ $pull: { 'additional.operatingSystems': args[0].split('-')[1] } });
return message.channel.createMessage(`***${this.client.util.emojis.SUCCESS} Removed OS code ${args[0]} from profile.***`);
}
if (args[0].split('-')[0] === 'lang' && ['js', 'py', 'rb', 'ts', 'rs', 'go', 'cfam', 'csharp', 'swift', 'java', 'kt', 'asm'].includes(args[0].split('-')[1])) {
const account = await this.client.db.member.findOne({ userID: message.member.id });
if (!account || !account?.additional.langs || account?.additional.langs.length < 1) {
const account = await this.client.db.Member.findOne({ userID: message.member.id });
if (account?.additional.langs.length < 1) {
return message.channel.createMessage(`***${this.client.util.emojis.ERROR} You don't have any languages to remove.***`);
}
await account.updateOne({ $pull: { 'additional.langs': args[0].split('-')[1] } });

View File

@ -15,9 +15,9 @@ export default class DelRedirect extends Command {
public async run(message: Message, args: string[]) {
try {
if (!args[0]) return this.client.commands.get('help').run(message, [this.name]);
const check = await this.client.db.redirect.findOne({ key: args[0].toLowerCase() });
const check = await this.client.db.Redirect.findOne({ key: args[0].toLowerCase() });
if (!check) return this.error(message.channel, `Redirect key ${args[0].toLowerCase()} doesn't exist.`);
await this.client.db.redirect.deleteOne({ key: args[0].toLowerCase() });
await this.client.db.Redirect.deleteOne({ key: args[0].toLowerCase() });
return this.success(message.channel, `Deleted redirect https://loc.sh/${args[0].toLowerCase()}.`);
} catch (err) {
return this.client.util.handleError(err, message, this);

View File

@ -1,5 +1,5 @@
import { Message } from 'eris';
import axios from 'axios';
import { Message, EmbedOptions } from 'eris';
import axios, { AxiosResponse } from 'axios';
import { Client, Command, RichEmbed } from '../class';
export default class DJS extends Command {
@ -17,34 +17,10 @@ export default class DJS extends Command {
try {
if (!args[0]) return this.client.commands.get('help').run(message, [this.name]);
let res;
try {
res = await axios.get(`https://djsdocs.sorta.moe/v2/embed?src=master&q=${args[0]}`);
} catch (err) {
this.error(message.channel, 'Please try again later, something unexpected happened.');
return this.client.util.handleError(err, message, this);
}
const { data } = res;
const { data }: AxiosResponse<EmbedOptions> = await axios.get(`https://djsdocs.sorta.moe/v2/embed?src=master&q=${args[0]}`);
if (!data) return this.error(message.channel, 'Could not find information. Try something else.');
const name: string = data.author?.name || '';
const icon_url: string = data.author?.icon_url || '';
const author_url: string = data.author?.url || '';
const description: string = data.description || 'None';
const title: string = data.title || '';
const embed = new RichEmbed();
embed.setAuthor(name, icon_url, author_url);
embed.setColor(0x2296f3);
embed.setTitle(title);
embed.setDescription(description);
if (data.fields !== undefined && data.fields.length > 0) {
data.fields.forEach((field) => {
embed.addField(field.name, field.value);
});
}
embed.setFooter(this.client.user.username, this.client.user.avatarURL);
embed.setTimestamp();
const embed = new RichEmbed(data);
return message.channel.createMessage({ embed });
} catch (err) {
return this.client.util.handleError(err, message, this);

View File

@ -47,13 +47,9 @@ export default class Game extends Command {
embed.setColor('#1ed760');
embed.addField('Song', mainStatus.details, true);
embed.addField('Artist', mainStatus.state, true);
// @ts-ignore
embed.addField('Album', mainStatus.assets.large_text);
// @ts-ignore
embed.addField('Start', `${new Date(mainStatus.timestamps.start).toLocaleTimeString('en-us')} ET`, true);
// @ts-ignore
embed.addField('End', `${new Date(mainStatus.timestamps.end).toLocaleTimeString('en-us')} ET`, true);
// @ts-ignore
embed.setThumbnail(`https://i.scdn.co/image/${mainStatus.assets.large_image.split(':')[1]}`);
embed.setFooter(`Listening to Spotify | ${this.client.user.username}`, 'https://media.discordapp.net/attachments/358674161566220288/496894273304920064/2000px-Spotify_logo_without_text.png');
embed.setTimestamp();

View File

@ -12,7 +12,6 @@ export default class Help extends Command {
this.enabled = true;
}
// eslint-disable-next-line consistent-return
public async run(message: Message, args: string[]) {
try {
if (args.length > 0) {
@ -110,7 +109,7 @@ export default class Help extends Command {
if (cmdPages.length === 1) return message.channel.createMessage({ embed: cmdPages[0] });
return createPaginationEmbed(message, cmdPages);
} catch (err) {
this.client.util.handleError(err, message, this, false);
return this.client.util.handleError(err, message, this, false);
}
}
}

17
src/commands/index.ts Normal file
View File

@ -0,0 +1,17 @@
export { default as additem } from './additem';
export { default as addredirect } from './addredirect';
export { default as ban } from './ban';
export { default as delitem } from './delitem';
export { default as delredirect } from './delredirect';
export { default as djs } from './djs';
export { default as eval } from './eval';
export { default as game } from './game';
export { default as help } from './help';
export { default as info } from './info';
export { default as kick } from './kick';
export { default as listredirects } from './listredirects';
export { default as npm } from './npm';
export { default as ping } from './ping';
export { default as roleinfo } from './roleinfo';
export { default as unban } from './unban';
export { default as whois } from './whois';

View File

@ -1,4 +1,4 @@
import { Message, User } from 'eris';
import { Message, User, Member } from 'eris';
import { Client, Command } from '../class';
export default class Kick extends Command {
@ -15,16 +15,15 @@ export default class Kick extends Command {
public async run(message: Message, args: string[]) {
try {
if (!args[0]) return this.client.commands.get('help').run(message, [this.name]);
const member = this.client.util.resolveMember(args[0], this.client.guilds.get(this.client.config.guildID));
let user: User;
if (!member) {
let user: Member = this.client.util.resolveMember(args[0], this.client.guilds.get(this.client.config.guildID));
if (!user) {
try {
user = await this.client.getRESTUser(args[0]);
user = await this.client.getRESTGuildMember(this.client.config.guildID, args[0]);
} catch {
return this.error(message.channel, 'Cannot find user.');
}
}
if (member && !this.client.util.moderation.checkPermissions(member, message.member)) return this.error(message.channel, 'Permission Denied.');
if (user && !this.client.util.moderation.checkPermissions(user, message.member)) return this.error(message.channel, 'Permission Denied.');
message.delete();
const reason: string = args[1];

View File

@ -16,7 +16,7 @@ export default class DelRedirect extends Command {
public async run(message: Message, args: string[]) {
try {
if (args[0]) {
const redirects = await this.client.db.redirect.find({ $or: [{ key: args[0].toLowerCase() }, { to: args[0].toLowerCase() }] });
const redirects = await this.client.db.Redirect.find({ $or: [{ key: args[0].toLowerCase() }, { to: args[0].toLowerCase() }] });
if (redirects.length <= 0) return this.error(message.channel, 'Could not find an entry matching that query.');
const embed = new RichEmbed();
embed.setTitle('Redirect Information');
@ -27,7 +27,7 @@ export default class DelRedirect extends Command {
embed.setTimestamp();
return message.channel.createMessage({ embed });
}
const redirects = await this.client.db.redirect.find();
const redirects = await this.client.db.Redirect.find();
if (!redirects) return this.error(message.channel, 'No redirect links found.');
const redirectArray: [{ name: string, value: string }?] = [];
for (const redirect of redirects) {

View File

@ -34,8 +34,7 @@ export default class NPM extends Command {
license = data.license;
}
let dependencies: string = 'None';
// eslint-disable-next-line no-prototype-builtins
if (version !== 'Unknown' && data.versions[version].hasOwnProperty('dependencies') && Object.keys(data.versions[version].dependencies).length > 0) {
if (version !== 'Unknown' && data.versions[version].dependencies !== undefined && Object.keys(data.versions[version].dependencies).length > 0) {
dependencies = Object.keys(data.versions[version].dependencies).join(', ');
}
const name: string = data.name || 'None';

View File

@ -41,7 +41,6 @@ export default class Whois extends Command {
embed.setThumbnail(member.avatarURL);
const ackResolve = this.resolveStaffInformation(member.id);
let description = '';
if (ackResolve) {
if (ackResolve?.title) {
description += `${emotes.titleAndDepartment} __**${ackResolve.title}**__\n\n`;
}
@ -57,7 +56,6 @@ export default class Whois extends Command {
if (ackResolve?.bio) {
description += `${emotes.bio} *${ackResolve.bio}*\n`;
}
}
description += `\n<@${member.id}>`;
embed.setDescription(description);
@ -95,7 +93,7 @@ export default class Whois extends Command {
if ((bit | 1073741824) === bit) permissions.push('Manage Emojis');
if ((bit | 4) === bit) permissions.push('Ban Members');
if ((bit | 2) === bit) permissions.push('Kick Members');
const account = await this.client.db.member.findOne({ userID: member.id });
const account = await this.client.db.Member.findOne({ userID: member.id });
if (account?.additional?.langs.length > 0) {
const langs: string[] = [];
for (const lang of account.additional.langs.sort((a, b) => a.localeCompare(b))) {

View File

@ -37,7 +37,7 @@
{
"name": "Midori",
"id": "109122112643440640",
"title": "Board of Directors",
"title": "Board of Directors [ON LEAVE]",
"emailAddress": "midori@staff.libraryofcode.org"
},
{
@ -101,13 +101,6 @@
"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": "Realitus",
"id": "156450671338586112",
"title": "Associate",
"github": "https://github.com/Realitus",
"bio": "A hobbyist software developer with some rather strange ideas, and even stranger implementations."
},
{
"name": "KhaaZ",
"id": "179908288337412096",
@ -133,6 +126,13 @@
"github": "https://github.com/gavintjhxx",
"bio": "Wake up. Eat. Code. Sleep. Loop()"
},
{
"name": "PlayerVMachine",
"id": "273999507174195203",
"title": "Instructor & Associate",
"emailAddress": "nicolas@staff.libraryofcode.org",
"bio": "I write C++ to pay off my student loans"
},
{
"name": "Null",
"id": "323673862971588609",

View File

@ -1,12 +1,13 @@
/* eslint-disable no-useless-return */
import { Message, TextChannel, NewsChannel } from 'eris';
import { Client } from '../class';
import { Client, Event } from '../class';
export default class {
export default class CommandHandler extends Event {
public client: Client;
constructor(client: Client) {
this.client = client;
super(client);
this.event = 'messageCreate';
}
public async run(message: Message) {

2
src/events/index.ts Normal file
View File

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

View File

@ -1,10 +1,11 @@
import { Client } from '../class';
import { Client, Event } from '../class';
export default class {
export default class Ready extends Event {
public client: Client;
constructor(client: Client) {
this.client = client;
super(client);
this.event = 'ready';
}
public async run() {

View File

@ -5,7 +5,7 @@ let interval: NodeJS.Timeout;
export default function checkLock(client: Client): NodeJS.Timeout {
interval = setInterval(async () => {
try {
const moderations = await client.db.moderation.find();
const moderations = await client.db.Moderation.find();
moderations.forEach(async (moderation) => {
if (!moderation.expiration) return;
if (moderation.expiration.processed) return;

View File

@ -3,7 +3,7 @@ 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();
await client.guilds.get(client.config.guildID)?.fetchAllMembers();
interval = setInterval(async () => {
await client.guilds.get(client.config.guildID).fetchAllMembers();
}, 1800000);

View File

@ -4,6 +4,8 @@
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');
@ -13,8 +15,8 @@ async function main(): Promise<void> {
await client.loadDatabase();
client.loadPlugins();
await client.loadIntervals();
await client.loadEvents();
await client.loadCommands();
await client.loadEvents(eventFiles);
await client.loadCommands(commandFiles);
client.connect();
}

View File

@ -5,6 +5,11 @@ export interface RedirectInterface extends Document {
to: string,
}
export interface RedirectRaw {
key: string,
to: string,
}
const Redirect: Schema = new Schema({
key: String,
to: String,

View File

@ -1,3 +1,3 @@
export { default as Member, MemberInterface } from './Member';
export { default as Moderation, ModerationInterface } from './Moderation';
export { default as Redirect, RedirectInterface } from './Redirect';
export { default as Redirect, RedirectInterface, RedirectRaw } from './Redirect';