Room version 12 and room upgrades
This commit is contained in:
Generated
+53
-41
@@ -24,7 +24,7 @@
|
|||||||
"better-sqlite3": "^12.2.0",
|
"better-sqlite3": "^12.2.0",
|
||||||
"chunk-text": "^2.0.1",
|
"chunk-text": "^2.0.1",
|
||||||
"cloudstorm": "^0.14.0",
|
"cloudstorm": "^0.14.0",
|
||||||
"discord-api-types": "^0.38.31",
|
"discord-api-types": "^0.38.36",
|
||||||
"domino": "^2.1.6",
|
"domino": "^2.1.6",
|
||||||
"enquirer": "^2.4.1",
|
"enquirer": "^2.4.1",
|
||||||
"entities": "^5.0.0",
|
"entities": "^5.0.0",
|
||||||
@@ -53,6 +53,20 @@
|
|||||||
"node": ">=20"
|
"node": ">=20"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"../extended-errors/enhance-errors": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"extraneous": true,
|
||||||
|
"license": "UNLICENSED",
|
||||||
|
"dependencies": {
|
||||||
|
"ts-expose-internals": "^5.6.3",
|
||||||
|
"ts-patch": "^3.3.0",
|
||||||
|
"typescript": "^5.9.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^22.19.1",
|
||||||
|
"ts-node": "^10.9.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"../tap-dot": {
|
"../tap-dot": {
|
||||||
"name": "@cloudrac3r/tap-dot",
|
"name": "@cloudrac3r/tap-dot",
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
@@ -67,27 +81,30 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-string-parser": {
|
"node_modules/@babel/helper-string-parser": {
|
||||||
"version": "7.24.8",
|
"version": "7.27.1",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
|
||||||
"integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==",
|
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-validator-identifier": {
|
"node_modules/@babel/helper-validator-identifier": {
|
||||||
"version": "7.24.7",
|
"version": "7.28.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
|
||||||
"integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==",
|
"integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/parser": {
|
"node_modules/@babel/parser": {
|
||||||
"version": "7.25.6",
|
"version": "7.28.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz",
|
||||||
"integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==",
|
"integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.25.6"
|
"@babel/types": "^7.28.5"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"parser": "bin/babel-parser.js"
|
"parser": "bin/babel-parser.js"
|
||||||
@@ -97,13 +114,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/types": {
|
"node_modules/@babel/types": {
|
||||||
"version": "7.25.6",
|
"version": "7.28.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz",
|
||||||
"integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==",
|
"integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-string-parser": "^7.24.8",
|
"@babel/helper-string-parser": "^7.27.1",
|
||||||
"@babel/helper-validator-identifier": "^7.24.7",
|
"@babel/helper-validator-identifier": "^7.28.5"
|
||||||
"to-fast-properties": "^2.0.0"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@@ -355,9 +372,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@emnapi/runtime": {
|
"node_modules/@emnapi/runtime": {
|
||||||
"version": "1.7.0",
|
"version": "1.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz",
|
||||||
"integrity": "sha512-oAYoQnCYaQZKVS53Fq23ceWMRxq5EhQsE0x0RdQ55jT7wagMu5k+fS39v1fiSLrtrLQlXwVINenqhLMtTrV/1Q==",
|
"integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -983,16 +1000,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/sourcemap-codec": {
|
"node_modules/@jridgewell/sourcemap-codec": {
|
||||||
"version": "1.4.15",
|
"version": "1.5.5",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
|
||||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
|
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/trace-mapping": {
|
"node_modules/@jridgewell/trace-mapping": {
|
||||||
"version": "0.3.19",
|
"version": "0.3.31",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
|
||||||
"integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==",
|
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/resolve-uri": "^3.1.0",
|
"@jridgewell/resolve-uri": "^3.1.0",
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||||
@@ -1702,9 +1721,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/discord-api-types": {
|
"node_modules/discord-api-types": {
|
||||||
"version": "0.38.33",
|
"version": "0.38.36",
|
||||||
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.38.33.tgz",
|
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.38.36.tgz",
|
||||||
"integrity": "sha512-oau1V7OzrNX8yNi+DfQpoLZCNCv7cTFmvPKwHfMrA/tewsO6iQKrMTzA7pa3iBSj0fED6NlklJ/1B/cC1kI08Q==",
|
"integrity": "sha512-qrbUbjjwtyeBg5HsAlm1C859epfOyiLjPqAOzkdWlCNsZCWJrertnETF/NwM8H+waMFU58xGSc5eXUfXah+WTQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"scripts/actions/documentation"
|
"scripts/actions/documentation"
|
||||||
@@ -2958,10 +2977,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/strip-ansi": {
|
"node_modules/strip-ansi": {
|
||||||
"version": "7.1.0",
|
"version": "7.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
|
||||||
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
|
"integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-regex": "^6.0.1"
|
"ansi-regex": "^6.0.1"
|
||||||
},
|
},
|
||||||
@@ -3176,14 +3196,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/to-fast-properties": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/token-stream": {
|
"node_modules/token-stream": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz",
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@
|
|||||||
"better-sqlite3": "^12.2.0",
|
"better-sqlite3": "^12.2.0",
|
||||||
"chunk-text": "^2.0.1",
|
"chunk-text": "^2.0.1",
|
||||||
"cloudstorm": "^0.14.0",
|
"cloudstorm": "^0.14.0",
|
||||||
"discord-api-types": "^0.38.31",
|
"discord-api-types": "^0.38.36",
|
||||||
"domino": "^2.1.6",
|
"domino": "^2.1.6",
|
||||||
"enquirer": "^2.4.1",
|
"enquirer": "^2.4.1",
|
||||||
"entities": "^5.0.0",
|
"entities": "^5.0.0",
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ function convertNameAndTopic(channel, guild, customName) {
|
|||||||
* Async because it may create the guild and/or upload the guild icon to mxc.
|
* Async because it may create the guild and/or upload the guild icon to mxc.
|
||||||
* @param {DiscordTypes.APIGuildTextChannel | DiscordTypes.APIThreadChannel} channel
|
* @param {DiscordTypes.APIGuildTextChannel | DiscordTypes.APIThreadChannel} channel
|
||||||
* @param {DiscordTypes.APIGuild} guild
|
* @param {DiscordTypes.APIGuild} guild
|
||||||
* @param {{api: {getStateEvent: typeof api.getStateEvent}}} di simple-as-nails dependency injection for the matrix API
|
* @param {{api: {getStateEvent: typeof api.getStateEvent, getStateEventOuter: typeof api.getStateEventOuter}}} di simple-as-nails dependency injection for the matrix API
|
||||||
*/
|
*/
|
||||||
async function channelToKState(channel, guild, di) {
|
async function channelToKState(channel, guild, di) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -126,16 +126,17 @@ async function channelToKState(channel, guild, di) {
|
|||||||
const everyoneCanSend = dUtils.hasPermission(everyonePermissions, DiscordTypes.PermissionFlagsBits.SendMessages)
|
const everyoneCanSend = dUtils.hasPermission(everyonePermissions, DiscordTypes.PermissionFlagsBits.SendMessages)
|
||||||
const everyoneCanMentionEveryone = dUtils.hasAllPermissions(everyonePermissions, ["MentionEveryone"])
|
const everyoneCanMentionEveryone = dUtils.hasAllPermissions(everyonePermissions, ["MentionEveryone"])
|
||||||
|
|
||||||
/** @type {Ty.Event.M_Power_Levels} */
|
const spacePowerDetails = await mUtils.getEffectivePower(guildSpaceID, [], di.api)
|
||||||
const spacePowerEvent = await di.api.getStateEvent(guildSpaceID, "m.room.power_levels", "")
|
const spaceCreatorsAndFounders = spacePowerDetails.allCreators
|
||||||
const spacePower = spacePowerEvent.users
|
.concat(Object.entries(spacePowerDetails.powerLevels.users ?? {}).filter(([, power]) => power >= spacePowerDetails.tombstone).map(([mxid]) => mxid))
|
||||||
|
|
||||||
const globalAdmins = select("member_power", ["mxid", "power_level"], {room_id: "*"}).all()
|
const globalAdmins = select("member_power", ["mxid", "power_level"], {room_id: "*"}).all()
|
||||||
const globalAdminPower = globalAdmins.reduce((a, c) => (a[c.mxid] = c.power_level, a), {})
|
const globalAdminPower = globalAdmins.reduce((a, c) => (a[c.mxid] = c.power_level, a), {})
|
||||||
const additionalCreators = select("member_power", "mxid", {room_id: "*"}, "AND power_level > 100").pluck().all()
|
|
||||||
|
|
||||||
|
const additionalCreators = select("member_power", "mxid", {room_id: "*"}, "AND power_level > 100").pluck().all().concat(spaceCreatorsAndFounders)
|
||||||
const creationContent = {}
|
const creationContent = {}
|
||||||
creationContent.additional_creators = additionalCreators
|
creationContent.additional_creators = additionalCreators
|
||||||
|
|
||||||
if (channel.type === DiscordTypes.ChannelType.GuildForum) creationContent.type = "m.space"
|
if (channel.type === DiscordTypes.ChannelType.GuildForum) creationContent.type = "m.space"
|
||||||
|
|
||||||
/** @type {any} */
|
/** @type {any} */
|
||||||
@@ -162,10 +163,10 @@ async function channelToKState(channel, guild, di) {
|
|||||||
notifications: {
|
notifications: {
|
||||||
room: everyoneCanMentionEveryone ? 0 : 20
|
room: everyoneCanMentionEveryone ? 0 : 20
|
||||||
},
|
},
|
||||||
users: {...spacePower, ...globalAdminPower}
|
users: {...spacePowerDetails.powerLevels.users, ...globalAdminPower}
|
||||||
},
|
},
|
||||||
[`uk.half-shot.bridge/moe.cadence.ooye://discord/${guild.id}/${channel.id}`]: {
|
[`uk.half-shot.bridge/moe.cadence.ooye://discord/${guild.id}/${channel.id}`]: {
|
||||||
bridgebot: `@${reg.sender_localpart}:${reg.ooye.server_name}`,
|
bridgebot: mUtils.bot,
|
||||||
protocol: {
|
protocol: {
|
||||||
id: "discord",
|
id: "discord",
|
||||||
displayname: "Discord"
|
displayname: "Discord"
|
||||||
|
|||||||
@@ -9,19 +9,44 @@ const testData = require("../../../test/data")
|
|||||||
const passthrough = require("../../passthrough")
|
const passthrough = require("../../passthrough")
|
||||||
const {db} = passthrough
|
const {db} = passthrough
|
||||||
|
|
||||||
|
function mockAPI(t) {
|
||||||
test("channel2room: discoverable privacy room", async t => {
|
|
||||||
let called = 0
|
let called = 0
|
||||||
async function getStateEvent(roomID, type, key) { // getting power levels from space to apply to room
|
return {
|
||||||
|
getCalled() {
|
||||||
|
return called
|
||||||
|
},
|
||||||
|
async getStateEvent(roomID, type, key) { // getting power levels from space to apply to room
|
||||||
called++
|
called++
|
||||||
t.equal(roomID, "!jjmvBegULiLucuWEHU:cadence.moe")
|
t.equal(roomID, "!jjmvBegULiLucuWEHU:cadence.moe")
|
||||||
t.equal(type, "m.room.power_levels")
|
t.equal(type, "m.room.power_levels")
|
||||||
t.equal(key, "")
|
t.equal(key, "")
|
||||||
return {users: {"@example:matrix.org": 50}}
|
return {users: {"@example:matrix.org": 50}, events: {"m.room.tombstone": 100}}
|
||||||
|
},
|
||||||
|
async getStateEventOuter(roomID, type, key) {
|
||||||
|
called++
|
||||||
|
t.equal(roomID, "!jjmvBegULiLucuWEHU:cadence.moe")
|
||||||
|
t.equal(type, "m.room.create")
|
||||||
|
t.equal(key, "")
|
||||||
|
return {
|
||||||
|
type: "m.room.create",
|
||||||
|
state_key: "",
|
||||||
|
content: {
|
||||||
|
room_version: "11"
|
||||||
|
},
|
||||||
|
event_id: "$create",
|
||||||
|
origin_server_ts: 0,
|
||||||
|
room_id: "!jjmvBegULiLucuWEHU:cadence.moe",
|
||||||
|
sender: "@_ooye_bot:cadence.moe"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test("channel2room: discoverable privacy room", async t => {
|
||||||
|
const api = mockAPI(t)
|
||||||
db.prepare("UPDATE guild_space SET privacy_level = 2").run()
|
db.prepare("UPDATE guild_space SET privacy_level = 2").run()
|
||||||
t.deepEqual(
|
t.deepEqual(
|
||||||
kstateStripConditionals(await channelToKState(testData.channel.general, testData.guild.general, {api: {getStateEvent}}).then(x => x.channelKState)),
|
kstateStripConditionals(await channelToKState(testData.channel.general, testData.guild.general, {api}).then(x => x.channelKState)),
|
||||||
Object.assign({}, testData.room.general, {
|
Object.assign({}, testData.room.general, {
|
||||||
"m.room.guest_access/": {guest_access: "forbidden"},
|
"m.room.guest_access/": {guest_access: "forbidden"},
|
||||||
"m.room.join_rules/": {join_rule: "public"},
|
"m.room.join_rules/": {join_rule: "public"},
|
||||||
@@ -29,58 +54,37 @@ test("channel2room: discoverable privacy room", async t => {
|
|||||||
"m.room.power_levels/": mixin({users: {"@example:matrix.org": 50}}, testData.room.general["m.room.power_levels/"])
|
"m.room.power_levels/": mixin({users: {"@example:matrix.org": 50}}, testData.room.general["m.room.power_levels/"])
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
t.equal(called, 1)
|
t.equal(api.getCalled(), 2)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("channel2room: linkable privacy room", async t => {
|
test("channel2room: linkable privacy room", async t => {
|
||||||
let called = 0
|
const api = mockAPI(t)
|
||||||
async function getStateEvent(roomID, type, key) { // getting power levels from space to apply to room
|
|
||||||
called++
|
|
||||||
t.equal(roomID, "!jjmvBegULiLucuWEHU:cadence.moe")
|
|
||||||
t.equal(type, "m.room.power_levels")
|
|
||||||
t.equal(key, "")
|
|
||||||
return {users: {"@example:matrix.org": 50}}
|
|
||||||
}
|
|
||||||
db.prepare("UPDATE guild_space SET privacy_level = 1").run()
|
db.prepare("UPDATE guild_space SET privacy_level = 1").run()
|
||||||
t.deepEqual(
|
t.deepEqual(
|
||||||
kstateStripConditionals(await channelToKState(testData.channel.general, testData.guild.general, {api: {getStateEvent}}).then(x => x.channelKState)),
|
kstateStripConditionals(await channelToKState(testData.channel.general, testData.guild.general, {api}).then(x => x.channelKState)),
|
||||||
Object.assign({}, testData.room.general, {
|
Object.assign({}, testData.room.general, {
|
||||||
"m.room.guest_access/": {guest_access: "forbidden"},
|
"m.room.guest_access/": {guest_access: "forbidden"},
|
||||||
"m.room.join_rules/": {join_rule: "public"},
|
"m.room.join_rules/": {join_rule: "public"},
|
||||||
"m.room.power_levels/": mixin({users: {"@example:matrix.org": 50}}, testData.room.general["m.room.power_levels/"])
|
"m.room.power_levels/": mixin({users: {"@example:matrix.org": 50}}, testData.room.general["m.room.power_levels/"])
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
t.equal(called, 1)
|
t.equal(api.getCalled(), 2)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("channel2room: invite-only privacy room", async t => {
|
test("channel2room: invite-only privacy room", async t => {
|
||||||
let called = 0
|
const api = mockAPI(t)
|
||||||
async function getStateEvent(roomID, type, key) { // getting power levels from space to apply to room
|
|
||||||
called++
|
|
||||||
t.equal(roomID, "!jjmvBegULiLucuWEHU:cadence.moe")
|
|
||||||
t.equal(type, "m.room.power_levels")
|
|
||||||
t.equal(key, "")
|
|
||||||
return {users: {"@example:matrix.org": 50}}
|
|
||||||
}
|
|
||||||
db.prepare("UPDATE guild_space SET privacy_level = 0").run()
|
db.prepare("UPDATE guild_space SET privacy_level = 0").run()
|
||||||
t.deepEqual(
|
t.deepEqual(
|
||||||
kstateStripConditionals(await channelToKState(testData.channel.general, testData.guild.general, {api: {getStateEvent}}).then(x => x.channelKState)),
|
kstateStripConditionals(await channelToKState(testData.channel.general, testData.guild.general, {api}).then(x => x.channelKState)),
|
||||||
Object.assign({}, testData.room.general, {
|
Object.assign({}, testData.room.general, {
|
||||||
"m.room.power_levels/": mixin({users: {"@example:matrix.org": 50}}, testData.room.general["m.room.power_levels/"])
|
"m.room.power_levels/": mixin({users: {"@example:matrix.org": 50}}, testData.room.general["m.room.power_levels/"])
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
t.equal(called, 1)
|
t.equal(api.getCalled(), 2)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("channel2room: room where limited people can mention everyone", async t => {
|
test("channel2room: room where limited people can mention everyone", async t => {
|
||||||
let called = 0
|
const api = mockAPI(t)
|
||||||
async function getStateEvent(roomID, type, key) { // getting power levels from space to apply to room
|
|
||||||
called++
|
|
||||||
t.equal(roomID, "!jjmvBegULiLucuWEHU:cadence.moe")
|
|
||||||
t.equal(type, "m.room.power_levels")
|
|
||||||
t.equal(key, "")
|
|
||||||
return {users: {"@example:matrix.org": 50}}
|
|
||||||
}
|
|
||||||
const limitedGuild = mixin({}, testData.guild.general)
|
const limitedGuild = mixin({}, testData.guild.general)
|
||||||
limitedGuild.roles[0].permissions = (BigInt(limitedGuild.roles[0].permissions) - 131072n).toString()
|
limitedGuild.roles[0].permissions = (BigInt(limitedGuild.roles[0].permissions) - 131072n).toString()
|
||||||
const limitedRoom = mixin({}, testData.room.general, {"m.room.power_levels/": {
|
const limitedRoom = mixin({}, testData.room.general, {"m.room.power_levels/": {
|
||||||
@@ -88,41 +92,27 @@ test("channel2room: room where limited people can mention everyone", async t =>
|
|||||||
users: {"@example:matrix.org": 50}
|
users: {"@example:matrix.org": 50}
|
||||||
}})
|
}})
|
||||||
t.deepEqual(
|
t.deepEqual(
|
||||||
kstateStripConditionals(await channelToKState(testData.channel.general, limitedGuild, {api: {getStateEvent}}).then(x => x.channelKState)),
|
kstateStripConditionals(await channelToKState(testData.channel.general, limitedGuild, {api}).then(x => x.channelKState)),
|
||||||
limitedRoom
|
limitedRoom
|
||||||
)
|
)
|
||||||
t.equal(called, 1)
|
t.equal(api.getCalled(), 2)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("channel2room: matrix room that already has a custom topic set", async t => {
|
test("channel2room: matrix room that already has a custom topic set", async t => {
|
||||||
let called = 0
|
const api = mockAPI(t)
|
||||||
async function getStateEvent(roomID, type, key) { // getting power levels from space to apply to room
|
|
||||||
called++
|
|
||||||
t.equal(roomID, "!jjmvBegULiLucuWEHU: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)
|
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}}})
|
const expected = mixin({}, testData.room.general, {"m.room.power_levels/": {notifications: {room: 20}, users: {"@example:matrix.org": 50}}})
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
delete expected["m.room.topic/"]
|
delete expected["m.room.topic/"]
|
||||||
t.deepEqual(
|
t.deepEqual(
|
||||||
kstateStripConditionals(await channelToKState(testData.channel.general, testData.guild.general, {api: {getStateEvent}}).then(x => x.channelKState)),
|
kstateStripConditionals(await channelToKState(testData.channel.general, testData.guild.general, {api}).then(x => x.channelKState)),
|
||||||
expected
|
expected
|
||||||
)
|
)
|
||||||
t.equal(called, 1)
|
t.equal(api.getCalled(), 2)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("channel2room: read-only discord channel", async t => {
|
test("channel2room: read-only discord channel", async t => {
|
||||||
let called = 0
|
const api = mockAPI(t)
|
||||||
async function getStateEvent(roomID, type, key) { // getting power levels from space to apply to room
|
|
||||||
called++
|
|
||||||
t.equal(roomID, "!jjmvBegULiLucuWEHU:cadence.moe")
|
|
||||||
t.equal(type, "m.room.power_levels")
|
|
||||||
t.equal(key, "")
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
const expected = {
|
const expected = {
|
||||||
"m.room.create/": {
|
"m.room.create/": {
|
||||||
additional_creators: ["@test_auto_invite:example.org"],
|
additional_creators: ["@test_auto_invite:example.org"],
|
||||||
@@ -164,6 +154,7 @@ test("channel2room: read-only discord channel", async t => {
|
|||||||
},
|
},
|
||||||
users: {
|
users: {
|
||||||
"@test_auto_invite:example.org": 150,
|
"@test_auto_invite:example.org": 150,
|
||||||
|
"@example:matrix.org": 50
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"m.space.parent/!jjmvBegULiLucuWEHU:cadence.moe": {
|
"m.space.parent/!jjmvBegULiLucuWEHU:cadence.moe": {
|
||||||
@@ -193,10 +184,10 @@ test("channel2room: read-only discord channel", async t => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
t.deepEqual(
|
t.deepEqual(
|
||||||
kstateStripConditionals(await channelToKState(testData.channel.updates, testData.guild.general, {api: {getStateEvent}}).then(x => x.channelKState)),
|
kstateStripConditionals(await channelToKState(testData.channel.updates, testData.guild.general, {api}).then(x => x.channelKState)),
|
||||||
expected
|
expected
|
||||||
)
|
)
|
||||||
t.equal(called, 1)
|
t.equal(api.getCalled(), 2)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("convertNameAndTopic: custom name and topic", t => {
|
test("convertNameAndTopic: custom name and topic", t => {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const {test} = require("supertape")
|
const {test} = require("supertape")
|
||||||
const {messageToEvent} = require("./message-to-event")
|
const {messageToEvent} = require("./message-to-event")
|
||||||
const data = require("../../../test/data")
|
const data = require("../../../test/data")
|
||||||
|
const {mockGetEffectivePower} = require("../../m2d/converters/utils.test")
|
||||||
const {db} = require("../../passthrough")
|
const {db} = require("../../passthrough")
|
||||||
|
|
||||||
test("message2event embeds: nothing but a field", async t => {
|
test("message2event embeds: nothing but a field", async t => {
|
||||||
@@ -86,17 +87,7 @@ test("message2event embeds: blockquote in embed", async t => {
|
|||||||
let called = 0
|
let called = 0
|
||||||
const events = await messageToEvent(data.message_with_embeds.blockquote_in_embed, data.guild.general, {}, {
|
const events = await messageToEvent(data.message_with_embeds.blockquote_in_embed, data.guild.general, {}, {
|
||||||
api: {
|
api: {
|
||||||
async getStateEvent(roomID, type, key) {
|
getEffectivePower: mockGetEffectivePower(),
|
||||||
called++
|
|
||||||
t.equal(roomID, "!qzDBLKlildpzrrOnFZ:cadence.moe")
|
|
||||||
t.equal(type, "m.room.power_levels")
|
|
||||||
t.equal(key, "")
|
|
||||||
return {
|
|
||||||
users: {
|
|
||||||
"@_ooye_bot:cadence.moe": 100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async getJoinedMembers(roomID) {
|
async getJoinedMembers(roomID) {
|
||||||
called++
|
called++
|
||||||
t.equal(roomID, "!qzDBLKlildpzrrOnFZ:cadence.moe")
|
t.equal(roomID, "!qzDBLKlildpzrrOnFZ:cadence.moe")
|
||||||
@@ -124,7 +115,7 @@ test("message2event embeds: blockquote in embed", async t => {
|
|||||||
formatted_body: "<blockquote><p><strong><a href=\"https://matrix.to/#/!qzDBLKlildpzrrOnFZ:cadence.moe/$dVCLyj6kxb3DaAWDtjcv2kdSny8JMMHdDhCMz8mDxVo?via=cadence.moe&via=example.invalid\">⏺️ minimus</a></strong></p><p>reply draft<br><blockquote>The following is a message composed via consensus of the Stinker Council.<br><br>For those who are not currently aware of our existence, we represent the organization known as Wonderland. Our previous mission centered around the assortment and study of puzzling objects, entities and other assorted phenomena. This mission was the focus of our organization for more than 28 years.<br><br>Due to circumstances outside of our control, this directive has now changed. Our new mission will be the extermination of the stinker race.<br><br>There will be no further communication.</blockquote></p><p><a href=\"https://matrix.to/#/!qzDBLKlildpzrrOnFZ:cadence.moe/$dVCLyj6kxb3DaAWDtjcv2kdSny8JMMHdDhCMz8mDxVo?via=cadence.moe&via=example.invalid\">Go to Message</a></p></blockquote>",
|
formatted_body: "<blockquote><p><strong><a href=\"https://matrix.to/#/!qzDBLKlildpzrrOnFZ:cadence.moe/$dVCLyj6kxb3DaAWDtjcv2kdSny8JMMHdDhCMz8mDxVo?via=cadence.moe&via=example.invalid\">⏺️ minimus</a></strong></p><p>reply draft<br><blockquote>The following is a message composed via consensus of the Stinker Council.<br><br>For those who are not currently aware of our existence, we represent the organization known as Wonderland. Our previous mission centered around the assortment and study of puzzling objects, entities and other assorted phenomena. This mission was the focus of our organization for more than 28 years.<br><br>Due to circumstances outside of our control, this directive has now changed. Our new mission will be the extermination of the stinker race.<br><br>There will be no further communication.</blockquote></p><p><a href=\"https://matrix.to/#/!qzDBLKlildpzrrOnFZ:cadence.moe/$dVCLyj6kxb3DaAWDtjcv2kdSny8JMMHdDhCMz8mDxVo?via=cadence.moe&via=example.invalid\">Go to Message</a></p></blockquote>",
|
||||||
"m.mentions": {}
|
"m.mentions": {}
|
||||||
}])
|
}])
|
||||||
t.equal(called, 2, "should call getStateEvent and getJoinedMembers once each")
|
t.equal(called, 1, "should call getJoinedMembers once")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("message2event embeds: crazy html is all escaped", async t => {
|
test("message2event embeds: crazy html is all escaped", async t => {
|
||||||
@@ -343,16 +334,7 @@ test("message2event embeds: tenor gif should show a video link without a provide
|
|||||||
test("message2event embeds: if discord creates an embed preview for a discord channel link, don't copy that embed", async t => {
|
test("message2event embeds: if discord creates an embed preview for a discord channel link, don't copy that embed", async t => {
|
||||||
const events = await messageToEvent(data.message_with_embeds.discord_server_included_punctuation_bad_discord, data.guild.general, {}, {
|
const events = await messageToEvent(data.message_with_embeds.discord_server_included_punctuation_bad_discord, data.guild.general, {}, {
|
||||||
api: {
|
api: {
|
||||||
async getStateEvent(roomID, type, key) {
|
getEffectivePower: mockGetEffectivePower(),
|
||||||
t.equal(roomID, "!TqlyQmifxGUggEmdBN:cadence.moe")
|
|
||||||
t.equal(type, "m.room.power_levels")
|
|
||||||
t.equal(key, "")
|
|
||||||
return {
|
|
||||||
users: {
|
|
||||||
"@_ooye_bot:cadence.moe": 100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async getJoinedMembers(roomID) {
|
async getJoinedMembers(roomID) {
|
||||||
t.equal(roomID, "!TqlyQmifxGUggEmdBN:cadence.moe")
|
t.equal(roomID, "!TqlyQmifxGUggEmdBN:cadence.moe")
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ const {test} = require("supertape")
|
|||||||
const {messageToEvent} = require("./message-to-event")
|
const {messageToEvent} = require("./message-to-event")
|
||||||
const {MatrixServerError} = require("../../matrix/mreq")
|
const {MatrixServerError} = require("../../matrix/mreq")
|
||||||
const data = require("../../../test/data")
|
const data = require("../../../test/data")
|
||||||
|
const {mockGetEffectivePower} = require("../../m2d/converters/utils.test")
|
||||||
const Ty = require("../../types")
|
const Ty = require("../../types")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,17 +67,7 @@ test("message2event: simple room mention", async t => {
|
|||||||
let called = 0
|
let called = 0
|
||||||
const events = await messageToEvent(data.message.simple_room_mention, data.guild.general, {}, {
|
const events = await messageToEvent(data.message.simple_room_mention, data.guild.general, {}, {
|
||||||
api: {
|
api: {
|
||||||
async getStateEvent(roomID, type, key) {
|
getEffectivePower: mockGetEffectivePower(),
|
||||||
called++
|
|
||||||
t.equal(roomID, "!BnKuBPCvyfOkhcUjEu:cadence.moe")
|
|
||||||
t.equal(type, "m.room.power_levels")
|
|
||||||
t.equal(key, "")
|
|
||||||
return {
|
|
||||||
users: {
|
|
||||||
"@_ooye_bot:cadence.moe": 100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async getJoinedMembers(roomID) {
|
async getJoinedMembers(roomID) {
|
||||||
called++
|
called++
|
||||||
t.equal(roomID, "!BnKuBPCvyfOkhcUjEu:cadence.moe")
|
t.equal(roomID, "!BnKuBPCvyfOkhcUjEu:cadence.moe")
|
||||||
@@ -97,24 +88,14 @@ test("message2event: simple room mention", async t => {
|
|||||||
format: "org.matrix.custom.html",
|
format: "org.matrix.custom.html",
|
||||||
formatted_body: '<a href="https://matrix.to/#/!BnKuBPCvyfOkhcUjEu:cadence.moe?via=cadence.moe&via=matrix.org">#worm-farm</a>'
|
formatted_body: '<a href="https://matrix.to/#/!BnKuBPCvyfOkhcUjEu:cadence.moe?via=cadence.moe&via=matrix.org">#worm-farm</a>'
|
||||||
}])
|
}])
|
||||||
t.equal(called, 2, "should call getStateEvent and getJoinedMembers once each")
|
t.equal(called, 1, "should call getJoinedMembers")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("message2event: simple room link", async t => {
|
test("message2event: simple room link", async t => {
|
||||||
let called = 0
|
let called = 0
|
||||||
const events = await messageToEvent(data.message.simple_room_link, data.guild.general, {}, {
|
const events = await messageToEvent(data.message.simple_room_link, data.guild.general, {}, {
|
||||||
api: {
|
api: {
|
||||||
async getStateEvent(roomID, type, key) {
|
getEffectivePower: mockGetEffectivePower(),
|
||||||
called++
|
|
||||||
t.equal(roomID, "!BnKuBPCvyfOkhcUjEu:cadence.moe")
|
|
||||||
t.equal(type, "m.room.power_levels")
|
|
||||||
t.equal(key, "")
|
|
||||||
return {
|
|
||||||
users: {
|
|
||||||
"@_ooye_bot:cadence.moe": 100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async getJoinedMembers(roomID) {
|
async getJoinedMembers(roomID) {
|
||||||
called++
|
called++
|
||||||
t.equal(roomID, "!BnKuBPCvyfOkhcUjEu:cadence.moe")
|
t.equal(roomID, "!BnKuBPCvyfOkhcUjEu:cadence.moe")
|
||||||
@@ -135,24 +116,14 @@ test("message2event: simple room link", async t => {
|
|||||||
format: "org.matrix.custom.html",
|
format: "org.matrix.custom.html",
|
||||||
formatted_body: '<a href="https://matrix.to/#/!BnKuBPCvyfOkhcUjEu:cadence.moe?via=cadence.moe&via=matrix.org">#worm-farm</a>'
|
formatted_body: '<a href="https://matrix.to/#/!BnKuBPCvyfOkhcUjEu:cadence.moe?via=cadence.moe&via=matrix.org">#worm-farm</a>'
|
||||||
}])
|
}])
|
||||||
t.equal(called, 2, "should call getStateEvent and getJoinedMembers once each")
|
t.equal(called, 1, "should call getJoinedMembers once")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("message2event: nicked room mention", async t => {
|
test("message2event: nicked room mention", async t => {
|
||||||
let called = 0
|
let called = 0
|
||||||
const events = await messageToEvent(data.message.nicked_room_mention, data.guild.general, {}, {
|
const events = await messageToEvent(data.message.nicked_room_mention, data.guild.general, {}, {
|
||||||
api: {
|
api: {
|
||||||
async getStateEvent(roomID, type, key) {
|
getEffectivePower: mockGetEffectivePower(),
|
||||||
called++
|
|
||||||
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
|
||||||
t.equal(type, "m.room.power_levels")
|
|
||||||
t.equal(key, "")
|
|
||||||
return {
|
|
||||||
users: {
|
|
||||||
"@_ooye_bot:cadence.moe": 100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async getJoinedMembers(roomID) {
|
async getJoinedMembers(roomID) {
|
||||||
called++
|
called++
|
||||||
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
||||||
@@ -173,7 +144,7 @@ test("message2event: nicked room mention", async t => {
|
|||||||
format: "org.matrix.custom.html",
|
format: "org.matrix.custom.html",
|
||||||
formatted_body: '<a href="https://matrix.to/#/!kLRqKKUQXcibIMtOpl:cadence.moe?via=cadence.moe&via=matrix.org">#main</a>'
|
formatted_body: '<a href="https://matrix.to/#/!kLRqKKUQXcibIMtOpl:cadence.moe?via=cadence.moe&via=matrix.org">#main</a>'
|
||||||
}])
|
}])
|
||||||
t.equal(called, 2, "should call getStateEvent and getJoinedMembers once each")
|
t.equal(called, 1, "should call getJoinedMembers once")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("message2event: unknown room mention", async t => {
|
test("message2event: unknown room mention", async t => {
|
||||||
@@ -224,17 +195,7 @@ test("message2event: simple message link", async t => {
|
|||||||
let called = 0
|
let called = 0
|
||||||
const events = await messageToEvent(data.message.simple_message_link, data.guild.general, {}, {
|
const events = await messageToEvent(data.message.simple_message_link, data.guild.general, {}, {
|
||||||
api: {
|
api: {
|
||||||
async getStateEvent(roomID, type, key) {
|
getEffectivePower: mockGetEffectivePower(),
|
||||||
called++
|
|
||||||
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
|
||||||
t.equal(type, "m.room.power_levels")
|
|
||||||
t.equal(key, "")
|
|
||||||
return {
|
|
||||||
users: {
|
|
||||||
"@_ooye_bot:cadence.moe": 100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async getJoinedMembers(roomID) {
|
async getJoinedMembers(roomID) {
|
||||||
called++
|
called++
|
||||||
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
||||||
@@ -255,13 +216,14 @@ test("message2event: simple message link", async t => {
|
|||||||
format: "org.matrix.custom.html",
|
format: "org.matrix.custom.html",
|
||||||
formatted_body: '<a href="https://matrix.to/#/!kLRqKKUQXcibIMtOpl:cadence.moe/$X16nfVks1wsrhq4E9SSLiqrf2N8KD0erD0scZG7U5xg?via=cadence.moe&via=super.invalid">https://matrix.to/#/!kLRqKKUQXcibIMtOpl:cadence.moe/$X16nfVks1wsrhq4E9SSLiqrf2N8KD0erD0scZG7U5xg?via=cadence.moe&via=super.invalid</a>'
|
formatted_body: '<a href="https://matrix.to/#/!kLRqKKUQXcibIMtOpl:cadence.moe/$X16nfVks1wsrhq4E9SSLiqrf2N8KD0erD0scZG7U5xg?via=cadence.moe&via=super.invalid">https://matrix.to/#/!kLRqKKUQXcibIMtOpl:cadence.moe/$X16nfVks1wsrhq4E9SSLiqrf2N8KD0erD0scZG7U5xg?via=cadence.moe&via=super.invalid</a>'
|
||||||
}])
|
}])
|
||||||
t.equal(called, 2, "should call getStateEvent and getJoinedMembers once each")
|
t.equal(called, 1, "should call getJoinedMembers once")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("message2event: message link that OOYE doesn't know about", async t => {
|
test("message2event: message link that OOYE doesn't know about", async t => {
|
||||||
let called = 0
|
let called = 0
|
||||||
const events = await messageToEvent(data.message.message_link_to_before_ooye, data.guild.general, {}, {
|
const events = await messageToEvent(data.message.message_link_to_before_ooye, data.guild.general, {}, {
|
||||||
api: {
|
api: {
|
||||||
|
getEffectivePower: mockGetEffectivePower(),
|
||||||
async getEventForTimestamp(roomID, ts) {
|
async getEventForTimestamp(roomID, ts) {
|
||||||
called++
|
called++
|
||||||
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
||||||
@@ -270,17 +232,6 @@ test("message2event: message link that OOYE doesn't know about", async t => {
|
|||||||
origin_server_ts: 1613287812754
|
origin_server_ts: 1613287812754
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async getStateEvent(roomID, type, key) { // for ?via calculation
|
|
||||||
called++
|
|
||||||
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
|
||||||
t.equal(type, "m.room.power_levels")
|
|
||||||
t.equal(key, "")
|
|
||||||
return {
|
|
||||||
users: {
|
|
||||||
"@_ooye_bot:cadence.moe": 100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async getJoinedMembers(roomID) { // for ?via calculation
|
async getJoinedMembers(roomID) { // for ?via calculation
|
||||||
called++
|
called++
|
||||||
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
||||||
@@ -303,7 +254,7 @@ test("message2event: message link that OOYE doesn't know about", async t => {
|
|||||||
formatted_body: "Me: I'll scroll up to find a certain message I'll send<br><em>scrolls up and clicks message links for god knows how long</em><br><em>completely forgets what they were looking for and simply begins scrolling up to find some fun moments</em><br><em>stumbles upon:</em> "
|
formatted_body: "Me: I'll scroll up to find a certain message I'll send<br><em>scrolls up and clicks message links for god knows how long</em><br><em>completely forgets what they were looking for and simply begins scrolling up to find some fun moments</em><br><em>stumbles upon:</em> "
|
||||||
+ '<a href="https://matrix.to/#/!kLRqKKUQXcibIMtOpl:cadence.moe/$E8IQDGFqYzOU7BwY5Z74Bg-cwaU9OthXSroaWtgYc7U?via=cadence.moe&via=matrix.org">https://matrix.to/#/!kLRqKKUQXcibIMtOpl:cadence.moe/$E8IQDGFqYzOU7BwY5Z74Bg-cwaU9OthXSroaWtgYc7U?via=cadence.moe&via=matrix.org</a>'
|
+ '<a href="https://matrix.to/#/!kLRqKKUQXcibIMtOpl:cadence.moe/$E8IQDGFqYzOU7BwY5Z74Bg-cwaU9OthXSroaWtgYc7U?via=cadence.moe&via=matrix.org">https://matrix.to/#/!kLRqKKUQXcibIMtOpl:cadence.moe/$E8IQDGFqYzOU7BwY5Z74Bg-cwaU9OthXSroaWtgYc7U?via=cadence.moe&via=matrix.org</a>'
|
||||||
}])
|
}])
|
||||||
t.equal(called, 3, "getEventForTimestamp, getStateEvent, and getJoinedMembers should be called once each")
|
t.equal(called, 2, "getEventForTimestamp and getJoinedMembers should be called once each")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("message2event: message timestamp failed to fetch", async t => {
|
test("message2event: message timestamp failed to fetch", async t => {
|
||||||
@@ -318,17 +269,7 @@ test("message2event: message timestamp failed to fetch", async t => {
|
|||||||
error: "Unable to find event from 1726762095974 in direction Direction.FORWARDS"
|
error: "Unable to find event from 1726762095974 in direction Direction.FORWARDS"
|
||||||
}, {})
|
}, {})
|
||||||
},
|
},
|
||||||
async getStateEvent(roomID, type, key) { // for ?via calculation
|
getEffectivePower: mockGetEffectivePower(),
|
||||||
called++
|
|
||||||
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
|
||||||
t.equal(type, "m.room.power_levels")
|
|
||||||
t.equal(key, "")
|
|
||||||
return {
|
|
||||||
users: {
|
|
||||||
"@_ooye_bot:cadence.moe": 100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async getJoinedMembers(roomID) { // for ?via calculation
|
async getJoinedMembers(roomID) { // for ?via calculation
|
||||||
called++
|
called++
|
||||||
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
||||||
@@ -351,7 +292,7 @@ test("message2event: message timestamp failed to fetch", async t => {
|
|||||||
formatted_body: "Me: I'll scroll up to find a certain message I'll send<br><em>scrolls up and clicks message links for god knows how long</em><br><em>completely forgets what they were looking for and simply begins scrolling up to find some fun moments</em><br><em>stumbles upon:</em> "
|
formatted_body: "Me: I'll scroll up to find a certain message I'll send<br><em>scrolls up and clicks message links for god knows how long</em><br><em>completely forgets what they were looking for and simply begins scrolling up to find some fun moments</em><br><em>stumbles upon:</em> "
|
||||||
+ '[unknown event, timestamp resolution failed, in room: <a href="https://matrix.to/#/!kLRqKKUQXcibIMtOpl:cadence.moe?via=cadence.moe&via=matrix.org">https://matrix.to/#/!kLRqKKUQXcibIMtOpl:cadence.moe?via=cadence.moe&via=matrix.org</a>]'
|
+ '[unknown event, timestamp resolution failed, in room: <a href="https://matrix.to/#/!kLRqKKUQXcibIMtOpl:cadence.moe?via=cadence.moe&via=matrix.org">https://matrix.to/#/!kLRqKKUQXcibIMtOpl:cadence.moe?via=cadence.moe&via=matrix.org</a>]'
|
||||||
}])
|
}])
|
||||||
t.equal(called, 3, "getEventForTimestamp, getStateEvent, and getJoinedMembers should be called once each")
|
t.equal(called, 2, "getEventForTimestamp and getJoinedMembers should be called once each")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("message2event: message link from another server", async t => {
|
test("message2event: message link from another server", async t => {
|
||||||
@@ -1136,6 +1077,7 @@ test("message2event: forwarded image", async t => {
|
|||||||
test("message2event: constructed forwarded message", async t => {
|
test("message2event: constructed forwarded message", async t => {
|
||||||
const events = await messageToEvent(data.message.constructed_forwarded_message, {}, {}, {
|
const events = await messageToEvent(data.message.constructed_forwarded_message, {}, {}, {
|
||||||
api: {
|
api: {
|
||||||
|
getEffectivePower: mockGetEffectivePower(),
|
||||||
async getJoinedMembers() {
|
async getJoinedMembers() {
|
||||||
return {
|
return {
|
||||||
joined: {
|
joined: {
|
||||||
@@ -1194,6 +1136,7 @@ test("message2event: constructed forwarded message", async t => {
|
|||||||
test("message2event: constructed forwarded text", async t => {
|
test("message2event: constructed forwarded text", async t => {
|
||||||
const events = await messageToEvent(data.message.constructed_forwarded_text, {}, {}, {
|
const events = await messageToEvent(data.message.constructed_forwarded_text, {}, {}, {
|
||||||
api: {
|
api: {
|
||||||
|
getEffectivePower: mockGetEffectivePower(),
|
||||||
async getJoinedMembers() {
|
async getJoinedMembers() {
|
||||||
return {
|
return {
|
||||||
joined: {
|
joined: {
|
||||||
@@ -1331,6 +1274,7 @@ test("message2event: vc invite event renders embed", async t => {
|
|||||||
test("message2event: vc invite event renders embed with room link", async t => {
|
test("message2event: vc invite event renders embed with room link", async t => {
|
||||||
const events = await messageToEvent({content: "https://discord.gg/placeholder?event=1381174024801095751"}, {}, {}, {
|
const events = await messageToEvent({content: "https://discord.gg/placeholder?event=1381174024801095751"}, {}, {}, {
|
||||||
api: {
|
api: {
|
||||||
|
getEffectivePower: mockGetEffectivePower(),
|
||||||
getJoinedMembers: async () => ({
|
getJoinedMembers: async () => ({
|
||||||
joined: {
|
joined: {
|
||||||
"@_ooye_bot:cadence.moe": {display_name: null, avatar_url: null},
|
"@_ooye_bot:cadence.moe": {display_name: null, avatar_url: null},
|
||||||
@@ -1380,6 +1324,7 @@ test("message2event: channel links are converted even inside lists (parser post-
|
|||||||
+ "\nThis list will probably change in the future"
|
+ "\nThis list will probably change in the future"
|
||||||
}, data.guild.general, {}, {
|
}, data.guild.general, {}, {
|
||||||
api: {
|
api: {
|
||||||
|
getEffectivePower: mockGetEffectivePower(),
|
||||||
getJoinedMembers(roomID) {
|
getJoinedMembers(roomID) {
|
||||||
called++
|
called++
|
||||||
t.equal(roomID, "!qzDBLKlildpzrrOnFZ:cadence.moe")
|
t.equal(roomID, "!qzDBLKlildpzrrOnFZ:cadence.moe")
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ const {test} = require("supertape")
|
|||||||
const {threadToAnnouncement} = require("./thread-to-announcement")
|
const {threadToAnnouncement} = require("./thread-to-announcement")
|
||||||
const data = require("../../../test/data")
|
const data = require("../../../test/data")
|
||||||
const Ty = require("../../types")
|
const Ty = require("../../types")
|
||||||
|
const {mockGetEffectivePower} = require("../../m2d/converters/utils.test")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} roomID
|
* @param {string} roomID
|
||||||
@@ -30,13 +31,7 @@ function mockGetEvent(t, roomID_in, eventID_in, outer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const viaApi = {
|
const viaApi = {
|
||||||
async getStateEvent(roomID, type, key) {
|
getEffectivePower: mockGetEffectivePower(),
|
||||||
return {
|
|
||||||
users: {
|
|
||||||
"@_ooye_bot:cadence.moe": 100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async getJoinedMembers(roomID) {
|
async getJoinedMembers(roomID) {
|
||||||
return {
|
return {
|
||||||
joined: {
|
joined: {
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
CREATE TABLE room_upgrade_pending (
|
||||||
|
new_room_id TEXT NOT NULL,
|
||||||
|
old_room_id TEXT NOT NULL UNIQUE,
|
||||||
|
PRIMARY KEY (new_room_id),
|
||||||
|
FOREIGN KEY (old_room_id) REFERENCES channel_room (room_id) ON DELETE CASCADE
|
||||||
|
) WITHOUT ROWID;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
a. If the bridge bot sim already has the correct ID:
|
||||||
|
- No rows updated.
|
||||||
|
|
||||||
|
b. If the bridge bot sim has the wrong ID but there's no duplicate:
|
||||||
|
- One row updated.
|
||||||
|
|
||||||
|
c. If the bridge bot sim has the wrong ID and there's a duplicate:
|
||||||
|
- One row updated (replaces an existing row).
|
||||||
|
*/
|
||||||
|
|
||||||
|
const {discord} = require("../../passthrough")
|
||||||
|
|
||||||
|
const ones = "₀₁₂₃₄₅₆₇₈₉"
|
||||||
|
const tens = "0123456789"
|
||||||
|
|
||||||
|
module.exports = async function(db) {
|
||||||
|
/** @type {{name: string, channel_id: string, thread_parent: string | null}[]} */
|
||||||
|
const rows = db.prepare("SELECT name, channel_id, thread_parent FROM channel_room WHERE guild_id IS NULL").all()
|
||||||
|
|
||||||
|
/** @type {Map<string, string>} channel or thread ID -> guild ID */
|
||||||
|
const cache = new Map()
|
||||||
|
|
||||||
|
// Process channels
|
||||||
|
process.stdout.write(` loading metadata for ${rows.length} channels/threads... `)
|
||||||
|
for (let counter = 1; counter <= rows.length; counter++) {
|
||||||
|
process.stdout.write(String(counter).at(-1) === "0" ? tens[(counter/10)%10] : ones[counter%10])
|
||||||
|
const row = rows[counter-1]
|
||||||
|
const id = row.thread_parent || row.channel_id
|
||||||
|
if (cache.has(id)) continue
|
||||||
|
|
||||||
|
try {
|
||||||
|
var channel = await discord.snow.channel.getChannel(id)
|
||||||
|
} catch (e) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const guildID = channel.guild_id
|
||||||
|
const channels = await discord.snow.guild.getGuildChannels(guildID)
|
||||||
|
for (const channel of channels) {
|
||||||
|
cache.set(channel.id, guildID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update channels and threads
|
||||||
|
process.stdout.write("\n")
|
||||||
|
db.transaction(() => {
|
||||||
|
// Fill in missing data
|
||||||
|
for (const row of rows) {
|
||||||
|
const guildID = cache.get(row.thread_parent) || cache.get(row.channel_id)
|
||||||
|
if (guildID) {
|
||||||
|
db.prepare("UPDATE channel_room SET guild_id = ? WHERE channel_id = ?").run(guildID, row.channel_id)
|
||||||
|
} else {
|
||||||
|
db.prepare("DELETE FROM webhook WHERE channel_id = ?").run(row.channel_id)
|
||||||
|
db.prepare("DELETE FROM channel_room WHERE channel_id = ?").run(row.channel_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
-- https://sqlite.org/lang_altertable.html
|
||||||
|
|
||||||
|
-- 1
|
||||||
|
PRAGMA foreign_keys=OFF;
|
||||||
|
-- 2
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
-- 4
|
||||||
|
CREATE TABLE "new_channel_room" (
|
||||||
|
"channel_id" TEXT NOT NULL,
|
||||||
|
"room_id" TEXT NOT NULL UNIQUE,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
"nick" TEXT,
|
||||||
|
"thread_parent" TEXT,
|
||||||
|
"custom_avatar" TEXT,
|
||||||
|
"last_bridged_pin_timestamp" INTEGER,
|
||||||
|
"speedbump_id" TEXT,
|
||||||
|
"speedbump_checked" INTEGER,
|
||||||
|
"speedbump_webhook_id" TEXT,
|
||||||
|
"guild_id" TEXT NOT NULL,
|
||||||
|
"custom_topic" INTEGER DEFAULT 0,
|
||||||
|
PRIMARY KEY("channel_id"),
|
||||||
|
FOREIGN KEY("guild_id") REFERENCES "guild_active"("guild_id") ON DELETE CASCADE
|
||||||
|
) WITHOUT ROWID;
|
||||||
|
|
||||||
|
-- 5
|
||||||
|
INSERT INTO new_channel_room
|
||||||
|
(channel_id, room_id, name, nick, thread_parent, custom_avatar, last_bridged_pin_timestamp, speedbump_id, speedbump_checked, speedbump_webhook_id, guild_id, custom_topic)
|
||||||
|
SELECT channel_id, room_id, name, nick, thread_parent, custom_avatar, last_bridged_pin_timestamp, speedbump_id, speedbump_checked, speedbump_webhook_id, guild_id, custom_topic
|
||||||
|
FROM channel_room;
|
||||||
|
|
||||||
|
-- 6
|
||||||
|
DROP TABLE channel_room;
|
||||||
|
|
||||||
|
-- 7
|
||||||
|
ALTER TABLE new_channel_room RENAME TO channel_room;
|
||||||
|
|
||||||
|
-- 10
|
||||||
|
PRAGMA foreign_key_check;
|
||||||
|
|
||||||
|
-- 11
|
||||||
|
COMMIT;
|
||||||
|
-- 12
|
||||||
|
PRAGMA foreign_keys=ON;
|
||||||
Vendored
+5
@@ -103,6 +103,11 @@ export type Models = {
|
|||||||
historical_room_index: number
|
historical_room_index: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
room_upgrade_pending: {
|
||||||
|
new_room_id: string
|
||||||
|
old_room_id: string
|
||||||
|
}
|
||||||
|
|
||||||
sim: {
|
sim: {
|
||||||
user_id: string
|
user_id: string
|
||||||
username: string
|
username: string
|
||||||
|
|||||||
@@ -9,13 +9,15 @@ const {InteractionMethods} = require("snowtransfer")
|
|||||||
|
|
||||||
/** @type {import("../../matrix/api")} */
|
/** @type {import("../../matrix/api")} */
|
||||||
const api = sync.require("../../matrix/api")
|
const api = sync.require("../../matrix/api")
|
||||||
|
/** @type {import("../../m2d/converters/utils")} */
|
||||||
|
const utils = sync.require("../../m2d/converters/utils")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {DiscordTypes.APIContextMenuGuildInteraction} interaction
|
* @param {DiscordTypes.APIContextMenuGuildInteraction} interaction
|
||||||
* @param {{api: typeof api}} di
|
* @param {{api: typeof api, utils: typeof utils}} di
|
||||||
* @returns {AsyncGenerator<{[k in keyof InteractionMethods]?: Parameters<InteractionMethods[k]>[2]}>}
|
* @returns {AsyncGenerator<{[k in keyof InteractionMethods]?: Parameters<InteractionMethods[k]>[2]}>}
|
||||||
*/
|
*/
|
||||||
async function* _interact({data, guild_id}, {api}) {
|
async function* _interact({data, guild_id}, {api, utils}) {
|
||||||
// Get message info
|
// Get message info
|
||||||
const row = from("event_message")
|
const row = from("event_message")
|
||||||
.join("message_room", "message_id").join("historical_channel_room", "historical_room_index")
|
.join("message_room", "message_id").join("historical_channel_room", "historical_room_index")
|
||||||
@@ -45,12 +47,10 @@ async function* _interact({data, guild_id}, {api}) {
|
|||||||
assert(spaceID)
|
assert(spaceID)
|
||||||
|
|
||||||
// Get the power level
|
// Get the power level
|
||||||
/** @type {Ty.Event.M_Power_Levels} */
|
const {powers: {[event.sender]: userPower, [utils.bot]: botPower}} = await utils.getEffectivePower(spaceID, [event.sender, utils.bot], api)
|
||||||
const powerLevelsContent = await api.getStateEvent(spaceID, "m.room.power_levels", "")
|
|
||||||
const userPower = powerLevelsContent.users?.[event.sender] || 0
|
|
||||||
|
|
||||||
// Administrators equal to the bot cannot be demoted
|
// Administrators/founders equal to the bot cannot be demoted
|
||||||
if (userPower >= 100) {
|
if (userPower >= botPower) {
|
||||||
return yield {createInteractionResponse: {
|
return yield {createInteractionResponse: {
|
||||||
type: DiscordTypes.InteractionResponseType.ChannelMessageWithSource,
|
type: DiscordTypes.InteractionResponseType.ChannelMessageWithSource,
|
||||||
data: {
|
data: {
|
||||||
@@ -60,6 +60,8 @@ async function* _interact({data, guild_id}, {api}) {
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const adminLabel = botPower === 100 ? "Admin (you cannot undo this!)" : "Admin"
|
||||||
|
|
||||||
yield {createInteractionResponse: {
|
yield {createInteractionResponse: {
|
||||||
type: DiscordTypes.InteractionResponseType.ChannelMessageWithSource,
|
type: DiscordTypes.InteractionResponseType.ChannelMessageWithSource,
|
||||||
data: {
|
data: {
|
||||||
@@ -82,9 +84,9 @@ async function* _interact({data, guild_id}, {api}) {
|
|||||||
value: "moderator",
|
value: "moderator",
|
||||||
default: userPower >= 50 && userPower < 100
|
default: userPower >= 50 && userPower < 100
|
||||||
}, {
|
}, {
|
||||||
label: "Admin (you cannot undo this!)",
|
label: adminLabel,
|
||||||
value: "admin",
|
value: "admin",
|
||||||
default: userPower === 100
|
default: userPower >= 100
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -138,7 +140,7 @@ async function* _interactEdit({data, guild_id, message}, {api}) {
|
|||||||
|
|
||||||
/** @param {DiscordTypes.APIContextMenuGuildInteraction} interaction */
|
/** @param {DiscordTypes.APIContextMenuGuildInteraction} interaction */
|
||||||
async function interact(interaction) {
|
async function interact(interaction) {
|
||||||
for await (const response of _interact(interaction, {api})) {
|
for await (const response of _interact(interaction, {api, utils})) {
|
||||||
if (response.createInteractionResponse) {
|
if (response.createInteractionResponse) {
|
||||||
// TODO: Test if it is reasonable to remove `await` from these calls. Or zip these calls with the next interaction iteration and use Promise.all.
|
// TODO: Test if it is reasonable to remove `await` from these calls. Or zip these calls with the next interaction iteration and use Promise.all.
|
||||||
await discord.snow.interaction.createInteractionResponse(interaction.id, interaction.token, response.createInteractionResponse)
|
await discord.snow.interaction.createInteractionResponse(interaction.id, interaction.token, response.createInteractionResponse)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ const {test} = require("supertape")
|
|||||||
const DiscordTypes = require("discord-api-types/v10")
|
const DiscordTypes = require("discord-api-types/v10")
|
||||||
const {select, db} = require("../../passthrough")
|
const {select, db} = require("../../passthrough")
|
||||||
const {_interact, _interactEdit} = require("./permissions")
|
const {_interact, _interactEdit} = require("./permissions")
|
||||||
|
const {mockGetEffectivePower} = require("../../m2d/converters/utils.test")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @template T
|
* @template T
|
||||||
@@ -46,6 +47,10 @@ test("permissions: reports permissions of selected matrix user (implicit default
|
|||||||
},
|
},
|
||||||
guild_id: "112760669178241024"
|
guild_id: "112760669178241024"
|
||||||
}, {
|
}, {
|
||||||
|
utils: {
|
||||||
|
bot: "@_ooye_bot:cadence.moe",
|
||||||
|
getEffectivePower: mockGetEffectivePower()
|
||||||
|
},
|
||||||
api: {
|
api: {
|
||||||
async getEvent(roomID, eventID) {
|
async getEvent(roomID, eventID) {
|
||||||
called++
|
called++
|
||||||
@@ -54,22 +59,13 @@ test("permissions: reports permissions of selected matrix user (implicit default
|
|||||||
return {
|
return {
|
||||||
sender: "@cadence:cadence.moe"
|
sender: "@cadence:cadence.moe"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
async getStateEvent(roomID, type, key) {
|
|
||||||
called++
|
|
||||||
t.equal(roomID, "!jjmvBegULiLucuWEHU:cadence.moe") // space ID
|
|
||||||
t.equal(type, "m.room.power_levels")
|
|
||||||
t.equal(key, "")
|
|
||||||
return {
|
|
||||||
users: {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
t.equal(msgs.length, 1)
|
t.equal(msgs.length, 1)
|
||||||
t.equal(msgs[0].createInteractionResponse.data.content, "Showing permissions for `@cadence:cadence.moe`. Click to edit.")
|
t.equal(msgs[0].createInteractionResponse.data.content, "Showing permissions for `@cadence:cadence.moe`. Click to edit.")
|
||||||
t.deepEqual(msgs[0].createInteractionResponse.data.components[0].components[0].options[0], {label: "Default", value: "default", default: true})
|
t.deepEqual(msgs[0].createInteractionResponse.data.components[0].components[0].options[0], {label: "Default", value: "default", default: true})
|
||||||
t.equal(called, 2)
|
t.equal(called, 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("permissions: reports permissions of selected matrix user (moderator)", async t => {
|
test("permissions: reports permissions of selected matrix user (moderator)", async t => {
|
||||||
@@ -80,6 +76,10 @@ test("permissions: reports permissions of selected matrix user (moderator)", asy
|
|||||||
},
|
},
|
||||||
guild_id: "112760669178241024"
|
guild_id: "112760669178241024"
|
||||||
}, {
|
}, {
|
||||||
|
utils: {
|
||||||
|
bot: "@_ooye_bot:cadence.moe",
|
||||||
|
getEffectivePower: mockGetEffectivePower(["@_ooye_bot:cadence.moe"], {"@cadence:cadence.moe": 50})
|
||||||
|
},
|
||||||
api: {
|
api: {
|
||||||
async getEvent(roomID, eventID) {
|
async getEvent(roomID, eventID) {
|
||||||
called++
|
called++
|
||||||
@@ -88,27 +88,16 @@ test("permissions: reports permissions of selected matrix user (moderator)", asy
|
|||||||
return {
|
return {
|
||||||
sender: "@cadence:cadence.moe"
|
sender: "@cadence:cadence.moe"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
async getStateEvent(roomID, type, key) {
|
|
||||||
called++
|
|
||||||
t.equal(roomID, "!jjmvBegULiLucuWEHU:cadence.moe") // space ID
|
|
||||||
t.equal(type, "m.room.power_levels")
|
|
||||||
t.equal(key, "")
|
|
||||||
return {
|
|
||||||
users: {
|
|
||||||
"@cadence:cadence.moe": 50
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
t.equal(msgs.length, 1)
|
t.equal(msgs.length, 1)
|
||||||
t.equal(msgs[0].createInteractionResponse.data.content, "Showing permissions for `@cadence:cadence.moe`. Click to edit.")
|
t.equal(msgs[0].createInteractionResponse.data.content, "Showing permissions for `@cadence:cadence.moe`. Click to edit.")
|
||||||
t.deepEqual(msgs[0].createInteractionResponse.data.components[0].components[0].options[1], {label: "Moderator", value: "moderator", default: true})
|
t.deepEqual(msgs[0].createInteractionResponse.data.components[0].components[0].options[1], {label: "Moderator", value: "moderator", default: true})
|
||||||
t.equal(called, 2)
|
t.equal(called, 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("permissions: reports permissions of selected matrix user (admin)", async t => {
|
test("permissions: reports permissions of selected matrix user (admin v12 can be demoted)", async t => {
|
||||||
let called = 0
|
let called = 0
|
||||||
const msgs = await fromAsync(_interact({
|
const msgs = await fromAsync(_interact({
|
||||||
data: {
|
data: {
|
||||||
@@ -116,6 +105,10 @@ test("permissions: reports permissions of selected matrix user (admin)", async t
|
|||||||
},
|
},
|
||||||
guild_id: "112760669178241024"
|
guild_id: "112760669178241024"
|
||||||
}, {
|
}, {
|
||||||
|
utils: {
|
||||||
|
bot: "@_ooye_bot:cadence.moe",
|
||||||
|
getEffectivePower: mockGetEffectivePower(["@_ooye_bot:cadence.moe"], {"@cadence:cadence.moe": 100})
|
||||||
|
},
|
||||||
api: {
|
api: {
|
||||||
async getEvent(roomID, eventID) {
|
async getEvent(roomID, eventID) {
|
||||||
called++
|
called++
|
||||||
@@ -124,24 +117,42 @@ test("permissions: reports permissions of selected matrix user (admin)", async t
|
|||||||
return {
|
return {
|
||||||
sender: "@cadence:cadence.moe"
|
sender: "@cadence:cadence.moe"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
async getStateEvent(roomID, type, key) {
|
|
||||||
called++
|
|
||||||
t.equal(roomID, "!jjmvBegULiLucuWEHU:cadence.moe") // space ID
|
|
||||||
t.equal(type, "m.room.power_levels")
|
|
||||||
t.equal(key, "")
|
|
||||||
return {
|
|
||||||
users: {
|
|
||||||
"@cadence:cadence.moe": 100
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}))
|
||||||
|
t.equal(msgs.length, 1)
|
||||||
|
t.equal(msgs[0].createInteractionResponse.data.content, "Showing permissions for `@cadence:cadence.moe`. Click to edit.")
|
||||||
|
t.deepEqual(msgs[0].createInteractionResponse.data.components[0].components[0].options[2], {label: "Admin", value: "admin", default: true})
|
||||||
|
t.equal(called, 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("permissions: reports permissions of selected matrix user (admin v11 cannot be demoted)", async t => {
|
||||||
|
let called = 0
|
||||||
|
const msgs = await fromAsync(_interact({
|
||||||
|
data: {
|
||||||
|
target_id: "1128118177155526666"
|
||||||
|
},
|
||||||
|
guild_id: "112760669178241024"
|
||||||
|
}, {
|
||||||
|
utils: {
|
||||||
|
bot: "@_ooye_bot:cadence.moe",
|
||||||
|
getEffectivePower: mockGetEffectivePower(["@_ooye_bot:cadence.moe"], {"@cadence:cadence.moe": 100, "@_ooye_bot:cadence.moe": 100}, "11")
|
||||||
|
},
|
||||||
|
api: {
|
||||||
|
async getEvent(roomID, eventID) {
|
||||||
|
called++
|
||||||
|
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe") // room ID
|
||||||
|
t.equal(eventID, "$Ij3qo7NxMA4VPexlAiIx2CB9JbsiGhJeyt-2OvkAUe4")
|
||||||
|
return {
|
||||||
|
sender: "@cadence:cadence.moe"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
t.equal(msgs.length, 1)
|
t.equal(msgs.length, 1)
|
||||||
t.equal(msgs[0].createInteractionResponse.data.content, "`@cadence:cadence.moe` has administrator permissions. This cannot be edited.")
|
t.equal(msgs[0].createInteractionResponse.data.content, "`@cadence:cadence.moe` has administrator permissions. This cannot be edited.")
|
||||||
t.notOk(msgs[0].createInteractionResponse.data.components)
|
t.notOk(msgs[0].createInteractionResponse.data.components)
|
||||||
t.equal(called, 2)
|
t.equal(called, 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("permissions: can update user to moderator", async t => {
|
test("permissions: can update user to moderator", async t => {
|
||||||
|
|||||||
@@ -447,9 +447,8 @@ async function checkWrittenMentions(content, senderMxid, roomID, guild, di) {
|
|||||||
let writtenMentionMatch = content.match(/(?:^|[^"[<>/A-Za-z0-9])@([A-Za-z][A-Za-z0-9._\[\]\(\)-]+):?/d) // /d flag for indices requires node.js 16+
|
let writtenMentionMatch = content.match(/(?:^|[^"[<>/A-Za-z0-9])@([A-Za-z][A-Za-z0-9._\[\]\(\)-]+):?/d) // /d flag for indices requires node.js 16+
|
||||||
if (writtenMentionMatch) {
|
if (writtenMentionMatch) {
|
||||||
if (writtenMentionMatch[1] === "room") { // convert @room to @everyone
|
if (writtenMentionMatch[1] === "room") { // convert @room to @everyone
|
||||||
const powerLevels = await di.api.getStateEvent(roomID, "m.room.power_levels", "")
|
const {powers: {[senderMxid]: userPower}, powerLevels} = await mxUtils.getEffectivePower(roomID, [senderMxid], di.api)
|
||||||
const userPower = powerLevels.users?.[senderMxid] || 0
|
if (userPower >= (powerLevels.notifications?.room ?? 50)) {
|
||||||
if (userPower >= powerLevels.notifications?.room) {
|
|
||||||
return {
|
return {
|
||||||
// @ts-ignore - typescript doesn't know about indices yet
|
// @ts-ignore - typescript doesn't know about indices yet
|
||||||
content: content.slice(0, writtenMentionMatch.indices[1][0]-1) + `@everyone` + content.slice(writtenMentionMatch.indices[1][1]),
|
content: content.slice(0, writtenMentionMatch.indices[1][0]-1) + `@everyone` + content.slice(writtenMentionMatch.indices[1][1]),
|
||||||
@@ -924,7 +923,6 @@ async function eventToMessage(event, guild, di) {
|
|||||||
|
|
||||||
// Respect sender's angle brackets
|
// Respect sender's angle brackets
|
||||||
const alreadySuppressed = content[match.index-1+offset] === "<" && content[match.index+match.length+offset] === ">"
|
const alreadySuppressed = content[match.index-1+offset] === "<" && content[match.index+match.length+offset] === ">"
|
||||||
console.error(content, match.index-1+offset, content[match.index-1+offset])
|
|
||||||
if (alreadySuppressed) continue
|
if (alreadySuppressed) continue
|
||||||
// Put < > around any surviving matrix.to links
|
// Put < > around any surviving matrix.to links
|
||||||
let shouldSuppress = !!match[0].match(/^https?:\/\/matrix\.to\//)
|
let shouldSuppress = !!match[0].match(/^https?:\/\/matrix\.to\//)
|
||||||
|
|||||||
@@ -4985,7 +4985,7 @@ test("event2message: @room converts to @everyone and is allowed when the room do
|
|||||||
event_id: "$SiXetU9h9Dg-M9Frcw_C6ahnoXZ3QPZe3MVJR5tcB9A"
|
event_id: "$SiXetU9h9Dg-M9Frcw_C6ahnoXZ3QPZe3MVJR5tcB9A"
|
||||||
}, data.guild.general, {
|
}, data.guild.general, {
|
||||||
api: {
|
api: {
|
||||||
getStateEvent(roomID, type, key) {
|
async getStateEvent(roomID, type, key) {
|
||||||
called++
|
called++
|
||||||
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
||||||
t.equal(type, "m.room.power_levels")
|
t.equal(type, "m.room.power_levels")
|
||||||
@@ -4996,6 +4996,19 @@ test("event2message: @room converts to @everyone and is allowed when the room do
|
|||||||
room: 0
|
room: 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
async getStateEventOuter(roomID, type, key) {
|
||||||
|
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
||||||
|
t.equal(type, "m.room.create")
|
||||||
|
t.equal(key, "")
|
||||||
|
return {
|
||||||
|
type: "m.room.create",
|
||||||
|
state_key: "",
|
||||||
|
sender: "@_ooye_bot:cadence.moe",
|
||||||
|
content: {
|
||||||
|
room_version: "11"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
@@ -5016,7 +5029,6 @@ test("event2message: @room converts to @everyone and is allowed when the room do
|
|||||||
})
|
})
|
||||||
|
|
||||||
test("event2message: @room converts to @everyone but is not allowed when the room restricts who can use it", async t => {
|
test("event2message: @room converts to @everyone but is not allowed when the room restricts who can use it", async t => {
|
||||||
let called = 0
|
|
||||||
t.deepEqual(
|
t.deepEqual(
|
||||||
await eventToMessage({
|
await eventToMessage({
|
||||||
type: "m.room.message",
|
type: "m.room.message",
|
||||||
@@ -5031,8 +5043,7 @@ test("event2message: @room converts to @everyone but is not allowed when the roo
|
|||||||
event_id: "$SiXetU9h9Dg-M9Frcw_C6ahnoXZ3QPZe3MVJR5tcB9A"
|
event_id: "$SiXetU9h9Dg-M9Frcw_C6ahnoXZ3QPZe3MVJR5tcB9A"
|
||||||
}, data.guild.general, {
|
}, data.guild.general, {
|
||||||
api: {
|
api: {
|
||||||
getStateEvent(roomID, type, key) {
|
async getStateEvent(roomID, type, key) {
|
||||||
called++
|
|
||||||
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
||||||
t.equal(type, "m.room.power_levels")
|
t.equal(type, "m.room.power_levels")
|
||||||
t.equal(key, "")
|
t.equal(key, "")
|
||||||
@@ -5042,6 +5053,19 @@ test("event2message: @room converts to @everyone but is not allowed when the roo
|
|||||||
room: 20
|
room: 20
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
async getStateEventOuter(roomID, type, key) {
|
||||||
|
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
||||||
|
t.equal(type, "m.room.create")
|
||||||
|
t.equal(key, "")
|
||||||
|
return {
|
||||||
|
type: "m.room.create",
|
||||||
|
state_key: "",
|
||||||
|
sender: "@_ooye_bot:cadence.moe",
|
||||||
|
content: {
|
||||||
|
room_version: "11"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
@@ -5062,7 +5086,6 @@ test("event2message: @room converts to @everyone but is not allowed when the roo
|
|||||||
})
|
})
|
||||||
|
|
||||||
test("event2message: @room converts to @everyone and is allowed if the user has sufficient power to use it", async t => {
|
test("event2message: @room converts to @everyone and is allowed if the user has sufficient power to use it", async t => {
|
||||||
let called = 0
|
|
||||||
t.deepEqual(
|
t.deepEqual(
|
||||||
await eventToMessage({
|
await eventToMessage({
|
||||||
type: "m.room.message",
|
type: "m.room.message",
|
||||||
@@ -5077,8 +5100,7 @@ test("event2message: @room converts to @everyone and is allowed if the user has
|
|||||||
event_id: "$SiXetU9h9Dg-M9Frcw_C6ahnoXZ3QPZe3MVJR5tcB9A"
|
event_id: "$SiXetU9h9Dg-M9Frcw_C6ahnoXZ3QPZe3MVJR5tcB9A"
|
||||||
}, data.guild.general, {
|
}, data.guild.general, {
|
||||||
api: {
|
api: {
|
||||||
getStateEvent(roomID, type, key) {
|
async getStateEvent(roomID, type, key) {
|
||||||
called++
|
|
||||||
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
||||||
t.equal(type, "m.room.power_levels")
|
t.equal(type, "m.room.power_levels")
|
||||||
t.equal(key, "")
|
t.equal(key, "")
|
||||||
@@ -5090,6 +5112,19 @@ test("event2message: @room converts to @everyone and is allowed if the user has
|
|||||||
room: 20
|
room: 20
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
async getStateEventOuter(roomID, type, key) {
|
||||||
|
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
||||||
|
t.equal(type, "m.room.create")
|
||||||
|
t.equal(key, "")
|
||||||
|
return {
|
||||||
|
type: "m.room.create",
|
||||||
|
state_key: "",
|
||||||
|
sender: "@_ooye_bot:cadence.moe",
|
||||||
|
content: {
|
||||||
|
room_version: "11"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ class MatrixStringBuilder {
|
|||||||
* https://spec.matrix.org/v1.9/appendices/#routing
|
* https://spec.matrix.org/v1.9/appendices/#routing
|
||||||
* https://gitdab.com/cadence/out-of-your-element/issues/11
|
* https://gitdab.com/cadence/out-of-your-element/issues/11
|
||||||
* @param {string} roomID
|
* @param {string} roomID
|
||||||
* @param {{[K in "getStateEvent" | "getStateEventOuter" | "getJoinedMembers"]: import("../../matrix/api")[K]}} api
|
* @param {{[K in "getStateEvent" | "getStateEventOuter" | "getJoinedMembers"]: import("../../matrix/api")[K]} | {getEffectivePower: (roomID: string, mxids: string[], api: any) => Promise<{powers: Record<string, number>, allCreators: string[], tombstone: number, roomCreate: Ty.Event.StateOuter<Ty.Event.M_Room_Create>, powerLevels: Ty.Event.M_Power_Levels}>, getJoinedMembers: import("../../matrix/api")["getJoinedMembers"]}} api
|
||||||
*/
|
*/
|
||||||
async function getViaServers(roomID, api) {
|
async function getViaServers(roomID, api) {
|
||||||
const candidates = []
|
const candidates = []
|
||||||
@@ -138,10 +138,10 @@ async function getViaServers(roomID, api) {
|
|||||||
candidates.push(reg.ooye.server_name)
|
candidates.push(reg.ooye.server_name)
|
||||||
// Candidate 1: Highest joined non-sim non-bot power level user in the room
|
// Candidate 1: Highest joined non-sim non-bot power level user in the room
|
||||||
// https://github.com/matrix-org/matrix-react-sdk/blob/552c65db98b59406fb49562e537a2721c8505517/src/utils/permalinks/Permalinks.ts#L172
|
// https://github.com/matrix-org/matrix-react-sdk/blob/552c65db98b59406fb49562e537a2721c8505517/src/utils/permalinks/Permalinks.ts#L172
|
||||||
const {allCreators, powerLevels} = await getEffectivePower(roomID, [bot], api)
|
const call = "getEffectivePower" in api ? api.getEffectivePower(roomID, [bot], api) : getEffectivePower(roomID, [bot], api)
|
||||||
|
const {allCreators, powerLevels} = await call
|
||||||
const sorted = allCreators.concat(Object.entries(powerLevels.users ?? {}).sort((a, b) => b[1] - a[1]).map(([mxid]) => mxid)) // Highest...
|
const sorted = allCreators.concat(Object.entries(powerLevels.users ?? {}).sort((a, b) => b[1] - a[1]).map(([mxid]) => mxid)) // Highest...
|
||||||
for (const power of sorted) {
|
for (const mxid of sorted) {
|
||||||
const mxid = power[0]
|
|
||||||
if (!(mxid in joined)) continue // joined...
|
if (!(mxid in joined)) continue // joined...
|
||||||
if (userRegex.some(r => mxid.match(r))) continue // non-sim non-bot...
|
if (userRegex.some(r => mxid.match(r))) continue // non-sim non-bot...
|
||||||
const match = mxid.match(/:(.*)/)
|
const match = mxid.match(/:(.*)/)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
const e = new Error("Custom error")
|
const e = new Error("Custom error")
|
||||||
|
|
||||||
const {test} = require("supertape")
|
const {test} = require("supertape")
|
||||||
const {eventSenderIsFromDiscord, getEventIDHash, MatrixStringBuilder, getViaServers} = require("./utils")
|
const {eventSenderIsFromDiscord, getEventIDHash, MatrixStringBuilder, getViaServers, roomHasAtLeastVersion} = require("./utils")
|
||||||
const util = require("util")
|
const util = require("util")
|
||||||
|
|
||||||
/** @param {string[]} mxids */
|
/** @param {string[]} mxids */
|
||||||
@@ -88,9 +88,42 @@ test("MatrixStringBuilder: complete code coverage", t => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string[]} [creators]
|
||||||
|
* @param {{[x: string]: number}} [users]
|
||||||
|
* @param {string} [roomVersion]
|
||||||
|
*/
|
||||||
|
function mockGetEffectivePower(creators = ["@_ooye_bot:cadence.moe"], users = {}, roomVersion = "12") {
|
||||||
|
return async function getEffectivePower(roomID, mxids) {
|
||||||
|
return {
|
||||||
|
allCreators: creators,
|
||||||
|
powerLevels: {users},
|
||||||
|
powers: mxids.reduce((a, mxid) => {
|
||||||
|
if (creators.includes(mxid) && roomHasAtLeastVersion(roomVersion, 12)) a[mxid] = Infinity
|
||||||
|
else if (mxid in users) a[mxid] = users[mxid]
|
||||||
|
else a[mxid] = 0
|
||||||
|
return a
|
||||||
|
}, {}),
|
||||||
|
roomCreate: {
|
||||||
|
type: "m.room.create",
|
||||||
|
state_key: "",
|
||||||
|
sender: creators[0],
|
||||||
|
content: {
|
||||||
|
additional_creators: creators.slice(1),
|
||||||
|
room_version: roomVersion
|
||||||
|
},
|
||||||
|
room_id: roomID,
|
||||||
|
origin_server_ts: 0,
|
||||||
|
event_id: "$create"
|
||||||
|
},
|
||||||
|
tombstone: roomVersion === "12" ? 150 : 100,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
test("getViaServers: returns the server name if the room only has sim users", async t => {
|
test("getViaServers: returns the server name if the room only has sim users", async t => {
|
||||||
const result = await getViaServers("!baby", {
|
const result = await getViaServers("!baby", {
|
||||||
getStateEvent: async () => ({}),
|
getEffectivePower: mockGetEffectivePower(),
|
||||||
getJoinedMembers: async () => joinedList(["@_ooye_bot:cadence.moe", "@_ooye_hazel:cadence.moe"])
|
getJoinedMembers: async () => joinedList(["@_ooye_bot:cadence.moe", "@_ooye_hazel:cadence.moe"])
|
||||||
})
|
})
|
||||||
t.deepEqual(result, ["cadence.moe"])
|
t.deepEqual(result, ["cadence.moe"])
|
||||||
@@ -98,7 +131,7 @@ test("getViaServers: returns the server name if the room only has sim users", as
|
|||||||
|
|
||||||
test("getViaServers: also returns the most popular servers in order", async t => {
|
test("getViaServers: also returns the most popular servers in order", async t => {
|
||||||
const result = await getViaServers("!baby", {
|
const result = await getViaServers("!baby", {
|
||||||
getStateEvent: async () => ({}),
|
getEffectivePower: mockGetEffectivePower(),
|
||||||
getJoinedMembers: async () => joinedList(["@_ooye_bot:cadence.moe", "@_ooye_hazel:cadence.moe", "@cadence:cadence.moe", "@singleuser:selfhosted.invalid", "@hazel:thecollective.invalid", "@june:thecollective.invalid"])
|
getJoinedMembers: async () => joinedList(["@_ooye_bot:cadence.moe", "@_ooye_hazel:cadence.moe", "@cadence:cadence.moe", "@singleuser:selfhosted.invalid", "@hazel:thecollective.invalid", "@june:thecollective.invalid"])
|
||||||
})
|
})
|
||||||
t.deepEqual(result, ["cadence.moe", "thecollective.invalid", "selfhosted.invalid"])
|
t.deepEqual(result, ["cadence.moe", "thecollective.invalid", "selfhosted.invalid"])
|
||||||
@@ -106,20 +139,27 @@ test("getViaServers: also returns the most popular servers in order", async t =>
|
|||||||
|
|
||||||
test("getViaServers: does not return IP address servers", async t => {
|
test("getViaServers: does not return IP address servers", async t => {
|
||||||
const result = await getViaServers("!baby", {
|
const result = await getViaServers("!baby", {
|
||||||
getStateEvent: async () => ({}),
|
getEffectivePower: mockGetEffectivePower(),
|
||||||
getJoinedMembers: async () => joinedList(["@_ooye_bot:cadence.moe", "@_ooye_hazel:cadence.moe", "@cadence:45.77.232.172:8443", "@cadence:[::1]:8443", "@cadence:123example.456example.invalid"])
|
getJoinedMembers: async () => joinedList(["@_ooye_bot:cadence.moe", "@_ooye_hazel:cadence.moe", "@cadence:45.77.232.172:8443", "@cadence:[::1]:8443", "@cadence:123example.456example.invalid"])
|
||||||
})
|
})
|
||||||
t.deepEqual(result, ["cadence.moe", "123example.456example.invalid"])
|
t.deepEqual(result, ["cadence.moe", "123example.456example.invalid"])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("getViaServers: also returns the highest power level user (v12 creator)", async t => {
|
||||||
|
const result = await getViaServers("!baby", {
|
||||||
|
getEffectivePower: mockGetEffectivePower(["@_ooye_bot:cadence.moe", "@singleuser:selfhosted.invalid"], {
|
||||||
|
"@moderator:tractor.invalid": 50
|
||||||
|
}),
|
||||||
|
getJoinedMembers: async () => joinedList(["@_ooye_bot:cadence.moe", "@_ooye_hazel:cadence.moe", "@cadence:cadence.moe", "@singleuser:selfhosted.invalid", "@hazel:thecollective.invalid", "@june:thecollective.invalid", "@moderator:tractor.invalid"])
|
||||||
|
})
|
||||||
|
t.deepEqual(result, ["cadence.moe", "selfhosted.invalid", "thecollective.invalid", "tractor.invalid"])
|
||||||
|
})
|
||||||
|
|
||||||
test("getViaServers: also returns the highest power level user (100)", async t => {
|
test("getViaServers: also returns the highest power level user (100)", async t => {
|
||||||
const result = await getViaServers("!baby", {
|
const result = await getViaServers("!baby", {
|
||||||
getStateEvent: async () => ({
|
getEffectivePower: mockGetEffectivePower(["@_ooye_bot:cadence.moe"], {
|
||||||
users: {
|
|
||||||
"@moderator:tractor.invalid": 50,
|
"@moderator:tractor.invalid": 50,
|
||||||
"@singleuser:selfhosted.invalid": 100,
|
"@singleuser:selfhosted.invalid": 100
|
||||||
"@_ooye_bot:cadence.moe": 100
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
getJoinedMembers: async () => joinedList(["@_ooye_bot:cadence.moe", "@_ooye_hazel:cadence.moe", "@cadence:cadence.moe", "@singleuser:selfhosted.invalid", "@hazel:thecollective.invalid", "@june:thecollective.invalid", "@moderator:tractor.invalid"])
|
getJoinedMembers: async () => joinedList(["@_ooye_bot:cadence.moe", "@_ooye_hazel:cadence.moe", "@cadence:cadence.moe", "@singleuser:selfhosted.invalid", "@hazel:thecollective.invalid", "@june:thecollective.invalid", "@moderator:tractor.invalid"])
|
||||||
})
|
})
|
||||||
@@ -128,11 +168,8 @@ test("getViaServers: also returns the highest power level user (100)", async t =
|
|||||||
|
|
||||||
test("getViaServers: also returns the highest power level user (50)", async t => {
|
test("getViaServers: also returns the highest power level user (50)", async t => {
|
||||||
const result = await getViaServers("!baby", {
|
const result = await getViaServers("!baby", {
|
||||||
getStateEvent: async () => ({
|
getEffectivePower: mockGetEffectivePower(["@_ooye_bot:cadence.moe"], {
|
||||||
users: {
|
"@moderator:tractor.invalid": 50
|
||||||
"@moderator:tractor.invalid": 50,
|
|
||||||
"@_ooye_bot:cadence.moe": 100
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
getJoinedMembers: async () => joinedList(["@_ooye_bot:cadence.moe", "@_ooye_hazel:cadence.moe", "@cadence:cadence.moe", "@moderator:tractor.invalid", "@hazel:thecollective.invalid", "@june:thecollective.invalid", "@singleuser:selfhosted.invalid"])
|
getJoinedMembers: async () => joinedList(["@_ooye_bot:cadence.moe", "@_ooye_hazel:cadence.moe", "@cadence:cadence.moe", "@moderator:tractor.invalid", "@hazel:thecollective.invalid", "@june:thecollective.invalid", "@singleuser:selfhosted.invalid"])
|
||||||
})
|
})
|
||||||
@@ -141,38 +178,23 @@ test("getViaServers: also returns the highest power level user (50)", async t =>
|
|||||||
|
|
||||||
test("getViaServers: returns at most 4 results", async t => {
|
test("getViaServers: returns at most 4 results", async t => {
|
||||||
const result = await getViaServers("!baby", {
|
const result = await getViaServers("!baby", {
|
||||||
getStateEvent: async () => ({
|
getEffectivePower: mockGetEffectivePower(["@_ooye_bot:cadence.moe"], {
|
||||||
users: {
|
|
||||||
"@moderator:tractor.invalid": 50,
|
"@moderator:tractor.invalid": 50,
|
||||||
"@singleuser:selfhosted.invalid": 100,
|
"@singleuser:selfhosted.invalid": 100
|
||||||
"@_ooye_bot:cadence.moe": 100
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
getJoinedMembers: async () => joinedList(["@_ooye_bot:cadence.moe", "@_ooye_hazel:cadence.moe", "@cadence:cadence.moe", "@moderator:tractor.invalid", "@singleuser:selfhosted.invalid", "@hazel:thecollective.invalid", "@cadence:123example.456example.invalid"])
|
getJoinedMembers: async () => joinedList(["@_ooye_bot:cadence.moe", "@_ooye_hazel:cadence.moe", "@cadence:cadence.moe", "@moderator:tractor.invalid", "@singleuser:selfhosted.invalid", "@hazel:thecollective.invalid", "@cadence:123example.456example.invalid"])
|
||||||
})
|
})
|
||||||
t.deepEqual(result.length, 4)
|
t.deepEqual(result.length, 4)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("getViaServers: returns results even when power levels can't be fetched", async t => {
|
|
||||||
const result = await getViaServers("!baby", {
|
|
||||||
getStateEvent: async () => {
|
|
||||||
throw new Error("event not found or something")
|
|
||||||
},
|
|
||||||
getJoinedMembers: async () => joinedList(["@_ooye_bot:cadence.moe", "@_ooye_hazel:cadence.moe", "@cadence:cadence.moe", "@moderator:tractor.invalid", "@singleuser:selfhosted.invalid", "@hazel:thecollective.invalid", "@cadence:123example.456example.invalid"])
|
|
||||||
})
|
|
||||||
t.deepEqual(result.length, 4)
|
|
||||||
})
|
|
||||||
|
|
||||||
test("getViaServers: only considers power levels of currently joined members", async t => {
|
test("getViaServers: only considers power levels of currently joined members", async t => {
|
||||||
const result = await getViaServers("!baby", {
|
const result = await getViaServers("!baby", {
|
||||||
getStateEvent: async () => ({
|
getEffectivePower: mockGetEffectivePower(["@_ooye_bot:cadence.moe", "@former_moderator:missing.invalid"], {
|
||||||
users: {
|
"@moderator:tractor.invalid": 50
|
||||||
"@moderator:tractor.invalid": 50,
|
|
||||||
"@former_moderator:missing.invalid": 100,
|
|
||||||
"@_ooye_bot:cadence.moe": 100
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
getJoinedMembers: async () => joinedList(["@_ooye_bot:cadence.moe", "@_ooye_hazel:cadence.moe", "@cadence:cadence.moe", "@moderator:tractor.invalid", "@hazel:thecollective.invalid", "@june:thecollective.invalid", "@singleuser:selfhosted.invalid"])
|
getJoinedMembers: async () => joinedList(["@_ooye_bot:cadence.moe", "@_ooye_hazel:cadence.moe", "@cadence:cadence.moe", "@moderator:tractor.invalid", "@hazel:thecollective.invalid", "@june:thecollective.invalid", "@singleuser:selfhosted.invalid"])
|
||||||
})
|
})
|
||||||
t.deepEqual(result, ["cadence.moe", "tractor.invalid", "thecollective.invalid", "selfhosted.invalid"])
|
t.deepEqual(result, ["cadence.moe", "tractor.invalid", "thecollective.invalid", "selfhosted.invalid"])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
module.exports.mockGetEffectivePower = mockGetEffectivePower
|
||||||
|
|||||||
+28
-15
@@ -26,6 +26,8 @@ const utils = sync.require("./converters/utils")
|
|||||||
const api = sync.require("../matrix/api")
|
const api = sync.require("../matrix/api")
|
||||||
/** @type {import("../d2m/actions/create-room")} */
|
/** @type {import("../d2m/actions/create-room")} */
|
||||||
const createRoom = sync.require("../d2m/actions/create-room")
|
const createRoom = sync.require("../d2m/actions/create-room")
|
||||||
|
/** @type {import("../matrix/room-upgrade")} */
|
||||||
|
const roomUpgrade = require("../matrix/room-upgrade")
|
||||||
const {reg} = require("../matrix/read-registration")
|
const {reg} = require("../matrix/read-registration")
|
||||||
|
|
||||||
let lastReportedEvent = 0
|
let lastReportedEvent = 0
|
||||||
@@ -171,9 +173,8 @@ async function onRetryReactionAdd(reactionEvent) {
|
|||||||
// To stop people injecting misleading messages, the reaction needs to come from either the original sender or a room moderator
|
// To stop people injecting misleading messages, the reaction needs to come from either the original sender or a room moderator
|
||||||
if (reactionEvent.sender !== event.sender) {
|
if (reactionEvent.sender !== event.sender) {
|
||||||
// Check if it's a room moderator
|
// Check if it's a room moderator
|
||||||
const powerLevelsStateContent = await api.getStateEvent(roomID, "m.room.power_levels", "")
|
const {powers: {[reactionEvent.sender]: senderPower}, powerLevels} = await utils.getEffectivePower(roomID, [reactionEvent.sender], api)
|
||||||
const powerLevel = powerLevelsStateContent.users?.[reactionEvent.sender] || 0
|
if (senderPower < (powerLevels.state_default ?? 50)) return
|
||||||
if (powerLevel < 50) return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retry
|
// Retry
|
||||||
@@ -330,6 +331,11 @@ async event => {
|
|||||||
if (event.state_key[0] !== "@") return
|
if (event.state_key[0] !== "@") return
|
||||||
const bot = `@${reg.sender_localpart}:${reg.ooye.server_name}`
|
const bot = `@${reg.sender_localpart}:${reg.ooye.server_name}`
|
||||||
|
|
||||||
|
if (event.state_key === bot) {
|
||||||
|
const upgraded = await roomUpgrade.onBotMembership(event)
|
||||||
|
if (upgraded) return
|
||||||
|
}
|
||||||
|
|
||||||
if (event.content.membership === "invite" && event.state_key === bot) {
|
if (event.content.membership === "invite" && event.state_key === bot) {
|
||||||
// We were invited to a room. We should join, and register the invite details for future reference in web.
|
// We were invited to a room. We should join, and register the invite details for future reference in web.
|
||||||
let attemptedApiMessage = "According to unsigned invite data."
|
let attemptedApiMessage = "According to unsigned invite data."
|
||||||
@@ -342,10 +348,10 @@ async event => {
|
|||||||
attemptedApiMessage = "According to unsigned invite data. SSS API unavailable: " + e.toString()
|
attemptedApiMessage = "According to unsigned invite data. SSS API unavailable: " + e.toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const name = getFromInviteRoomState(event.unsigned?.invite_room_state, "m.room.name", "name")
|
const name = getFromInviteRoomState(inviteRoomState, "m.room.name", "name")
|
||||||
const topic = getFromInviteRoomState(event.unsigned?.invite_room_state, "m.room.topic", "topic")
|
const topic = getFromInviteRoomState(inviteRoomState, "m.room.topic", "topic")
|
||||||
const avatar = getFromInviteRoomState(event.unsigned?.invite_room_state, "m.room.avatar", "url")
|
const avatar = getFromInviteRoomState(inviteRoomState, "m.room.avatar", "url")
|
||||||
const creationType = getFromInviteRoomState(event.unsigned?.invite_room_state, "m.room.create", "type")
|
const creationType = getFromInviteRoomState(inviteRoomState, "m.room.create", "type")
|
||||||
if (!name) return await api.leaveRoomWithReason(event.room_id, `Please only invite me to rooms that have a name/avatar set. Update the room details and reinvite! (${attemptedApiMessage})`)
|
if (!name) return await api.leaveRoomWithReason(event.room_id, `Please only invite me to rooms that have a name/avatar set. Update the room details and reinvite! (${attemptedApiMessage})`)
|
||||||
await api.joinRoom(event.room_id)
|
await api.joinRoom(event.room_id)
|
||||||
db.prepare("INSERT OR IGNORE INTO invite (mxid, room_id, type, name, topic, avatar) VALUES (?, ?, ?, ?, ?, ?)").run(event.sender, event.room_id, creationType, name, topic, avatar)
|
db.prepare("INSERT OR IGNORE INTO invite (mxid, room_id, type, name, topic, avatar) VALUES (?, ?, ?, ?, ?, ?)").run(event.sender, event.room_id, creationType, name, topic, avatar)
|
||||||
@@ -368,18 +374,14 @@ async event => {
|
|||||||
if (!exists) return // don't cache members in unbridged rooms
|
if (!exists) return // don't cache members in unbridged rooms
|
||||||
|
|
||||||
// Member is here
|
// Member is here
|
||||||
let powerLevel = 0
|
let {powers: {[event.state_key]: memberPower}, tombstone} = await utils.getEffectivePower(event.room_id, [event.state_key], api)
|
||||||
try {
|
if (memberPower === Infinity) memberPower = tombstone // database storage compatibility
|
||||||
/** @type {Ty.Event.M_Power_Levels} */
|
|
||||||
const powerLevelsEvent = await api.getStateEvent(event.room_id, "m.room.power_levels", "")
|
|
||||||
powerLevel = powerLevelsEvent.users?.[event.state_key] ?? powerLevelsEvent.users_default ?? 0
|
|
||||||
} catch (e) {}
|
|
||||||
const displayname = event.content.displayname || null
|
const displayname = event.content.displayname || null
|
||||||
const avatar_url = event.content.avatar_url
|
const avatar_url = event.content.avatar_url
|
||||||
db.prepare("INSERT INTO member_cache (room_id, mxid, displayname, avatar_url, power_level) VALUES (?, ?, ?, ?, ?) ON CONFLICT DO UPDATE SET displayname = ?, avatar_url = ?, power_level = ?").run(
|
db.prepare("INSERT INTO member_cache (room_id, mxid, displayname, avatar_url, power_level) VALUES (?, ?, ?, ?, ?) ON CONFLICT DO UPDATE SET displayname = ?, avatar_url = ?, power_level = ?").run(
|
||||||
event.room_id, event.state_key,
|
event.room_id, event.state_key,
|
||||||
displayname, avatar_url, powerLevel,
|
displayname, avatar_url, memberPower,
|
||||||
displayname, avatar_url, powerLevel
|
displayname, avatar_url, memberPower
|
||||||
)
|
)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
@@ -390,10 +392,21 @@ sync.addTemporaryListener(as, "type:m.room.power_levels", guard("m.room.power_le
|
|||||||
async event => {
|
async event => {
|
||||||
if (event.state_key !== "") return
|
if (event.state_key !== "") return
|
||||||
const existingPower = select("member_cache", "mxid", {room_id: event.room_id}).pluck().all()
|
const existingPower = select("member_cache", "mxid", {room_id: event.room_id}).pluck().all()
|
||||||
|
const {allCreators} = await utils.getEffectivePower(event.room_id, [], api)
|
||||||
const newPower = event.content.users || {}
|
const newPower = event.content.users || {}
|
||||||
for (const mxid of existingPower) {
|
for (const mxid of existingPower) {
|
||||||
|
if (!allCreators.includes(mxid)) {
|
||||||
db.prepare("UPDATE member_cache SET power_level = ? WHERE room_id = ? AND mxid = ?").run(newPower[mxid] || 0, event.room_id, mxid)
|
db.prepare("UPDATE member_cache SET power_level = ? WHERE room_id = ? AND mxid = ?").run(newPower[mxid] || 0, event.room_id, mxid)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
sync.addTemporaryListener(as, "type:m.room.tombstone", guard("m.room.tombstone",
|
||||||
|
/**
|
||||||
|
* @param {Ty.Event.StateOuter<Ty.Event.M_Room_Tombstone>} event
|
||||||
|
*/
|
||||||
|
async event => {
|
||||||
|
await roomUpgrade.onTombstone(event)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
module.exports.stringifyErrorStack = stringifyErrorStack
|
module.exports.stringifyErrorStack = stringifyErrorStack
|
||||||
|
|||||||
+2
-2
@@ -122,7 +122,7 @@ async function getEventForTimestamp(roomID, ts) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} roomID
|
* @param {string} roomID
|
||||||
* @returns {Promise<Ty.Event.BaseStateEvent[]>}
|
* @returns {Promise<Ty.Event.StateOuter<any>[]>}
|
||||||
*/
|
*/
|
||||||
function getAllState(roomID) {
|
function getAllState(roomID) {
|
||||||
return mreq.mreq("GET", `/client/v3/rooms/${roomID}/state`)
|
return mreq.mreq("GET", `/client/v3/rooms/${roomID}/state`)
|
||||||
@@ -142,7 +142,7 @@ function getStateEvent(roomID, type, key) {
|
|||||||
* @param {string} roomID
|
* @param {string} roomID
|
||||||
* @param {string} type
|
* @param {string} type
|
||||||
* @param {string} key
|
* @param {string} key
|
||||||
* @returns {Promise<Ty.Event.BaseStateEvent>} the entire state event
|
* @returns {Promise<Ty.Event.StateOuter<any>>} the entire state event
|
||||||
*/
|
*/
|
||||||
function getStateEventOuter(roomID, type, key) {
|
function getStateEventOuter(roomID, type, key) {
|
||||||
return mreq.mreq("GET", `/client/v3/rooms/${roomID}/state/${type}/${key}?format=event`)
|
return mreq.mreq("GET", `/client/v3/rooms/${roomID}/state/${type}/${key}?format=event`)
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ function kstateToCreationContent(kstate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("../types").Event.BaseStateEvent[]} events
|
* @param {import("../types").Event.StateOuter<any>[]} events
|
||||||
* @returns {any}
|
* @returns {any}
|
||||||
*/
|
*/
|
||||||
function stateToKState(events) {
|
function stateToKState(events) {
|
||||||
|
|||||||
@@ -123,12 +123,9 @@ const commands = [{
|
|||||||
}
|
}
|
||||||
if (matrixOnlyReason) {
|
if (matrixOnlyReason) {
|
||||||
// If uploading to Matrix, check if we have permission
|
// If uploading to Matrix, check if we have permission
|
||||||
const state = await api.getAllState(event.room_id)
|
const {powerLevels, powers: {[mxUtils.bot]: botPower}} = await mxUtils.getEffectivePower(event.room_id, [mxUtils.bot], api)
|
||||||
const kstate = ks.stateToKState(state)
|
const requiredPower = powerLevels.events["im.ponies.room_emotes"] ?? powerLevels.state_default ?? 50
|
||||||
const powerLevels = kstate["m.room.power_levels/"]
|
if (botPower < requiredPower) {
|
||||||
const required = powerLevels.events["im.ponies.room_emotes"] ?? powerLevels.state_default ?? 50
|
|
||||||
const have = powerLevels.users[`@${reg.sender_localpart}:${reg.ooye.server_name}`] ?? powerLevels.users_default ?? 0
|
|
||||||
if (have < required) {
|
|
||||||
return api.sendEvent(event.room_id, "m.room.message", {
|
return api.sendEvent(event.room_id, "m.room.message", {
|
||||||
...ctx,
|
...ctx,
|
||||||
msgtype: "m.text",
|
msgtype: "m.text",
|
||||||
|
|||||||
+6
-1
@@ -72,8 +72,13 @@ async function mreq(method, url, bodyIn, extra = {}) {
|
|||||||
}, extra)
|
}, extra)
|
||||||
|
|
||||||
const res = await fetch(baseUrl + url, opts)
|
const res = await fetch(baseUrl + url, opts)
|
||||||
|
const text = await res.text()
|
||||||
|
try {
|
||||||
/** @type {any} */
|
/** @type {any} */
|
||||||
const root = await res.json()
|
var root = JSON.parse(text)
|
||||||
|
} catch (e) {
|
||||||
|
throw new MatrixServerError(text, {baseUrl, url, ...opts})
|
||||||
|
}
|
||||||
|
|
||||||
if (!res.ok || root.errcode) {
|
if (!res.ok || root.errcode) {
|
||||||
delete opts.headers?.["Authorization"]
|
delete opts.headers?.["Authorization"]
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
// @ts-check
|
||||||
|
|
||||||
|
const assert = require("assert/strict")
|
||||||
|
const Ty = require("../types")
|
||||||
|
const {Semaphore} = require("@chriscdn/promise-semaphore")
|
||||||
|
const {tag} = require("@cloudrac3r/html-template-tag")
|
||||||
|
const {discord, db, sync, as, select, from} = require("../passthrough")
|
||||||
|
|
||||||
|
/** @type {import("./api")}) */
|
||||||
|
const api = sync.require("./api")
|
||||||
|
/** @type {import("../d2m/actions/create-room")}) */
|
||||||
|
const createRoom = sync.require("../d2m/actions/create-room")
|
||||||
|
/** @type {import("../m2d/converters/utils")}) */
|
||||||
|
const utils = sync.require("../m2d/converters/utils")
|
||||||
|
|
||||||
|
const roomUpgradeSema = new Semaphore()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Ty.Event.StateOuter<Ty.Event.M_Room_Tombstone>} event
|
||||||
|
*/
|
||||||
|
async function onTombstone(event) {
|
||||||
|
// Validate
|
||||||
|
if (event.state_key !== "") return
|
||||||
|
if (!event.content.replacement_room) return
|
||||||
|
|
||||||
|
// Set up
|
||||||
|
const oldRoomID = event.room_id
|
||||||
|
const newRoomID = event.content.replacement_room
|
||||||
|
const channel = select("channel_room", ["name", "channel_id"], {room_id: oldRoomID}).get()
|
||||||
|
if (!channel) return
|
||||||
|
db.prepare("REPLACE INTO room_upgrade_pending (new_room_id, old_room_id) VALUES (?, ?)").run(newRoomID, oldRoomID)
|
||||||
|
|
||||||
|
// Try joining
|
||||||
|
try {
|
||||||
|
await api.joinRoom(newRoomID)
|
||||||
|
} catch (e) {
|
||||||
|
const message = new utils.MatrixStringBuilder()
|
||||||
|
message.add(
|
||||||
|
`You upgraded the bridged room ${channel.name}. To keep bridging, I need you to invite me to the new room: https://matrix.to/#/${newRoomID}`,
|
||||||
|
tag`You upgraded the bridged room <strong>${channel.name}</strong>. To keep bridging, I need you to invite me to the new room: <a href="https://matrix.to/#/${newRoomID}">https://matrix.to/#/${newRoomID}</a>`
|
||||||
|
)
|
||||||
|
const privateRoomID = await api.usePrivateChat(event.sender)
|
||||||
|
await api.sendEvent(privateRoomID, "m.room.message", message.get())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now wait to be invited to/join the room that has the upgrade pending...
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Ty.Event.StateOuter<Ty.Event.M_Room_Member>} event
|
||||||
|
* @returns {Promise<boolean>} whether to cancel other membership actions
|
||||||
|
*/
|
||||||
|
async function onBotMembership(event) {
|
||||||
|
// Check if an upgrade is pending for this room
|
||||||
|
const newRoomID = event.room_id
|
||||||
|
const oldRoomID = select("room_upgrade_pending", "old_room_id", {new_room_id: newRoomID}).pluck().get()
|
||||||
|
if (!oldRoomID) return
|
||||||
|
|
||||||
|
// Check if is join/invite
|
||||||
|
if (event.content.membership !== "invite" && event.content.membership !== "join") return
|
||||||
|
|
||||||
|
return await roomUpgradeSema.request(async () => {
|
||||||
|
// If invited, join
|
||||||
|
if (event.content.membership === "invite") {
|
||||||
|
await api.joinRoom(newRoomID)
|
||||||
|
}
|
||||||
|
|
||||||
|
const channelRow = from("channel_room").join("guild_space", "guild_id").where({room_id: oldRoomID}).select("space_id", "guild_id", "channel_id").get()
|
||||||
|
assert(channelRow)
|
||||||
|
|
||||||
|
// Remove old room from space
|
||||||
|
await api.sendState(channelRow.space_id, "m.space.child", oldRoomID, {})
|
||||||
|
// await api.sendState(oldRoomID, "m.space.parent", spaceID, {}) // keep this - the room isn't advertised but should still be grouped if opened
|
||||||
|
|
||||||
|
// Remove declaration that old room is bridged (if able)
|
||||||
|
try {
|
||||||
|
await api.sendState(oldRoomID, "uk.half-shot.bridge", `moe.cadence.ooye://discord/${channelRow.guild_id}/${channelRow.channel_id}`, {})
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
// Update database
|
||||||
|
db.transaction(() => {
|
||||||
|
db.prepare("DELETE FROM room_upgrade_pending WHERE new_room_id = ?").run(newRoomID)
|
||||||
|
db.prepare("UPDATE channel_room SET room_id = ? WHERE channel_id = ?").run(newRoomID, channelRow.channel_id)
|
||||||
|
db.prepare("INSERT INTO historical_channel_room (room_id, reference_channel_id, upgraded_timestamp) VALUES (?, ?, ?)").run(newRoomID, channelRow.channel_id, Date.now())
|
||||||
|
})()
|
||||||
|
|
||||||
|
// Sync
|
||||||
|
await createRoom.syncRoom(channelRow.channel_id)
|
||||||
|
return true
|
||||||
|
}, event.room_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.onTombstone = onTombstone
|
||||||
|
module.exports.onBotMembership = onBotMembership
|
||||||
Vendored
-15
@@ -143,21 +143,6 @@ export namespace Event {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BaseStateEvent = {
|
|
||||||
type: string
|
|
||||||
room_id: string
|
|
||||||
sender: string
|
|
||||||
content: any
|
|
||||||
state_key: string
|
|
||||||
origin_server_ts: number
|
|
||||||
unsigned?: any
|
|
||||||
event_id: string
|
|
||||||
user_id: string
|
|
||||||
age: number
|
|
||||||
replaces_state: string
|
|
||||||
prev_content?: any
|
|
||||||
}
|
|
||||||
|
|
||||||
export type StrippedChildStateEvent = {
|
export type StrippedChildStateEvent = {
|
||||||
type: string
|
type: string
|
||||||
state_key: string
|
state_key: string
|
||||||
|
|||||||
+7
-18
@@ -10,6 +10,8 @@ const {discord, db, as, sync, select, from} = require("../../passthrough")
|
|||||||
const auth = sync.require("../auth")
|
const auth = sync.require("../auth")
|
||||||
/** @type {import("../../matrix/mreq")} */
|
/** @type {import("../../matrix/mreq")} */
|
||||||
const mreq = sync.require("../../matrix/mreq")
|
const mreq = sync.require("../../matrix/mreq")
|
||||||
|
/** @type {import("../../m2d/converters/utils")}*/
|
||||||
|
const utils = sync.require("../../m2d/converters/utils")
|
||||||
const {reg} = require("../../matrix/read-registration")
|
const {reg} = require("../../matrix/read-registration")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -87,18 +89,11 @@ as.router.post("/api/link-space", defineEventHandler(async event => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check bridge has PL 100
|
// Check bridge has PL 100
|
||||||
const me = `@${reg.sender_localpart}:${reg.ooye.server_name}`
|
const {powerLevels, powers: {[utils.bot]: selfPowerLevel, [session.data.mxid]: invitingPowerLevel}} = await utils.getEffectivePower(spaceID, [utils.bot, session.data.mxid], api)
|
||||||
/** @type {Ty.Event.M_Power_Levels?} */
|
if (selfPowerLevel < (powerLevels?.state_default ?? 50) || selfPowerLevel < 100) throw createError({status: 400, message: "Bad Request", data: "OOYE needs power level 100 (admin) in the target Matrix space"})
|
||||||
let powerLevelsStateContent = null
|
|
||||||
try {
|
|
||||||
powerLevelsStateContent = await api.getStateEvent(spaceID, "m.room.power_levels", "")
|
|
||||||
} catch (e) {}
|
|
||||||
const selfPowerLevel = powerLevelsStateContent?.users?.[me] ?? powerLevelsStateContent?.users_default ?? 0
|
|
||||||
if (selfPowerLevel < (powerLevelsStateContent?.state_default ?? 50) || selfPowerLevel < 100) throw createError({status: 400, message: "Bad Request", data: "OOYE needs power level 100 (admin) in the target Matrix space"})
|
|
||||||
|
|
||||||
// Check inviting user is a moderator in the space
|
// Check inviting user is a moderator in the space
|
||||||
const invitingPowerLevel = powerLevelsStateContent?.users?.[session.data.mxid] ?? powerLevelsStateContent?.users_default ?? 0
|
if (invitingPowerLevel < (powerLevels?.state_default ?? 50)) throw createError({status: 403, message: "Forbidden", data: `You need to be at least power level 50 (moderator) in the target Matrix space to set up OOYE, but you are currently power level ${invitingPowerLevel}.`})
|
||||||
if (invitingPowerLevel < (powerLevelsStateContent?.state_default ?? 50)) throw createError({status: 403, message: "Forbidden", data: `You need to be at least power level 50 (moderator) in the target Matrix space to set up OOYE, but you are currently power level ${invitingPowerLevel}.`})
|
|
||||||
|
|
||||||
// Insert database entry
|
// Insert database entry
|
||||||
db.transaction(() => {
|
db.transaction(() => {
|
||||||
@@ -169,14 +164,8 @@ as.router.post("/api/link", defineEventHandler(async event => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check bridge has PL 100
|
// Check bridge has PL 100
|
||||||
const me = `@${reg.sender_localpart}:${reg.ooye.server_name}`
|
const {powerLevels, powers: {[utils.bot]: selfPowerLevel}} = await utils.getEffectivePower(parsedBody.matrix, [utils.bot], api)
|
||||||
/** @type {Ty.Event.M_Power_Levels?} */
|
if (selfPowerLevel < (powerLevels?.state_default ?? 50) || selfPowerLevel < 100) throw createError({status: 400, message: "Bad Request", data: "OOYE needs power level 100 (admin) in the target Matrix room"})
|
||||||
let powerLevelsStateContent = null
|
|
||||||
try {
|
|
||||||
powerLevelsStateContent = await api.getStateEvent(parsedBody.matrix, "m.room.power_levels", "")
|
|
||||||
} catch (e) {}
|
|
||||||
const selfPowerLevel = powerLevelsStateContent?.users?.[me] ?? powerLevelsStateContent?.users_default ?? 0
|
|
||||||
if (selfPowerLevel < (powerLevelsStateContent?.state_default ?? 50) || selfPowerLevel < 100) throw createError({status: 400, message: "Bad Request", data: "OOYE needs power level 100 (admin) in the target Matrix room"})
|
|
||||||
|
|
||||||
// Insert database entry, but keep the room's existing properties if they are set
|
// Insert database entry, but keep the room's existing properties if they are set
|
||||||
const nick = await api.getStateEvent(parsedBody.matrix, "m.room.name", "").then(content => content.name || null).catch(() => null)
|
const nick = await api.getStateEvent(parsedBody.matrix, "m.room.name", "").then(content => content.name || null).catch(() => null)
|
||||||
|
|||||||
+91
-103
@@ -81,63 +81,6 @@ test("web link space: check that OOYE is joined", async t => {
|
|||||||
t.equal(called, 1)
|
t.equal(called, 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("web link space: check that OOYE has PL 100 (not missing)", async t => {
|
|
||||||
let called = 0
|
|
||||||
const [error] = await tryToCatch(() => router.test("post", "/api/link-space", {
|
|
||||||
sessionData: {
|
|
||||||
managedGuilds: ["665289423482519565"],
|
|
||||||
mxid: "@cadence:cadence.moe"
|
|
||||||
},
|
|
||||||
body: {
|
|
||||||
space_id: "!zTMspHVUBhFLLSdmnS:cadence.moe",
|
|
||||||
guild_id: "665289423482519565"
|
|
||||||
},
|
|
||||||
api: {
|
|
||||||
async joinRoom(roomID) {
|
|
||||||
called++
|
|
||||||
return roomID
|
|
||||||
},
|
|
||||||
async getStateEvent(roomID, type, key) {
|
|
||||||
called++
|
|
||||||
t.equal(roomID, "!zTMspHVUBhFLLSdmnS:cadence.moe")
|
|
||||||
t.equal(type, "m.room.power_levels")
|
|
||||||
throw new MatrixServerError({errcode: "M_NOT_FOUND", error: "what if I told you that power levels never existed"})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
t.equal(error.data, "OOYE needs power level 100 (admin) in the target Matrix space")
|
|
||||||
t.equal(called, 2)
|
|
||||||
})
|
|
||||||
|
|
||||||
test("web link space: check that OOYE has PL 100 (not users_default)", async t => {
|
|
||||||
let called = 0
|
|
||||||
const [error] = await tryToCatch(() => router.test("post", "/api/link-space", {
|
|
||||||
sessionData: {
|
|
||||||
managedGuilds: ["665289423482519565"],
|
|
||||||
mxid: "@cadence:cadence.moe"
|
|
||||||
},
|
|
||||||
body: {
|
|
||||||
space_id: "!zTMspHVUBhFLLSdmnS:cadence.moe",
|
|
||||||
guild_id: "665289423482519565"
|
|
||||||
},
|
|
||||||
api: {
|
|
||||||
async joinRoom(roomID) {
|
|
||||||
called++
|
|
||||||
return roomID
|
|
||||||
},
|
|
||||||
async getStateEvent(roomID, type, key) {
|
|
||||||
called++
|
|
||||||
t.equal(roomID, "!zTMspHVUBhFLLSdmnS:cadence.moe")
|
|
||||||
t.equal(type, "m.room.power_levels")
|
|
||||||
t.equal(key, "")
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
t.equal(error.data, "OOYE needs power level 100 (admin) in the target Matrix space")
|
|
||||||
t.equal(called, 2)
|
|
||||||
})
|
|
||||||
|
|
||||||
test("web link space: check that OOYE has PL 100 (not 50)", async t => {
|
test("web link space: check that OOYE has PL 100 (not 50)", async t => {
|
||||||
let called = 0
|
let called = 0
|
||||||
const [error] = await tryToCatch(() => router.test("post", "/api/link-space", {
|
const [error] = await tryToCatch(() => router.test("post", "/api/link-space", {
|
||||||
@@ -160,11 +103,28 @@ test("web link space: check that OOYE has PL 100 (not 50)", async t => {
|
|||||||
t.equal(type, "m.room.power_levels")
|
t.equal(type, "m.room.power_levels")
|
||||||
t.equal(key, "")
|
t.equal(key, "")
|
||||||
return {users: {"@_ooye_bot:cadence.moe": 50}}
|
return {users: {"@_ooye_bot:cadence.moe": 50}}
|
||||||
|
},
|
||||||
|
async getStateEventOuter(roomID, type, key) {
|
||||||
|
called++
|
||||||
|
t.equal(roomID, "!zTMspHVUBhFLLSdmnS:cadence.moe")
|
||||||
|
t.equal(type, "m.room.create")
|
||||||
|
t.equal(key, "")
|
||||||
|
return {
|
||||||
|
type: "m.room.create",
|
||||||
|
state_key: "",
|
||||||
|
sender: "@creator:cadence.moe",
|
||||||
|
room_id: "!zTMspHVUBhFLLSdmnS:cadence.moe",
|
||||||
|
event_id: "$create",
|
||||||
|
origin_server_ts: 0,
|
||||||
|
content: {
|
||||||
|
room_version: "11"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
t.equal(error.data, "OOYE needs power level 100 (admin) in the target Matrix space")
|
t.equal(error.data, "OOYE needs power level 100 (admin) in the target Matrix space")
|
||||||
t.equal(called, 2)
|
t.equal(called, 3)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("web link space: check that inviting user has PL 50", async t => {
|
test("web link space: check that inviting user has PL 50", async t => {
|
||||||
@@ -189,11 +149,28 @@ test("web link space: check that inviting user has PL 50", async t => {
|
|||||||
t.equal(type, "m.room.power_levels")
|
t.equal(type, "m.room.power_levels")
|
||||||
t.equal(key, "")
|
t.equal(key, "")
|
||||||
return {users: {"@_ooye_bot:cadence.moe": 100}}
|
return {users: {"@_ooye_bot:cadence.moe": 100}}
|
||||||
|
},
|
||||||
|
async getStateEventOuter(roomID, type, key) {
|
||||||
|
called++
|
||||||
|
t.equal(roomID, "!zTMspHVUBhFLLSdmnS:cadence.moe")
|
||||||
|
t.equal(type, "m.room.create")
|
||||||
|
t.equal(key, "")
|
||||||
|
return {
|
||||||
|
type: "m.room.create",
|
||||||
|
state_key: "",
|
||||||
|
sender: "@creator:cadence.moe",
|
||||||
|
room_id: "!zTMspHVUBhFLLSdmnS:cadence.moe",
|
||||||
|
event_id: "$create",
|
||||||
|
origin_server_ts: 0,
|
||||||
|
content: {
|
||||||
|
room_version: "11"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
t.equal(error.data, "You need to be at least power level 50 (moderator) in the target Matrix space to set up OOYE, but you are currently power level 0.")
|
t.equal(error.data, "You need to be at least power level 50 (moderator) in the target Matrix space to set up OOYE, but you are currently power level 0.")
|
||||||
t.equal(called, 2)
|
t.equal(called, 3)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("web link space: successfully adds entry to database and loads page", async t => {
|
test("web link space: successfully adds entry to database and loads page", async t => {
|
||||||
@@ -218,10 +195,27 @@ test("web link space: successfully adds entry to database and loads page", async
|
|||||||
t.equal(type, "m.room.power_levels")
|
t.equal(type, "m.room.power_levels")
|
||||||
t.equal(key, "")
|
t.equal(key, "")
|
||||||
return {users: {"@_ooye_bot:cadence.moe": 100, "@cadence:cadence.moe": 50}}
|
return {users: {"@_ooye_bot:cadence.moe": 100, "@cadence:cadence.moe": 50}}
|
||||||
|
},
|
||||||
|
async getStateEventOuter(roomID, type, key) {
|
||||||
|
called++
|
||||||
|
t.equal(roomID, "!zTMspHVUBhFLLSdmnS:cadence.moe")
|
||||||
|
t.equal(type, "m.room.create")
|
||||||
|
t.equal(key, "")
|
||||||
|
return {
|
||||||
|
type: "m.room.create",
|
||||||
|
state_key: "",
|
||||||
|
sender: "@creator:cadence.moe",
|
||||||
|
room_id: "!zTMspHVUBhFLLSdmnS:cadence.moe",
|
||||||
|
event_id: "$create",
|
||||||
|
origin_server_ts: 0,
|
||||||
|
content: {
|
||||||
|
room_version: "11"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
t.equal(called, 2)
|
t.equal(called, 3)
|
||||||
|
|
||||||
// check that the entry was added to the database
|
// check that the entry was added to the database
|
||||||
t.equal(select("guild_space", "privacy_level", {guild_id: "665289423482519565", space_id: "!zTMspHVUBhFLLSdmnS:cadence.moe"}).pluck().get(), 0)
|
t.equal(select("guild_space", "privacy_level", {guild_id: "665289423482519565", space_id: "!zTMspHVUBhFLLSdmnS:cadence.moe"}).pluck().get(), 0)
|
||||||
@@ -441,47 +435,7 @@ test("web link room: check that bridge can join room (uses via for join attempt)
|
|||||||
t.equal(called, 2)
|
t.equal(called, 2)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("web link room: check that bridge has PL 100 in target room (event missing)", async t => {
|
test("web link room: check that bridge has PL 100 in target room", async t => {
|
||||||
let called = 0
|
|
||||||
const [error] = await tryToCatch(() => router.test("post", "/api/link", {
|
|
||||||
sessionData: {
|
|
||||||
managedGuilds: ["665289423482519565"]
|
|
||||||
},
|
|
||||||
body: {
|
|
||||||
discord: "665310973967597573",
|
|
||||||
matrix: "!NDbIqNpJyPvfKRnNcr:cadence.moe",
|
|
||||||
guild_id: "665289423482519565"
|
|
||||||
},
|
|
||||||
api: {
|
|
||||||
async joinRoom(roomID) {
|
|
||||||
called++
|
|
||||||
return roomID
|
|
||||||
},
|
|
||||||
async *generateFullHierarchy(spaceID) {
|
|
||||||
called++
|
|
||||||
t.equal(spaceID, "!zTMspHVUBhFLLSdmnS:cadence.moe")
|
|
||||||
yield {
|
|
||||||
room_id: "!NDbIqNpJyPvfKRnNcr:cadence.moe",
|
|
||||||
children_state: [],
|
|
||||||
guest_can_join: false,
|
|
||||||
num_joined_members: 2
|
|
||||||
}
|
|
||||||
/* c8 ignore next */
|
|
||||||
},
|
|
||||||
async getStateEvent(roomID, type, key) {
|
|
||||||
called++
|
|
||||||
t.equal(roomID, "!NDbIqNpJyPvfKRnNcr:cadence.moe")
|
|
||||||
t.equal(type, "m.room.power_levels")
|
|
||||||
t.equal(key, "")
|
|
||||||
throw new MatrixServerError({errcode: "M_NOT_FOUND", error: "what if I told you there's no such thing as power levels"})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
t.equal(error.data, "OOYE needs power level 100 (admin) in the target Matrix room")
|
|
||||||
t.equal(called, 3)
|
|
||||||
})
|
|
||||||
|
|
||||||
test("web link room: check that bridge has PL 100 in target room (users default)", async t => {
|
|
||||||
let called = 0
|
let called = 0
|
||||||
const [error] = await tryToCatch(() => router.test("post", "/api/link", {
|
const [error] = await tryToCatch(() => router.test("post", "/api/link", {
|
||||||
sessionData: {
|
sessionData: {
|
||||||
@@ -514,11 +468,28 @@ test("web link room: check that bridge has PL 100 in target room (users default)
|
|||||||
t.equal(type, "m.room.power_levels")
|
t.equal(type, "m.room.power_levels")
|
||||||
t.equal(key, "")
|
t.equal(key, "")
|
||||||
return {users_default: 50}
|
return {users_default: 50}
|
||||||
|
},
|
||||||
|
async getStateEventOuter(roomID, type, key) {
|
||||||
|
called++
|
||||||
|
t.equal(roomID, "!NDbIqNpJyPvfKRnNcr:cadence.moe")
|
||||||
|
t.equal(type, "m.room.create")
|
||||||
|
t.equal(key, "")
|
||||||
|
return {
|
||||||
|
type: "m.room.create",
|
||||||
|
state_key: "",
|
||||||
|
sender: "@creator:cadence.moe",
|
||||||
|
room_id: "!NDbIqNpJyPvfKRnNcr:cadence.moe",
|
||||||
|
event_id: "$create",
|
||||||
|
origin_server_ts: 0,
|
||||||
|
content: {
|
||||||
|
room_version: "11"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
t.equal(error.data, "OOYE needs power level 100 (admin) in the target Matrix room")
|
t.equal(error.data, "OOYE needs power level 100 (admin) in the target Matrix room")
|
||||||
t.equal(called, 3)
|
t.equal(called, 4)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("web link room: successfully calls createRoom", async t => {
|
test("web link room: successfully calls createRoom", async t => {
|
||||||
@@ -568,6 +539,23 @@ test("web link room: successfully calls createRoom", async t => {
|
|||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async getStateEventOuter(roomID, type, key) {
|
||||||
|
called++
|
||||||
|
t.equal(roomID, "!NDbIqNpJyPvfKRnNcr:cadence.moe")
|
||||||
|
t.equal(type, "m.room.create")
|
||||||
|
t.equal(key, "")
|
||||||
|
return {
|
||||||
|
type: "m.room.create",
|
||||||
|
state_key: "",
|
||||||
|
sender: "@creator:cadence.moe",
|
||||||
|
room_id: "!NDbIqNpJyPvfKRnNcr:cadence.moe",
|
||||||
|
event_id: "$create",
|
||||||
|
origin_server_ts: 0,
|
||||||
|
content: {
|
||||||
|
room_version: "11"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
async sendEvent(roomID, type, content) {
|
async sendEvent(roomID, type, content) {
|
||||||
called++
|
called++
|
||||||
t.equal(roomID, "!NDbIqNpJyPvfKRnNcr:cadence.moe")
|
t.equal(roomID, "!NDbIqNpJyPvfKRnNcr:cadence.moe")
|
||||||
@@ -584,7 +572,7 @@ test("web link room: successfully calls createRoom", async t => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
t.equal(called, 8)
|
t.equal(called, 9)
|
||||||
})
|
})
|
||||||
|
|
||||||
// *****
|
// *****
|
||||||
|
|||||||
+15
-15
@@ -8,20 +8,20 @@ INSERT INTO guild_active (guild_id, autocreate) VALUES
|
|||||||
INSERT INTO guild_space (guild_id, space_id, privacy_level) VALUES
|
INSERT INTO guild_space (guild_id, space_id, privacy_level) VALUES
|
||||||
('112760669178241024', '!jjmvBegULiLucuWEHU:cadence.moe', 0);
|
('112760669178241024', '!jjmvBegULiLucuWEHU:cadence.moe', 0);
|
||||||
|
|
||||||
INSERT INTO channel_room (channel_id, room_id, name, nick, thread_parent, custom_avatar) VALUES
|
INSERT INTO channel_room (channel_id, room_id, name, nick, thread_parent, custom_avatar, guild_id) VALUES
|
||||||
('112760669178241024', '!kLRqKKUQXcibIMtOpl:cadence.moe', 'heave', 'main', NULL, NULL),
|
('112760669178241024', '!kLRqKKUQXcibIMtOpl:cadence.moe', 'heave', 'main', NULL, NULL, '112760669178241024'),
|
||||||
('687028734322147344', '!fGgIymcYWOqjbSRUdV:cadence.moe', 'slow-news-day', NULL, NULL, NULL),
|
('687028734322147344', '!fGgIymcYWOqjbSRUdV:cadence.moe', 'slow-news-day', NULL, NULL, NULL, '112760669178241024'),
|
||||||
('497161350934560778', '!CzvdIdUQXgUjDVKxeU:cadence.moe', 'amanda-spam', NULL, NULL, NULL),
|
('497161350934560778', '!CzvdIdUQXgUjDVKxeU:cadence.moe', 'amanda-spam', NULL, NULL, NULL, '66192955777486848'),
|
||||||
('160197704226439168', '!hYnGGlPHlbujVVfktC:cadence.moe', 'the-stanley-parable-channel', 'bots', NULL, NULL),
|
('160197704226439168', '!hYnGGlPHlbujVVfktC:cadence.moe', 'the-stanley-parable-channel', 'bots', NULL, NULL, '112760669178241024'),
|
||||||
('1100319550446252084', '!BnKuBPCvyfOkhcUjEu:cadence.moe', 'worm-farm', NULL, NULL, NULL),
|
('1100319550446252084', '!BnKuBPCvyfOkhcUjEu:cadence.moe', 'worm-farm', NULL, NULL, NULL, '66192955777486848'),
|
||||||
('1162005314908999790', '!FuDZhlOAtqswlyxzeR:cadence.moe', 'Hey.', NULL, '1100319550446252084', NULL),
|
('1162005314908999790', '!FuDZhlOAtqswlyxzeR:cadence.moe', 'Hey.', NULL, '1100319550446252084', NULL, '112760669178241024'),
|
||||||
('297272183716052993', '!rEOspnYqdOalaIFniV:cadence.moe', 'general', NULL, NULL, NULL),
|
('297272183716052993', '!rEOspnYqdOalaIFniV:cadence.moe', 'general', NULL, NULL, NULL, '66192955777486848'),
|
||||||
('122155380120748034', '!cqeGDbPiMFAhLsqqqq:cadence.moe', 'cadences-mind', 'coding', NULL, NULL),
|
('122155380120748034', '!cqeGDbPiMFAhLsqqqq:cadence.moe', 'cadences-mind', 'coding', NULL, NULL, '112760669178241024'),
|
||||||
('176333891320283136', '!qzDBLKlildpzrrOnFZ:cadence.moe', '🌈丨davids-horse_she-took-the-kids', 'wonderland', NULL, 'mxc://cadence.moe/EVvrSkKIRONHjtRJsMLmHWLS'),
|
('176333891320283136', '!qzDBLKlildpzrrOnFZ:cadence.moe', '🌈丨davids-horse_she-took-the-kids', 'wonderland', NULL, 'mxc://cadence.moe/EVvrSkKIRONHjtRJsMLmHWLS', '112760669178241024'),
|
||||||
('489237891895768942', '!tnedrGVYKFNUdnegvf:tchncs.de', 'ex-room-doesnt-exist-any-more', NULL, NULL, NULL),
|
('489237891895768942', '!tnedrGVYKFNUdnegvf:tchncs.de', 'ex-room-doesnt-exist-any-more', NULL, NULL, NULL, '66192955777486848'),
|
||||||
('1160894080998461480', '!TqlyQmifxGUggEmdBN:cadence.moe', 'ooyexperiment', NULL, NULL, NULL),
|
('1160894080998461480', '!TqlyQmifxGUggEmdBN:cadence.moe', 'ooyexperiment', NULL, NULL, NULL, '66192955777486848'),
|
||||||
('1161864271370666075', '!mHmhQQPwXNananMUqq:cadence.moe', 'updates', NULL, NULL, NULL),
|
('1161864271370666075', '!mHmhQQPwXNananMUqq:cadence.moe', 'updates', NULL, NULL, NULL, '665289423482519565'),
|
||||||
('1438284564815548418', '!MHxNpwtgVqWOrmyoTn:cadence.moe', 'sin-cave', NULL, NULL, NULL);
|
('1438284564815548418', '!MHxNpwtgVqWOrmyoTn:cadence.moe', 'sin-cave', NULL, NULL, NULL, '665289423482519565');
|
||||||
|
|
||||||
INSERT INTO historical_channel_room (reference_channel_id, room_id, upgraded_timestamp) SELECT channel_id, room_id, 0 FROM channel_room;
|
INSERT INTO historical_channel_room (reference_channel_id, room_id, upgraded_timestamp) SELECT channel_id, room_id, 0 FROM channel_room;
|
||||||
|
|
||||||
@@ -177,7 +177,7 @@ INSERT INTO reaction (hashed_event_id, message_id, encoded_emoji) VALUES
|
|||||||
(5162930312280790092, '1141501302736695317', '%F0%9F%90%88');
|
(5162930312280790092, '1141501302736695317', '%F0%9F%90%88');
|
||||||
|
|
||||||
INSERT INTO member_power (mxid, room_id, power_level) VALUES
|
INSERT INTO member_power (mxid, room_id, power_level) VALUES
|
||||||
('@test_auto_invite:example.org', '*', 100);
|
('@test_auto_invite:example.org', '*', 150);
|
||||||
|
|
||||||
INSERT INTO lottie (sticker_id, mxc_url) VALUES
|
INSERT INTO lottie (sticker_id, mxc_url) VALUES
|
||||||
('860171525772279849', 'mxc://cadence.moe/ZtvvVbwMIdUZeovWVyGVFCeR');
|
('860171525772279849', 'mxc://cadence.moe/ZtvvVbwMIdUZeovWVyGVFCeR');
|
||||||
|
|||||||
Reference in New Issue
Block a user