From ed344be4b5cd03f6752147b0b92a276114d0c9a8 Mon Sep 17 00:00:00 2001 From: Dark <7890309+DarkView@users.noreply.github.com> Date: Tue, 21 Jul 2020 23:11:05 +0200 Subject: [PATCH] Migrate PingableRoles to new Plugin structure --- .../PingableRoles/PingableRolesPlugin.ts | 46 ++++++++++++++++++ .../commands/PingableRoleDisableCmd.ts | 30 ++++++++++++ .../commands/PingableRoleEnableCmd.ts | 37 +++++++++++++++ .../events/ChangePingableEvts.ts | 47 +++++++++++++++++++ backend/src/plugins/PingableRoles/types.ts | 22 +++++++++ .../utils/disablePingableRoles.ts | 17 +++++++ .../utils/enablePingableRoles.ts | 17 +++++++ .../utils/getPingableRolesForChannel.ts | 14 ++++++ backend/src/plugins/availablePlugins.ts | 2 + 9 files changed, 232 insertions(+) create mode 100644 backend/src/plugins/PingableRoles/PingableRolesPlugin.ts create mode 100644 backend/src/plugins/PingableRoles/commands/PingableRoleDisableCmd.ts create mode 100644 backend/src/plugins/PingableRoles/commands/PingableRoleEnableCmd.ts create mode 100644 backend/src/plugins/PingableRoles/events/ChangePingableEvts.ts create mode 100644 backend/src/plugins/PingableRoles/types.ts create mode 100644 backend/src/plugins/PingableRoles/utils/disablePingableRoles.ts create mode 100644 backend/src/plugins/PingableRoles/utils/enablePingableRoles.ts create mode 100644 backend/src/plugins/PingableRoles/utils/getPingableRolesForChannel.ts diff --git a/backend/src/plugins/PingableRoles/PingableRolesPlugin.ts b/backend/src/plugins/PingableRoles/PingableRolesPlugin.ts new file mode 100644 index 00000000..50c705c3 --- /dev/null +++ b/backend/src/plugins/PingableRoles/PingableRolesPlugin.ts @@ -0,0 +1,46 @@ +import { PluginOptions } from "knub"; +import { PingableRolesPluginType, ConfigSchema } from "./types"; +import { zeppelinPlugin } from "../ZeppelinPluginBlueprint"; +import { GuildPingableRoles } from "src/data/GuildPingableRoles"; +import { PingableRoleEnableCmd } from "./commands/PingableRoleEnableCmd"; +import { PingableRoleDisableCmd } from "./commands/PingableRoleDisableCmd"; +import { TypingEnablePingableEvt, MessageCreateDisablePingableEvt } from "./events/ChangePingableEvts"; + +const defaultOptions: PluginOptions = { + config: { + can_manage: false, + }, + overrides: [ + { + level: ">=100", + config: { + can_manage: true, + }, + }, + ], +}; + +export const PingableRolesPlugin = zeppelinPlugin()("pingable_roles", { + configSchema: ConfigSchema, + defaultOptions, + + // prettier-ignore + commands: [ + PingableRoleEnableCmd, + PingableRoleDisableCmd, + ], + + // prettier-ignore + events: [ + TypingEnablePingableEvt, + MessageCreateDisablePingableEvt, + ], + + onLoad(pluginData) { + const { state, guild } = pluginData; + + state.pingableRoles = GuildPingableRoles.getGuildInstance(guild.id); + state.cache = new Map(); + state.timeouts = new Map(); + }, +}); diff --git a/backend/src/plugins/PingableRoles/commands/PingableRoleDisableCmd.ts b/backend/src/plugins/PingableRoles/commands/PingableRoleDisableCmd.ts new file mode 100644 index 00000000..9d635d0f --- /dev/null +++ b/backend/src/plugins/PingableRoles/commands/PingableRoleDisableCmd.ts @@ -0,0 +1,30 @@ +import { commandTypeHelpers as ct } from "../../../commandTypes"; +import { pingableRolesCmd } from "../types"; +import { sendErrorMessage, sendSuccessMessage } from "src/pluginUtils"; + +export const PingableRoleDisableCmd = pingableRolesCmd({ + trigger: ["pingable_role disable", "pingable_role d"], + permission: "can_manage", + + signature: { + channelId: ct.channelId(), + role: ct.role(), + }, + + async run({ message: msg, args, pluginData }) { + const pingableRole = await pluginData.state.pingableRoles.getByChannelAndRoleId(args.channelId, args.role.id); + if (!pingableRole) { + sendErrorMessage(pluginData, msg.channel, `**${args.role.name}** is not set as pingable in <#${args.channelId}>`); + return; + } + + await pluginData.state.pingableRoles.delete(args.channelId, args.role.id); + pluginData.state.cache.delete(args.channelId); + + sendSuccessMessage( + pluginData, + msg.channel, + `**${args.role.name}** is no longer set as pingable in <#${args.channelId}>`, + ); + }, +}); diff --git a/backend/src/plugins/PingableRoles/commands/PingableRoleEnableCmd.ts b/backend/src/plugins/PingableRoles/commands/PingableRoleEnableCmd.ts new file mode 100644 index 00000000..9927e49a --- /dev/null +++ b/backend/src/plugins/PingableRoles/commands/PingableRoleEnableCmd.ts @@ -0,0 +1,37 @@ +import { commandTypeHelpers as ct } from "../../../commandTypes"; +import { pingableRolesCmd } from "../types"; +import { sendErrorMessage, sendSuccessMessage } from "src/pluginUtils"; + +export const PingableRoleEnableCmd = pingableRolesCmd({ + trigger: "pingable_role", + permission: "can_manage", + + signature: { + channelId: ct.channelId(), + role: ct.role(), + }, + + async run({ message: msg, args, pluginData }) { + const existingPingableRole = await pluginData.state.pingableRoles.getByChannelAndRoleId( + args.channelId, + args.role.id, + ); + if (existingPingableRole) { + sendErrorMessage( + pluginData, + msg.channel, + `**${args.role.name}** is already set as pingable in <#${args.channelId}>`, + ); + return; + } + + await pluginData.state.pingableRoles.add(args.channelId, args.role.id); + pluginData.state.cache.delete(args.channelId); + + sendSuccessMessage( + pluginData, + msg.channel, + `**${args.role.name}** has been set as pingable in <#${args.channelId}>`, + ); + }, +}); diff --git a/backend/src/plugins/PingableRoles/events/ChangePingableEvts.ts b/backend/src/plugins/PingableRoles/events/ChangePingableEvts.ts new file mode 100644 index 00000000..82afa7f2 --- /dev/null +++ b/backend/src/plugins/PingableRoles/events/ChangePingableEvts.ts @@ -0,0 +1,47 @@ +import { pingableRolesEvt } from "../types"; +import { getPingableRolesForChannel } from "../utils/getPingableRolesForChannel"; +import { enablePingableRoles } from "../utils/enablePingableRoles"; +import { disablePingableRoles } from "../utils/disablePingableRoles"; + +const TIMEOUT = 10 * 1000; + +export const TypingEnablePingableEvt = pingableRolesEvt({ + event: "typingStart", + + async listener(meta) { + const pluginData = meta.pluginData; + const channel = meta.args.channel; + + const pingableRoles = await getPingableRolesForChannel(pluginData, channel.id); + if (pingableRoles.length === 0) return; + + if (pluginData.state.timeouts.has(channel.id)) { + clearTimeout(pluginData.state.timeouts.get(channel.id)); + } + + enablePingableRoles(pluginData, pingableRoles); + + const timeout = setTimeout(() => { + disablePingableRoles(pluginData, pingableRoles); + }, TIMEOUT); + pluginData.state.timeouts.set(channel.id, timeout); + }, +}); + +export const MessageCreateDisablePingableEvt = pingableRolesEvt({ + event: "messageCreate", + + async listener(meta) { + const pluginData = meta.pluginData; + const msg = meta.args.message; + + const pingableRoles = await getPingableRolesForChannel(pluginData, msg.channel.id); + if (pingableRoles.length === 0) return; + + if (pluginData.state.timeouts.has(msg.channel.id)) { + clearTimeout(pluginData.state.timeouts.get(msg.channel.id)); + } + + disablePingableRoles(pluginData, pingableRoles); + }, +}); diff --git a/backend/src/plugins/PingableRoles/types.ts b/backend/src/plugins/PingableRoles/types.ts new file mode 100644 index 00000000..3c8db322 --- /dev/null +++ b/backend/src/plugins/PingableRoles/types.ts @@ -0,0 +1,22 @@ +import * as t from "io-ts"; +import { BasePluginType, eventListener, command } from "knub"; +import { GuildPingableRoles } from "src/data/GuildPingableRoles"; +import { PingableRole } from "src/data/entities/PingableRole"; + +export const ConfigSchema = t.type({ + can_manage: t.boolean, +}); +export type TConfigSchema = t.TypeOf; + +export interface PingableRolesPluginType extends BasePluginType { + config: TConfigSchema; + + state: { + pingableRoles: GuildPingableRoles; + cache: Map; + timeouts: Map; + }; +} + +export const pingableRolesCmd = command(); +export const pingableRolesEvt = eventListener(); diff --git a/backend/src/plugins/PingableRoles/utils/disablePingableRoles.ts b/backend/src/plugins/PingableRoles/utils/disablePingableRoles.ts new file mode 100644 index 00000000..823ae705 --- /dev/null +++ b/backend/src/plugins/PingableRoles/utils/disablePingableRoles.ts @@ -0,0 +1,17 @@ +import { PingableRole } from "src/data/entities/PingableRole"; +import { PluginData } from "knub"; +import { PingableRolesPluginType } from "../types"; + +export function disablePingableRoles(pluginData: PluginData, pingableRoles: PingableRole[]) { + for (const pingableRole of pingableRoles) { + const role = pluginData.guild.roles.get(pingableRole.role_id); + if (!role) continue; + + role.edit( + { + mentionable: false, + }, + "Disable pingable role", + ); + } +} diff --git a/backend/src/plugins/PingableRoles/utils/enablePingableRoles.ts b/backend/src/plugins/PingableRoles/utils/enablePingableRoles.ts new file mode 100644 index 00000000..b8632dc7 --- /dev/null +++ b/backend/src/plugins/PingableRoles/utils/enablePingableRoles.ts @@ -0,0 +1,17 @@ +import { PingableRole } from "src/data/entities/PingableRole"; +import { PluginData } from "knub"; +import { PingableRolesPluginType } from "../types"; + +export function enablePingableRoles(pluginData: PluginData, pingableRoles: PingableRole[]) { + for (const pingableRole of pingableRoles) { + const role = pluginData.guild.roles.get(pingableRole.role_id); + if (!role) continue; + + role.edit( + { + mentionable: true, + }, + "Enable pingable role", + ); + } +} diff --git a/backend/src/plugins/PingableRoles/utils/getPingableRolesForChannel.ts b/backend/src/plugins/PingableRoles/utils/getPingableRolesForChannel.ts new file mode 100644 index 00000000..4e4ad089 --- /dev/null +++ b/backend/src/plugins/PingableRoles/utils/getPingableRolesForChannel.ts @@ -0,0 +1,14 @@ +import { PingableRole } from "src/data/entities/PingableRole"; +import { PluginData } from "knub"; +import { PingableRolesPluginType } from "../types"; + +export async function getPingableRolesForChannel( + pluginData: PluginData, + channelId: string, +): Promise { + if (!pluginData.state.cache.has(channelId)) { + pluginData.state.cache.set(channelId, await pluginData.state.pingableRoles.getForChannel(channelId)); + } + + return pluginData.state.cache.get(channelId); +} diff --git a/backend/src/plugins/availablePlugins.ts b/backend/src/plugins/availablePlugins.ts index 1345daee..d4f33249 100644 --- a/backend/src/plugins/availablePlugins.ts +++ b/backend/src/plugins/availablePlugins.ts @@ -8,12 +8,14 @@ import { AutoReactionsPlugin } from "./AutoReactions/AutoReactionsPlugin"; import { RemindersPlugin } from "./Reminders/RemindersPlugin"; import { UsernameSaverPlugin } from "./UsernameSaver/UsernameSaverPlugin"; import { WelcomeMessagePlugin } from "./WelcomeMessage/WelcomeMessagePlugin"; +import { PingableRolesPlugin } from "./PingableRoles/PingableRolesPlugin"; // prettier-ignore export const guildPlugins: Array> = [ AutoReactionsPlugin, LocateUserPlugin, PersistPlugin, + PingableRolesPlugin, NameHistoryPlugin, MessageSaverPlugin, RemindersPlugin,