From ad510794487cb6c27235f747141d2c21513d597c Mon Sep 17 00:00:00 2001 From: Cadence Ember Date: Sat, 1 Feb 2025 23:12:50 +1300 Subject: [PATCH] Don't overwrite room custom topics --- package-lock.json | 15 +++++++------- package.json | 2 +- src/d2m/actions/create-room.js | 5 ++++- src/d2m/actions/create-room.test.js | 20 +++++++++++++++++++ .../0018-add-custom-topic-to-channel-room.sql | 5 +++++ src/db/orm-defs.d.ts | 2 ++ src/m2d/event-dispatcher.js | 11 ++++++++++ src/types.d.ts | 4 ++++ src/web/routes/guild.test.js | 12 ++--------- 9 files changed, 57 insertions(+), 19 deletions(-) create mode 100644 src/db/migrations/0018-add-custom-topic-to-channel-room.sql diff --git a/package-lock.json b/package-lock.json index 1852245..7fd76a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@cloudrac3r/giframe": "^0.4.3", "@cloudrac3r/html-template-tag": "^5.0.1", "@cloudrac3r/in-your-element": "^1.0.0", - "@cloudrac3r/mixin-deep": "^3.0.0", + "@cloudrac3r/mixin-deep": "^3.0.1", "@cloudrac3r/pngjs": "^7.0.3", "@cloudrac3r/pug": "^4.0.4", "@cloudrac3r/turndown": "^7.1.4", @@ -281,9 +281,10 @@ } }, "node_modules/@cloudrac3r/mixin-deep": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@cloudrac3r/mixin-deep/-/mixin-deep-3.0.0.tgz", - "integrity": "sha512-yQz1wHSZbHfbKaGSjrV3wIG0e9MnElKlmekMKJPRdTn2jhF2Mt8wfMPX8U7v6rTyzR/7BTrX8CCUcrJMLgoQqw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cloudrac3r/mixin-deep/-/mixin-deep-3.0.1.tgz", + "integrity": "sha512-awxfIraHjJ/URNlZ0ROc78Tdjtfk/fM/Gnj1embfrSN08h/HpRtLmPc3xlG3T2vFAy1AkONaebd52u7o6kDaYw==", + "license": "MIT", "engines": { "node": ">=6" } @@ -3217,9 +3218,9 @@ "license": "MIT" }, "node_modules/undici": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.19.8.tgz", - "integrity": "sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==", + "version": "6.21.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.1.tgz", + "integrity": "sha512-q/1rj5D0/zayJB2FraXdaWxbhWiNKDvu8naDT2dl1yTlvJp4BLtOcp2a5BvgGNQpYYJzau7tf1WgKv3b+7mqpQ==", "license": "MIT", "engines": { "node": ">=18.17" diff --git a/package.json b/package.json index 1705c02..1d2e411 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "@cloudrac3r/giframe": "^0.4.3", "@cloudrac3r/html-template-tag": "^5.0.1", "@cloudrac3r/in-your-element": "^1.0.0", - "@cloudrac3r/mixin-deep": "^3.0.0", + "@cloudrac3r/mixin-deep": "^3.0.1", "@cloudrac3r/pngjs": "^7.0.3", "@cloudrac3r/pug": "^4.0.4", "@cloudrac3r/turndown": "^7.1.4", diff --git a/src/d2m/actions/create-room.js b/src/d2m/actions/create-room.js index f72f6ef..cf785ac 100644 --- a/src/d2m/actions/create-room.js +++ b/src/d2m/actions/create-room.js @@ -89,9 +89,10 @@ async function channelToKState(channel, guild, di) { assert(typeof parentSpaceID === "string") } - const channelRow = select("channel_room", ["nick", "custom_avatar"], {channel_id: channel.id}).get() + const channelRow = select("channel_room", ["nick", "custom_avatar", "custom_topic"], {channel_id: channel.id}).get() const customName = channelRow?.nick const customAvatar = channelRow?.custom_avatar + const hasCustomTopic = channelRow?.custom_topic const [convertedName, convertedTopic] = convertNameAndTopic(channel, guild, customName) const avatarEventContent = {} @@ -167,6 +168,8 @@ async function channelToKState(channel, guild, di) { } } + if (hasCustomTopic) delete channelKState["m.room.topic/"] + return {spaceID: parentSpaceID, privacyLevel, channelKState} } diff --git a/src/d2m/actions/create-room.test.js b/src/d2m/actions/create-room.test.js index a1766dd..0376d65 100644 --- a/src/d2m/actions/create-room.test.js +++ b/src/d2m/actions/create-room.test.js @@ -94,6 +94,26 @@ test("channel2room: room where limited people can mention everyone", async t => t.equal(called, 1) }) +test("channel2room: matrix room that already has a custom topic set", async t => { + let called = 0 + async function getStateEvent(roomID, type, key) { // getting power levels from space to apply to room + called++ + t.equal(roomID, "!jjWAGMeQdNrVZSSfvz:cadence.moe") + t.equal(type, "m.room.power_levels") + t.equal(key, "") + return {} + } + db.prepare("UPDATE channel_room SET custom_topic = 1 WHERE channel_id = ?").run(testData.channel.general.id) + const expected = mixin({}, testData.room.general, {"m.room.power_levels/": {notifications: {room: 20}}}) + // @ts-ignore + delete expected["m.room.topic/"] + t.deepEqual( + kstateStripConditionals(await channelToKState(testData.channel.general, testData.guild.general, {api: {getStateEvent}}).then(x => x.channelKState)), + expected + ) + t.equal(called, 1) +}) + test("convertNameAndTopic: custom name and topic", t => { t.deepEqual( _convertNameAndTopic({id: "123", name: "the-twilight-zone", topic: "Spooky stuff here. :ghost:", type: 0}, {id: "456"}, "hauntings"), diff --git a/src/db/migrations/0018-add-custom-topic-to-channel-room.sql b/src/db/migrations/0018-add-custom-topic-to-channel-room.sql new file mode 100644 index 0000000..c33d21c --- /dev/null +++ b/src/db/migrations/0018-add-custom-topic-to-channel-room.sql @@ -0,0 +1,5 @@ +BEGIN TRANSACTION; + +ALTER TABLE channel_room ADD COLUMN custom_topic INTEGER DEFAULT 0; + +COMMIT; diff --git a/src/db/orm-defs.d.ts b/src/db/orm-defs.d.ts index c235e99..a272625 100644 --- a/src/db/orm-defs.d.ts +++ b/src/db/orm-defs.d.ts @@ -10,6 +10,8 @@ export type Models = { speedbump_id: string | null speedbump_webhook_id: string | null speedbump_checked: number | null + guild_id: string | null + custom_topic: number } event_message: { diff --git a/src/m2d/event-dispatcher.js b/src/m2d/event-dispatcher.js index fc2a558..ac44a19 100644 --- a/src/m2d/event-dispatcher.js +++ b/src/m2d/event-dispatcher.js @@ -164,6 +164,17 @@ async event => { db.prepare("UPDATE channel_room SET nick = ? WHERE room_id = ?").run(name, event.room_id) })) +sync.addTemporaryListener(as, "type:m.room.topic", guard("m.room.topic", +/** + * @param {Ty.Event.StateOuter} event + */ +async event => { + if (event.state_key !== "") return + if (utils.eventSenderIsFromDiscord(event.sender)) return + const customTopic = +!!event.content.topic + db.prepare("UPDATE channel_room SET custom_topic = ? WHERE room_id = ?").run(customTopic, event.room_id) +})) + sync.addTemporaryListener(as, "type:m.room.pinned_events", guard("m.room.pinned_events", /** * @param {Ty.Event.StateOuter} event diff --git a/src/types.d.ts b/src/types.d.ts index 84aad44..cc33a4a 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -243,6 +243,10 @@ export namespace Event { name?: string } + export type M_Room_Topic = { + topic?: string + } + export type M_Room_PinnedEvents = { pinned: string[] } diff --git a/src/web/routes/guild.test.js b/src/web/routes/guild.test.js index 3952d14..a95cbea 100644 --- a/src/web/routes/guild.test.js +++ b/src/web/routes/guild.test.js @@ -177,16 +177,12 @@ test("api invite: can invite to a moderated guild", async t => { async inviteToRoom(roomID, mxidToInvite, mxid) { t.equal(roomID, "!jjWAGMeQdNrVZSSfvz:cadence.moe") called++ - }, - async setUserPowerCascade(roomID, mxid, power) { - t.equal(power, 0) - called++ } } }) ) t.notOk(error) - t.equal(called, 3) + t.equal(called, 2) }) test("api invite: does not reinvite joined users", async t => { @@ -205,14 +201,10 @@ test("api invite: does not reinvite joined users", async t => { async getStateEvent(roomID, type, key) { called++ return {membership: "join"} - }, - async setUserPowerCascade(roomID, mxid, power) { - t.equal(power, 0) - called++ } } }) ) t.notOk(error) - t.equal(called, 2) + t.equal(called, 1) })