Room version 12 and room upgrades
This commit is contained in:
@@ -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+
|
||||
if (writtenMentionMatch) {
|
||||
if (writtenMentionMatch[1] === "room") { // convert @room to @everyone
|
||||
const powerLevels = await di.api.getStateEvent(roomID, "m.room.power_levels", "")
|
||||
const userPower = powerLevels.users?.[senderMxid] || 0
|
||||
if (userPower >= powerLevels.notifications?.room) {
|
||||
const {powers: {[senderMxid]: userPower}, powerLevels} = await mxUtils.getEffectivePower(roomID, [senderMxid], di.api)
|
||||
if (userPower >= (powerLevels.notifications?.room ?? 50)) {
|
||||
return {
|
||||
// @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]),
|
||||
@@ -924,7 +923,6 @@ async function eventToMessage(event, guild, di) {
|
||||
|
||||
// Respect sender's angle brackets
|
||||
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
|
||||
// Put < > around any surviving matrix.to links
|
||||
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"
|
||||
}, data.guild.general, {
|
||||
api: {
|
||||
getStateEvent(roomID, type, key) {
|
||||
async getStateEvent(roomID, type, key) {
|
||||
called++
|
||||
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
||||
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
|
||||
}
|
||||
}
|
||||
},
|
||||
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 => {
|
||||
let called = 0
|
||||
t.deepEqual(
|
||||
await eventToMessage({
|
||||
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"
|
||||
}, data.guild.general, {
|
||||
api: {
|
||||
getStateEvent(roomID, type, key) {
|
||||
called++
|
||||
async getStateEvent(roomID, type, key) {
|
||||
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
||||
t.equal(type, "m.room.power_levels")
|
||||
t.equal(key, "")
|
||||
@@ -5042,6 +5053,19 @@ test("event2message: @room converts to @everyone but is not allowed when the roo
|
||||
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 => {
|
||||
let called = 0
|
||||
t.deepEqual(
|
||||
await eventToMessage({
|
||||
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"
|
||||
}, data.guild.general, {
|
||||
api: {
|
||||
getStateEvent(roomID, type, key) {
|
||||
called++
|
||||
async getStateEvent(roomID, type, key) {
|
||||
t.equal(roomID, "!kLRqKKUQXcibIMtOpl:cadence.moe")
|
||||
t.equal(type, "m.room.power_levels")
|
||||
t.equal(key, "")
|
||||
@@ -5090,6 +5112,19 @@ test("event2message: @room converts to @everyone and is allowed if the user has
|
||||
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://gitdab.com/cadence/out-of-your-element/issues/11
|
||||
* @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) {
|
||||
const candidates = []
|
||||
@@ -138,10 +138,10 @@ async function getViaServers(roomID, api) {
|
||||
candidates.push(reg.ooye.server_name)
|
||||
// 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
|
||||
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...
|
||||
for (const power of sorted) {
|
||||
const mxid = power[0]
|
||||
for (const mxid of sorted) {
|
||||
if (!(mxid in joined)) continue // joined...
|
||||
if (userRegex.some(r => mxid.match(r))) continue // non-sim non-bot...
|
||||
const match = mxid.match(/:(.*)/)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
const e = new Error("Custom error")
|
||||
|
||||
const {test} = require("supertape")
|
||||
const {eventSenderIsFromDiscord, getEventIDHash, MatrixStringBuilder, getViaServers} = require("./utils")
|
||||
const {eventSenderIsFromDiscord, getEventIDHash, MatrixStringBuilder, getViaServers, roomHasAtLeastVersion} = require("./utils")
|
||||
const util = require("util")
|
||||
|
||||
/** @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 => {
|
||||
const result = await getViaServers("!baby", {
|
||||
getStateEvent: async () => ({}),
|
||||
getEffectivePower: mockGetEffectivePower(),
|
||||
getJoinedMembers: async () => joinedList(["@_ooye_bot:cadence.moe", "@_ooye_hazel: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 => {
|
||||
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"])
|
||||
})
|
||||
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 => {
|
||||
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"])
|
||||
})
|
||||
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 => {
|
||||
const result = await getViaServers("!baby", {
|
||||
getStateEvent: async () => ({
|
||||
users: {
|
||||
"@moderator:tractor.invalid": 50,
|
||||
"@singleuser:selfhosted.invalid": 100,
|
||||
"@_ooye_bot:cadence.moe": 100
|
||||
}
|
||||
getEffectivePower: mockGetEffectivePower(["@_ooye_bot:cadence.moe"], {
|
||||
"@moderator:tractor.invalid": 50,
|
||||
"@singleuser:selfhosted.invalid": 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"])
|
||||
})
|
||||
@@ -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 => {
|
||||
const result = await getViaServers("!baby", {
|
||||
getStateEvent: async () => ({
|
||||
users: {
|
||||
"@moderator:tractor.invalid": 50,
|
||||
"@_ooye_bot:cadence.moe": 100
|
||||
}
|
||||
getEffectivePower: mockGetEffectivePower(["@_ooye_bot:cadence.moe"], {
|
||||
"@moderator:tractor.invalid": 50
|
||||
}),
|
||||
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 => {
|
||||
const result = await getViaServers("!baby", {
|
||||
getStateEvent: async () => ({
|
||||
users: {
|
||||
"@moderator:tractor.invalid": 50,
|
||||
"@singleuser:selfhosted.invalid": 100,
|
||||
"@_ooye_bot:cadence.moe": 100
|
||||
}
|
||||
getEffectivePower: mockGetEffectivePower(["@_ooye_bot:cadence.moe"], {
|
||||
"@moderator:tractor.invalid": 50,
|
||||
"@singleuser:selfhosted.invalid": 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"])
|
||||
})
|
||||
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 => {
|
||||
const result = await getViaServers("!baby", {
|
||||
getStateEvent: async () => ({
|
||||
users: {
|
||||
"@moderator:tractor.invalid": 50,
|
||||
"@former_moderator:missing.invalid": 100,
|
||||
"@_ooye_bot:cadence.moe": 100
|
||||
}
|
||||
getEffectivePower: mockGetEffectivePower(["@_ooye_bot:cadence.moe", "@former_moderator:missing.invalid"], {
|
||||
"@moderator:tractor.invalid": 50
|
||||
}),
|
||||
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"])
|
||||
})
|
||||
|
||||
module.exports.mockGetEffectivePower = mockGetEffectivePower
|
||||
|
||||
Reference in New Issue
Block a user