123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- import { isAuthorisedAsync } from "../util";
- import { Message } from "discord.js";
- import { getRepository } from "typeorm";
- import { Guide, GuideType, GuideKeyword } from "@shared/db/entity/Guide";
- import { CommandSet, Action, ActionType, Command } from "src/model/command";
- @CommandSet
- export class GuideCommands {
- async matchGuide(keywords: string[]) {
- let a = await getRepository(Guide).query(
- `select guide.*
- from guide
- inner join (select gk."guideId", count("guideKeywordId") as gc
- from guide_keywords_guide_keyword as gk
- where
- gk."guideKeywordId" in (select id
- from guide_keyword
- where
- guide_keyword.keyword in (${keywords.map((v, i) => `$${i + 1}`).join(",")}))
- group by gk."guideId") as gks
- on gks."guideId" = guide.id
- order by gc desc
- limit 1`,
- keywords
- ) as Guide[];
- if (a.length == 0)
- return null;
- return a[0];
- }
- async listGuides(msg: Message, guideType: string, message: string) {
- let repo = getRepository(Guide);
- let allGuides = await repo.createQueryBuilder("guide")
- .select(["guide.displayName"])
- .leftJoinAndSelect("guide.keywords", "keyword")
- .where("guide.type = :type", { type: guideType })
- .getMany();
- const MAX_GUIDES_PER_MSG = 30;
- let guides = `${msg.author.toString()} ${message}\n\`\`\``;
- let guideNum = 0;
- for (let guide of allGuides) {
- guides += `${guide.displayName} -- ${guide.keywords.map(k => k.keyword).join(" ")}\n`;
- guideNum++;
- if (guideNum == MAX_GUIDES_PER_MSG) {
- guides += "```";
- await msg.channel.send(guides);
- guides = "```\n";
- guideNum = 0;
- }
- }
- if (guideNum != 0) {
- guides += "```\n\nTo display the guides, ping me with one or more keywords, like `@NoctBot sybaris com`";
- await msg.channel.send(guides);
- }
- }
- @Action(ActionType.DIRECT_MENTION)
- async displayGuide(actionsDone: boolean, msg: Message, content: string) {
- if (actionsDone)
- return false;
- if (msg.attachments.size > 0 || content.length == 0)
- return false;
- let parts = content.split(" ").map(s => s.trim()).filter(s => s.length != 0);
- let guide = await this.matchGuide(parts);
- if (guide) {
- msg.channel.send(guide.content);
- return true;
- }
- return false;
- }
- @Command({
- pattern: /^make (\w+)\s+name:(.+)\s*keywords:(.+)\s*contents:((.*[\n\r]*)+)$/i,
- auth: true,
- documentation: {
- description: "Creates a new guide of the specified type, the specified keywords and content.",
- example: "make <GUIDE TYPE> <NEWLINE>name: <NAME> <NEWLINE> keywords: <KEYWORDS> <NEWLINE> contents: <CONTENTS>"
- }
- })
- async makeGuide(msg: Message, content: string, match: RegExpMatchArray) {
- if (!await isAuthorisedAsync(msg.member)) return;
- let type = match[1].toLowerCase();
- let name = match[2].trim();
- let keywords = match[3].toLowerCase().split(" ").map(s => s.trim()).filter(s => s.length != 0);
- let contents = match[4].trim();
- if (contents.length == 0) {
- msg.channel.send(
- `${msg.author.toString()} The guide must have some content!`
- );
- return;
- }
-
- if (!(<string[]>Object.values(GuideType)).includes(type)) {
- msg.channel.send(
- `${msg.author.toString()} The type ${type} is not a valid guide type!`
- );
- return;
- }
- let repo = getRepository(GuideKeyword);
- let guideRepo = getRepository(Guide);
- let existingKeywords = await repo.find({
- where: [
- ...keywords.map(k => ({ keyword: k }))
- ]
- });
- let existingGuide = await this.matchGuide(keywords);
- let addGuide = async () => {
- let newKeywords = new Set<string>();
- let knownKeywords = new Set(existingKeywords.map(e => e.keyword));
- for (let word of keywords) {
- if (!knownKeywords.has(word))
- newKeywords.add(word);
- }
- let addedKeywords = await repo.save([...newKeywords].map(k => repo.create({
- keyword: k
- })));
- await guideRepo.save(guideRepo.create({
- content: contents,
- displayName: name,
- keywords: [...existingKeywords, ...addedKeywords],
- type: type as GuideType
- }));
- };
- if (existingGuide) {
- let guideKeywordsCount = await repo
- .createQueryBuilder("keywords")
- .leftJoinAndSelect("keywords.relatedGuides", "guide")
- .where("guide.id = :id", { id: existingGuide.id })
- .getCount();
- if (guideKeywordsCount == existingKeywords.length)
- await guideRepo.update({ id: existingGuide.id }, {
- displayName: name,
- content: contents
- });
- else
- await addGuide();
- } else
- await addGuide();
- msg.channel.send(
- `${msg.author.toString()} Added/updated "${name}" (keywords \`${keywords.join(" ")}\`)!`
- );
- }
- @Command({
- pattern: /^delete (\w+)\s+(.+)$/i,
- auth: true,
- documentation: {
- example: "delete <guidetype> <keywords>",
- description: "Deletes a guide with the specified keywords"
- }
- })
- async deleteGuide(msg: Message, content: string, match: RegExpMatchArray) {
- if (!await isAuthorisedAsync(msg.member)) return;
- let type = match[1];
- let keywords = match[2].toLowerCase().split(" ").map(s => s.trim()).filter(s => s.length != 0);
- if (!(<string[]>Object.values(GuideType)).includes(type)) {
- await msg.channel.send(
- `${msg.author.toString()} The type ${type} is not a valid guide type!`
- );
- return;
- }
- let dedupedKeywords = [...new Set(keywords)];
- let repo = getRepository(GuideKeyword);
- let guideRepo = getRepository(Guide);
- let existingGuide = await this.matchGuide(keywords);
- if (existingGuide) {
- let guideKeywordsCount = await repo
- .createQueryBuilder("keywords")
- .leftJoinAndSelect("keywords.relatedGuides", "guide")
- .where("guide.id = :id", { id: existingGuide.id })
- .getCount();
- if (guideKeywordsCount == dedupedKeywords.length) {
- await guideRepo.delete({ id: existingGuide.id });
- await msg.channel.send(`${msg.author.toString()} Removed ${type} "${keywords.join(" ")}"!`);
- return;
- }
- }
- await msg.channel.send(`${msg.author.toString()} No such ${type} with keywords \`${keywords.join(" ")}\`! Did you forget to specify all keywords?`);
- }
- @Command({ pattern: "guides", documentation: { description: "Lists all guides and keywords that trigger them.", example: "guides" } })
- async showGuides(msg: Message) {
- await this.listGuides(msg, "guide", "Here are the guides I have:");
- }
- @Command({ pattern: "memes", documentation: {description: "Lists all memes and keywords that trigger them.", example: "memes"} })
- async showMemes(msg: Message) {
- await this.listGuides(msg, "meme", "Here are some random memes I have:")
- }
- @Command({ pattern: "misc", documentation: {description: "Lists all additional keywords the bot reacts to.", example: "misc"} })
- async showMisc(msg: Message) {
- await this.listGuides(msg, "misc", "These are some misc stuff I can also do:")
- }
- };
|