mirror of
https://github.com/ZeppelinBot/Zeppelin.git
synced 2025-03-15 05:41:51 +00:00
tags: delete command/response msg if the other is deleted
This commit is contained in:
parent
145f5866cf
commit
50c6233190
6 changed files with 208 additions and 13 deletions
|
@ -11,12 +11,13 @@ export class QueuedEventEmitter {
|
||||||
this.queue = new Queue();
|
this.queue = new Queue();
|
||||||
}
|
}
|
||||||
|
|
||||||
on(eventName: string, listener: Listener) {
|
on(eventName: string, listener: Listener): Listener {
|
||||||
if (!this.listeners.has(eventName)) {
|
if (!this.listeners.has(eventName)) {
|
||||||
this.listeners.set(eventName, []);
|
this.listeners.set(eventName, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.listeners.get(eventName).push(listener);
|
this.listeners.get(eventName).push(listener);
|
||||||
|
return listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
off(eventName: string, listener: Listener) {
|
off(eventName: string, listener: Listener) {
|
||||||
|
@ -28,6 +29,15 @@ export class QueuedEventEmitter {
|
||||||
listeners.splice(listeners.indexOf(listener), 1);
|
listeners.splice(listeners.indexOf(listener), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
once(eventName: string, listener: Listener): Listener {
|
||||||
|
const handler = this.on(eventName, (...args) => {
|
||||||
|
const result = listener(...args);
|
||||||
|
this.off(eventName, handler);
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
emit(eventName: string, args: any[] = []): Promise<void> {
|
emit(eventName: string, args: any[] = []): Promise<void> {
|
||||||
const listeners = [...(this.listeners.get(eventName) || []), ...(this.listeners.get("*") || [])];
|
const listeners = [...(this.listeners.get(eventName) || []), ...(this.listeners.get("*") || [])];
|
||||||
|
|
||||||
|
|
|
@ -146,6 +146,7 @@ export class GuildSavedMessages extends BaseRepository {
|
||||||
|
|
||||||
const inserted = await this.messages.findOne(data.id);
|
const inserted = await this.messages.findOne(data.id);
|
||||||
this.events.emit("create", [inserted]);
|
this.events.emit("create", [inserted]);
|
||||||
|
this.events.emit(`create:${data.id}`, [inserted]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async createFromMsg(msg: Message, overrides = {}) {
|
async createFromMsg(msg: Message, overrides = {}) {
|
||||||
|
@ -180,6 +181,7 @@ export class GuildSavedMessages extends BaseRepository {
|
||||||
|
|
||||||
if (deleted) {
|
if (deleted) {
|
||||||
this.events.emit("delete", [deleted]);
|
this.events.emit("delete", [deleted]);
|
||||||
|
this.events.emit(`delete:${id}`, [deleted]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,6 +229,7 @@ export class GuildSavedMessages extends BaseRepository {
|
||||||
);
|
);
|
||||||
|
|
||||||
this.events.emit("update", [newMessage, oldMessage]);
|
this.events.emit("update", [newMessage, oldMessage]);
|
||||||
|
this.events.emit(`update:${id}`, [newMessage, oldMessage]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveEditFromMsg(msg: Message) {
|
async saveEditFromMsg(msg: Message) {
|
||||||
|
@ -247,4 +250,31 @@ export class GuildSavedMessages extends BaseRepository {
|
||||||
this.toBePermanent.add(id);
|
this.toBePermanent.add(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async onceMessageAvailable(id: string, handler: (msg: SavedMessage) => any, timeout: number = 60 * 1000) {
|
||||||
|
let called = false;
|
||||||
|
let onceEventListener;
|
||||||
|
let timeoutFn;
|
||||||
|
|
||||||
|
const callHandler = async (msg: SavedMessage) => {
|
||||||
|
this.events.off(`create:${id}`, onceEventListener);
|
||||||
|
clearTimeout(timeoutFn);
|
||||||
|
|
||||||
|
if (called) return;
|
||||||
|
called = true;
|
||||||
|
|
||||||
|
await handler(msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
onceEventListener = this.events.once(`create:${id}`, callHandler);
|
||||||
|
timeoutFn = setTimeout(() => {
|
||||||
|
called = true;
|
||||||
|
callHandler(null);
|
||||||
|
}, timeout);
|
||||||
|
|
||||||
|
const messageInDB = await this.find(id);
|
||||||
|
if (messageInDB) {
|
||||||
|
callHandler(messageInDB);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
import { Tag } from "./entities/Tag";
|
import { Tag } from "./entities/Tag";
|
||||||
import { getRepository, Repository } from "typeorm";
|
import { getRepository, Repository } from "typeorm";
|
||||||
import { BaseRepository } from "./BaseRepository";
|
import { BaseRepository } from "./BaseRepository";
|
||||||
|
import { TagResponse } from "./entities/TagResponse";
|
||||||
|
|
||||||
export class GuildTags extends BaseRepository {
|
export class GuildTags extends BaseRepository {
|
||||||
private tags: Repository<Tag>;
|
private tags: Repository<Tag>;
|
||||||
|
private tagResponses: Repository<TagResponse>;
|
||||||
|
|
||||||
constructor(guildId) {
|
constructor(guildId) {
|
||||||
super(guildId);
|
super(guildId);
|
||||||
this.tags = getRepository(Tag);
|
this.tags = getRepository(Tag);
|
||||||
|
this.tagResponses = getRepository(TagResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
async all(): Promise<Tag[]> {
|
async all(): Promise<Tag[]> {
|
||||||
|
@ -57,4 +60,30 @@ export class GuildTags extends BaseRepository {
|
||||||
tag
|
tag
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async findResponseByCommandMessageId(messageId: string): Promise<TagResponse> {
|
||||||
|
return this.tagResponses.findOne({
|
||||||
|
where: {
|
||||||
|
guild_id: this.guildId,
|
||||||
|
command_message_id: messageId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async findResponseByResponseMessageId(messageId: string): Promise<TagResponse> {
|
||||||
|
return this.tagResponses.findOne({
|
||||||
|
where: {
|
||||||
|
guild_id: this.guildId,
|
||||||
|
response_message_id: messageId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async addResponse(cmdMessageId, responseMessageId) {
|
||||||
|
await this.tagResponses.insert({
|
||||||
|
guild_id: this.guildId,
|
||||||
|
command_message_id: cmdMessageId,
|
||||||
|
response_message_id: responseMessageId
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
14
src/data/entities/TagResponse.ts
Normal file
14
src/data/entities/TagResponse.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { Entity, Column, PrimaryColumn, CreateDateColumn } from "typeorm";
|
||||||
|
|
||||||
|
@Entity("tag_responses")
|
||||||
|
export class TagResponse {
|
||||||
|
@Column()
|
||||||
|
@PrimaryColumn()
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@Column() guild_id: string;
|
||||||
|
|
||||||
|
@Column() command_message_id: string;
|
||||||
|
|
||||||
|
@Column() response_message_id: string;
|
||||||
|
}
|
59
src/migrations/1546770935261-CreateTagResponsesTable.ts
Normal file
59
src/migrations/1546770935261-CreateTagResponsesTable.ts
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
import { MigrationInterface, QueryRunner, Table } from "typeorm";
|
||||||
|
|
||||||
|
export class CreateTagResponsesTable1546770935261 implements MigrationInterface {
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<any> {
|
||||||
|
await queryRunner.createTable(
|
||||||
|
new Table({
|
||||||
|
name: "tag_responses",
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: "id",
|
||||||
|
type: "int",
|
||||||
|
unsigned: true,
|
||||||
|
isGenerated: true,
|
||||||
|
generationStrategy: "increment",
|
||||||
|
isPrimary: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "guild_id",
|
||||||
|
type: "bigint",
|
||||||
|
unsigned: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "command_message_id",
|
||||||
|
type: "bigint",
|
||||||
|
unsigned: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "response_message_id",
|
||||||
|
type: "bigint",
|
||||||
|
unsigned: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
indices: [
|
||||||
|
{
|
||||||
|
columnNames: ["guild_id"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
foreignKeys: [
|
||||||
|
{
|
||||||
|
columnNames: ["command_message_id"],
|
||||||
|
referencedTableName: "messages",
|
||||||
|
referencedColumnNames: ["id"],
|
||||||
|
onDelete: "CASCADE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
columnNames: ["response_message_id"],
|
||||||
|
referencedTableName: "messages",
|
||||||
|
referencedColumnNames: ["id"],
|
||||||
|
onDelete: "CASCADE"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<any> {
|
||||||
|
await queryRunner.dropTable("tag_responses");
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,17 +1,24 @@
|
||||||
import { Plugin, decorators as d } from "knub";
|
import { Plugin, decorators as d } from "knub";
|
||||||
import { Message } from "eris";
|
import { Message, TextChannel } from "eris";
|
||||||
import { errorMessage, successMessage } from "../utils";
|
import { errorMessage, successMessage } from "../utils";
|
||||||
import { GuildTags } from "../data/GuildTags";
|
import { GuildTags } from "../data/GuildTags";
|
||||||
|
import { GuildSavedMessages } from "../data/GuildSavedMessages";
|
||||||
|
import { SavedMessage } from "../data/entities/SavedMessage";
|
||||||
|
|
||||||
export class TagsPlugin extends Plugin {
|
export class TagsPlugin extends Plugin {
|
||||||
public static pluginName = "tags";
|
public static pluginName = "tags";
|
||||||
|
|
||||||
protected tags: GuildTags;
|
protected tags: GuildTags;
|
||||||
|
protected savedMessages: GuildSavedMessages;
|
||||||
|
|
||||||
|
private onMessageCreateFn;
|
||||||
|
private onMessageDeleteFn;
|
||||||
|
|
||||||
getDefaultOptions() {
|
getDefaultOptions() {
|
||||||
return {
|
return {
|
||||||
config: {
|
config: {
|
||||||
prefix: "!!"
|
prefix: "!!",
|
||||||
|
deleteWithCommand: true
|
||||||
},
|
},
|
||||||
|
|
||||||
permissions: {
|
permissions: {
|
||||||
|
@ -32,6 +39,18 @@ export class TagsPlugin extends Plugin {
|
||||||
|
|
||||||
onLoad() {
|
onLoad() {
|
||||||
this.tags = GuildTags.getInstance(this.guildId);
|
this.tags = GuildTags.getInstance(this.guildId);
|
||||||
|
this.savedMessages = GuildSavedMessages.getInstance(this.guildId);
|
||||||
|
|
||||||
|
this.onMessageCreateFn = this.onMessageCreate.bind(this);
|
||||||
|
this.savedMessages.events.on("create", this.onMessageCreateFn);
|
||||||
|
|
||||||
|
this.onMessageDeleteFn = this.onMessageDelete.bind(this);
|
||||||
|
this.savedMessages.events.on("delete", this.onMessageDeleteFn);
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnload() {
|
||||||
|
this.savedMessages.events.off("create", this.onMessageCreateFn);
|
||||||
|
this.savedMessages.events.off("delete", this.onMessageDeleteFn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@d.command("tag list")
|
@d.command("tag list")
|
||||||
|
@ -72,20 +91,54 @@ export class TagsPlugin extends Plugin {
|
||||||
msg.channel.createMessage(successMessage(`Tag set! Use it with: \`${prefix}${args.tag}\``));
|
msg.channel.createMessage(successMessage(`Tag set! Use it with: \`${prefix}${args.tag}\``));
|
||||||
}
|
}
|
||||||
|
|
||||||
@d.event("messageCreate")
|
async onMessageCreate(msg: SavedMessage) {
|
||||||
@d.permission("use")
|
const member = this.guild.members.get(msg.user_id);
|
||||||
async onMessageCreate(msg: Message) {
|
if (!this.hasPermission("use", { member, channelId: msg.channel_id })) return;
|
||||||
if (!msg.content) return;
|
|
||||||
if (msg.type !== 0) return;
|
|
||||||
if (!msg.author || msg.author.bot) return;
|
|
||||||
|
|
||||||
const prefix = this.configValueForMsg(msg, "prefix");
|
if (!msg.data.content) return;
|
||||||
if (!msg.content.startsWith(prefix)) return;
|
if (msg.is_bot) return;
|
||||||
|
|
||||||
const withoutPrefix = msg.content.slice(prefix.length);
|
const prefix = this.configValueForMemberIdAndChannelId(msg.user_id, msg.channel_id, "prefix");
|
||||||
|
if (!msg.data.content.startsWith(prefix)) return;
|
||||||
|
|
||||||
|
const withoutPrefix = msg.data.content.slice(prefix.length);
|
||||||
const tag = await this.tags.find(withoutPrefix);
|
const tag = await this.tags.find(withoutPrefix);
|
||||||
if (!tag) return;
|
if (!tag) return;
|
||||||
|
|
||||||
msg.channel.createMessage(tag.body);
|
const channel = this.guild.channels.get(msg.channel_id) as TextChannel;
|
||||||
|
const responseMsg = await channel.createMessage(tag.body);
|
||||||
|
|
||||||
|
// Save the command-response message pair once the message is in our database
|
||||||
|
this.savedMessages.onceMessageAvailable(responseMsg.id, async theMsg => {
|
||||||
|
await this.tags.addResponse(msg.id, responseMsg.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async onMessageDelete(msg: SavedMessage) {
|
||||||
|
// Command message was deleted -> delete the response as well
|
||||||
|
const commandMsgResponse = await this.tags.findResponseByCommandMessageId(msg.id);
|
||||||
|
if (commandMsgResponse) {
|
||||||
|
const channel = this.guild.channels.get(msg.channel_id) as TextChannel;
|
||||||
|
if (!channel) return;
|
||||||
|
|
||||||
|
const responseMsg = await this.savedMessages.find(commandMsgResponse.response_message_id);
|
||||||
|
if (!responseMsg || responseMsg.deleted_at != null) return;
|
||||||
|
|
||||||
|
await channel.deleteMessage(commandMsgResponse.response_message_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response was deleted -> delete the command message as well
|
||||||
|
const responseMsgResponse = await this.tags.findResponseByResponseMessageId(msg.id);
|
||||||
|
if (responseMsgResponse) {
|
||||||
|
const channel = this.guild.channels.get(msg.channel_id) as TextChannel;
|
||||||
|
if (!channel) return;
|
||||||
|
|
||||||
|
const commandMsg = await this.savedMessages.find(responseMsgResponse.command_message_id);
|
||||||
|
if (!commandMsg || commandMsg.deleted_at != null) return;
|
||||||
|
|
||||||
|
await channel.deleteMessage(responseMsgResponse.command_message_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue