mirror of
https://github.com/tulir/gomuks.git
synced 2025-04-19 18:13:41 -05:00
parent
8ecbd2316c
commit
a0ab756562
4 changed files with 101 additions and 15 deletions
|
@ -13,15 +13,70 @@
|
|||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// import { ACLEventContent } from "@/api/types"
|
||||
import { Fragment, JSX } from "react"
|
||||
import { ACLEventContent } from "@/api/types"
|
||||
import { listDiff } from "@/util/diff.ts"
|
||||
import { humanJoinReact, joinReact } from "@/util/reactjoin.tsx"
|
||||
import EventContentProps from "./props.ts"
|
||||
|
||||
function joinServers(arr: string[]): JSX.Element[] {
|
||||
return humanJoinReact(arr.map(item => <code className="server-name">{item}</code>))
|
||||
}
|
||||
|
||||
function makeACLChangeString(
|
||||
addedAllow: string[], removedAllow: string[],
|
||||
addedDeny: string[], removedDeny: string[],
|
||||
prevAllowIP: boolean, newAllowIP: boolean,
|
||||
) {
|
||||
const parts = []
|
||||
if (addedDeny.length > 0) {
|
||||
parts.push(<>Servers matching {joinServers(addedDeny)} are now banned.</>)
|
||||
}
|
||||
if (removedDeny.length > 0) {
|
||||
parts.push(<>Servers matching {joinServers(removedDeny)} were removed from the ban list.</>)
|
||||
}
|
||||
if (addedAllow.length > 0) {
|
||||
parts.push(<>Servers matching {joinServers(addedAllow)} are now allowed.</>)
|
||||
}
|
||||
if (removedAllow.length > 0) {
|
||||
parts.push(<>Servers matching {joinServers(removedAllow)} were removed from the allowed list.</>)
|
||||
}
|
||||
if (prevAllowIP !== newAllowIP) {
|
||||
parts.push(
|
||||
<>Participating from a server using an IP literal hostname is now {newAllowIP ? "allowed" : "banned"}.</>,
|
||||
)
|
||||
}
|
||||
return joinReact(parts)
|
||||
}
|
||||
|
||||
function ensureArray(val: unknown): string[] {
|
||||
return Array.isArray(val) ? val : []
|
||||
}
|
||||
|
||||
const ACLBody = ({ event, sender }: EventContentProps) => {
|
||||
// const content = event.content as ACLEventContent
|
||||
// const prevContent = event.unsigned.prev_content as ACLEventContent | undefined
|
||||
// TODO diff content and prevContent
|
||||
const content = event.content as ACLEventContent
|
||||
const prevContent = event.unsigned.prev_content as ACLEventContent | undefined
|
||||
const [addedAllow, removedAllow] = listDiff(ensureArray(content.allow), ensureArray(prevContent?.allow))
|
||||
const [addedDeny, removedDeny] = listDiff(ensureArray(content.deny), ensureArray(prevContent?.deny))
|
||||
const prevAllowIP = prevContent?.allow_ip_literals ?? true
|
||||
const newAllowIP = content.allow_ip_literals ?? true
|
||||
if (
|
||||
prevAllowIP === newAllowIP
|
||||
&& !addedAllow.length && !removedAllow.length
|
||||
&& !addedDeny.length && !removedDeny.length
|
||||
) {
|
||||
return <div className="acl-body">
|
||||
{sender?.content.displayname ?? event.sender} sent a server ACL event with no changes
|
||||
</div>
|
||||
}
|
||||
let changeString = makeACLChangeString(addedAllow, removedAllow, addedDeny, removedDeny, prevAllowIP, newAllowIP)
|
||||
if (ensureArray(content.allow).length === 0) {
|
||||
changeString = [<Fragment key="yay">
|
||||
🎉 All servers are banned from participating! This room can no longer be used.
|
||||
</Fragment>]
|
||||
}
|
||||
return <div className="acl-body">
|
||||
{sender?.content.displayname ?? event.sender} changed the server ACLs
|
||||
{sender?.content.displayname ?? event.sender} changed the server ACLs: {changeString}
|
||||
</div>
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ import { oxfordHumanJoin } from "@/util/join.ts"
|
|||
import EventContentProps from "./props.ts"
|
||||
|
||||
function renderPinChanges(content: PinnedEventsContent, prevContent?: PinnedEventsContent): string {
|
||||
const { added, removed } = listDiff(content.pinned ?? [], prevContent?.pinned ?? [])
|
||||
const [added, removed] = listDiff(content.pinned ?? [], prevContent?.pinned ?? [])
|
||||
if (added.length) {
|
||||
if (removed.length) {
|
||||
return `pinned ${oxfordHumanJoin(added)} and unpinned ${oxfordHumanJoin(removed)}`
|
||||
|
|
|
@ -15,19 +15,19 @@
|
|||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
const minSizeForSet = 10
|
||||
|
||||
export function listDiff<T>(newArr: T[], oldArr: T[]): { added: T[], removed: T[] } {
|
||||
export function listDiff<T>(newArr: T[], oldArr: T[]): [added: T[], removed: T[]] {
|
||||
if (oldArr.length < minSizeForSet && newArr.length < minSizeForSet) {
|
||||
return {
|
||||
removed: oldArr.filter(item => !newArr.includes(item)),
|
||||
added: newArr.filter(item => !oldArr.includes(item)),
|
||||
}
|
||||
return [
|
||||
newArr.filter(item => !oldArr.includes(item)),
|
||||
oldArr.filter(item => !newArr.includes(item)),
|
||||
]
|
||||
}
|
||||
const oldSet = new Set(oldArr)
|
||||
const newSet = new Set(newArr)
|
||||
return {
|
||||
removed: oldArr.filter(item => !newSet.has(item)),
|
||||
added: newArr.filter(item => !oldSet.has(item)),
|
||||
}
|
||||
return [
|
||||
newArr.filter(item => !oldSet.has(item)),
|
||||
oldArr.filter(item => !newSet.has(item)),
|
||||
]
|
||||
}
|
||||
|
||||
export function objectDiff<T>(
|
||||
|
|
31
web/src/util/reactjoin.tsx
Normal file
31
web/src/util/reactjoin.tsx
Normal file
|
@ -0,0 +1,31 @@
|
|||
// gomuks - A Matrix client written in Go.
|
||||
// Copyright (C) 2024 Tulir Asokan
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import { Fragment, JSX } from "react"
|
||||
|
||||
export function humanJoinReact(
|
||||
arr: (string | JSX.Element)[],
|
||||
sep: string | JSX.Element = ", ",
|
||||
lastSep: string | JSX.Element = " and ",
|
||||
): JSX.Element[] {
|
||||
return arr.map((elem, idx) =>
|
||||
<Fragment key={idx}>
|
||||
{elem}
|
||||
{idx < arr.length - 1 ? (idx === arr.length - 2 ? lastSep : sep) : null}
|
||||
</Fragment>)
|
||||
}
|
||||
|
||||
export const oxfordHumanJoinReact = (arr: (string | JSX.Element)[]) => humanJoinReact(arr, ", ", ", and ")
|
||||
export const joinReact = (arr: (string | JSX.Element)[]) => humanJoinReact(arr, " ", " ")
|
Loading…
Add table
Reference in a new issue