mirror of
https://github.com/DarthKilroy/Spot.git
synced 2025-12-19 18:26:48 +00:00
rewrite
this is a rewrite of the bot in typescript. detritus is used as a discord library instead of discord.js
This commit is contained in:
parent
6688d4dcd8
commit
56091a6df7
33 changed files with 731 additions and 1116 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
|
|
||||||
RUN apk add nodejs-current yarn
|
RUN apk add nodejs-current npm yarn git
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY package.json yarn.lock /app/
|
COPY package.json yarn.lock /app/
|
||||||
|
|
@ -8,4 +8,4 @@ RUN yarn
|
||||||
|
|
||||||
COPY . /app
|
COPY . /app
|
||||||
|
|
||||||
CMD ["node", "bot.js"]
|
CMD ["yarn", "ts-node", "bot.ts"]
|
||||||
45
bot.js
45
bot.js
|
|
@ -1,45 +0,0 @@
|
||||||
const Logger = require('@lilywonhalf/pretty-logger');
|
|
||||||
|
|
||||||
const { Client } = require('discord.js');
|
|
||||||
const Config = require('./config.json');
|
|
||||||
const Command = require('./model/command');
|
|
||||||
const fs = require('fs');
|
|
||||||
const dotenv = require('dotenv')
|
|
||||||
|
|
||||||
dotenv.config();
|
|
||||||
|
|
||||||
global.bot = new Client({ fetchAllMembers: true });
|
|
||||||
global.isRightGuild = (guildSnowflake) => guildSnowflake === Config.guild;
|
|
||||||
|
|
||||||
const crashRecover = (exception) => {
|
|
||||||
Logger.exception(exception);
|
|
||||||
Logger.notice('Need reboot');
|
|
||||||
};
|
|
||||||
|
|
||||||
process.on('uncaughtException', crashRecover);
|
|
||||||
bot.on('error', crashRecover);
|
|
||||||
|
|
||||||
Command.init();
|
|
||||||
|
|
||||||
const help = require("./command/help");
|
|
||||||
bot.ws.on('INTERACTION_CREATE', help.interactionHandler);
|
|
||||||
|
|
||||||
bot.on('ready', () => {
|
|
||||||
fs.readdirSync('./event/')
|
|
||||||
.filter(filename => filename.endsWith('.js'))
|
|
||||||
.map(filename => filename.substr(0, filename.length - 3))
|
|
||||||
.forEach(filename => {
|
|
||||||
const event = filename.replace(/([_-][a-z])/gu, character => `${character.substr(1).toUpperCase()}`);
|
|
||||||
|
|
||||||
if (filename !== 'ready') {
|
|
||||||
bot.on(event, require(`./event/${filename}`));
|
|
||||||
} else {
|
|
||||||
require(`./event/${filename}`)();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Logger.info('--------');
|
|
||||||
|
|
||||||
Logger.info('Logging in...');
|
|
||||||
bot.login(process.env.token);
|
|
||||||
48
bot.ts
Normal file
48
bot.ts
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
import * as dotenv from 'dotenv';
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
|
import config from "./config";
|
||||||
|
|
||||||
|
import { Socket } from 'detritus-client-socket/lib/gateway';
|
||||||
|
import { Client } from "detritus-client-rest";
|
||||||
|
|
||||||
|
import * as types from 'discord-api-types/v10';
|
||||||
|
|
||||||
|
const socket = new Socket(process.env.token!, { intents: 33283 });
|
||||||
|
export const restClient = new Client(process.env.token);
|
||||||
|
|
||||||
|
import handleMessage from './messageHandler';
|
||||||
|
import help from './command/help';
|
||||||
|
|
||||||
|
socket.on('packet', async (evt: types.GatewayDispatchPayload) => handleEvtInner(evt).catch(e => console.error(e, JSON.stringify(e, null, 2))));
|
||||||
|
|
||||||
|
async function handleEvtInner(evt: types.GatewayDispatchPayload) {
|
||||||
|
if (evt.op != 0) return;
|
||||||
|
if (evt.t == 'READY') {
|
||||||
|
console.log("successfully logged in:", evt.d.user);
|
||||||
|
}
|
||||||
|
|
||||||
|
// i am quite sure this is the correct type
|
||||||
|
// @ts-expect-error
|
||||||
|
if (evt.t == 'INTERACTION_CREATE') await help.interactionHandler(evt.d);
|
||||||
|
|
||||||
|
if (evt.t == 'GUILD_MEMBER_ADD') {
|
||||||
|
if (evt.d.guild_id != config.guild) return;
|
||||||
|
if (evt.d.user!.bot) return;
|
||||||
|
|
||||||
|
const msg = `Welcome, <@${evt.d.user!.id}>! If you joined for any specific support questions `
|
||||||
|
+ `please check out <#863171642905591830> first to see if your issue is known, `
|
||||||
|
+ `and make sure that your app is up-to-date before posting.`;
|
||||||
|
await restClient.createMessage(config.channels.joins, { content: msg });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evt.t == 'MESSAGE_CREATE') {
|
||||||
|
if (evt.d.guild_id != config.guild) return;
|
||||||
|
if (evt.d.author.bot) return;
|
||||||
|
await handleMessage(evt.d).catch(console.error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
console.log('Logging in...');
|
||||||
|
socket.connect("https://gateway.discord.gg");
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
const Logger = require('@lilywonhalf/pretty-logger');
|
|
||||||
const Discord = require('discord.js');
|
|
||||||
const CommandCategory = require('../model/command-category');
|
|
||||||
const Guild = require('../model/guild');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
aliases: ['av'],
|
|
||||||
category: CommandCategory.FUN,
|
|
||||||
isAllowedForContext: () => true,
|
|
||||||
description: 'Displays the avatar of the specified member.',
|
|
||||||
process: async (message, args) => {
|
|
||||||
let user = null;
|
|
||||||
|
|
||||||
if (args.length > 0) {
|
|
||||||
const result = Guild.findDesignatedMemberInMessage(message);
|
|
||||||
|
|
||||||
if (result.foundMembers.length > 0) {
|
|
||||||
if (result.foundMembers[0].user !== undefined) {
|
|
||||||
user = result.foundMembers[0].user;
|
|
||||||
} else {
|
|
||||||
user = result.foundMembers[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
user = message.author;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user !== null) {
|
|
||||||
const url = user.displayAvatarURL({ dynamic: true });
|
|
||||||
|
|
||||||
message.channel.send(new Discord.MessageAttachment(
|
|
||||||
url + '?size=2048',
|
|
||||||
user.id + url.substr(url.lastIndexOf('.'))
|
|
||||||
)).catch(error => Logger.warning(error.toString()));
|
|
||||||
} else {
|
|
||||||
message.reply('I... Have no idea who that could be, sorry.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
25
command/avatar.ts
Normal file
25
command/avatar.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { APIGuildMember, APIUser, GatewayMessageCreateDispatchData } from "discord-api-types/v10";
|
||||||
|
import { restClient } from "../bot";
|
||||||
|
import CommandCategory from "../model/command-category";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
aliases: ['avatar', 'av'],
|
||||||
|
category: CommandCategory.FUN,
|
||||||
|
isAllowedForContext: (_: GatewayMessageCreateDispatchData) => true,
|
||||||
|
description: 'Displays the avatar of the specified member.',
|
||||||
|
process: async (message: GatewayMessageCreateDispatchData, args: string[]) => {
|
||||||
|
let user: APIUser;
|
||||||
|
|
||||||
|
if (message.mentions.length == 0)
|
||||||
|
user = message.author;
|
||||||
|
|
||||||
|
else if (message.mentions.length > 1)
|
||||||
|
return restClient.createMessage(message.channel_id, `<@${message.author.id}>, there are too many mentions in this message! `
|
||||||
|
+`please pick only one user whose avatar you want to show.`);
|
||||||
|
|
||||||
|
else user = message.mentions[0];
|
||||||
|
|
||||||
|
const url = `https://cdn.discordapp.com/avatars/${user.id}/${user.avatar}.png?size=2048`;
|
||||||
|
await restClient.createMessage(message.channel_id, { embed: { image: { url } } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
const Logger = require('@lilywonhalf/pretty-logger');
|
|
||||||
const Config = require('../config.json');
|
|
||||||
const CommandCategory = require('../model/command-category');
|
|
||||||
const CommandPermission = require('../model/command-permission');
|
|
||||||
const { search } = require('../model/jira');
|
|
||||||
|
|
||||||
const MAX_CHARACTERS = 1950;
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
aliases: ['change-log', 'cl'],
|
|
||||||
category: CommandCategory.MODERATION,
|
|
||||||
isAllowedForContext: CommandPermission.isMemberMod,
|
|
||||||
description: 'Builds the changelog for a given version',
|
|
||||||
process: async (message, args) => {
|
|
||||||
|
|
||||||
const errorHandler = async (error) => {
|
|
||||||
if (error) {
|
|
||||||
Logger.exception(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
await message.reactions.removeAll();
|
|
||||||
await message.react('❌');
|
|
||||||
}
|
|
||||||
|
|
||||||
await message.react('⏳').catch(() => {});
|
|
||||||
const issues = args.length > 0 && args[0] ? await search(args[0]).catch(errorHandler) : await search().catch(errorHandler);
|
|
||||||
|
|
||||||
const taskType = Config.jira.issueTypes.task;
|
|
||||||
const bugType = Config.jira.issueTypes.bug;
|
|
||||||
const features = issues.filter(issue => parseInt(issue.fields.issuetype.id) === taskType);
|
|
||||||
const bugs = issues.filter(issue => parseInt(issue.fields.issuetype.id) === bugType);
|
|
||||||
|
|
||||||
if (features.length < 1 && bugs.length < 1) {
|
|
||||||
await message.channel.send('No issues found.');
|
|
||||||
await message.reactions.removeAll().catch(() => {});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const output = `${features.map(
|
|
||||||
issue => `* Feature: ${issue.key} - ${issue.fields.summary}`
|
|
||||||
).join('\n')}\n\n${bugs.map(
|
|
||||||
issue => `* Fixed: ${issue.key} - ${issue.fields.summary}`
|
|
||||||
).join('\n')}`.trim();
|
|
||||||
const messages = [];
|
|
||||||
let currentMessage = '```';
|
|
||||||
|
|
||||||
for (let line of output.split('\n')) {
|
|
||||||
if (currentMessage.length + line.length >= MAX_CHARACTERS) {
|
|
||||||
messages.push(`${currentMessage}\`\`\``);
|
|
||||||
currentMessage = '```';
|
|
||||||
}
|
|
||||||
|
|
||||||
currentMessage = `${currentMessage}\n${line}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
messages.push(`${currentMessage}\`\`\``);
|
|
||||||
|
|
||||||
for (let messageToSend of messages) {
|
|
||||||
await message.channel.send(messageToSend).catch(() => {});
|
|
||||||
}
|
|
||||||
|
|
||||||
await message.reactions.removeAll().catch(() => {});
|
|
||||||
await message.react('✔').catch(() => {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
67
command/changelog.ts
Normal file
67
command/changelog.ts
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
import { GatewayMessageCreateDispatchData } from 'discord-api-types/v10';
|
||||||
|
|
||||||
|
import CommandCategory from '../model/command-category';
|
||||||
|
import * as CommandPermission from '../model/command-permission';
|
||||||
|
|
||||||
|
import config from '../config';
|
||||||
|
import { restClient } from '../bot';
|
||||||
|
|
||||||
|
import search from '../model/jira';
|
||||||
|
|
||||||
|
const MAX_CHARACTERS = 1950;
|
||||||
|
|
||||||
|
export default {
|
||||||
|
aliases: ['changelog', 'change-log', 'cl'],
|
||||||
|
category: CommandCategory.MODERATION,
|
||||||
|
isAllowedForContext: CommandPermission.isMemberMod,
|
||||||
|
description: 'Builds the changelog for a given version',
|
||||||
|
process: async (message: GatewayMessageCreateDispatchData, args: string[]) => {
|
||||||
|
const errorHandler = async (error: any) => {
|
||||||
|
await restClient.deleteReactions(message.channel_id, message.id);
|
||||||
|
await restClient.createReaction(message.channel_id, message.id, '❌');
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
await restClient.createReaction(message.channel_id, message.id, '⏳').catch(() => {});
|
||||||
|
const issues = args.length > 0 && args[0] ? await search(args[0]).catch(errorHandler) : await search().catch(errorHandler);
|
||||||
|
|
||||||
|
const taskType = config.jira.issueTypes.task;
|
||||||
|
const bugType = config.jira.issueTypes.bug;
|
||||||
|
const features = issues?.filter(issue => parseInt(issue.fields.issuetype.id) === taskType) ?? [];
|
||||||
|
const bugs = issues?.filter(issue => parseInt(issue.fields.issuetype.id) === bugType) ?? [];
|
||||||
|
|
||||||
|
if (features.length < 1 && bugs.length < 1) {
|
||||||
|
await restClient.createMessage(message.channel_id, 'No issues found.');
|
||||||
|
await restClient.deleteReactions(message.channel_id, message.id);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const output = `${features.map(
|
||||||
|
issue => `* Feature: ${issue.key} - ${issue.fields.summary}`
|
||||||
|
).join('\n')}\n\n${bugs.map(
|
||||||
|
issue => `* Fixed: ${issue.key} - ${issue.fields.summary}`
|
||||||
|
).join('\n')}`.trim();
|
||||||
|
const messages: string[] = [];
|
||||||
|
let currentMessage = '```';
|
||||||
|
|
||||||
|
for (let line of output.split('\n')) {
|
||||||
|
if (currentMessage.length + line.length >= MAX_CHARACTERS) {
|
||||||
|
messages.push(`${currentMessage}\`\`\``);
|
||||||
|
currentMessage = '```';
|
||||||
|
}
|
||||||
|
|
||||||
|
currentMessage = `${currentMessage}\n${line}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
messages.push(`${currentMessage}\`\`\``);
|
||||||
|
|
||||||
|
for (let messageToSend of messages) {
|
||||||
|
await restClient.createMessage(message.channel_id, messageToSend);
|
||||||
|
}
|
||||||
|
|
||||||
|
await restClient.deleteReactions(message.channel_id, message.id).catch(() => {});
|
||||||
|
await restClient.createReaction(message.channel_id, message.id, '✔');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
const Config = require('../config.json');
|
|
||||||
const CommandCategory = require('../model/command-category');
|
|
||||||
const CommandPermission = require('../model/command-permission');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
aliases: ['clear', 'purge'],
|
|
||||||
category: CommandCategory.MODERATION,
|
|
||||||
isAllowedForContext: CommandPermission.isMemberMod,
|
|
||||||
description: 'Deletes messages in bulk.',
|
|
||||||
process: async (message, args) => {
|
|
||||||
if (args.length > 0 && parseInt(args[0]) > 0) {
|
|
||||||
await message.channel.bulkDelete(Math.min(parseInt(args[0]) + 1, 100));
|
|
||||||
} else {
|
|
||||||
message.reply(`You have to tell me how many messages I should clean. \`${Config.prefix}clean 10\` for example.`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
25
command/clean.ts
Normal file
25
command/clean.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { APIMessage, GatewayMessageCreateDispatchData } from 'discord-api-types/v10';
|
||||||
|
|
||||||
|
import CommandCategory from '../model/command-category';
|
||||||
|
import * as CommandPermission from '../model/command-permission';
|
||||||
|
|
||||||
|
import config from '../config';
|
||||||
|
import { restClient } from '../bot';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
aliases: ['clean', 'clear', 'purge'],
|
||||||
|
category: CommandCategory.MODERATION,
|
||||||
|
isAllowedForContext: CommandPermission.isMemberMod,
|
||||||
|
description: 'Deletes messages in bulk.',
|
||||||
|
process: async (message: GatewayMessageCreateDispatchData, args: string[]) => {
|
||||||
|
if (args.length > 0 && parseInt(args[0]) > 0) {
|
||||||
|
// sometimes abstractions are nice...
|
||||||
|
// await message.channel.bulkDelete(Math.min(parseInt(args[0]) + 1, 100));
|
||||||
|
|
||||||
|
const messages = await restClient.fetchMessages(message.channel_id, { limit: Math.min(parseInt(args[0]) + 1, 100) });
|
||||||
|
restClient.bulkDeleteMessages(message.channel_id, messages.map((x: APIMessage) => x.id));
|
||||||
|
} else {
|
||||||
|
restClient.createMessage(message.channel_id, `You have to tell me how many messages I should clean. \`${config.prefix}clean 10\` for example.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
182
command/embed.js
182
command/embed.js
|
|
@ -1,182 +0,0 @@
|
||||||
const { MessageEmbed, Message } = require('discord.js');
|
|
||||||
const CommandCategory = require('../model/command-category');
|
|
||||||
const CommandPermission = require('../model/command-permission');
|
|
||||||
|
|
||||||
const RGB_REGEX = /(\d{1,3})\D*,\D*(\d{1,3})\D*,\D*(\d{1,3})\D*/u;
|
|
||||||
|
|
||||||
class EmbedDialog
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @param {Message} message
|
|
||||||
*/
|
|
||||||
constructor(message) {
|
|
||||||
this.embed = new MessageEmbed();
|
|
||||||
this.message = message;
|
|
||||||
this.channel = message.channel;
|
|
||||||
this.destinationChannel = null;
|
|
||||||
|
|
||||||
this.prompt = (question, hideSkip = false) => {
|
|
||||||
return this.channel.send(`${question}\n*${!hideSkip ? '`skip` to skip, ' : ''}\`cancel\` to cancel*`);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.isMessageSkip = message => message.content.toLowerCase() === 'skip';
|
|
||||||
|
|
||||||
this.messageFilter = testedMessage => {
|
|
||||||
const byAuthor = testedMessage.author.id === message.author.id;
|
|
||||||
const hasContent = testedMessage.cleanContent.trim().length > 0;
|
|
||||||
|
|
||||||
return byAuthor && hasContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.channelMessageFilter = testedMessage => {
|
|
||||||
return this.messageFilter(testedMessage)
|
|
||||||
&& (this.isMessageSkip(testedMessage) || testedMessage.mentions.channels.size > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.returnFirstOfCollection = collection => collection && collection.size ? collection.first() : null;
|
|
||||||
this.awaitOptions = { max: 1, time: 5 * MINUTE, errors: ['time'] };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {function} filter
|
|
||||||
* @returns {Promise<Message>}
|
|
||||||
*/
|
|
||||||
this.awaitMessage = (filter = this.messageFilter) => {
|
|
||||||
return this.channel.awaitMessages(
|
|
||||||
filter,
|
|
||||||
this.awaitOptions
|
|
||||||
).then(async collection => {
|
|
||||||
let message = this.returnFirstOfCollection(collection);
|
|
||||||
|
|
||||||
if (message && message.content.toLowerCase() === 'cancel') {
|
|
||||||
message = null;
|
|
||||||
await this.channel.send('Cancelling embed creation.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return message;
|
|
||||||
}).catch(async () => {
|
|
||||||
await this.channel.send('Time out, cancelling embed creation.');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async execute() {
|
|
||||||
let confirmation = true;
|
|
||||||
|
|
||||||
await this.prompt('#️⃣ In which **channel** would you like this embed to be posted?');
|
|
||||||
const channelMessage = await this.awaitMessage(this.channelMessageFilter);
|
|
||||||
|
|
||||||
if (!channelMessage) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isMessageSkip(channelMessage)) {
|
|
||||||
this.destinationChannel = this.channel;
|
|
||||||
confirmation = false;
|
|
||||||
} else {
|
|
||||||
this.destinationChannel = channelMessage.mentions.channels.first();
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.prompt('📰 What do you want the **title** of this embed to be (you can also ping someone so it appears as they are saying what is going to be the description)?');
|
|
||||||
const titleMessage = await this.awaitMessage(this.messageFilter);
|
|
||||||
|
|
||||||
if (!titleMessage) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.isMessageSkip(titleMessage)) {
|
|
||||||
if (titleMessage.mentions.members.size > 0) {
|
|
||||||
const member = titleMessage.mentions.members.first();
|
|
||||||
this.embed.setAuthor(member.displayName, member.user.displayAvatarURL({dynamic: true}));
|
|
||||||
} else {
|
|
||||||
this.embed.setTitle(titleMessage.content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.prompt('🎨 What do you want the **color** of this embed to be?');
|
|
||||||
const colourMessage = await this.awaitMessage(this.messageFilter);
|
|
||||||
|
|
||||||
if (!colourMessage) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isMessageSkip(colourMessage)) {
|
|
||||||
this.embed.setColor(APP_MAIN_COLOUR);
|
|
||||||
} else {
|
|
||||||
if (colourMessage.content.startsWith('#')) {
|
|
||||||
this.embed.setColor(parseInt(colourMessage.content.substr(1), 16));
|
|
||||||
} else if (colourMessage.content.startsWith('0x')) {
|
|
||||||
this.embed.setColor(parseInt(colourMessage.content.substr(2), 16));
|
|
||||||
} else if (RGB_REGEX.test(colourMessage.content)) {
|
|
||||||
const [, red, green, blue] = colourMessage.content.match(RGB_REGEX);
|
|
||||||
this.embed.setColor([parseInt(red), parseInt(green), parseInt(blue)]);
|
|
||||||
} else {
|
|
||||||
this.embed.setColor(colourMessage.content.toUpperCase().replace(/[^A-Z]+/gu, '_'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.prompt('💬 What do you want the **description** (contents) of this embed to be?', true);
|
|
||||||
const descriptionMessage = await this.awaitMessage(this.messageFilter);
|
|
||||||
|
|
||||||
if (!descriptionMessage) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.embed.setDescription(descriptionMessage.content);
|
|
||||||
await this.destinationChannel.send(this.embed);
|
|
||||||
|
|
||||||
if (confirmation) {
|
|
||||||
return this.channel.send(`✅ The embed has been posted in ${this.destinationChannel}.`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Embed
|
|
||||||
{
|
|
||||||
static instance = null;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
if (Embed.instance !== null) {
|
|
||||||
return Embed.instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.aliases = [];
|
|
||||||
this.category = CommandCategory.MODERATION;
|
|
||||||
this.isAllowedForContext = CommandPermission.isMemberModOrHelper;
|
|
||||||
this.description = 'Allows to post an embed';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Message} message
|
|
||||||
* @param {Array} args
|
|
||||||
*/
|
|
||||||
async process(message, args) {
|
|
||||||
if (args.length > 0) {
|
|
||||||
let destinationChannel = message.channel;
|
|
||||||
let deleteMessage = true;
|
|
||||||
|
|
||||||
if (/<#\d+>/u.test(args[0])) {
|
|
||||||
destinationChannel = message.mentions.channels.first();
|
|
||||||
args.shift();
|
|
||||||
deleteMessage = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const embed = new MessageEmbed();
|
|
||||||
|
|
||||||
embed.setColor(APP_MAIN_COLOUR);
|
|
||||||
embed.setDescription(args.join(' '));
|
|
||||||
await destinationChannel.send(embed);
|
|
||||||
|
|
||||||
if (deleteMessage) {
|
|
||||||
await message.delete();
|
|
||||||
} else {
|
|
||||||
await message.react('✅');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const dialog = new EmbedDialog(message);
|
|
||||||
|
|
||||||
return dialog.execute();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = new Embed();
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
const Discord = require('discord.js');
|
|
||||||
const Logger = require('@lilywonhalf/pretty-logger');
|
|
||||||
const Config = require('../config.json');
|
|
||||||
const CommandCategory = require('../model/command-category');
|
|
||||||
const CommandPermission = require('../model/command-permission');
|
|
||||||
|
|
||||||
// Including every model here so that it's ready to be used by the command
|
|
||||||
const Guild = require('../model/guild');
|
|
||||||
|
|
||||||
const JAVASCRIPT_LOGO_URL = 'https://i.discord.fr/IEV8.png';
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
aliases: [],
|
|
||||||
category: CommandCategory.BOT_MANAGEMENT,
|
|
||||||
isAllowedForContext: CommandPermission.isMommy,
|
|
||||||
process: async (message) => {
|
|
||||||
const code = message.content
|
|
||||||
.substr(Config.prefix.length + 'eval'.length)
|
|
||||||
.trim()
|
|
||||||
.replace(/(`{3})js\n(.+)\n\1/iu, '$2')
|
|
||||||
.trim();
|
|
||||||
|
|
||||||
await message.react('✔');
|
|
||||||
Logger.notice('Eval: ' + code);
|
|
||||||
let output = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
output = eval(`${code}`); // Spoopy! 🎃 🦇 👻 ☠ 🕷
|
|
||||||
} catch (exception) {
|
|
||||||
output = `**${exception.name}: ${exception.message}**\n${exception.stack}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const embed = new Discord.MessageEmbed()
|
|
||||||
.setAuthor('Eval', JAVASCRIPT_LOGO_URL)
|
|
||||||
.setColor(0x00FF00)
|
|
||||||
.setDescription(output);
|
|
||||||
|
|
||||||
message.channel.send(embed).catch(error => Logger.warning(error.toString()));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
40
command/eval.ts
Normal file
40
command/eval.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
import CommandCategory from "../model/command-category";
|
||||||
|
import * as CommandPermission from '../model/command-permission';
|
||||||
|
|
||||||
|
import config from "../config";
|
||||||
|
import { APIMessage } from "discord-api-types/v10";
|
||||||
|
import { restClient } from "../bot";
|
||||||
|
|
||||||
|
const JAVASCRIPT_LOGO_URL = 'https://i.discord.fr/IEV8.png';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
aliases: ['eval'],
|
||||||
|
category: CommandCategory.BOT_MANAGEMENT,
|
||||||
|
isAllowedForContext: CommandPermission.isMommy,
|
||||||
|
process: async (message: APIMessage) => {
|
||||||
|
const code = message.content
|
||||||
|
.substr(config.prefix.length + 'eval'.length)
|
||||||
|
.trim()
|
||||||
|
.replace(/(`{3})js\n(.+)\n\1/iu, '$2')
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
console.log('Eval: ' + code);
|
||||||
|
let output: string | null = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
output = eval(`${code}`); // Spoopy! 🎃 🦇 👻 ☠ 🕷
|
||||||
|
} catch (exception) {
|
||||||
|
// @ts-expect-error
|
||||||
|
output = `**${exception.name}: ${exception.message}**\n${exception.stack}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
restClient.createMessage(message.channel_id, { embed: {
|
||||||
|
author: {
|
||||||
|
name: 'Eval',
|
||||||
|
iconUrl: JAVASCRIPT_LOGO_URL,
|
||||||
|
},
|
||||||
|
color: 0x00FF00,
|
||||||
|
description: output!,
|
||||||
|
}}).catch(error => console.warn(error.toString()));
|
||||||
|
}
|
||||||
|
};
|
||||||
132
command/help.js
132
command/help.js
|
|
@ -1,132 +0,0 @@
|
||||||
const CommandPermission = require('../model/command-permission');
|
|
||||||
const CommandCategory = require('../model/command-category');
|
|
||||||
|
|
||||||
const commands = require('../model/command').commandList;
|
|
||||||
const messages = require('../model/messages');
|
|
||||||
|
|
||||||
const cachelessRequire = (path) => {
|
|
||||||
if (!typeof path === 'string') {
|
|
||||||
delete require.cache[require.resolve(path)];
|
|
||||||
}
|
|
||||||
|
|
||||||
return typeof path === 'string' ? require(path) : null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const cleanString = (str) => str === null || str === undefined ? null : str
|
|
||||||
.replace('_', ' ')
|
|
||||||
.split(' ')
|
|
||||||
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
||||||
.join(' ');
|
|
||||||
|
|
||||||
const mainPage = (id) => {
|
|
||||||
const buttons = Object.keys(CommandCategory).map(c => ({
|
|
||||||
type: 2,
|
|
||||||
style: 1,
|
|
||||||
label: cleanString(c),
|
|
||||||
custom_id: `help-${id}-${c}`,
|
|
||||||
}))
|
|
||||||
|
|
||||||
return {
|
|
||||||
embeds: [{
|
|
||||||
title: 'Help command',
|
|
||||||
color: 0xA95B44,
|
|
||||||
description:
|
|
||||||
'Spot stands for **S**imply **P**lural b**ot**. This bot is mainly used to generate changelogs and help ' +
|
|
||||||
'with the definition of features, so recurring questions can be answered more quickly.\n' +
|
|
||||||
'\n' +
|
|
||||||
'Commands are classified by categories because displaying every command in this small box would be ' +
|
|
||||||
'confusing and would break Discord\'s character limit. Click on a buttom below to show the commands ' +
|
|
||||||
'available in the corresponding category, or type `.help <category name>`.\n'
|
|
||||||
}],
|
|
||||||
components: [{
|
|
||||||
'type': 1,
|
|
||||||
'components': buttons,
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const categoryPage = (cat, id, direct = false) => {
|
|
||||||
const c = Object.values(CommandCategory).map(x => cleanString(x).toLowerCase());
|
|
||||||
if (!c.includes(cat.toLowerCase()))
|
|
||||||
return;
|
|
||||||
|
|
||||||
let data = {
|
|
||||||
embeds: [{
|
|
||||||
title: `Help command | ${cleanString(cat)}`,
|
|
||||||
color: 0xA95B44,
|
|
||||||
}],
|
|
||||||
components: [{
|
|
||||||
'type': 1,
|
|
||||||
'components': [{
|
|
||||||
type: 2,
|
|
||||||
style: 2,
|
|
||||||
label: 'Back',
|
|
||||||
custom_id: `help-${id}-home`,
|
|
||||||
}],
|
|
||||||
}]
|
|
||||||
};
|
|
||||||
|
|
||||||
if (direct) delete data.components;
|
|
||||||
|
|
||||||
if (cat.toLowerCase() === cleanString(CommandCategory.RESOURCE).toLowerCase())
|
|
||||||
data.embeds[0].fields = messages.getList();
|
|
||||||
else
|
|
||||||
data.embeds[0].fields = Array.from(commands.keys()).map(x => {
|
|
||||||
const cmd = cachelessRequire(commands.get(x));
|
|
||||||
if (cleanString(cmd.category)?.toLowerCase() !== cat.toLowerCase()) return;
|
|
||||||
return { name: x, value: cmd.description ?? 'No description.'};
|
|
||||||
}).filter(x => x);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
aliases: ["commands"],
|
|
||||||
category: CommandCategory.INFO,
|
|
||||||
isAllowedForContext: () => true,
|
|
||||||
description: 'Provides the list of commands.',
|
|
||||||
process: async (message, args) => {
|
|
||||||
if (!args[0])
|
|
||||||
await bot.api.channels(message.channel.id).messages.post({ data: mainPage(message.author.id) });
|
|
||||||
else
|
|
||||||
await bot.api.channels(message.channel.id).messages.post({
|
|
||||||
data:
|
|
||||||
categoryPage(args.join(' '), message.author.id, true)
|
|
||||||
?? {
|
|
||||||
content: 'Category not found.',
|
|
||||||
message_reference: { message_id: message.id, guild_id: message.guild?.id },
|
|
||||||
allowed_mentions: { parse: [] },
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports.interactionHandler = async (event) => {
|
|
||||||
const user = event.member ? event.member.user.id : event.user.id;
|
|
||||||
const customId = event.data.custom_id;
|
|
||||||
|
|
||||||
let ret;
|
|
||||||
|
|
||||||
if (!customId.startsWith(`help-${user}`)) {
|
|
||||||
ret = {
|
|
||||||
type: 4,
|
|
||||||
data: {
|
|
||||||
flags: 64,
|
|
||||||
content: 'This help command was sent by someone else. Please run `.help` again.',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} else if (customId.endsWith('home')) {
|
|
||||||
ret = { type: 7, data: mainPage(user) };
|
|
||||||
} else {
|
|
||||||
let page = categoryPage(cleanString(customId.split(`help-${user}-`).join('')), user);
|
|
||||||
|
|
||||||
if (page) {
|
|
||||||
ret = { type: 7, data: page };
|
|
||||||
} else {
|
|
||||||
ret = { type: 4, data: { flags: 64, content: 'Category not found.' }}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return await bot.api.interactions(event.id, event.token).callback.post({ data: ret })
|
|
||||||
}
|
|
||||||
125
command/help.ts
Normal file
125
command/help.ts
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
import { restClient } from "../bot";
|
||||||
|
import CommandCategory from "../model/command-category";
|
||||||
|
import * as CommandPermission from '../model/command-permission';
|
||||||
|
import * as types from 'discord-api-types/v10';
|
||||||
|
|
||||||
|
import { Command, commands } from "../messageHandler";
|
||||||
|
import * as messages from "../model/messages";
|
||||||
|
import { GatewayMessageCreateDispatchData } from "discord-api-types/v10";
|
||||||
|
|
||||||
|
const cleanString = (str: string | null | undefined) => (str === null || str === undefined) ? undefined : str
|
||||||
|
.replace('_', ' ')
|
||||||
|
.split(' ')
|
||||||
|
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
||||||
|
.join(' ');
|
||||||
|
|
||||||
|
const mainPage = (id: string) => {
|
||||||
|
const buttons = Object.values(CommandCategory).filter(x => typeof x === 'string').map(c => ({
|
||||||
|
type: 2,
|
||||||
|
style: 1,
|
||||||
|
label: cleanString(c),
|
||||||
|
customId: `help-${id}-${c}`,
|
||||||
|
}))
|
||||||
|
|
||||||
|
return {
|
||||||
|
embeds: [{
|
||||||
|
title: 'Help command',
|
||||||
|
color: 0xA95B44,
|
||||||
|
description:
|
||||||
|
'Spot stands for **S**imply **P**lural b**ot**. This bot is mainly used to generate changelogs and help ' +
|
||||||
|
'with the definition of features, so recurring questions can be answered more quickly.\n' +
|
||||||
|
'\n' +
|
||||||
|
'Commands are classified by categories because displaying every command in this small box would be ' +
|
||||||
|
'confusing and would break Discord\'s character limit. Click on a buttom below to show the commands ' +
|
||||||
|
'available in the corresponding category, or type `.help <category name>`.\n'
|
||||||
|
}],
|
||||||
|
components: [{
|
||||||
|
'type': 1,
|
||||||
|
'components': buttons,
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const categoryPage = (cat: string, id: string, direct = false) => {
|
||||||
|
const c = Object.values(CommandCategory).filter(x => typeof x === 'string').map(x => cleanString(x)?.toLowerCase());
|
||||||
|
if (!c.includes(cat.toLowerCase()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
let data = {
|
||||||
|
embeds: [{
|
||||||
|
title: `Help command | ${cleanString(cat)}`,
|
||||||
|
color: 0xA95B44,
|
||||||
|
}],
|
||||||
|
components: [{
|
||||||
|
'type': 1,
|
||||||
|
'components': [{
|
||||||
|
type: 2,
|
||||||
|
style: 2,
|
||||||
|
label: 'Back',
|
||||||
|
customId: `help-${id}-home`,
|
||||||
|
}],
|
||||||
|
}],
|
||||||
|
};
|
||||||
|
|
||||||
|
// @ts-expect-error
|
||||||
|
if (direct) delete data.components;
|
||||||
|
|
||||||
|
if (cat == CommandCategory.RESOURCE)
|
||||||
|
// @ts-expect-error
|
||||||
|
data.embeds[0].fields = messages.getList();
|
||||||
|
else
|
||||||
|
// @ts-expect-error
|
||||||
|
data.embeds[0].fields = commands.map((cmd: Command) => {
|
||||||
|
if (cmd.category !== cat) return;
|
||||||
|
return { name: cmd.aliases[0], value: cmd.description ?? 'No description.'};
|
||||||
|
}).filter(x => x);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
aliases: ['help', "commands", 'h'],
|
||||||
|
category: CommandCategory.INFO,
|
||||||
|
isAllowedForContext: (_: GatewayMessageCreateDispatchData) => true,
|
||||||
|
description: 'Provides the list of commands.',
|
||||||
|
process: async (message: GatewayMessageCreateDispatchData, args: string[]) => {
|
||||||
|
if (!args[0])
|
||||||
|
await restClient.createMessage(message.channel_id, mainPage(message.author.id) );
|
||||||
|
else
|
||||||
|
await restClient.createMessage(message.channel_id, categoryPage(args.join(' '), message.author.id, true)
|
||||||
|
?? {
|
||||||
|
content: 'Category not found.',
|
||||||
|
messageReference: { messageId: message.id, guildId: message.guild_id },
|
||||||
|
allowedMentions: { parse: [] },
|
||||||
|
})
|
||||||
|
},
|
||||||
|
interactionHandler: async (event: types.APIMessageComponentInteraction) => {
|
||||||
|
const user = event.member ? event.member.user.id : event.user!.id;
|
||||||
|
const customId = event.data.custom_id;
|
||||||
|
|
||||||
|
let ret;
|
||||||
|
|
||||||
|
if (!customId.startsWith(`help-${user}`)) {
|
||||||
|
ret = {
|
||||||
|
type: 4,
|
||||||
|
data: {
|
||||||
|
flags: 64,
|
||||||
|
content: 'This help command was sent by someone else. Please run `.help` again.',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else if (customId.endsWith('home')) {
|
||||||
|
ret = { type: 7, data: mainPage(user) };
|
||||||
|
} else {
|
||||||
|
let page = categoryPage(cleanString(customId.split(`help-${user}-`).join(''))!, user);
|
||||||
|
|
||||||
|
if (page) {
|
||||||
|
ret = { type: 7, data: page };
|
||||||
|
} else {
|
||||||
|
ret = { type: 4, data: { flags: 64, content: 'Category not found.' }}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return await restClient.createInteractionResponse(event.id, event.token, ret);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -1,36 +1,38 @@
|
||||||
const CommandCategory = require('../model/command-category');
|
import CommandCategory from "../model/command-category";
|
||||||
const CommandPermission = require('../model/command-permission');
|
import * as CommandPermission from '../model/command-permission';
|
||||||
|
|
||||||
const axios = require('axios');
|
import axios from "axios";
|
||||||
|
import { APIMessage, GatewayMessageCreateDispatchData } from "discord-api-types/v10";
|
||||||
|
import { restClient } from "../bot";
|
||||||
|
|
||||||
module.exports = {
|
export default {
|
||||||
aliases: [],
|
aliases: ['ticket'],
|
||||||
category: CommandCategory.MODERATION,
|
category: CommandCategory.MODERATION,
|
||||||
isAllowedForContext: CommandPermission.isMemberModOrHelper,
|
isAllowedForContext: CommandPermission.isMemberModOrHelper,
|
||||||
process: async (message) => {
|
process: async (message: GatewayMessageCreateDispatchData, args: string[]) => {
|
||||||
if (message.reference == null)
|
if (message.message_reference == null)
|
||||||
return message.reply("missing reply");
|
return restClient.createMessage(message.channel_id, `<@${message.author.id}>, missing reply`);
|
||||||
|
|
||||||
let reply = await message.channel.messages.fetch(message.reference.messageID);
|
let reply: APIMessage = await restClient.fetchMessage(message.channel_id, message.message_reference.message_id!);
|
||||||
|
|
||||||
let user = null;
|
let user = null;
|
||||||
|
|
||||||
if (reply.webhookID != null) {
|
if (reply.webhook_id != null) {
|
||||||
let pkmsg = await axios(`https://api.pluralkit.me/v2/messages/${reply.id}`);
|
let pkmsg = await axios(`https://api.pluralkit.me/v2/messages/${reply.id}`);
|
||||||
user = pkmsg.data.sender;
|
user = pkmsg.data.sender;
|
||||||
} else {
|
} else {
|
||||||
user = reply.author.id;
|
user = reply.author.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
message.delete();
|
restClient.deleteMessage(message.channel_id, message.id).catch(() => {});
|
||||||
message.client.api.channels(message.channel.id).messages.post({ data: {
|
restClient.createMessage(message.channel_id, {
|
||||||
content: `<@${user}>: Please send us a support ticket for your specific issue using this link: <https://apparyllis.atlassian.net/servicedesk/customer/portal/3>\n`
|
content: `<@${user}>: Please send us a support ticket for your specific issue using this link: <https://apparyllis.atlassian.net/servicedesk/customer/portal/3>\n`
|
||||||
+ `You can also click the button below this message.\n\n`
|
+ `You can also click the button below this message.\n\n`
|
||||||
+ `Select the support type that best fits your issue. Make sure to fill out any information that is requested.\n\n`
|
+ `Select the support type that best fits your issue. Make sure to fill out any information that is requested.\n\n`
|
||||||
+ `Once you fill out the ticket, you will receive an email with a confirmation.\nWhen the developer answers the ticket, you will get another email, `
|
+ `Once you fill out the ticket, you will receive an email with a confirmation.\nWhen the developer answers the ticket, you will get another email, `
|
||||||
+ `so please watch your email (and spam folder) for a reply.`,
|
+ `so please watch your email (and spam folder) for a reply.`,
|
||||||
message_reference: { message_id: reply.id },
|
messageReference: { messageId: reply.id },
|
||||||
components: [{ type: 1, components: [{ type: 2, style: 5, label: "Submit ticket", url: "https://apparyllis.atlassian.net/servicedesk/customer/portals" }]}]
|
components: [{ type: 1, components: [{ type: 2, style: 5, label: "Submit ticket", url: "https://apparyllis.atlassian.net/servicedesk/customer/portals" }]}]
|
||||||
}});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
{
|
export default {
|
||||||
"prefix": ".",
|
"prefix": ".",
|
||||||
"guild": "793906174356619286",
|
"guild": "793906174356619286",
|
||||||
"mom": "840806601957965864",
|
"mom": "840806601957965864",
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
const Guild = require('../model/guild');
|
|
||||||
|
|
||||||
module.exports = async (member) => {
|
|
||||||
if ((member.guild === null || isRightGuild(member.guild.id)) && !member.user.bot) {
|
|
||||||
Guild.guildMemberAddHandler(member);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
const Command = require('../model/command');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Message} message
|
|
||||||
*/
|
|
||||||
module.exports = async (message) => {
|
|
||||||
const user = message.author;
|
|
||||||
|
|
||||||
if ((message.guild === null || isRightGuild(message.guild.id)) && !user.bot) {
|
|
||||||
await Command.parseMessage(message);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
const Logger = require('@lilywonhalf/pretty-logger');
|
|
||||||
const Config = require('../config.json');
|
|
||||||
const Guild = require('../model/guild');
|
|
||||||
|
|
||||||
module.exports = async () => {
|
|
||||||
Logger.info('Logged in as ' + bot.user.username + '#' + bot.user.discriminator);
|
|
||||||
|
|
||||||
Logger.info('--------');
|
|
||||||
|
|
||||||
Logger.info('Syncing guilds...');
|
|
||||||
await Guild.init();
|
|
||||||
Logger.info('Guilds synced. Serving in ' + Guild.discordGuild.name);
|
|
||||||
|
|
||||||
Logger.info('--------');
|
|
||||||
|
|
||||||
if (process.argv[3] === '--reboot') {
|
|
||||||
bot.users.cache.get(Config.mom).send(`I'm back :) !`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
46
messageHandler.ts
Normal file
46
messageHandler.ts
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
import * as types from 'discord-api-types/v10';
|
||||||
|
import CommandCategory from './model/command-category';
|
||||||
|
import { restClient } from './bot';
|
||||||
|
import config from './config';
|
||||||
|
|
||||||
|
import avatar from './command/avatar';
|
||||||
|
import changelog from './command/changelog';
|
||||||
|
import clean from './command/clean';
|
||||||
|
import eval from './command/eval';
|
||||||
|
import help from './command/help';
|
||||||
|
import ticket from './command/ticket';
|
||||||
|
|
||||||
|
import * as customMessages from './model/messages';
|
||||||
|
|
||||||
|
export interface Command {
|
||||||
|
aliases: string[];
|
||||||
|
category: CommandCategory;
|
||||||
|
isAllowedForContext(_: types.GatewayMessageCreateDispatchData): boolean;
|
||||||
|
description?: string;
|
||||||
|
process(_: types.GatewayMessageCreateDispatchData, __: string[]): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const privCommands: Record<string, Command> = {};
|
||||||
|
|
||||||
|
export const commands = [avatar, changelog, clean, eval, help, ticket];
|
||||||
|
|
||||||
|
|
||||||
|
commands.map((x: Command) => {
|
||||||
|
x.aliases.map(a => privCommands[a] = x);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default async function handleMessage(message: types.GatewayMessageCreateDispatchData) {
|
||||||
|
if (!message.content.toLowerCase().startsWith(config.prefix))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
let args = message.content.substr(config.prefix.length).trim().split(' ');
|
||||||
|
const calledCommand = args.shift()!.toLowerCase();
|
||||||
|
|
||||||
|
const embed = customMessages.getEmbed(calledCommand);
|
||||||
|
if (embed != null)
|
||||||
|
return await restClient.createMessage(message.channel_id, { embed });
|
||||||
|
|
||||||
|
const foundCommand = privCommands[calledCommand];
|
||||||
|
if (foundCommand == null || !foundCommand.isAllowedForContext(message)) return;
|
||||||
|
await foundCommand.process(message, args);
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
{
|
{
|
||||||
"categories":
|
"categories": {
|
||||||
{
|
|
||||||
"guides": {
|
"guides": {
|
||||||
"name": "Guides",
|
"name": "Guides",
|
||||||
"desc": "Guides on how to do things in the app",
|
"desc": "Guides on how to do things in the app",
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
const CommandCategory = {
|
|
||||||
MODERATION: 'moderation',
|
|
||||||
BOT_MANAGEMENT: 'bot_management',
|
|
||||||
FUN: 'fun',
|
|
||||||
RESOURCE: 'resource'
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = CommandCategory;
|
|
||||||
9
model/command-category.ts
Normal file
9
model/command-category.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
enum CommandCategory {
|
||||||
|
INFO = 'Info',
|
||||||
|
MODERATION = 'Moderation',
|
||||||
|
BOT_MANAGEMENT = 'Bot Managenent',
|
||||||
|
FUN = 'Fun',
|
||||||
|
RESOURCE = 'Resource'
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CommandCategory;
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
const Config = require('../config.json');
|
|
||||||
const Guild = require('./guild');
|
|
||||||
|
|
||||||
const CommandPermission = {
|
|
||||||
/**
|
|
||||||
* @param {Message} message
|
|
||||||
* @returns {Promise.<boolean>}
|
|
||||||
*/
|
|
||||||
isMommy: async (message) => {
|
|
||||||
const member = await Guild.getMemberFromMessage(message);
|
|
||||||
|
|
||||||
return member.id === Config.mom;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Message} message
|
|
||||||
* @returns {Promise.<boolean>}
|
|
||||||
*/
|
|
||||||
isMemberMod: async (message) => {
|
|
||||||
const member = await Guild.getMemberFromMessage(message);
|
|
||||||
|
|
||||||
return member.id === Config.mom || await Guild.isMemberMod(member);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Message} message
|
|
||||||
* @returns {Promise.<boolean>}
|
|
||||||
*/
|
|
||||||
isMemberModOrHelper: async (message) => {
|
|
||||||
const member = await Guild.getMemberFromMessage(message);
|
|
||||||
|
|
||||||
return await CommandPermission.isMemberMod(message) || await Guild.isMemberHelper(member);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = CommandPermission;
|
|
||||||
9
model/command-permission.ts
Normal file
9
model/command-permission.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { GatewayMessageCreateDispatchData } from 'discord-api-types/v10';
|
||||||
|
import config from '../config';
|
||||||
|
|
||||||
|
export const isMommy = (message: GatewayMessageCreateDispatchData) => message.author.id == config.mom;
|
||||||
|
export const isMemberMod = (message: GatewayMessageCreateDispatchData) => message.member!.roles.includes(config.roles.mod);
|
||||||
|
export const isMemberModOrHelper = (message: GatewayMessageCreateDispatchData) =>
|
||||||
|
message.member!.roles.includes(config.roles.mod)
|
||||||
|
|| message.member!.roles.includes(config.roles.helper);
|
||||||
|
|
||||||
105
model/command.js
105
model/command.js
|
|
@ -1,105 +0,0 @@
|
||||||
const fs = require('fs');
|
|
||||||
const Discord = require('discord.js');
|
|
||||||
const Config = require('../config.json');
|
|
||||||
const Guild = require('./guild');
|
|
||||||
|
|
||||||
const customMessages = require("./messages");
|
|
||||||
|
|
||||||
const cachelessRequire = (path) => {
|
|
||||||
if (typeof path === 'string') {
|
|
||||||
delete require.cache[require.resolve(path)];
|
|
||||||
}
|
|
||||||
|
|
||||||
return typeof path === 'string' ? require(path) : null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Command = {
|
|
||||||
commandList: new Discord.Collection(),
|
|
||||||
commandAliases: {},
|
|
||||||
|
|
||||||
init: () => {
|
|
||||||
Command.commandList = new Discord.Collection();
|
|
||||||
Command.commandAliases = {};
|
|
||||||
|
|
||||||
fs.readdirSync('command/').forEach(file => {
|
|
||||||
if (file.substr(file.lastIndexOf('.')).toLowerCase() === '.js') {
|
|
||||||
const commandPath = `../command/${file}`;
|
|
||||||
const commandInstance = cachelessRequire(commandPath);
|
|
||||||
|
|
||||||
if (commandInstance !== null) {
|
|
||||||
const commandName = file.substr(0, file.lastIndexOf('.')).toLowerCase();
|
|
||||||
|
|
||||||
Command.commandList.set(commandName, commandPath);
|
|
||||||
|
|
||||||
if (commandInstance.aliases !== undefined && commandInstance.aliases !== null) {
|
|
||||||
commandInstance.aliases.forEach(alias => {
|
|
||||||
Command.commandAliases[alias.toLowerCase()] = commandName;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Message} message
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
parseMessage: async (message) => {
|
|
||||||
if (!message.content.toLowerCase().startsWith(Config.prefix))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
let content = message.content.substr(Config.prefix.length).trim().split(' ');
|
|
||||||
const calledCommand = content.shift().toLowerCase();
|
|
||||||
|
|
||||||
if (embed = customMessages.getEmbed(calledCommand))
|
|
||||||
return await message.channel.send({embed});
|
|
||||||
|
|
||||||
if (!await Command.isValid(calledCommand, message)) return;
|
|
||||||
|
|
||||||
const member = await Guild.getMemberFromMessage(message);
|
|
||||||
if (member === null)
|
|
||||||
return message.reply('sorry, you do not seem to be on the server.');
|
|
||||||
|
|
||||||
let commandName = calledCommand;
|
|
||||||
|
|
||||||
if (Command.commandAliases.hasOwnProperty(calledCommand))
|
|
||||||
commandName = Command.commandAliases[calledCommand];
|
|
||||||
|
|
||||||
const commandInstance = cachelessRequire(Command.commandList.get(commandName));
|
|
||||||
|
|
||||||
if (commandInstance !== null)
|
|
||||||
commandInstance.process(message, content, Command);
|
|
||||||
else
|
|
||||||
Command.commandList.delete(commandName);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} command
|
|
||||||
* @param {Message} message
|
|
||||||
* @return {Promise.<boolean>}
|
|
||||||
*/
|
|
||||||
isValid: async (command, message) => {
|
|
||||||
let canonicalCommand = command.toLowerCase();
|
|
||||||
let valid = Command.commandList.has(canonicalCommand);
|
|
||||||
|
|
||||||
if (!valid && Command.commandAliases.hasOwnProperty(canonicalCommand)) {
|
|
||||||
canonicalCommand = Command.commandAliases[command];
|
|
||||||
valid = Command.commandList.has(canonicalCommand);
|
|
||||||
}
|
|
||||||
|
|
||||||
const commandInstance = cachelessRequire(Command.commandList.get(canonicalCommand));
|
|
||||||
|
|
||||||
if (commandInstance === null) {
|
|
||||||
Command.commandList.delete(canonicalCommand);
|
|
||||||
}
|
|
||||||
|
|
||||||
valid = valid
|
|
||||||
&& commandInstance !== null
|
|
||||||
&& await commandInstance.isAllowedForContext(message);
|
|
||||||
|
|
||||||
return valid;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = Command;
|
|
||||||
173
model/guild.js
173
model/guild.js
|
|
@ -1,173 +0,0 @@
|
||||||
const Logger = require('@lilywonhalf/pretty-logger');
|
|
||||||
const Config = require('../config.json');
|
|
||||||
const Discord = require('discord.js');
|
|
||||||
|
|
||||||
const cachelessRequire = (path) => {
|
|
||||||
if (typeof path === 'string') {
|
|
||||||
delete require.cache[require.resolve(path)];
|
|
||||||
}
|
|
||||||
|
|
||||||
return typeof path === 'string' ? require(path) : null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Guild = {
|
|
||||||
/** {Guild} */
|
|
||||||
discordGuild: null,
|
|
||||||
|
|
||||||
/** {TextChannel} */
|
|
||||||
joinsChannel: null,
|
|
||||||
|
|
||||||
/** {Collection} */
|
|
||||||
messagesCache: new Discord.Collection(),
|
|
||||||
|
|
||||||
init: async () => {
|
|
||||||
Guild.discordGuild = bot.guilds.cache.find(guild => guild.id === Config.guild);
|
|
||||||
Guild.joinsChannel = Guild.discordGuild.channels.cache.find(channel => channel.id === Config.channels.joins);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param message
|
|
||||||
* @returns {Promise.<GuildMember|null>}
|
|
||||||
*/
|
|
||||||
getMemberFromMessage: async (message) => {
|
|
||||||
return await Guild.discordGuild.members.fetch(message.author).catch(exception => {
|
|
||||||
Logger.error(exception.toString());
|
|
||||||
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {GuildMember} member
|
|
||||||
*/
|
|
||||||
isMemberMod: (member) => {
|
|
||||||
return member !== undefined && member !== null && member.roles.cache.has(Config.roles.mod);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {GuildMember} member
|
|
||||||
*/
|
|
||||||
isMemberHelper: (member) => {
|
|
||||||
return member !== undefined && member !== null && member.roles.cache.has(Config.roles.helper);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} roleName
|
|
||||||
* @returns {Role|null}
|
|
||||||
*/
|
|
||||||
getRoleByName: (roleName) => {
|
|
||||||
return roleName === undefined || roleName === null ? null : Guild.discordGuild.roles.cache.find(
|
|
||||||
role => role.name.toLowerCase() === roleName.toLowerCase()
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {GuildMember} member
|
|
||||||
* @param {Snowflake} snowflake - The Role snowflake.
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
memberHasRole: (member, snowflake) => {
|
|
||||||
return member !== undefined && member !== null && member.roles.cache.some(role => role.id === snowflake);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Message} message
|
|
||||||
* @returns {Discord.MessageEmbed}
|
|
||||||
*/
|
|
||||||
messageToEmbed: async (message) => {
|
|
||||||
const member = await Guild.getMemberFromMessage(message);
|
|
||||||
const suffix = member !== null && member.nickname !== null && member.nickname !== undefined ? ` aka ${member.nickname}` : '';
|
|
||||||
const embeds = message.embeds.filter(embed => embed.author.name && embed.author.iconURL);
|
|
||||||
|
|
||||||
let authorName = `${message.author.username}#${message.author.discriminator}${suffix}`;
|
|
||||||
let authorImage = message.author.displayAvatarURL({ dynamic: true });
|
|
||||||
let description = message.content;
|
|
||||||
let timestamp = message.createdTimestamp;
|
|
||||||
let image = null;
|
|
||||||
|
|
||||||
if (message.attachments.size > 0) {
|
|
||||||
image = message.attachments.first().url;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (description.length < 1 && embeds.length > 0) {
|
|
||||||
const embed = embeds[0];
|
|
||||||
description = embed.description ? embed.description.trim() : '';
|
|
||||||
|
|
||||||
if (message.author.bot) {
|
|
||||||
if (embed.author) {
|
|
||||||
authorName = embed.author.name;
|
|
||||||
authorImage = embed.author.iconURL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (embed.timestamp) {
|
|
||||||
timestamp = embed.timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (embed.image) {
|
|
||||||
image = embed.image.url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Discord.MessageEmbed()
|
|
||||||
.setAuthor(authorName, authorImage)
|
|
||||||
.setColor(0x00FF00)
|
|
||||||
.setDescription(description)
|
|
||||||
.setTimestamp(timestamp)
|
|
||||||
.setImage(image);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Message} message
|
|
||||||
* @returns {{certain: boolean, foundMembers: Array}}
|
|
||||||
*/
|
|
||||||
findDesignatedMemberInMessage: (message) => {
|
|
||||||
let foundMembers = [];
|
|
||||||
let certain = true;
|
|
||||||
const memberList = bot.users.cache.concat(Guild.discordGuild.members.cache);
|
|
||||||
|
|
||||||
if (message.mentions.members !== null && message.mentions.members.size > 0) {
|
|
||||||
foundMembers = message.mentions.members.array();
|
|
||||||
} else if (message.content.match(/[0-9]{18}/u) !== null) {
|
|
||||||
const ids = message.content.match(/[0-9]{18}/gu);
|
|
||||||
|
|
||||||
ids.map(id => {
|
|
||||||
if (memberList.has(id)) {
|
|
||||||
foundMembers.push(memberList.get(id));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
certain = false;
|
|
||||||
memberList.forEach(member => {
|
|
||||||
const user = member.user === undefined ? member : member.user;
|
|
||||||
|
|
||||||
const hasNickname = member.nickname !== undefined && member.nickname !== null;
|
|
||||||
const nickname = hasNickname ? `${member.nickname.toLowerCase()}#${user.discriminator}` : '';
|
|
||||||
const username = `${user.username.toLowerCase()}#${user.discriminator}`;
|
|
||||||
const content = message.cleanContent.toLowerCase().split(' ').splice(1).join(' ');
|
|
||||||
|
|
||||||
if (content.length > 0) {
|
|
||||||
const contentInNickname = hasNickname ? nickname.indexOf(content) > -1 : false;
|
|
||||||
const contentInUsername = username.indexOf(content) > -1;
|
|
||||||
const nicknameInContent = hasNickname ? content.indexOf(nickname) > -1 : false;
|
|
||||||
const usernameInContent = content.indexOf(username) > -1;
|
|
||||||
|
|
||||||
if (contentInNickname || contentInUsername || nicknameInContent || usernameInContent) {
|
|
||||||
foundMembers.push(member);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
certain,
|
|
||||||
foundMembers
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
guildMemberAddHandler: (member) => {
|
|
||||||
Guild.joinsChannel.send(`Welcome, ${member}! If you joined for any specific support questions please check out <#863171642905591830> first to see if your issue is known, and make sure that your app is up-to-date before posting.`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = Guild;
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
const axios = require('axios');
|
|
||||||
const Config = require('../config.json');
|
|
||||||
|
|
||||||
const ENDPOINTS = {
|
|
||||||
search: '/search'
|
|
||||||
};
|
|
||||||
|
|
||||||
class Jira
|
|
||||||
{
|
|
||||||
async search(version) {
|
|
||||||
const params = {
|
|
||||||
'jql': 'project%20%3D%20SP%20AND%20status%20in%20(%22Claimed%20Fixed%22%2C%20%22In%20Pre-Testing%22)%20AND%20updated%20%3E%3D%20-24h%20ORDER%20BY%20created%20DESC',
|
|
||||||
'maxResults': 100,
|
|
||||||
'startAt': 0
|
|
||||||
};
|
|
||||||
|
|
||||||
if (version) {
|
|
||||||
params.jql = `project%20%3D%20SP%20AND%20status%20in%20(%22Claimed%20Fixed%22%2C%20%22In%20Pre-Testing%22)%20AND%20%22Fixed%20In%20Version%5BNumber%5D%22%20%3D%20%22${version}%22%20ORDER%20BY%20created%20DESC`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const issues = [];
|
|
||||||
let response = null;
|
|
||||||
|
|
||||||
do {
|
|
||||||
const httpParams = Object.keys(params).map(key => `${key}=${params[key]}`).join('&');
|
|
||||||
const url = `${Config.jira.baseUrl}${ENDPOINTS.search}?${httpParams}`;
|
|
||||||
response = await axios(url);
|
|
||||||
|
|
||||||
issues.push(...response.data.issues);
|
|
||||||
params.startAt += 100;
|
|
||||||
} while (response.data.issues.length > 99 && response.data.total > 100);
|
|
||||||
|
|
||||||
return issues;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = new Jira();
|
|
||||||
30
model/jira.ts
Normal file
30
model/jira.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import * as axios from 'axios';
|
||||||
|
import config from '../config';
|
||||||
|
|
||||||
|
export default async function search(version?: string): Promise<any[]> {
|
||||||
|
const params = {
|
||||||
|
'jql': 'project%20%3D%20SP%20AND%20status%20in%20(%22Claimed%20Fixed%22%2C%20%22In%20Pre-Testing%22)%20AND%20updated%20%3E%3D%20-24h%20ORDER%20BY%20created%20DESC',
|
||||||
|
'maxResults': 100,
|
||||||
|
'startAt': 0
|
||||||
|
};
|
||||||
|
|
||||||
|
if (version) {
|
||||||
|
params.jql = `project%20%3D%20SP%20AND%20status%20in%20(%22Claimed%20Fixed%22%2C%20%22In%20Pre-Testing%22)%20AND%20%22Fixed%20In%20Version%5BNumber%5D%22%20%3D%20%22${version}%22%20ORDER%20BY%20created%20DESC`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const issues: any[] = [];
|
||||||
|
let response: any | null = null;
|
||||||
|
|
||||||
|
do {
|
||||||
|
// @ts-expect-error
|
||||||
|
const httpParams = Object.keys(params).map(key => `${key}=${params[key]}`).join('&');
|
||||||
|
const url = `${config.jira.baseUrl}/search?${httpParams}`;
|
||||||
|
// what even is this
|
||||||
|
response = JSON.parse((await new axios.Axios({}).get(url)).data);
|
||||||
|
|
||||||
|
issues.push(...response!.issues);
|
||||||
|
params.startAt += 100;
|
||||||
|
} while (response!.issues.length > 99 && response!.total > 100);
|
||||||
|
|
||||||
|
return issues;
|
||||||
|
}
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
const fs = require("fs")
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
const messages = {};
|
|
||||||
|
|
||||||
const load = () =>
|
|
||||||
{
|
|
||||||
const messagesFile = fs.readFileSync(path.join(__dirname, '..', 'messages.json'))
|
|
||||||
const messagesJson = JSON.parse(messagesFile);
|
|
||||||
|
|
||||||
const messagesList = messagesJson["faq"];
|
|
||||||
|
|
||||||
messagesList.forEach((msg) => {
|
|
||||||
messages[msg["title"]] = msg
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
load();
|
|
||||||
|
|
||||||
// interface Message {
|
|
||||||
// names string[];
|
|
||||||
// description string;
|
|
||||||
// title string;
|
|
||||||
// text string;
|
|
||||||
// friendlyName string;
|
|
||||||
// category string;
|
|
||||||
// }
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
get names() {
|
|
||||||
return names;
|
|
||||||
},
|
|
||||||
get messages() {
|
|
||||||
return messages;
|
|
||||||
},
|
|
||||||
get: (name) => messages[name],
|
|
||||||
getList: () => Object.keys(messages).map(msg => ({ name: messages[msg].names[0], value: messages[msg].description })),
|
|
||||||
getEmbed: (name) => {
|
|
||||||
|
|
||||||
let foundMsg = null
|
|
||||||
Object.keys(messages).forEach((msgKey) =>
|
|
||||||
{
|
|
||||||
if (foundMsg) return;
|
|
||||||
|
|
||||||
const msg = messages[msgKey]
|
|
||||||
|
|
||||||
if (msg.names.includes(name))
|
|
||||||
{
|
|
||||||
foundMsg = msg;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!foundMsg) return;
|
|
||||||
|
|
||||||
return {
|
|
||||||
color: "A95B44",
|
|
||||||
author: {
|
|
||||||
name: foundMsg.title,
|
|
||||||
iconURL: bot.user.displayAvatarURL({ dynamic: true }),
|
|
||||||
},
|
|
||||||
description: foundMsg.text,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
58
model/messages.ts
Normal file
58
model/messages.ts
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
import { restClient } from "../bot";
|
||||||
|
|
||||||
|
interface Message {
|
||||||
|
names: string[];
|
||||||
|
description: string;
|
||||||
|
title: string;
|
||||||
|
text: string;
|
||||||
|
friendlyName: string;
|
||||||
|
category: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const messages: Record<string, Message> = {};
|
||||||
|
let avatarUrl = "";
|
||||||
|
|
||||||
|
const load = async () =>
|
||||||
|
{
|
||||||
|
const messagesList = require('../messages.json')["faq"];
|
||||||
|
messagesList.forEach((msg: any) => {
|
||||||
|
messages[msg["title"]] = msg
|
||||||
|
})
|
||||||
|
|
||||||
|
const userInfo = await restClient.fetchMe();
|
||||||
|
avatarUrl = `https://cdn.discordapp.com/avatars/${userInfo.id}/${userInfo.avatar}.png`;
|
||||||
|
console.log(avatarUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
load();
|
||||||
|
|
||||||
|
|
||||||
|
export const get = (name: string) => messages[name];
|
||||||
|
export const getList = () => Object.keys(messages).map(msg => ({ name: messages[msg].names[0], value: messages[msg].description }));
|
||||||
|
|
||||||
|
export const getEmbed = (name: string) => {
|
||||||
|
let foundMsg: Message | undefined;
|
||||||
|
Object.keys(messages).forEach((msgKey) =>
|
||||||
|
{
|
||||||
|
if (foundMsg) return;
|
||||||
|
|
||||||
|
const msg = messages[msgKey]
|
||||||
|
|
||||||
|
if (msg.names.includes(name))
|
||||||
|
{
|
||||||
|
foundMsg = msg;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (foundMsg == null) return;
|
||||||
|
|
||||||
|
return {
|
||||||
|
color: 0xA95B44,
|
||||||
|
author: {
|
||||||
|
name: foundMsg.title,
|
||||||
|
iconUrl: avatarUrl,
|
||||||
|
},
|
||||||
|
description: foundMsg.text,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,9 +9,12 @@
|
||||||
"author": "Lily Wonhalf <lilywonhalf@gmail.com>",
|
"author": "Lily Wonhalf <lilywonhalf@gmail.com>",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lilywonhalf/pretty-logger": "^1.1.3",
|
|
||||||
"axios": "^1.1.3",
|
"axios": "^1.1.3",
|
||||||
"discord.js": "^14.6.0",
|
"detritus-client-rest": "git+https://github.com/Tupperbox/DiscordRest",
|
||||||
"dotenv": "^16.0.3"
|
"detritus-client-socket": "git+https://github.com/Tupperbox/DiscordSocket",
|
||||||
|
"discord-api-types": "^0.37.14",
|
||||||
|
"dotenv": "^16.0.3",
|
||||||
|
"ts-node": "^10.9.1",
|
||||||
|
"typescript": "^4.8.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
334
yarn.lock
334
yarn.lock
|
|
@ -2,138 +2,250 @@
|
||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
"@discordjs/collection@^0.1.6":
|
"@cspotcode/source-map-support@^0.8.0":
|
||||||
"integrity" "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ=="
|
version "0.8.1"
|
||||||
"resolved" "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz"
|
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1"
|
||||||
"version" "0.1.6"
|
integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==
|
||||||
|
|
||||||
"@discordjs/form-data@^3.0.1":
|
|
||||||
"integrity" "sha512-ZfFsbgEXW71Rw/6EtBdrP5VxBJy4dthyC0tpQKGKmYFImlmmrykO14Za+BiIVduwjte0jXEBlhSKf0MWbFp9Eg=="
|
|
||||||
"resolved" "https://registry.npmjs.org/@discordjs/form-data/-/form-data-3.0.1.tgz"
|
|
||||||
"version" "3.0.1"
|
|
||||||
dependencies:
|
dependencies:
|
||||||
"asynckit" "^0.4.0"
|
"@jridgewell/trace-mapping" "0.3.9"
|
||||||
"combined-stream" "^1.0.8"
|
|
||||||
"mime-types" "^2.1.12"
|
|
||||||
|
|
||||||
"@lilywonhalf/pretty-logger@^1.1.3":
|
"@jridgewell/resolve-uri@^3.0.3":
|
||||||
"integrity" "sha512-DcEGjCrQV2j6Hl29G4zD5M/84hzrt1xw7uPOZtZLWFzrCB5OWS/64RWl/y5/om0walTIYf7Nv00hCzfRS8gw4A=="
|
version "3.1.0"
|
||||||
"resolved" "https://registry.npmjs.org/@lilywonhalf/pretty-logger/-/pretty-logger-1.1.3.tgz"
|
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
|
||||||
"version" "1.1.3"
|
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
|
||||||
|
|
||||||
"abort-controller@^3.0.0":
|
"@jridgewell/sourcemap-codec@^1.4.10":
|
||||||
"integrity" "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="
|
version "1.4.14"
|
||||||
"resolved" "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz"
|
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
|
||||||
"version" "3.0.0"
|
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
|
||||||
|
|
||||||
|
"@jridgewell/trace-mapping@0.3.9":
|
||||||
|
version "0.3.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9"
|
||||||
|
integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"event-target-shim" "^5.0.0"
|
"@jridgewell/resolve-uri" "^3.0.3"
|
||||||
|
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||||
|
|
||||||
"asynckit@^0.4.0":
|
"@tsconfig/node10@^1.0.7":
|
||||||
"integrity" "sha1-x57Zf380y48robyXkLzDZkdLS3k= sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
version "1.0.9"
|
||||||
"resolved" "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz"
|
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2"
|
||||||
"version" "0.4.0"
|
integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==
|
||||||
|
|
||||||
"axios@^0.21.1":
|
"@tsconfig/node12@^1.0.7":
|
||||||
"integrity" "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg=="
|
version "1.0.11"
|
||||||
"resolved" "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz"
|
resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d"
|
||||||
"version" "0.21.4"
|
integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==
|
||||||
|
|
||||||
|
"@tsconfig/node14@^1.0.0":
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1"
|
||||||
|
integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==
|
||||||
|
|
||||||
|
"@tsconfig/node16@^1.0.2":
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e"
|
||||||
|
integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==
|
||||||
|
|
||||||
|
"@types/node@^14.17.1":
|
||||||
|
version "14.18.32"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.32.tgz#8074f7106731f1a12ba993fe8bad86ee73905014"
|
||||||
|
integrity sha512-Y6S38pFr04yb13qqHf8uk1nHE3lXgQ30WZbv1mLliV9pt0NjvqdWttLcrOYLnXbOafknVYRHZGoMSpR9UwfYow==
|
||||||
|
|
||||||
|
acorn-walk@^8.1.1:
|
||||||
|
version "8.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
|
||||||
|
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
|
||||||
|
|
||||||
|
acorn@^8.4.1:
|
||||||
|
version "8.8.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8"
|
||||||
|
integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==
|
||||||
|
|
||||||
|
arg@^4.1.0:
|
||||||
|
version "4.1.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
|
||||||
|
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
|
||||||
|
|
||||||
|
asynckit@^0.4.0:
|
||||||
|
version "0.4.0"
|
||||||
|
resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz"
|
||||||
|
integrity "sha1-x57Zf380y48robyXkLzDZkdLS3k= sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||||
|
|
||||||
|
axios@^1.1.3:
|
||||||
|
version "1.1.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/axios/-/axios-1.1.3.tgz#8274250dada2edf53814ed7db644b9c2866c1e35"
|
||||||
|
integrity sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"follow-redirects" "^1.14.0"
|
follow-redirects "^1.15.0"
|
||||||
|
form-data "^4.0.0"
|
||||||
|
proxy-from-env "^1.1.0"
|
||||||
|
|
||||||
"combined-stream@^1.0.8":
|
combined-stream@^1.0.8:
|
||||||
"integrity" "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="
|
version "1.0.8"
|
||||||
"resolved" "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz"
|
resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz"
|
||||||
"version" "1.0.8"
|
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"delayed-stream" "~1.0.0"
|
delayed-stream "~1.0.0"
|
||||||
|
|
||||||
"delayed-stream@~1.0.0":
|
create-require@^1.1.0:
|
||||||
"integrity" "sha1-3zrhmayt+31ECqrgsp4icrJOxhk= sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
|
version "1.1.1"
|
||||||
"resolved" "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
|
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
|
||||||
"version" "1.0.0"
|
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
|
||||||
|
|
||||||
"discord.js@^12.2.0":
|
delayed-stream@~1.0.0:
|
||||||
"integrity" "sha512-D3nkOa/pCkNyn6jLZnAiJApw2N9XrIsXUAdThf01i7yrEuqUmDGc7/CexVWwEcgbQR97XQ+mcnqJpmJ/92B4Aw=="
|
version "1.0.0"
|
||||||
"resolved" "https://registry.npmjs.org/discord.js/-/discord.js-12.5.3.tgz"
|
resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
|
||||||
"version" "12.5.3"
|
integrity "sha1-3zrhmayt+31ECqrgsp4icrJOxhk= sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
|
||||||
|
|
||||||
|
"detritus-client-rest@git+https://github.com/Tupperbox/DiscordRest":
|
||||||
|
version "0.10.5"
|
||||||
|
resolved "git+https://github.com/Tupperbox/DiscordRest#15c7aa2d1782c55c30a60b53f754b6938e658346"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@discordjs/collection" "^0.1.6"
|
detritus-rest "^0.7.0"
|
||||||
"@discordjs/form-data" "^3.0.1"
|
detritus-utils "^0.4.0"
|
||||||
"abort-controller" "^3.0.0"
|
|
||||||
"node-fetch" "^2.6.1"
|
|
||||||
"prism-media" "^1.2.9"
|
|
||||||
"setimmediate" "^1.0.5"
|
|
||||||
"tweetnacl" "^1.0.3"
|
|
||||||
"ws" "^7.4.4"
|
|
||||||
|
|
||||||
"dotenv@^16.0.3":
|
"detritus-client-socket@git+https://github.com/Tupperbox/DiscordSocket":
|
||||||
"integrity" "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ=="
|
version "0.8.3"
|
||||||
"resolved" "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz"
|
resolved "git+https://github.com/Tupperbox/DiscordSocket#44c6815e2e0cb0c6fdf42bc77ff91127413b5c58"
|
||||||
"version" "16.0.3"
|
|
||||||
|
|
||||||
"event-target-shim@^5.0.0":
|
|
||||||
"integrity" "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
|
|
||||||
"resolved" "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz"
|
|
||||||
"version" "5.0.1"
|
|
||||||
|
|
||||||
"follow-redirects@^1.14.0":
|
|
||||||
"integrity" "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
|
|
||||||
"resolved" "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz"
|
|
||||||
"version" "1.15.2"
|
|
||||||
|
|
||||||
"mime-db@1.50.0":
|
|
||||||
"integrity" "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A=="
|
|
||||||
"resolved" "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz"
|
|
||||||
"version" "1.50.0"
|
|
||||||
|
|
||||||
"mime-types@^2.1.12":
|
|
||||||
"integrity" "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g=="
|
|
||||||
"resolved" "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz"
|
|
||||||
"version" "2.1.33"
|
|
||||||
dependencies:
|
dependencies:
|
||||||
"mime-db" "1.50.0"
|
"@types/node" "^14.17.1"
|
||||||
|
detritus-utils "^0.4.0"
|
||||||
|
ws "^7.4.6"
|
||||||
|
|
||||||
"node-fetch@^2.6.1":
|
detritus-rest@^0.7.0:
|
||||||
"integrity" "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ=="
|
version "0.7.0"
|
||||||
"resolved" "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz"
|
resolved "https://registry.yarnpkg.com/detritus-rest/-/detritus-rest-0.7.0.tgz#15d7a98c7038935de7ba2a88eeed83aba1c88ed7"
|
||||||
"version" "2.6.7"
|
integrity sha512-T5FNXpyv5F69ZXEz6z8mWo5yiz7Mhrg+HQsZumih/uDeqf3+1AvZgNI4XLscG1D56F0o5DSyXkoOxDgd2oeTgA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"whatwg-url" "^5.0.0"
|
form-data "^3.0.0"
|
||||||
|
node-fetch "^2.6.1"
|
||||||
|
|
||||||
"prism-media@^1.2.9":
|
detritus-utils@^0.4.0:
|
||||||
"integrity" "sha512-L6UsGHcT6i4wrQhFF1aPK+MNYgjRqR2tUoIqEY+CG1NqVkMjPRKzS37j9f8GiYPlD6wG9ruBj+q5Ax+bH8Ik1g=="
|
version "0.4.0"
|
||||||
"resolved" "https://registry.npmjs.org/prism-media/-/prism-media-1.3.2.tgz"
|
resolved "https://registry.yarnpkg.com/detritus-utils/-/detritus-utils-0.4.0.tgz#42c01e029bd716c5be30a82ee4c621136f64ef35"
|
||||||
"version" "1.3.2"
|
integrity sha512-XO9crk1eCOecajzOg4WMsvcgXV/3GAltV0nt+kXXmglwcKyh/5DpQ7jmQ/2HycEN0dGBdgLCLPzYMxrWPN9gpw==
|
||||||
|
|
||||||
"setimmediate@^1.0.5":
|
diff@^4.0.1:
|
||||||
"integrity" "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="
|
version "4.0.2"
|
||||||
"resolved" "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz"
|
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
|
||||||
"version" "1.0.5"
|
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
|
||||||
|
|
||||||
"tr46@~0.0.3":
|
discord-api-types@^0.37.14:
|
||||||
"integrity" "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
version "0.37.14"
|
||||||
"resolved" "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz"
|
resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.37.14.tgz#0fb10a5bb3ff9415afac12d7eaecc68b430d372a"
|
||||||
"version" "0.0.3"
|
integrity sha512-byBH7SfDCMJwxdqeS8k5sihltH88/YPhuwx+vF2cftSxFLdxyHyU/ZxDL3bq+LB2c4ls/TymE76/ISlLfniUXg==
|
||||||
|
|
||||||
"tweetnacl@^1.0.3":
|
dotenv@^16.0.3:
|
||||||
"integrity" "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="
|
version "16.0.3"
|
||||||
"resolved" "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz"
|
resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz"
|
||||||
"version" "1.0.3"
|
integrity sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==
|
||||||
|
|
||||||
"webidl-conversions@^3.0.0":
|
follow-redirects@^1.15.0:
|
||||||
"integrity" "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
version "1.15.2"
|
||||||
"resolved" "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz"
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
|
||||||
"version" "3.0.1"
|
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
|
||||||
|
|
||||||
"whatwg-url@^5.0.0":
|
form-data@^3.0.0:
|
||||||
"integrity" "sha1-lmRU6HZUYuN2RNNib2dCzotwll0= sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="
|
version "3.0.1"
|
||||||
"resolved" "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz"
|
resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f"
|
||||||
"version" "5.0.0"
|
integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"tr46" "~0.0.3"
|
asynckit "^0.4.0"
|
||||||
"webidl-conversions" "^3.0.0"
|
combined-stream "^1.0.8"
|
||||||
|
mime-types "^2.1.12"
|
||||||
|
|
||||||
"ws@^7.4.4":
|
form-data@^4.0.0:
|
||||||
"integrity" "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w=="
|
version "4.0.0"
|
||||||
"resolved" "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz"
|
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
|
||||||
"version" "7.5.5"
|
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
|
||||||
|
dependencies:
|
||||||
|
asynckit "^0.4.0"
|
||||||
|
combined-stream "^1.0.8"
|
||||||
|
mime-types "^2.1.12"
|
||||||
|
|
||||||
|
make-error@^1.1.1:
|
||||||
|
version "1.3.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
|
||||||
|
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
|
||||||
|
|
||||||
|
mime-db@1.50.0:
|
||||||
|
version "1.50.0"
|
||||||
|
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz"
|
||||||
|
integrity sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==
|
||||||
|
|
||||||
|
mime-types@^2.1.12:
|
||||||
|
version "2.1.33"
|
||||||
|
resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz"
|
||||||
|
integrity sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==
|
||||||
|
dependencies:
|
||||||
|
mime-db "1.50.0"
|
||||||
|
|
||||||
|
node-fetch@^2.6.1:
|
||||||
|
version "2.6.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
|
||||||
|
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
|
||||||
|
dependencies:
|
||||||
|
whatwg-url "^5.0.0"
|
||||||
|
|
||||||
|
proxy-from-env@^1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
|
||||||
|
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
|
||||||
|
|
||||||
|
tr46@~0.0.3:
|
||||||
|
version "0.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
|
||||||
|
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
|
||||||
|
|
||||||
|
ts-node@^10.9.1:
|
||||||
|
version "10.9.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b"
|
||||||
|
integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==
|
||||||
|
dependencies:
|
||||||
|
"@cspotcode/source-map-support" "^0.8.0"
|
||||||
|
"@tsconfig/node10" "^1.0.7"
|
||||||
|
"@tsconfig/node12" "^1.0.7"
|
||||||
|
"@tsconfig/node14" "^1.0.0"
|
||||||
|
"@tsconfig/node16" "^1.0.2"
|
||||||
|
acorn "^8.4.1"
|
||||||
|
acorn-walk "^8.1.1"
|
||||||
|
arg "^4.1.0"
|
||||||
|
create-require "^1.1.0"
|
||||||
|
diff "^4.0.1"
|
||||||
|
make-error "^1.1.1"
|
||||||
|
v8-compile-cache-lib "^3.0.1"
|
||||||
|
yn "3.1.1"
|
||||||
|
|
||||||
|
typescript@^4.8.4:
|
||||||
|
version "4.8.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6"
|
||||||
|
integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==
|
||||||
|
|
||||||
|
v8-compile-cache-lib@^3.0.1:
|
||||||
|
version "3.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
|
||||||
|
integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==
|
||||||
|
|
||||||
|
webidl-conversions@^3.0.0:
|
||||||
|
version "3.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
|
||||||
|
integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
|
||||||
|
|
||||||
|
whatwg-url@^5.0.0:
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
|
||||||
|
integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
|
||||||
|
dependencies:
|
||||||
|
tr46 "~0.0.3"
|
||||||
|
webidl-conversions "^3.0.0"
|
||||||
|
|
||||||
|
ws@^7.4.6:
|
||||||
|
version "7.5.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591"
|
||||||
|
integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==
|
||||||
|
|
||||||
|
yn@3.1.1:
|
||||||
|
version "3.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
|
||||||
|
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue