From 5d727d7114ee80e153ef7f42bddcb19753f48e5e Mon Sep 17 00:00:00 2001 From: gnuxie Date: Mon, 10 Feb 2025 10:07:51 +0000 Subject: [PATCH] Modify 'listInfo' from status command. This function now distinguishes between lists we are watching, lists that are protected, and lists that we have parted from. I don't like it. This should exist on the `PolicyRoomsManager` and this is a complete and total mess. I don't know if there is time to fix it yet. --- src/Draupnir.ts | 11 +- src/commands/Ban.tsx | 10 ++ src/commands/CreateBanListCommand.ts | 20 +++- src/commands/Rooms.tsx | 45 ++++---- src/commands/Rules.tsx | 30 ++++-- src/commands/StatusCommand.tsx | 143 ++++++++++++++++--------- src/commands/Unban.ts | 10 ++ src/protections/BanPropagation.tsx | 26 +++-- test/unit/commands/BanCommandTest.ts | 12 +++ test/unit/commands/UnbanCommandTest.ts | 4 + 10 files changed, 212 insertions(+), 99 deletions(-) diff --git a/src/Draupnir.ts b/src/Draupnir.ts index 6f4a4685..cd5d7062 100644 --- a/src/Draupnir.ts +++ b/src/Draupnir.ts @@ -298,17 +298,24 @@ export class Draupnir implements Client, MatrixAdaptorContext { * This means this is only used in the index.ts. */ public async startupComplete(): Promise { - const statusInfo = await draupnirStatusInfo(this); try { await this.managementRoomOutput.logMessage( LogLevel.INFO, "Draupnir@startup", "Startup complete. Now monitoring rooms." ); + const statusInfo = await draupnirStatusInfo(this); + if (isError(statusInfo)) { + log.error( + `Was unable to get the status information for draupnir`, + statusInfo.error + ); + return; + } await sendMatrixEventsFromDeadDocument( this.clientPlatform.toRoomMessageSender(), this.managementRoomID, - renderStatusInfo(statusInfo), + renderStatusInfo(statusInfo.ok), {} ); } catch (ex) { diff --git a/src/commands/Ban.tsx b/src/commands/Ban.tsx index 00259c43..1ecbffb6 100644 --- a/src/commands/Ban.tsx +++ b/src/commands/Ban.tsx @@ -20,8 +20,10 @@ import { } from "matrix-protection-suite"; import { findPolicyRoomIDFromShortcode } from "./CreateBanListCommand"; import { + MatrixRoomID, MatrixRoomReference, MatrixUserID, + StringRoomID, StringUserID, } from "@the-draupnir-project/matrix-basic-types"; import { @@ -57,6 +59,8 @@ export type DraupnirBanCommandContext = { defaultReasons: string[]; roomResolver: RoomResolver; clientUserID: StringUserID; + allJoinedRooms: StringRoomID[]; + protectedRooms: MatrixRoomID[]; }; export const DraupnirBanCommand = describeCommand({ @@ -108,6 +112,8 @@ export const DraupnirBanCommand = describeCommand({ policyRoomManager, roomResolver, clientUserID, + allJoinedRooms, + protectedRooms, }: DraupnirBanCommandContext, _info: BasicInvocationInformation, _keywords, @@ -120,6 +126,8 @@ export const DraupnirBanCommand = describeCommand({ ? await findPolicyRoomIDFromShortcode( issuerManager, policyRoomManager, + allJoinedRooms, + protectedRooms, clientUserID, policyRoomDesignator ) @@ -172,6 +180,8 @@ DraupnirContextToCommandContextTranslator.registerTranslation( defaultReasons: draupnir.config.commands.ban.defaultReasons, roomResolver: draupnir.clientPlatform.toRoomResolver(), clientUserID: draupnir.clientUserID, + allJoinedRooms: draupnir.clientRooms.currentRevision.allJoinedRooms, + protectedRooms: draupnir.protectedRoomsSet.allProtectedRooms, }; } ); diff --git a/src/commands/CreateBanListCommand.ts b/src/commands/CreateBanListCommand.ts index dfaf9a6b..6d5bfe37 100644 --- a/src/commands/CreateBanListCommand.ts +++ b/src/commands/CreateBanListCommand.ts @@ -18,10 +18,11 @@ import { PropagationType, isError, } from "matrix-protection-suite"; -import { listInfo } from "./StatusCommand"; +import { getWatchedPolicyRoomsInfo } from "./StatusCommand"; import { Draupnir } from "../Draupnir"; import { MatrixRoomID, + StringRoomID, StringUserID, } from "@the-draupnir-project/matrix-basic-types"; import { @@ -91,13 +92,24 @@ DraupnirInterfaceAdaptor.describeRenderer(DraupnirListCreateCommand, { export async function findPolicyRoomIDFromShortcode( issuerManager: PolicyListConfig, policyRoomManager: PolicyRoomManager, + allJoinedRooms: StringRoomID[], + protectedRooms: MatrixRoomID[], editingClientUserID: StringUserID, shortcode: string ): Promise> { - const info = await listInfo(issuerManager, policyRoomManager); - const matchingRevisions = info.filter( - (list) => list.revision.shortcode === shortcode + const info = await getWatchedPolicyRoomsInfo( + issuerManager, + policyRoomManager, + allJoinedRooms, + protectedRooms ); + if (isError(info)) { + return info; + } + const matchingRevisions = [ + ...info.ok.subscribedAndProtectedLists, + ...info.ok.subscribedLists, + ].filter((list) => list.revision.shortcode === shortcode); if (matchingRevisions.length === 0 || matchingRevisions[0] === undefined) { return ActionError.Result( `Could not find a policy room from the shortcode: ${shortcode}` diff --git a/src/commands/Rooms.tsx b/src/commands/Rooms.tsx index 6a7ff49d..a3cf57e3 100644 --- a/src/commands/Rooms.tsx +++ b/src/commands/Rooms.tsx @@ -31,8 +31,8 @@ import { Draupnir } from "../Draupnir"; import { Result } from "@gnuxie/typescript-result"; import { DraupnirInterfaceAdaptor } from "./DraupnirCommandPrerequisites"; import { - listInfo as getListInfo, - ListInfo, + getWatchedPolicyRoomsInfo, + WatchedPolicyRoomInfo, renderPolicyList, } from "./StatusCommand"; @@ -43,9 +43,9 @@ type RoomListItem = { }; type ListRoomsCommandInfo = { - joinedAndProtectedLists: ListInfo[]; - joinedAndWatchedLists: ListInfo[]; - partedAndWatchedLists: ListInfo[]; + joinedAndProtectedLists: WatchedPolicyRoomInfo[]; + joinedAndWatchedLists: WatchedPolicyRoomInfo[]; + partedAndWatchedLists: RoomListItem[]; joinedAndProtectedRooms: RoomListItem[]; joinedAndUnprotectedRooms: RoomListItem[]; partedAndProtectedRooms: RoomListItem[]; @@ -57,10 +57,15 @@ export const DraupnirListProtectedRoomsCommand = describeCommand({ async executor(draupnir: Draupnir): Promise> { const allJoinedRooms = draupnir.clientRooms.currentRevision.allJoinedRooms; const allProtectedRooms = draupnir.protectedRoomsSet.allProtectedRooms; - const listInfo = await getListInfo( + const listInfo = await getWatchedPolicyRoomsInfo( draupnir.protectedRoomsSet.issuerManager, - draupnir.policyRoomManager + draupnir.policyRoomManager, + draupnir.clientRooms.currentRevision.allJoinedRooms, + draupnir.protectedRoomsSet.allProtectedRooms ); + if (isError(listInfo)) { + return listInfo; + } const makeRoomListItem = (room: MatrixRoomID) => { const revision = draupnir.protectedRoomsSet.setRoomState.getRevision( room.toRoomIDOrAlias() @@ -72,24 +77,10 @@ export const DraupnirListProtectedRoomsCommand = describeCommand({ } }; return Ok({ - joinedAndProtectedLists: listInfo.filter( - (list) => - allJoinedRooms.includes(list.revision.room.toRoomIDOrAlias()) && - allProtectedRooms.find( - (room) => - room.toRoomIDOrAlias() === list.revision.room.toRoomIDOrAlias() - ) - ), - joinedAndWatchedLists: listInfo.filter( - (list) => - allJoinedRooms.includes(list.revision.room.toRoomIDOrAlias()) && - !allProtectedRooms.find( - (room) => - room.toRoomIDOrAlias() === list.revision.room.toRoomIDOrAlias() - ) - ), - partedAndWatchedLists: listInfo.filter( - (list) => !allJoinedRooms.includes(list.revision.room.toRoomIDOrAlias()) + joinedAndProtectedLists: listInfo.ok.subscribedAndProtectedLists, + joinedAndWatchedLists: listInfo.ok.subscribedLists, + partedAndWatchedLists: listInfo.ok.subscribedButPartedLists.map( + (profile) => makeRoomListItem(profile.room) ), joinedAndProtectedRooms: allProtectedRooms .filter((room) => allJoinedRooms.includes(room.toRoomIDOrAlias())) @@ -110,7 +101,7 @@ export const DraupnirListProtectedRoomsCommand = describeCommand({ }); function renderPolicyLists( - rooms: ListInfo[], + rooms: WatchedPolicyRoomInfo[], options: { name: string } ): DocumentNode { if (rooms.length === 0) { @@ -178,7 +169,7 @@ DraupnirInterfaceAdaptor.describeRenderer(DraupnirListProtectedRoomsCommand, { {renderPolicyLists(result.ok.joinedAndWatchedLists, { name: "Joined and watched unprotected policy rooms", })} - {renderPolicyLists(result.ok.partedAndWatchedLists, { + {renderRoomList(result.ok.partedAndWatchedLists, { name: "Parted policy rooms that are still marked as watched", })} {renderRoomList(result.ok.joinedAndProtectedRooms, { diff --git a/src/commands/Rules.tsx b/src/commands/Rules.tsx index b954d52b..37510865 100644 --- a/src/commands/Rules.tsx +++ b/src/commands/Rules.tsx @@ -14,7 +14,7 @@ import { PolicyRule, isError, } from "matrix-protection-suite"; -import { listInfo } from "./StatusCommand"; +import { getWatchedPolicyRoomsInfo } from "./StatusCommand"; import { StringRoomID, MatrixRoomID, @@ -90,12 +90,20 @@ export const DraupnirListRulesCommand = describeCommand({ summary: "Lists the rules currently in use by Draupnir.", parameters: [], async executor(draupnir: Draupnir): Promise> { - const infoResult = await listInfo( + const infoResult = await getWatchedPolicyRoomsInfo( draupnir.protectedRoomsSet.issuerManager, - draupnir.policyRoomManager + draupnir.policyRoomManager, + draupnir.clientRooms.currentRevision.allJoinedRooms, + draupnir.protectedRoomsSet.allProtectedRooms ); + if (isError(infoResult)) { + return infoResult; + } return Ok( - infoResult.map((policyRoom) => ({ + [ + ...infoResult.ok.subscribedAndProtectedLists, + ...infoResult.ok.subscribedLists, + ].map((policyRoom) => ({ room: policyRoom.revision.room, roomID: policyRoom.revision.room.toRoomIDOrAlias(), profile: policyRoom.watchedListProfile, @@ -127,12 +135,20 @@ export const DraupnirRulesMatchingCommand = describeCommand({ _rest, entity ): Promise> { - const policyRooms = await listInfo( + const policyRooms = await getWatchedPolicyRoomsInfo( draupnir.protectedRoomsSet.issuerManager, - draupnir.policyRoomManager + draupnir.policyRoomManager, + draupnir.clientRooms.currentRevision.allJoinedRooms, + draupnir.protectedRoomsSet.allProtectedRooms ); + if (isError(policyRooms)) { + return policyRooms; + } return Ok( - policyRooms.map((policyRoom) => { + [ + ...policyRooms.ok.subscribedAndProtectedLists, + ...policyRooms.ok.subscribedLists, + ].map((policyRoom) => { return { room: policyRoom.revision.room, roomID: policyRoom.revision.room.toRoomIDOrAlias(), diff --git a/src/commands/StatusCommand.tsx b/src/commands/StatusCommand.tsx index 40ac6628..5fd42982 100644 --- a/src/commands/StatusCommand.tsx +++ b/src/commands/StatusCommand.tsx @@ -1,4 +1,4 @@ -// Copyright 2022 Gnuxie +// Copyright 2022 - 2025 Gnuxie // Copyright 2019 - 2022 The Matrix.org Foundation C.I.C. // // SPDX-License-Identifier: AFL-3.0 AND Apache-2.0 @@ -26,60 +26,103 @@ import { describeCommand, } from "@the-draupnir-project/interface-manager"; import { DraupnirInterfaceAdaptor } from "./DraupnirCommandPrerequisites"; +import { + MatrixRoomID, + StringRoomID, +} from "@the-draupnir-project/matrix-basic-types"; +import { Result } from "@gnuxie/typescript-result"; export const DraupnirStatusCommand = describeCommand({ summary: "Show the status of the bot.", parameters: [], async executor(draupnir: Draupnir): Promise> { - return Ok(await draupnirStatusInfo(draupnir)); + return await draupnirStatusInfo(draupnir); }, }); -export interface ListInfo { +export interface WatchedPolicyRoomInfo { watchedListProfile: PolicyRoomWatchProfile; revision: PolicyRoomRevision; } -export interface StatusInfo { +export type WatchedPolicyRoomsInfo = { + subscribedLists: WatchedPolicyRoomInfo[]; + subscribedAndProtectedLists: WatchedPolicyRoomInfo[]; + subscribedButPartedLists: PolicyRoomWatchProfile[]; +}; + +export type StatusInfo = { numberOfProtectedRooms: number; numberOfUniqueMembers: number; - subscribedLists: ListInfo[]; - subscribedAndProtectedLists: ListInfo[]; version: string; repository: string; documentationURL: string; +} & WatchedPolicyRoomsInfo; + +async function findRevisionIssuers( + policyRoomManager: PolicyRoomManager, + profiles: PolicyRoomWatchProfile[] +): Promise> { + const issuers: WatchedPolicyRoomInfo[] = []; + for (const profile of profiles) { + const issuerResult = await policyRoomManager.getPolicyRoomRevisionIssuer( + profile.room + ); + if (isError(issuerResult)) { + return issuerResult.elaborate( + "Unable to find a policy room revision issuer for a watched policy list" + ); + } + issuers.push({ + watchedListProfile: profile, + revision: issuerResult.ok.currentRevision, + }); + } + return Ok(issuers); } -export async function listInfo( +export async function getWatchedPolicyRoomsInfo( issuerManager: PolicyListConfig, - policyRoomManager: PolicyRoomManager -): Promise { + policyRoomManager: PolicyRoomManager, + allJoinedRooms: StringRoomID[], + protectedRooms: MatrixRoomID[] +): Promise> { const watchedListProfiles = issuerManager.allWatchedLists; - const issuerResults = await Promise.all( - watchedListProfiles.map((profile) => - policyRoomManager.getPolicyRoomRevisionIssuer(profile.room) + const subscribedAndProtectedLists = await findRevisionIssuers( + policyRoomManager, + watchedListProfiles.filter( + (profile) => + allJoinedRooms.includes(profile.room.toRoomIDOrAlias()) && + protectedRooms.find( + (protectedRoom) => + protectedRoom.toRoomIDOrAlias() === profile.room.toRoomIDOrAlias() + ) ) ); - return issuerResults.map((result) => { - if (isError(result)) { - throw result.expect( - "We should be able to get the issuers for all of the watched lits." - ); - } - const revision = result.ok.currentRevision; - const associatedProfile = watchedListProfiles.find( + if (isError(subscribedAndProtectedLists)) { + return subscribedAndProtectedLists; + } + const subscribedLists = await findRevisionIssuers( + policyRoomManager, + watchedListProfiles.filter( (profile) => - profile.room.toRoomIDOrAlias() === revision.room.toRoomIDOrAlias() - ); - if (associatedProfile === undefined) { - throw new TypeError( - `Shouldn't be possible to have got a result for a list profile we don't have` - ); - } - return { - watchedListProfile: associatedProfile, - revision: revision, - }; + allJoinedRooms.includes(profile.room.toRoomIDOrAlias()) && + !protectedRooms.find( + (protectedRoom) => + protectedRoom.toRoomIDOrAlias() === profile.room.toRoomIDOrAlias() + ) + ) + ); + if (isError(subscribedLists)) { + return subscribedLists; + } + const subscribedButPartedLists = watchedListProfiles.filter( + (profile) => !allJoinedRooms.includes(profile.room.toRoomIDOrAlias()) + ); + return Ok({ + subscribedLists: subscribedLists.ok, + subscribedAndProtectedLists: subscribedAndProtectedLists.ok, + subscribedButPartedLists, }); } @@ -95,35 +138,30 @@ DraupnirInterfaceAdaptor.describeRenderer(DraupnirStatusCommand, { // FIXME: need a shoutout to dependencies in here and NOTICE info. export async function draupnirStatusInfo( draupnir: Draupnir -): Promise { - const watchedListInfo = await listInfo( +): Promise> { + const watchedListInfo = await getWatchedPolicyRoomsInfo( draupnir.protectedRoomsSet.issuerManager, - draupnir.policyRoomManager + draupnir.policyRoomManager, + draupnir.clientRooms.currentRevision.allJoinedRooms, + draupnir.protectedRoomsSet.allProtectedRooms ); - const protectedWatchedLists = watchedListInfo.filter((info) => - draupnir.protectedRoomsSet.isProtectedRoom( - info.revision.room.toRoomIDOrAlias() - ) - ); - const unprotectedListProfiles = watchedListInfo.filter( - (info) => - !draupnir.protectedRoomsSet.isProtectedRoom( - info.revision.room.toRoomIDOrAlias() - ) - ); - return { + if (isError(watchedListInfo)) { + return watchedListInfo; + } + return Ok({ numberOfProtectedRooms: draupnir.protectedRoomsSet.allProtectedRooms.length, numberOfUniqueMembers: draupnir.protectedRoomsSet.setMembership.currentRevision.uniqueMemberCount(), - subscribedLists: unprotectedListProfiles, - subscribedAndProtectedLists: protectedWatchedLists, + subscribedLists: watchedListInfo.ok.subscribedLists, + subscribedAndProtectedLists: watchedListInfo.ok.subscribedAndProtectedLists, + subscribedButPartedLists: watchedListInfo.ok.subscribedButPartedLists, documentationURL: DOCUMENTATION_URL, version: SOFTWARE_VERSION, repository: PACKAGE_JSON["repository"] ?? "Unknown", - }; + }); } -export function renderPolicyList(list: ListInfo): DocumentNode { +export function renderPolicyList(list: WatchedPolicyRoomInfo): DocumentNode { return (
  • @@ -141,7 +179,10 @@ export function renderPolicyList(list: ListInfo): DocumentNode { } export function renderStatusInfo(info: StatusInfo): DocumentNode { - const renderPolicyLists = (header: string, lists: ListInfo[]) => { + const renderPolicyLists = ( + header: string, + lists: WatchedPolicyRoomInfo[] + ) => { const renderedLists = lists.map(renderPolicyList); return ( diff --git a/src/commands/Unban.ts b/src/commands/Unban.ts index f2ca7ba7..88fc5bb7 100644 --- a/src/commands/Unban.ts +++ b/src/commands/Unban.ts @@ -24,7 +24,9 @@ import { findPolicyRoomIDFromShortcode } from "./CreateBanListCommand"; import { isStringUserID, MatrixGlob, + MatrixRoomID, MatrixUserID, + StringRoomID, StringUserID, } from "@the-draupnir-project/matrix-basic-types"; import { @@ -115,6 +117,8 @@ export type DraupnirUnbanCommandContext = { roomUnbanner: RoomUnbanner; unlistedUserRedactionQueue: UnlistedUserRedactionQueue; roomInviter: RoomInviter; + allJoinedRooms: StringRoomID[]; + protectedRooms: MatrixRoomID[]; }; export const DraupnirUnbanCommand = describeCommand({ @@ -178,12 +182,16 @@ export const DraupnirUnbanCommand = describeCommand({ issuerManager, clientUserID, unlistedUserRedactionQueue, + allJoinedRooms, + protectedRooms, } = context; const policyRoomReference = typeof policyRoomDesignator === "string" ? await findPolicyRoomIDFromShortcode( issuerManager, policyRoomManager, + allJoinedRooms, + protectedRooms, clientUserID, policyRoomDesignator ) @@ -252,6 +260,8 @@ DraupnirContextToCommandContextTranslator.registerTranslation( roomUnbanner: draupnir.clientPlatform.toRoomUnbanner(), unlistedUserRedactionQueue: draupnir.unlistedUserRedactionQueue, roomInviter: draupnir.clientPlatform.toRoomInviter(), + allJoinedRooms: draupnir.clientRooms.currentRevision.allJoinedRooms, + protectedRooms: draupnir.protectedRoomsSet.allProtectedRooms, }; } ); diff --git a/src/protections/BanPropagation.tsx b/src/protections/BanPropagation.tsx index 389911d7..52729c87 100644 --- a/src/protections/BanPropagation.tsx +++ b/src/protections/BanPropagation.tsx @@ -43,7 +43,7 @@ import { import { Draupnir } from "../Draupnir"; import { resolveRoomReferenceSafe } from "matrix-protection-suite-for-matrix-bot-sdk"; import { DraupnirProtection } from "./Protection"; -import { listInfo } from "../commands/StatusCommand"; +import { getWatchedPolicyRoomsInfo } from "../commands/StatusCommand"; import { MatrixReactionHandler } from "../commands/interface-manager/MatrixReactionHandler"; import { MatrixRoomID, @@ -342,10 +342,6 @@ export class BanPropagationProtection PolicyRuleType.User, Recommendation.Ban ); - const policyRoomInfo = await listInfo( - draupnir.protectedRoomsSet.issuerManager, - draupnir.policyRoomManager - ); const roomsBannedFrom = this.protectedRoomsSet.setRoomMembership.allRooms.filter( (revision) => @@ -370,14 +366,28 @@ export class BanPropagationProtection (map, rule) => addRule(map, rule), new Map() ); + const policyRoomInfo = await getWatchedPolicyRoomsInfo( + draupnir.protectedRoomsSet.issuerManager, + draupnir.policyRoomManager, + draupnir.clientRooms.currentRevision.allJoinedRooms, + draupnir.protectedRoomsSet.allProtectedRooms + ); + if (isError(policyRoomInfo)) { + log.error( + `Unable to fetch policy rooms info to be able to prompt to unban ${change.userID}`, + policyRoomInfo.error + ); + return; + } await promptUnbanPropagation( this.draupnir, change, change.roomID, [...rulesByPolicyRoom.entries()].map(([policyRoomID, rules]) => { - const info = policyRoomInfo.find( - (i) => i.revision.room.toRoomIDOrAlias() === policyRoomID - ); + const info = [ + ...policyRoomInfo.ok.subscribedAndProtectedLists, + ...policyRoomInfo.ok.subscribedLists, + ].find((i) => i.revision.room.toRoomIDOrAlias() === policyRoomID); if (info === undefined) { throw new TypeError( `Shouldn't be possible to have a rule from an unwatched list.` diff --git a/test/unit/commands/BanCommandTest.ts b/test/unit/commands/BanCommandTest.ts index 0c53808d..928a2123 100644 --- a/test/unit/commands/BanCommandTest.ts +++ b/test/unit/commands/BanCommandTest.ts @@ -82,6 +82,10 @@ describe("Test the DraupnirBanCommand", function () { issuerManager: protectedRoomsSet.issuerManager, defaultReasons: ["spam"], clientUserID: `@draupnir:ourserver.example.com` as StringUserID, + allJoinedRooms: protectedRoomsSet.allProtectedRooms.map((room) => + room.toRoomIDOrAlias() + ), + protectedRooms: protectedRoomsSet.allProtectedRooms, }, {}, MatrixUserIDPresentationType.wrap( @@ -115,6 +119,10 @@ describe("Test the DraupnirBanCommand", function () { issuerManager: protectedRoomsSet.issuerManager, defaultReasons: ["spam"], clientUserID: `@draupnir:ourserver.example.com` as StringUserID, + allJoinedRooms: protectedRoomsSet.allProtectedRooms.map((room) => + room.toRoomIDOrAlias() + ), + protectedRooms: protectedRoomsSet.allProtectedRooms, }, {}, MatrixUserIDPresentationType.wrap( @@ -168,6 +176,10 @@ describe("Test the DraupnirBanCommand", function () { issuerManager: protectedRoomsSet.issuerManager, defaultReasons: ["spam"], clientUserID: `@draupnir:ourserver.example.com` as StringUserID, + allJoinedRooms: protectedRoomsSet.allProtectedRooms.map((room) => + room.toRoomIDOrAlias() + ), + protectedRooms: protectedRoomsSet.allProtectedRooms, }, { rest: ["spam"], diff --git a/test/unit/commands/UnbanCommandTest.ts b/test/unit/commands/UnbanCommandTest.ts index 68ea7388..faa66bfb 100644 --- a/test/unit/commands/UnbanCommandTest.ts +++ b/test/unit/commands/UnbanCommandTest.ts @@ -142,6 +142,10 @@ describe("Test the DraupnirUnbanCommand", function () { return Ok(undefined); }, }), + allJoinedRooms: protectedRoomsSet.allProtectedRooms.map((room) => + room.toRoomIDOrAlias() + ), + protectedRooms: protectedRoomsSet.allProtectedRooms, }, { rest: ["spam"],