diff --git a/src/bot.ts b/src/bot.ts index 47c18ade8ec5f60c7789b7b8afdf85666ed66936..6959373196717186a959b38814617c32bcc682e6 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -62,6 +62,7 @@ export class DiscordBot { client.on("guildMemberAdd", (newMember) => { this.AddGuildMember(newMember); }); client.on("guildMemberRemove", (oldMember) => { this.RemoveGuildMember(oldMember); }); client.on("guildMemberUpdate", (_, newMember) => { this.UpdateGuildMember(newMember); }); + client.on("messageDelete", (msg) => {this.DeleteDiscordMessage(msg); }); client.on("message", (msg) => { Bluebird.delay(MSG_PROCESS_DELAY).then(() => { this.OnMessage(msg); }); @@ -212,7 +213,7 @@ export class DiscordBot { log.verbose("DiscordBot", "Sent ", m); this.sentMessages.push(m.id); const evt = new DbEvent(); - evt.MatrixId = event.event_id; + evt.MatrixId = event.event_id + ";" + event.room_id; evt.DiscordId = m.id; // Webhooks don't send guild info. evt.GuildId = guildId; @@ -222,6 +223,29 @@ export class DiscordBot { return; } + public async ProcessMatrixRedact(event: any) { + log.error("DiscordBot", `Got redact request for ${event.reacts}`); + const storeEvent = await this.store.Get(DbEvent, {matrix_id: event.redacts + ";" + event.room_id}); + if (!storeEvent.Result) { + log.warn("DiscordBot", `Could not redact because the event was in the store.`); + return; + } + while (storeEvent.Next()) { + log.info("DiscordBot", `Deleting discord msg ${storeEvent.DiscordId}`); + if (!this.bot.guilds.has(storeEvent.GuildId)) { + log.warn("DiscordBot", `Could not redact because the guild could not be found.`); + return; + } + if (!this.bot.guilds.get(storeEvent.GuildId).channels.has(storeEvent.ChannelId)) { + log.warn("DiscordBot", `Could not redact because the guild could not be found.`); + return; + } + const channel = <Discord.TextChannel> this.bot.guilds.get(storeEvent.GuildId) + .channels.get(storeEvent.ChannelId); + await channel.fetchMessage(storeEvent.DiscordId); + } + } + public OnUserQuery (userId: string): any { return false; } @@ -541,7 +565,7 @@ export class DiscordBot { format: "org.matrix.custom.html", }).then((res) => { const evt = new DbEvent(); - evt.MatrixId = res.event_id; + evt.MatrixId = res.event_id + ";" + room; evt.DiscordId = msg.id; evt.ChannelId = msg.channel.id; evt.GuildId = msg.guild.id; @@ -554,4 +578,19 @@ export class DiscordBot { log.verbose("DiscordBot", "Failed to send message into room.", err); }); } + + private async DeleteDiscordMessage(msg: Discord.Message) { + log.error("DiscordBot", `Got delete event for ${msg.id}`); + const storeEvent = await this.store.Get(DbEvent, {discord_id: msg.id}); + if (!storeEvent.Result) { + log.warn("DiscordBot", `Could not redact because the event was in the store.`); + return; + } + while (storeEvent.Next()) { + log.info("DiscordBot", `Deleting discord msg ${storeEvent.DiscordId}`); + const client = this.bridge.getIntent().getClient(); + const matrixIds = storeEvent.MatrixId.split(";"); + await client.redactEvent(matrixIds[1], matrixIds[0]); + } + } } diff --git a/src/db/dbdataemoji.ts b/src/db/dbdataemoji.ts index 943096d9af60aa37c56496c6b6bd496a586bb597..46d8b79cd424423455521b407ad74af4bf77b46f 100644 --- a/src/db/dbdataemoji.ts +++ b/src/db/dbdataemoji.ts @@ -12,7 +12,6 @@ export class DbGuildEmoji implements IDbData { public Result: boolean; public RunQuery(store: DiscordStore, params: any): Promise<null> { - log.silly("DiscordStore", "_get_schema_version"); return store.db.getAsync(` SELECT * FROM guild_emoji diff --git a/src/db/dbdataevent.ts b/src/db/dbdataevent.ts index f89ef6872150de7632b4b5f4755f834788ea4190..58ca681bcf9f4f28191593d011075aafc2d9b36f 100644 --- a/src/db/dbdataevent.ts +++ b/src/db/dbdataevent.ts @@ -1,26 +1,31 @@ import { DiscordStore } from "../store"; -import { IDbData } from "./dbdatainterface"; +import { IDbData, IDbDataMany } from "./dbdatainterface"; import * as log from "npmlog"; -export class DbEvent implements IDbData { +export class DbEvent implements IDbDataMany { public MatrixId: string; public DiscordId: string; public GuildId: string; public ChannelId: string; public Result: boolean; + private rows: any[]; + + get ResultCount(): number { + return this.rows.length; + } public async RunQuery(store: DiscordStore, params: any): Promise<null> { - log.silly("DiscordStore", "_get_schema_version"); - let rowM = null; + this.rows = []; + let rowsM = null; if (params.matrix_id) { - rowM = await store.db.getAsync(` + rowsM = await store.db.allAsync(` SELECT * FROM event_store WHERE matrix_id = $id`, { $id: params.matrix_id, }); } else if (params.discord_id) { - rowM = await store.db.getAsync(` + rowsM = await store.db.allAsync(` SELECT * FROM event_store WHERE discord_id = $id`, { @@ -29,27 +34,39 @@ export class DbEvent implements IDbData { } else { throw new Error("Unknown/incorrect id given as a param"); } - this.Result = rowM !== undefined; - if (this.Result) { - this.MatrixId = rowM.matrix_id; - this.DiscordId = rowM.discord_id; - const rowD = await store.db.getAsync(` - SELECT * - FROM discord_msg_store - WHERE msg_id = $id`, { - $id: rowM.discord_id, - }); - if (rowD !== undefined) { - this.GuildId = rowD.guild_id; - this.ChannelId = rowD.guild_id; - } else { - this.Result = false; - throw new Error("Could not find discord event data in discord_msg_store"); + + for (const rowM of rowsM) { + const row = { + matrix_id: rowM.matrix_id, + discord_id: rowM.discord_id, + }; + for (const rowD of await store.db.allAsync(` + SELECT * + FROM discord_msg_store + WHERE msg_id = $id`, { + $id: rowM.discord_id, + })) { + const insertRow: any = Object.assign({}, row); + insertRow.guild_id = rowD.guild_id; + insertRow.channel_id = rowD.channel_id; + this.rows.push(insertRow); } } + this.Result = this.rows.length !== 0; return null; } + public Next(): boolean { + if (!this.Result || this.ResultCount === 0) { + return false; + } + const item = this.rows.shift(); + this.MatrixId = item.matrix_id; + this.DiscordId = item.discord_id; + this.GuildId = item.guild_id; + this.ChannelId = item.channel_id; + } + public async Insert(store: DiscordStore): Promise<null> { await store.db.runAsync(` INSERT INTO event_store @@ -58,6 +75,16 @@ export class DbEvent implements IDbData { $matrix_id: this.MatrixId, $discord_id: this.DiscordId, }); + // Check if the discord item exists? + const msgExists = await store.db.getAsync(` + SELECT * + FROM discord_msg_store + WHERE msg_id = $id`, { + $id: this.DiscordId, + }) !== undefined; + if (msgExists) { + return; + } return store.db.runAsync(` INSERT INTO discord_msg_store (msg_id, guild_id, channel_id) diff --git a/src/db/dbdatainterface.ts b/src/db/dbdatainterface.ts index 74ab8d7afdc0c56ae4105adb2823276d0985607d..efc46e41999ee954881cfaa805ddf8e841217d17 100644 --- a/src/db/dbdatainterface.ts +++ b/src/db/dbdatainterface.ts @@ -7,3 +7,8 @@ export interface IDbData { Update(store: DiscordStore): Promise<null|Error>; Delete(store: DiscordStore): Promise<null|Error>; } + +export interface IDbDataMany extends IDbData { + ResultCount: number; + Next(): boolean; +} diff --git a/src/matrixroomhandler.ts b/src/matrixroomhandler.ts index d5872b3ab530532663d8f38f26001db9cd6a78ae..9c2ee740e040fb3b9f4e89de9996024aaa0544a2 100644 --- a/src/matrixroomhandler.ts +++ b/src/matrixroomhandler.ts @@ -72,12 +72,13 @@ export class MatrixRoomHandler { } if (event.type === "m.room.member" && event.content.membership === "invite") { this.HandleInvite(event); - } - if (event.type === "m.room.message" && context.rooms.remote) { + } else if (event.type === "m.room.redaction" && context.rooms.remote) { + this.discord.ProcessMatrixRedact(event); + } else if (event.type === "m.room.message" && context.rooms.remote) { log.verbose("MatrixRoomHandler", "Got m.room.message event"); const srvChanPair = context.rooms.remote.roomId.substr("_discord".length).split("_", ROOM_NAME_PARTS); return this.discord.ProcessMatrixMsgEvent(event, srvChanPair[0], srvChanPair[1]).catch((err) => { - log.warn("There was an error sending a matrix event", err); + log.warn("MatrixRoomHandler", "There was an error sending a matrix event", err); }); } else { log.verbose("MatrixRoomHandler", "Got non m.room.message event"); diff --git a/test/test_store.ts b/test/test_store.ts index 46287b08cf44a79091a4aacc1ec17beaf68dbe5b..4d6c2bd969eb25da1539ba41b5b58213c98d7751 100644 --- a/test/test_store.ts +++ b/test/test_store.ts @@ -102,16 +102,47 @@ describe("DiscordStore", () => { event.ChannelId = "123"; await store.Insert(event); const getEventDiscord = await store.Get(DbEvent, {discord_id: "456"}); + getEventDiscord.Next(); Chai.assert.equal(getEventDiscord.MatrixId, "123"); Chai.assert.equal(getEventDiscord.DiscordId, "456"); Chai.assert.equal(getEventDiscord.GuildId, "123"); Chai.assert.equal(getEventDiscord.ChannelId, "123"); const getEventMatrix = await store.Get(DbEvent, {matrix_id: "123"}); + getEventMatrix.Next(); Chai.assert.equal(getEventMatrix.MatrixId, "123"); Chai.assert.equal(getEventMatrix.DiscordId, "456"); Chai.assert.equal(getEventMatrix.GuildId, "123"); Chai.assert.equal(getEventMatrix.ChannelId, "123"); }); + const MSG_COUNT = 5; + it("should get multiple discord msgs successfully", async () => { + const store = new DiscordStore(":memory:"); + await store.init(); + for (let i = 0; i < MSG_COUNT; i++) { + const event = new DbEvent(); + event.MatrixId = "123"; + event.DiscordId = "456" + i; + event.GuildId = "123"; + event.ChannelId = "123"; + await store.Insert(event); + } + const getEventDiscord = await store.Get(DbEvent, {matrix_id: "123"}); + Chai.assert.equal(getEventDiscord.ResultCount, MSG_COUNT); + }); + it("should get multiple matrix msgs successfully", async () => { + const store = new DiscordStore(":memory:"); + await store.init(); + for (let i = 0; i < MSG_COUNT; i++) { + const event = new DbEvent(); + event.MatrixId = "123" + i; + event.DiscordId = "456"; + event.GuildId = "123"; + event.ChannelId = "123"; + await store.Insert(event); + } + const getEventMatrix = await store.Get(DbEvent, {discord_id: "456"}); + Chai.assert.equal(getEventMatrix.ResultCount, MSG_COUNT); + }); it("should not return nonexistant event", async () => { const store = new DiscordStore(":memory:"); await store.init(); @@ -129,6 +160,7 @@ describe("DiscordStore", () => { await store.Insert(event); await store.Delete(event); const getEvent = await store.Get(DbEvent, {matrix_id: "123"}); + getEvent.Next(); Chai.assert.isFalse(getEvent.Result); }); });