From 9814c3a525b230d30eb02ff86d3af0e97e2a74be Mon Sep 17 00:00:00 2001 From: nexy7574 Date: Wed, 9 Apr 2025 03:25:07 +0100 Subject: [PATCH] Add a button to remove all loaded timeline events from user --- web/src/ui/rightpanel/UserModeration.tsx | 73 +++++++++++++++++++++++- 1 file changed, 70 insertions(+), 3 deletions(-) diff --git a/web/src/ui/rightpanel/UserModeration.tsx b/web/src/ui/rightpanel/UserModeration.tsx index 3f2d586..147c04c 100644 --- a/web/src/ui/rightpanel/UserModeration.tsx +++ b/web/src/ui/rightpanel/UserModeration.tsx @@ -15,13 +15,15 @@ // along with this program. If not, see . import { use } from "react" import Client from "@/api/client.ts" -import { RoomStateStore } from "@/api/statestore" +import { RoomStateStore, useRoomTimeline } from "@/api/statestore" import { MemDBEvent, MembershipAction } from "@/api/types" +import { useRoomContext } from "@/ui/roomview/roomcontext.ts" import ConfirmWithMessageModal from "../menu/ConfirmWithMessageModal.tsx" import { getPowerLevels } from "../menu/util.ts" import { ModalContext } from "../modal" import StartDMButton from "./StartDMButton.tsx" import UserIgnoreButton from "./UserIgnoreButton.tsx" +import DeleteIcon from "@/icons/delete.svg?react" import BanIcon from "@/icons/gavel.svg?react" import InviteIcon from "@/icons/person-add.svg?react" import KickIcon from "@/icons/person-remove.svg?react" @@ -35,7 +37,9 @@ interface UserModerationProps { const UserModeration = ({ userID, client, member, room }: UserModerationProps) => { const openModal = use(ModalContext) - const hasPL = (action: "invite" | "kick" | "ban") => { + const roomCtx = useRoomContext() + const timeline = useRoomTimeline(roomCtx.store) + const hasPL = (action: "invite" | "kick" | "ban" | "redact") => { if (!room) { throw new Error("hasPL called without room") } @@ -44,7 +48,7 @@ const UserModeration = ({ userID, client, member, room }: UserModerationProps) = return ownPL >= (pls.invite ?? 0) } const otherUserPL = pls.users?.[userID] ?? pls.users_default ?? 0 - return ownPL >= (pls[action] ?? 50) && ownPL > otherUserPL + return ownPL >= (pls[action] ?? pls.state_default ?? 50) && ownPL > otherUserPL } const runAction = (action: MembershipAction) => { @@ -76,6 +80,63 @@ const UserModeration = ({ userID, client, member, room }: UserModerationProps) = }) } } + const calculateRedactions = () => { + if (!room) { + return [] + } + return timeline.filter(evt => { + return evt !== null && evt.room_id == room.roomID && evt.sender === userID && !evt.redacted_by + }) as MemDBEvent[] // there's no nulls in this one + } + const redactRecentMessages = () => { + if (!room) { + throw new Error("redactRecentMessages called without room") + } + const callback = async (reason: string) => { + const tasks = [] + for (const evt of calculateRedactions()) { + // for(let i=0;i<3;i++) { + // try { + // await client.rpc.redactEvent(evt.room_id, evt.event_id, reason) + // break + // } catch (e) { + // // If the error is a 429, retry. + // // TODO: get the ratelimit from the error and use it for a more precise sleep + // if (e instanceof Error && e.message.includes("M_LIMIT_EXCEEDED")) { + // const retryAfter = (2 ** i) + Math.random() + // console.warn("Rate limited, retrying in %.2f seconds...", retryAfter) + // await new Promise(resolve => setTimeout(resolve, retryAfter * 1000)) + // } else { + // throw e + // } + // } + // } + tasks.push(client.rpc.redactEvent(evt.room_id, evt.event_id, reason)) + } + Promise.all(tasks).catch((e) => { + console.error(e) + window.alert(`Failed to redact events: ${e}`) + }) + return true + } + const evtCount = calculateRedactions().length + return () => { + openModal({ + dimmed: true, + boxed: true, + innerBoxClass: "confirm-message-modal", + content: Are you sure you want to redact all currently loaded timeline events + of {userID}? This will remove approximately {evtCount} events.} + placeholder="Reason (optional)" + confirmButton={`Redact ~${evtCount} events`} + onConfirm={callback} + />, + }) + } + } const membership = member?.content.membership || "leave" return
@@ -111,6 +172,12 @@ const UserModeration = ({ userID, client, member, room }: UserModerationProps) = Unban )} + {room && hasPL("redact") && ( + + )}
}