2022-03-18 16:08:32 -04:00
|
|
|
/*
|
2024-09-09 14:57:16 +01:00
|
|
|
Copyright 2024 New Vector Ltd.
|
2022-03-18 16:08:32 -04:00
|
|
|
Copyright 2021 The Matrix.org Foundation C.I.C.
|
|
|
|
|
|
2025-01-06 11:18:54 +00:00
|
|
|
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
2024-09-09 14:57:16 +01:00
|
|
|
Please see LICENSE files in the repository root for full details.
|
2022-03-18 16:08:32 -04:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import React, { useState } from "react";
|
|
|
|
|
import { logger } from "matrix-js-sdk/src/logger";
|
2023-08-09 08:18:41 +01:00
|
|
|
import { MatrixClient, RoomMember, Room, MatrixEvent, EventTimeline, EventType } from "matrix-js-sdk/src/matrix";
|
2022-03-18 16:08:32 -04:00
|
|
|
|
|
|
|
|
import { _t } from "../../../languageHandler";
|
|
|
|
|
import dis from "../../../dispatcher/dispatcher";
|
|
|
|
|
import { Action } from "../../../dispatcher/actions";
|
|
|
|
|
import BaseDialog from "../dialogs/BaseDialog";
|
|
|
|
|
import InfoDialog from "../dialogs/InfoDialog";
|
|
|
|
|
import DialogButtons from "../elements/DialogButtons";
|
|
|
|
|
import StyledCheckbox from "../elements/StyledCheckbox";
|
|
|
|
|
|
2023-02-28 10:31:48 +00:00
|
|
|
interface Props {
|
2022-03-18 16:08:32 -04:00
|
|
|
matrixClient: MatrixClient;
|
|
|
|
|
room: Room;
|
|
|
|
|
member: RoomMember;
|
2023-02-28 10:31:48 +00:00
|
|
|
onFinished(redact?: boolean): void;
|
2022-03-18 16:08:32 -04:00
|
|
|
}
|
|
|
|
|
|
2023-02-28 10:31:48 +00:00
|
|
|
const BulkRedactDialog: React.FC<Props> = (props) => {
|
2022-03-18 16:08:32 -04:00
|
|
|
const { matrixClient: cli, room, member, onFinished } = props;
|
|
|
|
|
const [keepStateEvents, setKeepStateEvents] = useState(true);
|
|
|
|
|
|
2023-03-27 08:01:09 +01:00
|
|
|
let timeline: EventTimeline | null = room.getLiveTimeline();
|
2023-02-13 11:39:16 +00:00
|
|
|
let eventsToRedact: MatrixEvent[] = [];
|
2022-03-18 16:08:32 -04:00
|
|
|
while (timeline) {
|
|
|
|
|
eventsToRedact = [
|
|
|
|
|
...eventsToRedact,
|
|
|
|
|
...timeline.getEvents().filter(
|
|
|
|
|
(event) =>
|
|
|
|
|
event.getSender() === member.userId &&
|
|
|
|
|
!event.isRedacted() &&
|
|
|
|
|
!event.isRedaction() &&
|
|
|
|
|
event.getType() !== EventType.RoomCreate &&
|
|
|
|
|
// Don't redact ACLs because that'll obliterate the room
|
|
|
|
|
// See https://github.com/matrix-org/synapse/issues/4042 for details.
|
|
|
|
|
event.getType() !== EventType.RoomServerAcl &&
|
|
|
|
|
// Redacting encryption events is equally bad
|
|
|
|
|
event.getType() !== EventType.RoomEncryption,
|
|
|
|
|
),
|
|
|
|
|
];
|
|
|
|
|
timeline = timeline.getNeighbouringTimeline(EventTimeline.BACKWARDS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (eventsToRedact.length === 0) {
|
|
|
|
|
return (
|
|
|
|
|
<InfoDialog
|
|
|
|
|
onFinished={onFinished}
|
2023-10-03 19:17:26 +01:00
|
|
|
title={_t("user_info|redact|no_recent_messages_title", { user: member.name })}
|
2022-03-18 16:08:32 -04:00
|
|
|
description={
|
|
|
|
|
<div>
|
2023-10-03 19:17:26 +01:00
|
|
|
<p>{_t("user_info|redact|no_recent_messages_description")}</p>
|
2022-03-18 16:08:32 -04:00
|
|
|
</div>
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
eventsToRedact = eventsToRedact.filter((event) => !(keepStateEvents && event.isState()));
|
|
|
|
|
const count = eventsToRedact.length;
|
|
|
|
|
const user = member.name;
|
|
|
|
|
|
2023-01-12 13:25:14 +00:00
|
|
|
const redact = async (): Promise<void> => {
|
2022-03-18 16:08:32 -04:00
|
|
|
logger.info(`Started redacting recent ${count} messages for ${member.userId} in ${room.roomId}`);
|
|
|
|
|
dis.dispatch({
|
|
|
|
|
action: Action.BulkRedactStart,
|
|
|
|
|
room_id: room.roomId,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Submitting a large number of redactions freezes the UI,
|
|
|
|
|
// so first yield to allow to rerender after closing the dialog.
|
|
|
|
|
await Promise.resolve();
|
|
|
|
|
await Promise.all(
|
2023-01-12 13:25:14 +00:00
|
|
|
eventsToRedact.reverse().map(async (event): Promise<void> => {
|
2022-03-18 16:08:32 -04:00
|
|
|
try {
|
2023-03-27 08:01:09 +01:00
|
|
|
await cli.redactEvent(room.roomId, event.getId()!);
|
2022-03-18 16:08:32 -04:00
|
|
|
} catch (err) {
|
|
|
|
|
// log and swallow errors
|
|
|
|
|
logger.error("Could not redact", event.getId());
|
|
|
|
|
logger.error(err);
|
|
|
|
|
}
|
|
|
|
|
}),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
logger.info(`Finished redacting recent ${count} messages for ${member.userId} in ${room.roomId}`);
|
|
|
|
|
dis.dispatch({
|
|
|
|
|
action: Action.BulkRedactEnd,
|
|
|
|
|
room_id: room.roomId,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<BaseDialog
|
|
|
|
|
className="mx_BulkRedactDialog"
|
|
|
|
|
onFinished={onFinished}
|
2023-10-03 19:17:26 +01:00
|
|
|
title={_t("user_info|redact|confirm_title", { user })}
|
2022-03-18 16:08:32 -04:00
|
|
|
contentId="mx_Dialog_content"
|
|
|
|
|
>
|
|
|
|
|
<div className="mx_Dialog_content" id="mx_Dialog_content">
|
2023-10-03 19:17:26 +01:00
|
|
|
<p>{_t("user_info|redact|confirm_description_1", { count, user })}</p>
|
|
|
|
|
<p>{_t("user_info|redact|confirm_description_2")}</p>
|
2022-03-18 16:08:32 -04:00
|
|
|
<StyledCheckbox checked={keepStateEvents} onChange={(e) => setKeepStateEvents(e.target.checked)}>
|
2023-10-03 19:17:26 +01:00
|
|
|
{_t("user_info|redact|confirm_keep_state_label")}
|
2022-03-18 16:08:32 -04:00
|
|
|
</StyledCheckbox>
|
|
|
|
|
<div className="mx_BulkRedactDialog_checkboxMicrocopy">
|
2023-10-03 19:17:26 +01:00
|
|
|
{_t("user_info|redact|confirm_keep_state_explainer")}
|
2022-12-12 12:24:14 +01:00
|
|
|
</div>
|
2022-03-18 16:08:32 -04:00
|
|
|
</div>
|
|
|
|
|
<DialogButtons
|
2023-10-03 19:17:26 +01:00
|
|
|
primaryButton={_t("user_info|redact|confirm_button", { count })}
|
2022-03-18 16:08:32 -04:00
|
|
|
primaryButtonClass="danger"
|
|
|
|
|
primaryDisabled={count === 0}
|
|
|
|
|
onPrimaryButtonClick={() => {
|
2024-06-13 15:15:59 +01:00
|
|
|
setTimeout(redact, 0);
|
2022-03-18 16:08:32 -04:00
|
|
|
onFinished(true);
|
|
|
|
|
}}
|
|
|
|
|
onCancel={() => onFinished(false)}
|
|
|
|
|
/>
|
|
|
|
|
</BaseDialog>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default BulkRedactDialog;
|