diff --git a/d2m/actions/create-room.js b/d2m/actions/create-room.js index 29bcdc0..c8f0661 100644 --- a/d2m/actions/create-room.js +++ b/d2m/actions/create-room.js @@ -95,11 +95,6 @@ async function channelToKState(channel, guild) { type: "m.room_membership", room_id: spaceID }] - }, - "m.room.power_levels/": { - events: { - "m.room.avatar": 0 - } } } @@ -119,56 +114,24 @@ async function createRoom(channel, guild, spaceID, kstate) { if (channel.type === DiscordTypes.ChannelType.PublicThread) threadParent = channel.parent_id const invite = threadParent ? [] : ["@cadence:cadence.moe"] // TODO - const roomID = await postApplyPowerLevels(kstate, async kstate => { - const [convertedName, convertedTopic] = convertNameAndTopic(channel, guild, null) - const roomID = await api.createRoom({ - name: convertedName, - topic: convertedTopic, - preset: "private_chat", - visibility: "private", - invite, - initial_state: ks.kstateToState(kstate) - }) - - db.prepare("INSERT INTO channel_room (channel_id, room_id, name, nick, thread_parent) VALUES (?, ?, ?, NULL, ?)").run(channel.id, roomID, channel.name, threadParent) - - return roomID + const [convertedName, convertedTopic] = convertNameAndTopic(channel, guild, null) + const roomID = await api.createRoom({ + name: convertedName, + topic: convertedTopic, + preset: "private_chat", + visibility: "private", + invite, + initial_state: ks.kstateToState(kstate) }) - // Put the newly created child into the space, no need to await this + db.prepare("INSERT INTO channel_room (channel_id, room_id, name, nick, thread_parent) VALUES (?, ?, ?, NULL, ?)").run(channel.id, roomID, channel.name, threadParent) + + // Put the newly created child into the space _syncSpaceMember(channel, spaceID, roomID) return roomID } -/** - * Handling power levels separately. The spec doesn't specify what happens, Dendrite differs, - * and Synapse does an absolutely insane *shallow merge* of what I provide on top of what it creates. - * We don't want the `events` key to be overridden completely. - * https://github.com/matrix-org/synapse/blob/develop/synapse/handlers/room.py#L1170-L1210 - * https://github.com/matrix-org/matrix-spec/issues/492 - * @param {any} kstate - * @param {(_: any) => Promise} callback must return room ID - * @returns {Promise} room ID - */ -async function postApplyPowerLevels(kstate, callback) { - const powerLevelContent = kstate["m.room.power_levels/"] - const kstateWithoutPowerLevels = {...kstate} - delete kstateWithoutPowerLevels["m.room.power_levels/"] - - /** @type {string} */ - const roomID = await callback(kstateWithoutPowerLevels) - - // Now *really* apply the power level overrides on top of what Synapse *really* set - if (powerLevelContent) { - const newRoomKState = await roomToKState(roomID) - const newRoomPowerLevelsDiff = ks.diffKState(newRoomKState, {"m.room.power_levels/": powerLevelContent}) - await applyKStateDiffToRoom(roomID, newRoomPowerLevelsDiff) - } - - return roomID -} - /** * @param {DiscordTypes.APIGuildChannel} channel */ @@ -327,6 +290,5 @@ module.exports.createAllForGuild = createAllForGuild module.exports.channelToKState = channelToKState module.exports.roomToKState = roomToKState module.exports.applyKStateDiffToRoom = applyKStateDiffToRoom -module.exports.postApplyPowerLevels = postApplyPowerLevels module.exports._convertNameAndTopic = convertNameAndTopic module.exports._unbridgeRoom = _unbridgeRoom diff --git a/d2m/actions/create-space.js b/d2m/actions/create-space.js index 46fa71f..34aa25f 100644 --- a/d2m/actions/create-space.js +++ b/d2m/actions/create-space.js @@ -21,24 +21,23 @@ const ks = sync.require("../../matrix/kstate") async function createSpace(guild, kstate) { const name = kstate["m.room.name/"].name const topic = kstate["m.room.topic/"]?.topic || undefined + assert(name) - const roomID = await createRoom.postApplyPowerLevels(kstate, async kstate => { - return api.createRoom({ - name, - preset: "private_chat", // cannot join space unless invited - visibility: "private", - power_level_content_override: { - events_default: 100, // space can only be managed by bridge - invite: 0 // any existing member can invite others - }, - invite: ["@cadence:cadence.moe"], // TODO - topic, - creation_content: { - type: "m.space" - }, - initial_state: ks.kstateToState(kstate) - }) + const roomID = await api.createRoom({ + name, + preset: "private_chat", // cannot join space unless invited + visibility: "private", + power_level_content_override: { + events_default: 100, // space can only be managed by bridge + invite: 0 // any existing member can invite others + }, + invite: ["@cadence:cadence.moe"], // TODO + topic, + creation_content: { + type: "m.space" + }, + initial_state: ks.kstateToState(kstate) }) db.prepare("INSERT INTO guild_space (guild_id, space_id) VALUES (?, ?)").run(guild.id, roomID) return roomID diff --git a/db/data-for-test.sql b/db/data-for-test.sql index ec9f9ec..4a406c9 100644 --- a/db/data-for-test.sql +++ b/db/data-for-test.sql @@ -34,7 +34,6 @@ CREATE TABLE IF NOT EXISTS "channel_room" ( "name" TEXT, "nick" TEXT, "thread_parent" TEXT, - "custom_avatar" TEXT, PRIMARY KEY("channel_id") ); CREATE TABLE IF NOT EXISTS "event_message" ( @@ -56,11 +55,11 @@ BEGIN TRANSACTION; INSERT INTO guild_space (guild_id, space_id) VALUES ('112760669178241024', '!jjWAGMeQdNrVZSSfvz:cadence.moe'); -INSERT INTO channel_room (channel_id, room_id, name, nick, thread_parent, custom_avatar) VALUES -('112760669178241024', '!kLRqKKUQXcibIMtOpl:cadence.moe', 'heave', 'main', NULL, NULL), -('497161350934560778', '!edUxjVdzgUvXDUIQCK:cadence.moe', 'amanda-spam', NULL, NULL, NULL), -('160197704226439168', '!uCtjHhfGlYbVnPVlkG:cadence.moe', 'the-stanley-parable-channel', 'bots', NULL, NULL), -('1100319550446252084', '!PnyBKvUBOhjuCucEfk:cadence.moe', 'worm-farm', NULL, NULL, NULL); +INSERT INTO channel_room (channel_id, room_id, name, nick, thread_parent) VALUES +('112760669178241024', '!kLRqKKUQXcibIMtOpl:cadence.moe', 'heave', 'main', NULL), +('497161350934560778', '!edUxjVdzgUvXDUIQCK:cadence.moe', 'amanda-spam', NULL, NULL), +('160197704226439168', '!uCtjHhfGlYbVnPVlkG:cadence.moe', 'the-stanley-parable-channel', 'bots', NULL), +('1100319550446252084', '!PnyBKvUBOhjuCucEfk:cadence.moe', 'worm-farm', NULL, NULL); INSERT INTO sim (discord_id, sim_name, localpart, mxid) VALUES ('0', 'bot', '_ooye_bot', '@_ooye_bot:cadence.moe'), diff --git a/matrix/api.js b/matrix/api.js index 2e0763e..9eff6c7 100644 --- a/matrix/api.js +++ b/matrix/api.js @@ -169,7 +169,7 @@ async function profileSetAvatarUrl(mxid, avatar_url) { async function setUserPower(roomID, mxid, power) { assert(roomID[0] === "!") assert(mxid[0] === "@") - // Yes there's no shortcut https://github.com/matrix-org/matrix-appservice-bridge/blob/2334b0bae28a285a767fe7244dad59f5a5963037/src/components/intent.ts#L352 + // Yes it's this hard https://github.com/matrix-org/matrix-appservice-bridge/blob/2334b0bae28a285a767fe7244dad59f5a5963037/src/components/intent.ts#L352 const powerLevels = await getStateEvent(roomID, "m.room.power_levels", "") const users = powerLevels.users || {} if (power != null) { diff --git a/matrix/kstate.js b/matrix/kstate.js index e840254..1b2ca14 100644 --- a/matrix/kstate.js +++ b/matrix/kstate.js @@ -1,7 +1,6 @@ // @ts-check -const assert = require("assert").strict -const mixin = require("mixin-deep") +const assert = require("assert") /** Mutates the input. */ function kstateStripConditionals(kstate) { @@ -44,32 +43,18 @@ function diffKState(actual, target) { // go through each key that it should have for (const key of Object.keys(target)) { if (!key.includes("/")) throw new Error(`target kstate's key "${key}" does not contain a slash separator; if a blank state_key was intended, add a trailing slash to the kstate key.`) - - if (key === "m.room.power_levels/") { - // Special handling for power levels, we want to deep merge the actual and target into the final state. - if (!(key in actual)) throw new Error(`want to apply a power levels diff, but original power level data is missing\nstarted with: ${JSON.stringify(actual)}\nwant to apply: ${JSON.stringify(target)}`) - const temp = mixin({}, actual[key], target[key]) - try { - assert.deepEqual(actual[key], temp) - } catch (e) { - // they differ. use the newly prepared object as the diff. - diff[key] = temp - } - - } else if (key in actual) { + if (key in actual) { // diff try { assert.deepEqual(actual[key], target[key]) } catch (e) { - // they differ. use the target as the diff. + // they differ. reassign the target diff[key] = target[key] } - } else { // not present, needs to be added diff[key] = target[key] } - // keys that are missing in "actual" will not be deleted on "target" (no action) } return diff diff --git a/matrix/kstate.test.js b/matrix/kstate.test.js index 11d5131..1541898 100644 --- a/matrix/kstate.test.js +++ b/matrix/kstate.test.js @@ -92,57 +92,3 @@ test("diffKState: detects new properties", t => { } ) }) - -test("diffKState: power levels are mixed together", t => { - const original = { - "m.room.power_levels/": { - "ban": 50, - "events": { - "m.room.name": 100, - "m.room.power_levels": 100 - }, - "events_default": 0, - "invite": 50, - "kick": 50, - "notifications": { - "room": 20 - }, - "redact": 50, - "state_default": 50, - "users": { - "@example:localhost": 100 - }, - "users_default": 0 - } - } - const result = diffKState(original, { - "m.room.power_levels/": { - "events": { - "m.room.avatar": 0 - } - } - }) - t.deepEqual(result, { - "m.room.power_levels/": { - "ban": 50, - "events": { - "m.room.name": 100, - "m.room.power_levels": 100, - "m.room.avatar": 0 - }, - "events_default": 0, - "invite": 50, - "kick": 50, - "notifications": { - "room": 20 - }, - "redact": 50, - "state_default": 50, - "users": { - "@example:localhost": 100 - }, - "users_default": 0 - } - }) - t.notDeepEqual(original, result) -}) diff --git a/package-lock.json b/package-lock.json index e808e1f..875e329 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "js-yaml": "^4.1.0", "matrix-appservice": "^2.0.0", "matrix-js-sdk": "^24.1.0", - "mixin-deep": "github:cloudrac3r/mixin-deep#v3.0.0", + "mixin-deep": "^2.0.1", "node-fetch": "^2.6.7", "prettier-bytes": "^1.0.4", "snowtransfer": "^0.8.0", @@ -2111,9 +2111,9 @@ } }, "node_modules/mixin-deep": { - "version": "3.0.0", - "resolved": "git+ssh://git@github.com/cloudrac3r/mixin-deep.git#2dd70d6b8644263f7ed2c1620506c9eb3f11d32a", - "license": "MIT", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-2.0.1.tgz", + "integrity": "sha512-imbHQNRglyaplMmjBLL3V5R6Bfq5oM+ivds3SKgc6oRtzErEnBUUc5No11Z2pilkUvl42gJvi285xTNswcKCMA==", "engines": { "node": ">=6" } diff --git a/package.json b/package.json index 67aeade..bc0a0db 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "js-yaml": "^4.1.0", "matrix-appservice": "^2.0.0", "matrix-js-sdk": "^24.1.0", - "mixin-deep": "github:cloudrac3r/mixin-deep#v3.0.0", + "mixin-deep": "^2.0.1", "node-fetch": "^2.6.7", "prettier-bytes": "^1.0.4", "snowtransfer": "^0.8.0", diff --git a/stdin.js b/stdin.js index ce612f5..61a2a08 100644 --- a/stdin.js +++ b/stdin.js @@ -14,7 +14,6 @@ const mreq = sync.require("./matrix/mreq") const api = sync.require("./matrix/api") const sendEvent = sync.require("./m2d/actions/send-event") const eventDispatcher = sync.require("./d2m/event-dispatcher") -const ks = sync.require("./matrix/kstate") const guildID = "112760669178241024" const extraContext = {} diff --git a/test/data.js b/test/data.js index 6ed2f42..30d108a 100644 --- a/test/data.js +++ b/test/data.js @@ -27,7 +27,7 @@ module.exports = { "m.room.guest_access/": {guest_access: "can_join"}, "m.room.history_visibility/": {history_visibility: "invited"}, "m.space.parent/!jjWAGMeQdNrVZSSfvz:cadence.moe": { - via: ["cadence.moe"], + via: ["cadence.moe"], // TODO: put the proper server here canonical: true }, "m.room.join_rules/": { @@ -40,11 +40,6 @@ module.exports = { "m.room.avatar/": { discord_path: "/icons/112760669178241024/a_f83622e09ead74f0c5c527fe241f8f8c.png?size=1024", url: "mxc://cadence.moe/zKXGZhmImMHuGQZWJEFKJbsF" - }, - "m.room.power_levels/": { - events: { - "m.room.avatar": 0 - } } } },