From 4a1a14be5923b393d196a9c19b08e7bf40e4810e Mon Sep 17 00:00:00 2001 From: Dragory Date: Sun, 5 Aug 2018 01:32:59 +0300 Subject: [PATCH] Add Tags plugin --- .../20180805011100_create_tags_table.js | 17 +++++ src/data/GuildTags.ts | 48 ++++++++++++ src/index.ts | 12 ++- src/models/Tag.ts | 9 +++ src/plugins/Tags.ts | 73 +++++++++++++++++++ src/utils.ts | 4 +- 6 files changed, 158 insertions(+), 5 deletions(-) create mode 100644 migrations/20180805011100_create_tags_table.js create mode 100644 src/data/GuildTags.ts create mode 100644 src/models/Tag.ts create mode 100644 src/plugins/Tags.ts diff --git a/migrations/20180805011100_create_tags_table.js b/migrations/20180805011100_create_tags_table.js new file mode 100644 index 00000000..2cbab3c2 --- /dev/null +++ b/migrations/20180805011100_create_tags_table.js @@ -0,0 +1,17 @@ +exports.up = async function(knex) { + if (! await knex.schema.hasTable('tags')) { + await knex.schema.createTable('tags', table => { + table.bigInteger('guild_id').unsigned().notNullable(); + table.string('tag', 64).notNullable(); + table.bigInteger('user_id').unsigned().notNullable(); + table.text('body').notNullable(); + table.dateTime('created_at').defaultTo(knex.raw('NOW()')); + + table.primary(['guild_id', 'tag']); + }); + } +}; + +exports.down = async function(knex) { + await knex.schema.dropTableIfExists('tags'); +}; diff --git a/src/data/GuildTags.ts b/src/data/GuildTags.ts new file mode 100644 index 00000000..f432642b --- /dev/null +++ b/src/data/GuildTags.ts @@ -0,0 +1,48 @@ +import knex from "../knex"; +import moment from "moment-timezone"; +import Tag from "../models/Tag"; + +export class GuildTags { + protected guildId: string; + + constructor(guildId) { + this.guildId = guildId; + } + + async find(tag): Promise { + const result = await knex("tags") + .where("guild_id", this.guildId) + .where("tag", tag) + .first(); + + return result ? new Tag(result) : null; + } + + async createOrUpdate(tag, body, userId) { + const existingTag = await this.find(tag); + if (existingTag) { + await knex("tags") + .where("guild_id", this.guildId) + .where("tag", tag) + .update({ + body, + user_id: userId, + created_at: knex.raw("NOW()") + }); + } else { + await knex("tags").insert({ + guild_id: this.guildId, + user_id: userId, + tag, + body + }); + } + } + + async delete(tag) { + await knex("tags") + .where("guild_id", this.guildId) + .where("tag", tag) + .delete(); + } +} diff --git a/src/index.ts b/src/index.ts index db39d9b9..a5bc560e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -23,7 +23,13 @@ moment.tz.setDefault("UTC"); import { Client } from "eris"; import { Knub, logger } from "knub"; +import knex from "./knex"; + +// Global plugins import { BotControlPlugin } from "./plugins/BotControl"; +import { LogServerPlugin } from "./plugins/LogServer"; + +// Guild plugins import { ModActionsPlugin } from "./plugins/ModActions"; import { UtilityPlugin } from "./plugins/Utility"; import { LogsPlugin } from "./plugins/Logs"; @@ -32,8 +38,7 @@ import { ReactionRolesPlugin } from "./plugins/ReactionRoles"; import { CensorPlugin } from "./plugins/Censor"; import { PersistPlugin } from "./plugins/Persist"; import { SpamPlugin } from "./plugins/Spam"; -import { LogServerPlugin } from "./plugins/LogServer"; -import knex from "./knex"; +import { TagsPlugin } from "./plugins/Tags"; // Run latest database migrations logger.info("Running database migrations"); @@ -52,7 +57,8 @@ knex.migrate.latest().then(() => { reaction_roles: ReactionRolesPlugin, censor: CensorPlugin, persist: PersistPlugin, - spam: SpamPlugin + spam: SpamPlugin, + tags: TagsPlugin }, globalPlugins: { bot_control: BotControlPlugin, diff --git a/src/models/Tag.ts b/src/models/Tag.ts new file mode 100644 index 00000000..343de491 --- /dev/null +++ b/src/models/Tag.ts @@ -0,0 +1,9 @@ +import Model from "./Model"; + +export default class Tag extends Model { + public guild_id: string; + public tag: string; + public user_id: string; + public body: string; + public created_at: string; +} diff --git a/src/plugins/Tags.ts b/src/plugins/Tags.ts new file mode 100644 index 00000000..948afc66 --- /dev/null +++ b/src/plugins/Tags.ts @@ -0,0 +1,73 @@ +import { Plugin, decorators as d } from "knub"; +import { Channel, Message, TextChannel } from "eris"; +import { errorMessage, successMessage } from "../utils"; +import { GuildTags } from "../data/GuildTags"; + +export class TagsPlugin extends Plugin { + protected tags: GuildTags; + + getDefaultOptions() { + return { + config: { + prefix: "!!" + }, + + permissions: { + create: false, + use: true + }, + + overrides: [ + { + level: ">=50", + permissions: { + create: true + } + } + ] + }; + } + + onLoad() { + this.tags = new GuildTags(this.guildId); + } + + @d.command("tag", " ") + @d.permission("create") + async tagCmd(msg: Message, args: { tag: string; body: string }) { + await this.tags.createOrUpdate(args.tag, args.body, msg.author.id); + + const prefix = this.configValue("prefix"); + msg.channel.createMessage(successMessage(`Tag set! Use it with: \`${prefix}${args.tag}\``)); + } + + @d.command("tag_delete", "") + @d.permission("create") + async deleteTagCmd(msg: Message, args: { tag: string }) { + const tag = await this.tags.find(args.tag); + if (!tag) { + msg.channel.createMessage(errorMessage("No tag with that name")); + return; + } + + await this.tags.delete(args.tag); + msg.channel.createMessage(successMessage("Tag deleted!")); + } + + @d.event("messageCreate") + @d.permission("use") + async onMessageCreate(msg: Message) { + if (!msg.content) return; + if (msg.type !== 0) return; + if (!msg.author || msg.author.bot) return; + + const prefix = this.configValueForMsg(msg, "prefix"); + if (!msg.content.startsWith(prefix)) return; + + const withoutPrefix = msg.content.slice(prefix.length); + const tag = await this.tags.find(withoutPrefix); + if (!tag) return; + + msg.channel.createMessage(tag.body); + } +} diff --git a/src/utils.ts b/src/utils.ts index a6b4649f..f641f9f5 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -74,8 +74,8 @@ export function stripObjectToScalars(obj, includedNested: string[] = []) { const stringFormatRegex = /{([^{}]+?)}/g; export function formatTemplateString(str: string, values) { - return str.replace(stringFormatRegex, (match, val) => { - const value = at(values, val)[0]; + return str.replace(stringFormatRegex, (match, prop) => { + const value = at(values, prop)[0]; return typeof value === "string" || typeof value === "number" ? String(value) : ""; }); }