Files
Draupnir/test/unit/commands/UnbanCommandTest.ts
gnuxie a45d308597 Refactor and improve the unban command.
We no longer want to accept an argument for the list. We will just
find all appropriate policies and remove them, like we do with the
unban prompt (which we still might want to update to use the new
`--no-confirm` prompt later).

We fix the bugs where the unban command was inviting users regardless
of whether the `--invite` option was provided.

The unban command now uses a preview which shows all the policies that
will have to be removed to unban a user, all the rooms they will need
to be unbanned from, and any rooms that they will be invited to if the
`--invite` option is used.
2025-02-28 12:19:59 +00:00

168 lines
5.2 KiB
TypeScript

// SPDX-FileCopyrightText: 2024 Gnuxie <Gnuxie@protonmail.com>
//
// SPDX-License-Identifier: AFL-3.0
import { CommandExecutorHelper } from "@the-draupnir-project/interface-manager";
import {
MatrixRoomID,
MatrixRoomReference,
MatrixUserID,
StringUserID,
} from "@the-draupnir-project/matrix-basic-types";
import {
Membership,
Ok,
PolicyRoomEditor,
PolicyRoomManager,
PolicyRuleType,
PowerLevelsEventContent,
Recommendation,
RoomInviter,
RoomResolver,
RoomUnbanner,
describeProtectedRoomsSet,
isError,
} from "matrix-protection-suite";
import { createMock } from "ts-auto-mock";
import expect from "expect";
import { DraupnirUnbanCommand } from "../../../src/commands/unban/Unban";
import ManagementRoomOutput from "../../../src/managementroom/ManagementRoomOutput";
import { UnlistedUserRedactionQueue } from "../../../src/queues/UnlistedUserRedactionQueue";
const DraupnirUserID = `@draupnir:ourserver.example.com` as StringUserID;
const ExistingBanUserID = "@existing-spam:spam.example.com" as StringUserID;
async function createProtectedRooms() {
return await describeProtectedRoomsSet({
rooms: [
{
membershipDescriptions: [
{
sender: DraupnirUserID,
target: ExistingBanUserID,
membership: Membership.Ban,
},
],
policyDescriptions: [
{
entity: ExistingBanUserID,
recommendation: Recommendation.Ban,
type: PolicyRuleType.User,
},
],
stateDescriptions: [
{
sender: DraupnirUserID,
type: "m.room.power_levels",
state_key: "",
content: {
users: {
[DraupnirUserID]: 100,
},
} satisfies PowerLevelsEventContent,
},
],
},
],
});
}
describe("Test the DraupnirUnbanCommand", function () {
const roomResolver = createMock<RoomResolver>({
async resolveRoom(roomReference) {
if (roomReference instanceof MatrixRoomID) {
return Ok(roomReference);
}
throw new TypeError(`We don't really expect to resolve anything`);
},
});
it("Will add a user to the policy list when they are banned", async function () {
const { protectedRoomsSet, policyRoomManager, roomStateManager } =
await createProtectedRooms();
const roomUnbanner = createMock<RoomUnbanner>({
async unbanUser(roomOrRoomID, userID, reason) {
const room =
roomOrRoomID instanceof MatrixRoomID
? roomOrRoomID
: MatrixRoomReference.fromRoomID(roomOrRoomID);
expect(userID).toBe(ExistingBanUserID);
roomStateManager.appendState({
room,
membershipDescriptions: [
{
sender: DraupnirUserID,
target: userID,
membership: Membership.Leave,
...(reason === undefined ? {} : { reason }),
},
],
});
return Ok(undefined);
},
});
const policyRoom = protectedRoomsSet.allProtectedRooms[0];
if (policyRoom === undefined) {
throw new TypeError(
`There should be a policy room available from the setup`
);
}
const revisionIssuer =
await policyRoomManager.getPolicyRoomRevisionIssuer(policyRoom);
if (isError(revisionIssuer)) {
throw new TypeError(`Test is wrong`);
}
const mockPolicyRoomManager = createMock<PolicyRoomManager>({
async getPolicyRoomEditor(room) {
expect(room).toBe(policyRoom);
return Ok(
createMock<PolicyRoomEditor>({
async unbanEntity(ruleType, entity) {
expect(ruleType).toBe(PolicyRuleType.User);
expect(entity).toBe(ExistingBanUserID);
return Ok(revisionIssuer.ok.currentRevision.allRules());
},
})
);
},
});
const banResult = await CommandExecutorHelper.execute(
DraupnirUnbanCommand,
{
policyRoomManager: mockPolicyRoomManager,
setRoomMembership: protectedRoomsSet.setRoomMembership,
managementRoomOutput: createMock<ManagementRoomOutput>(),
roomResolver,
watchedPolicyRooms: protectedRoomsSet.watchedPolicyRooms,
clientUserID: `@draupnir:ourserver.example.com` as StringUserID,
noop: false,
roomUnbanner,
unlistedUserRedactionQueue: createMock<UnlistedUserRedactionQueue>(),
roomInviter: createMock<RoomInviter>({
async inviteUser() {
return Ok(undefined);
},
}),
setMembership: protectedRoomsSet.setMembership,
setPoliciesMatchingMembership:
protectedRoomsSet.setPoliciesMatchingMembership.currentRevision,
},
{
rest: ["spam"],
},
MatrixUserID.fromUserID(ExistingBanUserID)
);
expect(banResult.isOkay).toBe(true);
const membership = protectedRoomsSet.setRoomMembership.getRevision(
policyRoom.toRoomIDOrAlias()
);
if (membership === undefined) {
throw new TypeError(
`We should be able to get the membership for the protected policy room`
);
}
expect(membership.membershipForUser(ExistingBanUserID)?.membership).toBe(
Membership.Ban
);
});
});