From 2f7c59826642564db6f38bf9f082cd801e1e1ebd Mon Sep 17 00:00:00 2001 From: gnuxie Date: Mon, 10 Feb 2025 16:39:03 +0000 Subject: [PATCH] Use the new `WatchedPolicyRooms` MPS feature. This simplifies anything to do with the way policy rooms are watched. There was a lot of weird glue code around finding policy rooms and revisions that has just been whipped out into the WatchedPolicyRooms abstraction. --- src/appservice/AppServiceDraupnirManager.ts | 7 +- src/commands/Ban.tsx | 36 +++--- src/commands/CreateBanListCommand.ts | 71 +----------- src/commands/Rooms.tsx | 23 ++-- src/commands/Rules.tsx | 47 ++------ src/commands/StatusCommand.tsx | 106 +++++------------- src/commands/Unban.ts | 38 +++---- src/commands/WatchUnwatchCommand.ts | 24 ++-- .../DraupnirProtectedRoomsSet.ts | 14 ++- src/protections/BanPropagation.tsx | 44 ++------ .../ProtectedRooms/ProtectJoinedRooms.tsx | 7 +- src/protections/RedactionSynchronisation.ts | 3 +- .../invitation/WatchRoomsOnInvite.tsx | 10 +- test/integration/banPropagationTest.ts | 13 +-- test/unit/commands/BanCommandTest.ts | 18 +-- test/unit/commands/UnbanCommandTest.ts | 6 +- test/unit/commands/WatchUnwatchCommandTest.ts | 19 ++-- 17 files changed, 140 insertions(+), 346 deletions(-) diff --git a/src/appservice/AppServiceDraupnirManager.ts b/src/appservice/AppServiceDraupnirManager.ts index 99c9ec77..2ebe88b5 100644 --- a/src/appservice/AppServiceDraupnirManager.ts +++ b/src/appservice/AppServiceDraupnirManager.ts @@ -23,7 +23,6 @@ import { ActionExceptionKind, ActionResult, Ok, - PropagationType, Task, isError, } from "matrix-protection-suite"; @@ -412,9 +411,7 @@ async function createFirstList( if (isError(addRoomResult)) { return addRoomResult; } - return await draupnir.protectedRoomsSet.issuerManager.watchList( - PropagationType.Direct, - policyRoom.ok, - {} + return await draupnir.protectedRoomsSet.watchedPolicyRooms.watchPolicyRoomDirectly( + policyRoom.ok ); } diff --git a/src/commands/Ban.tsx b/src/commands/Ban.tsx index 1ecbffb6..a8995845 100644 --- a/src/commands/Ban.tsx +++ b/src/commands/Ban.tsx @@ -1,4 +1,4 @@ -// Copyright 2022 - 2023 Gnuxie +// Copyright 2022 - 2025 Gnuxie // Copyright 2019 - 2021 The Matrix.org Foundation C.I.C. // // SPDX-License-Identifier: AFL-3.0 AND Apache-2.0 @@ -16,14 +16,11 @@ import { Ok, PolicyRoomManager, RoomResolver, - PolicyListConfig, + WatchedPolicyRooms, } from "matrix-protection-suite"; -import { findPolicyRoomIDFromShortcode } from "./CreateBanListCommand"; import { - MatrixRoomID, MatrixRoomReference, MatrixUserID, - StringRoomID, StringUserID, } from "@the-draupnir-project/matrix-basic-types"; import { @@ -40,6 +37,7 @@ import { DraupnirContextToCommandContextTranslator, DraupnirInterfaceAdaptor, } from "./DraupnirCommandPrerequisites"; +import { ResultError } from "@gnuxie/typescript-result"; export async function findPolicyRoomEditorFromRoomReference( roomResolver: RoomResolver, @@ -55,12 +53,10 @@ export async function findPolicyRoomEditorFromRoomReference( export type DraupnirBanCommandContext = { policyRoomManager: PolicyRoomManager; - issuerManager: PolicyListConfig; + watchedPolicyRooms: WatchedPolicyRooms; defaultReasons: string[]; roomResolver: RoomResolver; clientUserID: StringUserID; - allJoinedRooms: StringRoomID[]; - protectedRooms: MatrixRoomID[]; }; export const DraupnirBanCommand = describeCommand({ @@ -108,12 +104,9 @@ export const DraupnirBanCommand = describeCommand({ }, async executor( { - issuerManager, + watchedPolicyRooms, policyRoomManager, roomResolver, - clientUserID, - allJoinedRooms, - protectedRooms, }: DraupnirBanCommandContext, _info: BasicInvocationInformation, _keywords, @@ -123,18 +116,19 @@ export const DraupnirBanCommand = describeCommand({ ): Promise> { const policyRoomReference = typeof policyRoomDesignator === "string" - ? await findPolicyRoomIDFromShortcode( - issuerManager, - policyRoomManager, - allJoinedRooms, - protectedRooms, - clientUserID, - policyRoomDesignator + ? Ok( + watchedPolicyRooms.findPolicyRoomFromShortcode(policyRoomDesignator) + ?.room ) : Ok(policyRoomDesignator); if (isError(policyRoomReference)) { return policyRoomReference; } + if (policyRoomReference.ok === undefined) { + return ResultError.Result( + `Unable to find a policy room from the shortcode ${policyRoomDesignator.toString()}` + ); + } const policyListEditorResult = await findPolicyRoomEditorFromRoomReference( roomResolver, policyRoomManager, @@ -176,12 +170,10 @@ DraupnirContextToCommandContextTranslator.registerTranslation( function (draupnir) { return { policyRoomManager: draupnir.policyRoomManager, - issuerManager: draupnir.protectedRoomsSet.issuerManager, + watchedPolicyRooms: draupnir.protectedRoomsSet.watchedPolicyRooms, 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 6d5bfe37..6934cb4b 100644 --- a/src/commands/CreateBanListCommand.ts +++ b/src/commands/CreateBanListCommand.ts @@ -8,23 +8,9 @@ // https://github.com/matrix-org/mjolnir // -import { - ActionError, - ActionResult, - Ok, - PolicyListConfig, - PolicyRoomManager, - PolicyRuleType, - PropagationType, - isError, -} from "matrix-protection-suite"; -import { getWatchedPolicyRoomsInfo } from "./StatusCommand"; +import { ActionResult, isError } from "matrix-protection-suite"; import { Draupnir } from "../Draupnir"; -import { - MatrixRoomID, - StringRoomID, - StringUserID, -} from "@the-draupnir-project/matrix-basic-types"; +import { MatrixRoomID } from "@the-draupnir-project/matrix-basic-types"; import { BasicInvocationInformation, ParsedKeywords, @@ -53,11 +39,10 @@ export async function createList( if (isError(newList)) { return newList; } - const watchResult = await draupnir.protectedRoomsSet.issuerManager.watchList( - PropagationType.Direct, - newList.ok, - {} - ); + const watchResult = + await draupnir.protectedRoomsSet.watchedPolicyRooms.watchPolicyRoomDirectly( + newList.ok + ); if (isError(watchResult)) { return watchResult; } @@ -88,47 +73,3 @@ export const DraupnirListCreateCommand = describeCommand({ DraupnirInterfaceAdaptor.describeRenderer(DraupnirListCreateCommand, { isAlwaysSupposedToUseDefaultRenderer: true, }); - -export async function findPolicyRoomIDFromShortcode( - issuerManager: PolicyListConfig, - policyRoomManager: PolicyRoomManager, - allJoinedRooms: StringRoomID[], - protectedRooms: MatrixRoomID[], - editingClientUserID: StringUserID, - shortcode: string -): Promise> { - 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}` - ); - } else if (matchingRevisions.length === 1) { - return Ok(matchingRevisions[0].revision.room); - } else { - const remainingRevisions = matchingRevisions.filter((revision) => - revision.revision.isAbleToEdit(editingClientUserID, PolicyRuleType.User) - ); - if ( - remainingRevisions.length !== 1 || - remainingRevisions[0] === undefined - ) { - return ActionError.Result( - `The shortcode ${shortcode} is ambiguous and is currently used by ${remainingRevisions.length} lists.` - ); - } else { - return Ok(remainingRevisions[0].revision.room); - } - } -} diff --git a/src/commands/Rooms.tsx b/src/commands/Rooms.tsx index a3cf57e3..75226fe0 100644 --- a/src/commands/Rooms.tsx +++ b/src/commands/Rooms.tsx @@ -14,6 +14,7 @@ import { ActionResult, Ok, Revision, + WatchedPolicyRoom, isError, } from "matrix-protection-suite"; import { @@ -31,8 +32,7 @@ import { Draupnir } from "../Draupnir"; import { Result } from "@gnuxie/typescript-result"; import { DraupnirInterfaceAdaptor } from "./DraupnirCommandPrerequisites"; import { - getWatchedPolicyRoomsInfo, - WatchedPolicyRoomInfo, + groupWatchedPolicyRoomsByProtectionStatus, renderPolicyList, } from "./StatusCommand"; @@ -43,9 +43,9 @@ type RoomListItem = { }; type ListRoomsCommandInfo = { - joinedAndProtectedLists: WatchedPolicyRoomInfo[]; - joinedAndWatchedLists: WatchedPolicyRoomInfo[]; - partedAndWatchedLists: RoomListItem[]; + joinedAndProtectedLists: WatchedPolicyRoom[]; + joinedAndWatchedLists: WatchedPolicyRoom[]; + partedAndWatchedLists: WatchedPolicyRoom[]; joinedAndProtectedRooms: RoomListItem[]; joinedAndUnprotectedRooms: RoomListItem[]; partedAndProtectedRooms: RoomListItem[]; @@ -57,9 +57,8 @@ export const DraupnirListProtectedRoomsCommand = describeCommand({ async executor(draupnir: Draupnir): Promise> { const allJoinedRooms = draupnir.clientRooms.currentRevision.allJoinedRooms; const allProtectedRooms = draupnir.protectedRoomsSet.allProtectedRooms; - const listInfo = await getWatchedPolicyRoomsInfo( - draupnir.protectedRoomsSet.issuerManager, - draupnir.policyRoomManager, + const listInfo = groupWatchedPolicyRoomsByProtectionStatus( + draupnir.protectedRoomsSet.watchedPolicyRooms, draupnir.clientRooms.currentRevision.allJoinedRooms, draupnir.protectedRoomsSet.allProtectedRooms ); @@ -79,9 +78,7 @@ export const DraupnirListProtectedRoomsCommand = describeCommand({ return Ok({ joinedAndProtectedLists: listInfo.ok.subscribedAndProtectedLists, joinedAndWatchedLists: listInfo.ok.subscribedLists, - partedAndWatchedLists: listInfo.ok.subscribedButPartedLists.map( - (profile) => makeRoomListItem(profile.room) - ), + partedAndWatchedLists: listInfo.ok.subscribedButPartedLists, joinedAndProtectedRooms: allProtectedRooms .filter((room) => allJoinedRooms.includes(room.toRoomIDOrAlias())) .map(makeRoomListItem), @@ -101,7 +98,7 @@ export const DraupnirListProtectedRoomsCommand = describeCommand({ }); function renderPolicyLists( - rooms: WatchedPolicyRoomInfo[], + rooms: WatchedPolicyRoom[], options: { name: string } ): DocumentNode { if (rooms.length === 0) { @@ -169,7 +166,7 @@ DraupnirInterfaceAdaptor.describeRenderer(DraupnirListProtectedRoomsCommand, { {renderPolicyLists(result.ok.joinedAndWatchedLists, { name: "Joined and watched unprotected policy rooms", })} - {renderRoomList(result.ok.partedAndWatchedLists, { + {renderPolicyLists(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 37510865..75908613 100644 --- a/src/commands/Rules.tsx +++ b/src/commands/Rules.tsx @@ -14,7 +14,6 @@ import { PolicyRule, isError, } from "matrix-protection-suite"; -import { getWatchedPolicyRoomsInfo } from "./StatusCommand"; import { StringRoomID, MatrixRoomID, @@ -90,24 +89,12 @@ export const DraupnirListRulesCommand = describeCommand({ summary: "Lists the rules currently in use by Draupnir.", parameters: [], async executor(draupnir: Draupnir): Promise> { - const infoResult = await getWatchedPolicyRoomsInfo( - draupnir.protectedRoomsSet.issuerManager, - draupnir.policyRoomManager, - draupnir.clientRooms.currentRevision.allJoinedRooms, - draupnir.protectedRoomsSet.allProtectedRooms - ); - if (isError(infoResult)) { - return infoResult; - } return Ok( - [ - ...infoResult.ok.subscribedAndProtectedLists, - ...infoResult.ok.subscribedLists, - ].map((policyRoom) => ({ - room: policyRoom.revision.room, - roomID: policyRoom.revision.room.toRoomIDOrAlias(), - profile: policyRoom.watchedListProfile, - matches: policyRoom.revision.allRules(), + draupnir.protectedRoomsSet.watchedPolicyRooms.allRooms.map((profile) => ({ + room: profile.revision.room, + roomID: profile.revision.room.toRoomIDOrAlias(), + profile: profile, + matches: profile.revision.allRules(), })) ); }, @@ -135,27 +122,13 @@ export const DraupnirRulesMatchingCommand = describeCommand({ _rest, entity ): Promise> { - const policyRooms = await getWatchedPolicyRoomsInfo( - draupnir.protectedRoomsSet.issuerManager, - draupnir.policyRoomManager, - draupnir.clientRooms.currentRevision.allJoinedRooms, - draupnir.protectedRoomsSet.allProtectedRooms - ); - if (isError(policyRooms)) { - return policyRooms; - } return Ok( - [ - ...policyRooms.ok.subscribedAndProtectedLists, - ...policyRooms.ok.subscribedLists, - ].map((policyRoom) => { + draupnir.protectedRoomsSet.watchedPolicyRooms.allRooms.map((profile) => { return { - room: policyRoom.revision.room, - roomID: policyRoom.revision.room.toRoomIDOrAlias(), - matches: policyRoom.revision.allRulesMatchingEntity( - entity.toString() - ), - profile: policyRoom.watchedListProfile, + room: profile.revision.room, + roomID: profile.revision.room.toRoomIDOrAlias(), + matches: profile.revision.allRulesMatchingEntity(entity.toString()), + profile: profile, }; }) ); diff --git a/src/commands/StatusCommand.tsx b/src/commands/StatusCommand.tsx index 5fd42982..33a1764f 100644 --- a/src/commands/StatusCommand.tsx +++ b/src/commands/StatusCommand.tsx @@ -12,11 +12,9 @@ import { DOCUMENTATION_URL, PACKAGE_JSON, SOFTWARE_VERSION } from "../config"; import { ActionResult, Ok, - PolicyListConfig, - PolicyRoomManager, - PolicyRoomRevision, - PolicyRoomWatchProfile, PolicyRuleType, + WatchedPolicyRoom, + WatchedPolicyRooms, isError, } from "matrix-protection-suite"; import { Draupnir } from "../Draupnir"; @@ -40,15 +38,10 @@ export const DraupnirStatusCommand = describeCommand({ }, }); -export interface WatchedPolicyRoomInfo { - watchedListProfile: PolicyRoomWatchProfile; - revision: PolicyRoomRevision; -} - export type WatchedPolicyRoomsInfo = { - subscribedLists: WatchedPolicyRoomInfo[]; - subscribedAndProtectedLists: WatchedPolicyRoomInfo[]; - subscribedButPartedLists: PolicyRoomWatchProfile[]; + subscribedLists: WatchedPolicyRoom[]; + subscribedAndProtectedLists: WatchedPolicyRoom[]; + subscribedButPartedLists: WatchedPolicyRoom[]; }; export type StatusInfo = { @@ -59,69 +52,34 @@ export type StatusInfo = { 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 getWatchedPolicyRoomsInfo( - issuerManager: PolicyListConfig, - policyRoomManager: PolicyRoomManager, +export function groupWatchedPolicyRoomsByProtectionStatus( + watchedPolicyRooms: WatchedPolicyRooms, allJoinedRooms: StringRoomID[], protectedRooms: MatrixRoomID[] -): Promise> { - const watchedListProfiles = issuerManager.allWatchedLists; - const subscribedAndProtectedLists = await findRevisionIssuers( - policyRoomManager, - watchedListProfiles.filter( - (profile) => - allJoinedRooms.includes(profile.room.toRoomIDOrAlias()) && - protectedRooms.find( - (protectedRoom) => - protectedRoom.toRoomIDOrAlias() === profile.room.toRoomIDOrAlias() - ) - ) +): Result { + const watchedListProfiles = watchedPolicyRooms.allRooms; + const subscribedAndProtectedLists = watchedListProfiles.filter( + (profile) => + allJoinedRooms.includes(profile.room.toRoomIDOrAlias()) && + protectedRooms.find( + (protectedRoom) => + protectedRoom.toRoomIDOrAlias() === profile.room.toRoomIDOrAlias() + ) ); - if (isError(subscribedAndProtectedLists)) { - return subscribedAndProtectedLists; - } - const subscribedLists = await findRevisionIssuers( - policyRoomManager, - watchedListProfiles.filter( - (profile) => - allJoinedRooms.includes(profile.room.toRoomIDOrAlias()) && - !protectedRooms.find( - (protectedRoom) => - protectedRoom.toRoomIDOrAlias() === profile.room.toRoomIDOrAlias() - ) - ) + const subscribedLists = watchedListProfiles.filter( + (profile) => + 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, + subscribedLists: subscribedLists, + subscribedAndProtectedLists: subscribedAndProtectedLists, subscribedButPartedLists, }); } @@ -139,9 +97,8 @@ DraupnirInterfaceAdaptor.describeRenderer(DraupnirStatusCommand, { export async function draupnirStatusInfo( draupnir: Draupnir ): Promise> { - const watchedListInfo = await getWatchedPolicyRoomsInfo( - draupnir.protectedRoomsSet.issuerManager, - draupnir.policyRoomManager, + const watchedListInfo = groupWatchedPolicyRoomsByProtectionStatus( + draupnir.protectedRoomsSet.watchedPolicyRooms, draupnir.clientRooms.currentRevision.allJoinedRooms, draupnir.protectedRoomsSet.allProtectedRooms ); @@ -161,14 +118,14 @@ export async function draupnirStatusInfo( }); } -export function renderPolicyList(list: WatchedPolicyRoomInfo): DocumentNode { +export function renderPolicyList(list: WatchedPolicyRoom): DocumentNode { return (
  • {list.revision.room.toRoomIDOrAlias()} {" "} ({list.revision.shortcode ?? ""}) propagation:{" "} - {list.watchedListProfile.propagation} (rules:{" "} + {list.propagation} (rules:{" "} {list.revision.allRulesOfType(PolicyRuleType.Server).length} servers,{" "} {list.revision.allRulesOfType(PolicyRuleType.User).length} users,{" "} {list.revision.allRulesOfType(PolicyRuleType.Room).length} rooms) (last @@ -179,10 +136,7 @@ export function renderPolicyList(list: WatchedPolicyRoomInfo): DocumentNode { } export function renderStatusInfo(info: StatusInfo): DocumentNode { - const renderPolicyLists = ( - header: string, - lists: WatchedPolicyRoomInfo[] - ) => { + const renderPolicyLists = (header: string, lists: WatchedPolicyRoom[]) => { const renderedLists = lists.map(renderPolicyList); return ( diff --git a/src/commands/Unban.ts b/src/commands/Unban.ts index 88fc5bb7..c101985e 100644 --- a/src/commands/Unban.ts +++ b/src/commands/Unban.ts @@ -11,22 +11,19 @@ import { isError, Ok, - PolicyListConfig, PolicyRoomManager, PolicyRuleType, RoomInviter, RoomResolver, RoomUnbanner, SetRoomMembership, + WatchedPolicyRooms, } from "matrix-protection-suite"; import { LogLevel } from "matrix-bot-sdk"; -import { findPolicyRoomIDFromShortcode } from "./CreateBanListCommand"; import { isStringUserID, MatrixGlob, - MatrixRoomID, MatrixUserID, - StringRoomID, StringUserID, } from "@the-draupnir-project/matrix-basic-types"; import { @@ -38,13 +35,12 @@ import { tuple, union, } from "@the-draupnir-project/interface-manager"; -import { Result } from "@gnuxie/typescript-result"; +import { Result, ResultError } from "@gnuxie/typescript-result"; import { DraupnirContextToCommandContextTranslator, DraupnirInterfaceAdaptor, } from "./DraupnirCommandPrerequisites"; import ManagementRoomOutput from "../managementroom/ManagementRoomOutput"; -import { DraupnirBanCommandContext } from "./Ban"; import { UnlistedUserRedactionQueue } from "../queues/UnlistedUserRedactionQueue"; async function unbanUserFromRooms( @@ -108,7 +104,7 @@ async function unbanUserFromRooms( export type DraupnirUnbanCommandContext = { policyRoomManager: PolicyRoomManager; - issuerManager: PolicyListConfig; + watchedPolicyRooms: WatchedPolicyRooms; roomResolver: RoomResolver; clientUserID: StringUserID; setMembership: SetRoomMembership; @@ -117,8 +113,6 @@ export type DraupnirUnbanCommandContext = { roomUnbanner: RoomUnbanner; unlistedUserRedactionQueue: UnlistedUserRedactionQueue; roomInviter: RoomInviter; - allJoinedRooms: StringRoomID[]; - protectedRooms: MatrixRoomID[]; }; export const DraupnirUnbanCommand = describeCommand({ @@ -143,7 +137,7 @@ export const DraupnirUnbanCommand = describeCommand({ prompt: async function ({ policyRoomManager, clientUserID, - }: DraupnirBanCommandContext) { + }: DraupnirUnbanCommandContext) { return Ok({ suggestions: policyRoomManager .getEditablePolicyRoomIDs(clientUserID, PolicyRuleType.User) @@ -179,26 +173,24 @@ export const DraupnirUnbanCommand = describeCommand({ const { roomResolver, policyRoomManager, - issuerManager, - clientUserID, + watchedPolicyRooms, unlistedUserRedactionQueue, - allJoinedRooms, - protectedRooms, } = context; const policyRoomReference = typeof policyRoomDesignator === "string" - ? await findPolicyRoomIDFromShortcode( - issuerManager, - policyRoomManager, - allJoinedRooms, - protectedRooms, - clientUserID, - policyRoomDesignator + ? Ok( + watchedPolicyRooms.findPolicyRoomFromShortcode(policyRoomDesignator) + ?.room ) : Ok(policyRoomDesignator); if (isError(policyRoomReference)) { return policyRoomReference; } + if (policyRoomReference.ok === undefined) { + return ResultError.Result( + `Unable to find a policy room from the shortcode ${policyRoomDesignator.toString()}` + ); + } const policyRoom = await roomResolver.resolveRoom(policyRoomReference.ok); if (isError(policyRoom)) { return policyRoom; @@ -251,7 +243,7 @@ DraupnirContextToCommandContextTranslator.registerTranslation( function (draupnir) { return { policyRoomManager: draupnir.policyRoomManager, - issuerManager: draupnir.protectedRoomsSet.issuerManager, + watchedPolicyRooms: draupnir.protectedRoomsSet.watchedPolicyRooms, roomResolver: draupnir.clientPlatform.toRoomResolver(), clientUserID: draupnir.clientUserID, setMembership: draupnir.protectedRoomsSet.setRoomMembership, @@ -260,8 +252,6 @@ 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/commands/WatchUnwatchCommand.ts b/src/commands/WatchUnwatchCommand.ts index 6a221cd8..5298bd4e 100644 --- a/src/commands/WatchUnwatchCommand.ts +++ b/src/commands/WatchUnwatchCommand.ts @@ -9,9 +9,8 @@ // import { - PolicyListConfig, - PropagationType, RoomResolver, + WatchedPolicyRooms, isError, } from "matrix-protection-suite"; import { @@ -27,7 +26,7 @@ import { } from "./DraupnirCommandPrerequisites"; export type DraupnirWatchUnwatchCommandContext = { - issuerManager: PolicyListConfig; + watchedPolicyRooms: WatchedPolicyRooms; roomResolver: RoomResolver; }; @@ -39,7 +38,7 @@ export const DraupnirWatchPolicyRoomCommand = describeCommand({ acceptor: MatrixRoomReferencePresentationSchema, }), async executor( - { issuerManager, roomResolver }: DraupnirWatchUnwatchCommandContext, + { watchedPolicyRooms, roomResolver }: DraupnirWatchUnwatchCommandContext, _info, _keywords, _rest, @@ -50,18 +49,14 @@ export const DraupnirWatchPolicyRoomCommand = describeCommand({ return policyRoom; } if ( - issuerManager.allWatchedLists.some( + watchedPolicyRooms.allRooms.some( (profile) => profile.room.toRoomIDOrAlias() === policyRoom.ok.toRoomIDOrAlias() ) ) { return ResultError.Result("We are already watching this list."); } - return await issuerManager.watchList( - PropagationType.Direct, - policyRoom.ok, - {} - ); + return await watchedPolicyRooms.watchPolicyRoomDirectly(policyRoom.ok); }, }); @@ -73,7 +68,7 @@ export const DraupnirUnwatchPolicyRoomCommand = describeCommand({ acceptor: MatrixRoomReferencePresentationSchema, }), async executor( - { issuerManager, roomResolver }: DraupnirWatchUnwatchCommandContext, + { watchedPolicyRooms, roomResolver }: DraupnirWatchUnwatchCommandContext, _info, _keywords, _rest, @@ -83,10 +78,7 @@ export const DraupnirUnwatchPolicyRoomCommand = describeCommand({ if (isError(policyRoom)) { return policyRoom; } - return await issuerManager.unwatchList( - PropagationType.Direct, - policyRoom.ok - ); + return await watchedPolicyRooms.unwatchPolicyRoom(policyRoom.ok); }, }); @@ -100,7 +92,7 @@ for (const command of [ DraupnirContextToCommandContextTranslator.registerTranslation( command, (draupnir: Draupnir) => ({ - issuerManager: draupnir.protectedRoomsSet.issuerManager, + watchedPolicyRooms: draupnir.protectedRoomsSet.watchedPolicyRooms, roomResolver: draupnir.clientPlatform.toRoomResolver(), }) ); diff --git a/src/draupnirfactory/DraupnirProtectedRoomsSet.ts b/src/draupnirfactory/DraupnirProtectedRoomsSet.ts index 19f40d50..498605d2 100644 --- a/src/draupnirfactory/DraupnirProtectedRoomsSet.ts +++ b/src/draupnirfactory/DraupnirProtectedRoomsSet.ts @@ -38,6 +38,7 @@ import { StandardProtectionsManager, StandardSetRoomMembership, StandardSetRoomState, + StandardWatchedPolicyRooms, isError, } from "matrix-protection-suite"; import { @@ -59,7 +60,6 @@ const log = new Logger("DraupnirProtectedRoomsSet"); async function makePolicyListConfig( client: MatrixSendClient, - policyRoomManager: PolicyRoomManager, roomJoiner: RoomJoiner ): Promise> { const result = await MjolnirPolicyRoomsConfig.createFromStore( @@ -67,7 +67,6 @@ async function makePolicyListConfig( client, MJOLNIR_WATCHED_POLICY_ROOMS_EVENT_TYPE ), - policyRoomManager, roomJoiner ); return result; @@ -192,12 +191,19 @@ export async function makeProtectedRoomsSet( } const policyListConfig = await makePolicyListConfig( client, - policyRoomManager, clientPlatform.toRoomJoiner() ); if (isError(policyListConfig)) { return policyListConfig; } + const watchedPolicyRooms = await StandardWatchedPolicyRooms.create( + policyListConfig.ok, + policyRoomManager, + clientPlatform.toRoomJoiner() + ); + if (isError(watchedPolicyRooms)) { + return watchedPolicyRooms; + } const protectionsConfig = await makeProtectionsManager( client, roomStateManager, @@ -209,7 +215,7 @@ export async function makeProtectedRoomsSet( return protectionsConfig; } const protectedRoomsSet = new StandardProtectedRoomsSet( - policyListConfig.ok, + watchedPolicyRooms.ok, protectedRoomsManager.ok, protectionsConfig.ok, userID, diff --git a/src/protections/BanPropagation.tsx b/src/protections/BanPropagation.tsx index 52729c87..df814170 100644 --- a/src/protections/BanPropagation.tsx +++ b/src/protections/BanPropagation.tsx @@ -43,7 +43,6 @@ import { import { Draupnir } from "../Draupnir"; import { resolveRoomReferenceSafe } from "matrix-protection-suite-for-matrix-bot-sdk"; import { DraupnirProtection } from "./Protection"; -import { getWatchedPolicyRoomsInfo } from "../commands/StatusCommand"; import { MatrixReactionHandler } from "../commands/interface-manager/MatrixReactionHandler"; import { MatrixRoomID, @@ -310,15 +309,14 @@ export class BanPropagationProtection this.handleBan(ban); } for (const unban of unbans) { - void Task(this.handleUnban(unban, this.draupnir)); + void Task(this.handleUnban(unban)); } return Ok(undefined); } private handleBan(change: MembershipChange): void { const policyRevision = - this.protectedRoomsSet.issuerManager.policyListRevisionIssuer - .currentRevision; + this.protectedRoomsSet.watchedPolicyRooms.currentRevision; const rulesMatchingUser = policyRevision.allRulesMatchingEntity( change.userID, PolicyRuleType.User, @@ -330,13 +328,9 @@ export class BanPropagationProtection void Task(promptBanPropagation(this.draupnir, change)); } - private async handleUnban( - change: MembershipChange, - draupnir: Draupnir - ): Promise { + private async handleUnban(change: MembershipChange): Promise { const policyRevision = - this.protectedRoomsSet.issuerManager.policyListRevisionIssuer - .currentRevision; + this.protectedRoomsSet.watchedPolicyRooms.currentRevision; const rulesMatchingUser = policyRevision.allRulesMatchingEntity( change.userID, PolicyRuleType.User, @@ -366,38 +360,25 @@ 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.ok.subscribedAndProtectedLists, - ...policyRoomInfo.ok.subscribedLists, - ].find((i) => i.revision.room.toRoomIDOrAlias() === policyRoomID); - if (info === undefined) { + const profile = + this.draupnir.protectedRoomsSet.watchedPolicyRooms.allRooms.find( + (i) => i.revision.room.toRoomIDOrAlias() === policyRoomID + ); + if (profile === undefined) { throw new TypeError( `Shouldn't be possible to have a rule from an unwatched list.` ); } return { - room: info.revision.room, + room: profile.revision.room, roomID: policyRoomID, matches: rules, - profile: info.watchedListProfile, + profile: profile, }; }), roomsBannedFrom.map((revision) => revision.room) @@ -465,8 +446,7 @@ export class BanPropagationProtection // the unban from lists code should be moved to a standard consequence. const errors: RoomUpdateError[] = []; const policyRevision = - this.protectedRoomsSet.issuerManager.policyListRevisionIssuer - .currentRevision; + this.protectedRoomsSet.watchedPolicyRooms.currentRevision; const rulesMatchingUser = policyRevision.allRulesMatchingEntity( context.target, PolicyRuleType.User, diff --git a/src/protections/ProtectedRooms/ProtectJoinedRooms.tsx b/src/protections/ProtectedRooms/ProtectJoinedRooms.tsx index d8f2e1a2..0d927d19 100644 --- a/src/protections/ProtectedRooms/ProtectJoinedRooms.tsx +++ b/src/protections/ProtectedRooms/ProtectJoinedRooms.tsx @@ -69,10 +69,9 @@ export class ProtectedJoinedRooms { } public async syncProtectedRooms() { - const policyRooms = - this.protectedRoomsSet.issuerManager.allWatchedLists.map((profile) => - profile.room.toRoomIDOrAlias() - ); + const policyRooms = this.protectedRoomsSet.watchedPolicyRooms.allRooms.map( + (profile) => profile.room.toRoomIDOrAlias() + ); const roomsToProtect = this.clientRooms.currentRevision.allJoinedRooms.filter((roomID) => { return ( diff --git a/src/protections/RedactionSynchronisation.ts b/src/protections/RedactionSynchronisation.ts index 44facce2..31e9c8fc 100644 --- a/src/protections/RedactionSynchronisation.ts +++ b/src/protections/RedactionSynchronisation.ts @@ -124,8 +124,7 @@ export class RedactionSynchronisationProtection change.membershipChangeType === MembershipChangeType.Rejoined ) { const policyRevision = - this.protectedRoomsSet.issuerManager.policyListRevisionIssuer - .currentRevision; + this.protectedRoomsSet.watchedPolicyRooms.currentRevision; const matchingPolicy = policyRevision.findRuleMatchingEntity( change.userID, PolicyRuleType.User, diff --git a/src/protections/invitation/WatchRoomsOnInvite.tsx b/src/protections/invitation/WatchRoomsOnInvite.tsx index 3f03df3e..0e782edc 100644 --- a/src/protections/invitation/WatchRoomsOnInvite.tsx +++ b/src/protections/invitation/WatchRoomsOnInvite.tsx @@ -15,7 +15,6 @@ import { MembershipEvent, Ok, PermalinkSchema, - PropagationType, ProtectedRoomsSet, RoomEvent, RoomStateRevision, @@ -215,11 +214,10 @@ export class WatchRoomsOnInvite { ); return; } - const addResult = await this.protectedRoomsSet.issuerManager.watchList( - PropagationType.Direct, - resolvedRoom.ok, - {} - ); + const addResult = + await this.protectedRoomsSet.watchedPolicyRooms.watchPolicyRoomDirectly( + resolvedRoom.ok + ); if (isError(addResult)) { addResult.elaborate( `Could not watch the policy room: ${resolvedRoom.ok.toPermalink()}` diff --git a/test/integration/banPropagationTest.ts b/test/integration/banPropagationTest.ts index de486544..275b5dd0 100644 --- a/test/integration/banPropagationTest.ts +++ b/test/integration/banPropagationTest.ts @@ -10,7 +10,6 @@ import { MembershipChangeType, NoticeMessageContent, PolicyRuleType, - PropagationType, RoomMessage, Value, findProtection, @@ -86,10 +85,8 @@ describe("Ban propagation test", function () { 100 ); await draupnir.client.joinRoom(policyListId); - await draupnir.protectedRoomsSet.issuerManager.watchList( - PropagationType.Direct, - MatrixRoomReference.fromRoomID(policyListId as StringRoomID), - {} + await draupnir.protectedRoomsSet.watchedPolicyRooms.watchPolicyRoomDirectly( + MatrixRoomReference.fromRoomID(policyListId as StringRoomID) ); // check for the prompt @@ -119,8 +116,7 @@ describe("Ban propagation test", function () { await new Promise((resolve) => setTimeout(resolve, 10000)); const policyListRevisionAfterBan = - draupnir.protectedRoomsSet.issuerManager.policyListRevisionIssuer - .currentRevision; + draupnir.protectedRoomsSet.watchedPolicyRooms.currentRevision; const rules = policyListRevisionAfterBan.allRulesMatchingEntity( spamUserID, PolicyRuleType.User @@ -154,8 +150,7 @@ describe("Ban propagation test", function () { ); await new Promise((resolve) => setTimeout(resolve, 10000)); const policyListRevisionAfterUnBan = - draupnir.protectedRoomsSet.issuerManager.policyListRevisionIssuer - .currentRevision; + draupnir.protectedRoomsSet.watchedPolicyRooms.currentRevision; const rulesAfterUnban = policyListRevisionAfterUnBan.allRulesMatchingEntity( diff --git a/test/unit/commands/BanCommandTest.ts b/test/unit/commands/BanCommandTest.ts index 928a2123..7d5e7230 100644 --- a/test/unit/commands/BanCommandTest.ts +++ b/test/unit/commands/BanCommandTest.ts @@ -79,13 +79,9 @@ describe("Test the DraupnirBanCommand", function () { { policyRoomManager, roomResolver, - issuerManager: protectedRoomsSet.issuerManager, + watchedPolicyRooms: protectedRoomsSet.watchedPolicyRooms, defaultReasons: ["spam"], clientUserID: `@draupnir:ourserver.example.com` as StringUserID, - allJoinedRooms: protectedRoomsSet.allProtectedRooms.map((room) => - room.toRoomIDOrAlias() - ), - protectedRooms: protectedRoomsSet.allProtectedRooms, }, {}, MatrixUserIDPresentationType.wrap( @@ -116,13 +112,9 @@ describe("Test the DraupnirBanCommand", function () { { policyRoomManager, roomResolver, - issuerManager: protectedRoomsSet.issuerManager, + watchedPolicyRooms: protectedRoomsSet.watchedPolicyRooms, defaultReasons: ["spam"], clientUserID: `@draupnir:ourserver.example.com` as StringUserID, - allJoinedRooms: protectedRoomsSet.allProtectedRooms.map((room) => - room.toRoomIDOrAlias() - ), - protectedRooms: protectedRoomsSet.allProtectedRooms, }, {}, MatrixUserIDPresentationType.wrap( @@ -173,13 +165,9 @@ describe("Test the DraupnirBanCommand", function () { { policyRoomManager, roomResolver, - issuerManager: protectedRoomsSet.issuerManager, + watchedPolicyRooms: protectedRoomsSet.watchedPolicyRooms, 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 faa66bfb..121c4f6c 100644 --- a/test/unit/commands/UnbanCommandTest.ts +++ b/test/unit/commands/UnbanCommandTest.ts @@ -132,7 +132,7 @@ describe("Test the DraupnirUnbanCommand", function () { setMembership: protectedRoomsSet.setRoomMembership, managementRoomOutput: createMock(), roomResolver, - issuerManager: protectedRoomsSet.issuerManager, + watchedPolicyRooms: protectedRoomsSet.watchedPolicyRooms, clientUserID: `@draupnir:ourserver.example.com` as StringUserID, noop: false, roomUnbanner, @@ -142,10 +142,6 @@ describe("Test the DraupnirUnbanCommand", function () { return Ok(undefined); }, }), - allJoinedRooms: protectedRoomsSet.allProtectedRooms.map((room) => - room.toRoomIDOrAlias() - ), - protectedRooms: protectedRoomsSet.allProtectedRooms, }, { rest: ["spam"], diff --git a/test/unit/commands/WatchUnwatchCommandTest.ts b/test/unit/commands/WatchUnwatchCommandTest.ts index 734c0911..87d0350c 100644 --- a/test/unit/commands/WatchUnwatchCommandTest.ts +++ b/test/unit/commands/WatchUnwatchCommandTest.ts @@ -10,9 +10,9 @@ import { import expect from "expect"; import { Ok, - PolicyListConfig, PropagationType, RoomResolver, + WatchedPolicyRooms, isError, isOk, } from "matrix-protection-suite"; @@ -27,10 +27,9 @@ describe("Test the WatchUnwatchCommmands", function () { const policyRoom = MatrixRoomReference.fromRoomID( "!room:example.com" as StringRoomID ); - const issuerManager = createMock({ - async watchList(propagation, room, _options) { + const watchedPolicyRooms = createMock({ + async watchPolicyRoomDirectly(room) { expect(room).toBe(policyRoom); - expect(propagation).toBe(PropagationType.Direct); return Ok(undefined); }, }); @@ -45,21 +44,19 @@ describe("Test the WatchUnwatchCommmands", function () { it("DraupnirWatchCommand", async function () { const result = await CommandExecutorHelper.execute( DraupnirWatchPolicyRoomCommand, - { issuerManager, roomResolver }, + { watchedPolicyRooms, roomResolver }, {}, policyRoom ); expect(isOk(result)).toBe(true); }); it("Draupnir watch command should return an error if the room is already being watched", async function () { - const issuerManagerWithWatchedList = createMock({ - allWatchedLists: [ - { room: policyRoom, propagation: PropagationType.Direct, options: {} }, - ], + const issuerManagerWithWatchedList = createMock({ + allRooms: [{ room: policyRoom, propagation: PropagationType.Direct }], }); const result = await CommandExecutorHelper.execute( DraupnirWatchPolicyRoomCommand, - { issuerManager: issuerManagerWithWatchedList, roomResolver }, + { watchedPolicyRooms: issuerManagerWithWatchedList, roomResolver }, {}, policyRoom ); @@ -68,7 +65,7 @@ describe("Test the WatchUnwatchCommmands", function () { it("DraupnirUnwatchCommand", async function () { const result = await CommandExecutorHelper.execute( DraupnirUnwatchPolicyRoomCommand, - { issuerManager, roomResolver }, + { watchedPolicyRooms, roomResolver }, {}, policyRoom );