"use strict";
// Copyright 2022 Gnuxie <Gnuxie@protonmail.com>
// Copyright 2019 - 2021 The Matrix.org Foundation C.I.C.
//
// SPDX-License-Identifier: Apache-2.0
//
// SPDX-FileAttributionText: <text>
// This modified file incorporates work from mjolnir
// https://github.com/matrix-org/mjolnir
// </text>
Object.defineProperty(exports, "__esModule", { value: true });
exports.EventRedactionQueue = exports.RedactUserInRoom = void 0;
const matrix_bot_sdk_1 = require("@vector-im/matrix-bot-sdk");
const utils_1 = require("../utils");
const matrix_protection_suite_1 = require("matrix-protection-suite");
const matrix_basic_types_1 = require("@the-draupnir-project/matrix-basic-types");
/**
 * Redacts all of the messages a user has sent to one room.
 */
class RedactUserInRoom {
    userID;
    roomID;
    constructor(userID, roomID) {
        this.userID = userID;
        this.roomID = roomID;
    }
    async redact(client, managementRoom) {
        await managementRoom.logMessage(matrix_bot_sdk_1.LogLevel.DEBUG, "Draupnir", `Redacting events from ${this.userID} in room ${this.roomID}.`);
        await (0, utils_1.redactUserMessagesIn)(client, managementRoom, this.userID, [
            this.roomID,
        ]);
    }
    redactionEqual(redaction) {
        if (redaction instanceof RedactUserInRoom) {
            return (redaction.userID === this.userID && redaction.roomID === this.roomID);
        }
        else {
            return false;
        }
    }
}
exports.RedactUserInRoom = RedactUserInRoom;
/**
 * This is a queue for events so that other protections can happen first (e.g. applying room bans to every room).
 */
class EventRedactionQueue {
    /**
     * This map is indexed by roomId and its values are a list of redactions waiting to be processed for that room.
     */
    toRedact = new Map();
    /**
     * Test whether the redaction is already present in the queue.
     * @param redaction a QueuedRedaction.
     * @returns True if the queue already has the redaction, false otherwise.
     */
    has(redaction) {
        return !!this.toRedact
            .get(redaction.roomID)
            ?.find((r) => r.redactionEqual(redaction));
    }
    /**
     * Adds a `QueuedRedaction` to the queue. It will be processed when `process` is called.
     * @param redaction A `QueuedRedaction` to await processing
     * @returns `true` if the redaction was added to the queue, `false` if it is a duplicate of a redaction already present in the queue.
     */
    add(redaction) {
        if (this.has(redaction)) {
            return false;
        }
        else {
            const entry = this.toRedact.get(redaction.roomID);
            if (entry) {
                entry.push(redaction);
            }
            else {
                this.toRedact.set(redaction.roomID, [redaction]);
            }
            return true;
        }
    }
    /**
     * Process the redaction queue, carrying out the action of each `QueuedRedaction` in sequence.
     * If a redaction cannot be processed, the redaction is skipped and removed from the queue.
     * We then carry on processing the next redactions.
     * The reason we skip is at the moment is that we would have to think about all of the situations
     * where we would not want failures to try again (e.g. messages were already redacted) and handle them explicitly.
     * @param client The matrix client to use for processing redactions.
     * @param limitToRoomId If the roomId is provided, only redactions for that room will be processed.
     * @returns A description of any errors encountered by each QueuedRedaction that was processed.
     */
    async process(client, managementRoom, limitToRoomID) {
        const errors = [];
        const redact = async (currentBatch) => {
            for (const redaction of currentBatch) {
                try {
                    await redaction.redact(client, managementRoom);
                }
                catch (e) {
                    // FIXME: all of this code is "legacy", from the RoomUpdateException
                    // type to the message destructuring. Instead it should be using
                    let message = "<no message>";
                    if (typeof e === "object" && e !== null) {
                        if ("message" in e && typeof e.message === "string") {
                            message = e.message;
                        }
                        else if ("body" in e &&
                            typeof e.body === "object" &&
                            e.body !== null &&
                            "error" in e.body &&
                            typeof e.body.error === "string") {
                            message = e.body.error;
                        }
                    }
                    const error = new matrix_protection_suite_1.RoomUpdateException(matrix_basic_types_1.MatrixRoomReference.fromRoomID(redaction.roomID), matrix_protection_suite_1.ActionExceptionKind.Unknown, (0, matrix_protection_suite_1.assertThrowableIsError)(e), message);
                    errors.push(error);
                }
            }
        };
        if (limitToRoomID) {
            // There might not actually be any queued redactions for this room.
            const queuedRedactions = this.toRedact.get(limitToRoomID);
            if (queuedRedactions) {
                this.toRedact.delete(limitToRoomID);
                await redact(queuedRedactions);
            }
        }
        else {
            for (const [roomId, redactions] of this.toRedact) {
                this.toRedact.delete(roomId);
                await redact(redactions);
            }
        }
        return errors;
    }
}
exports.EventRedactionQueue = EventRedactionQueue;
//# sourceMappingURL=EventRedactionQueue.js.map