Skip to content

Commit

Permalink
Gnuxie/consequence renderer clarity (#356)
Browse files Browse the repository at this point in the history
* Allow span attributes to be rendered.

* Update for MPS 0.18.0.

* Add some consistency to capability renderers.
  • Loading branch information
Gnuxie authored Apr 18, 2024
1 parent 1a36668 commit 3d02c72
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 47 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@
"js-yaml": "^4.1.0",
"jsdom": "^24.0.0",
"matrix-appservice-bridge": "^9.0.1",
"matrix-protection-suite": "npm:@gnuxie/matrix-protection-suite@0.17.1",
"matrix-protection-suite-for-matrix-bot-sdk": "npm:@gnuxie/matrix-protection-suite-for-matrix-bot-sdk@0.17.1",
"matrix-protection-suite": "npm:@gnuxie/matrix-protection-suite@0.18.0",
"matrix-protection-suite-for-matrix-bot-sdk": "npm:@gnuxie/matrix-protection-suite-for-matrix-bot-sdk@0.18.0",
"parse-duration": "^1.0.2",
"pg": "^8.8.0",
"shell-quote": "^1.7.3",
Expand Down
15 changes: 12 additions & 3 deletions src/capabilities/CommonRenderers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,25 +44,34 @@ export function renderExceptionTrail(error: ActionError): DocumentNode {

export function renderFailedSingularConsequence(
description: DescriptionMeta,
title: DocumentNode,
error: ActionError
): DocumentNode {
return <fragment>
<details>
<summary><code>{description.name}</code>: {error.mostRelevantElaboration}</summary>
<summary><code>{description.name}</code>: {title} - {renderOutcome(false)}</summary>
{error.mostRelevantElaboration}
{renderDetailsNotice(error)}
{renderElaborationTrail(error)}
{renderExceptionTrail(error)}
</details>
</fragment>
}

export function renderOutcome(isOutcomeOk: boolean): DocumentNode {
const colour = isOutcomeOk ? '#7cfc00' : '#E01F2B';
return <fragment>
<span data-mx-color={colour}>{isOutcomeOk ? 'OK' : 'Failed'}</span>
</fragment>
}

function renderRoomOutcomeOk(roomID: StringRoomID): DocumentNode {
return <span>{renderRoomPill(MatrixRoomReference.fromRoomID(roomID))} - OK</span>
return <span>{renderRoomPill(MatrixRoomReference.fromRoomID(roomID))} - {renderOutcome(true)}</span>
}
function renderRoomOutcomeError(roomID: StringRoomID, error: ActionError): DocumentNode {
return <fragment>
<details>
<summary>{renderRoomPill(MatrixRoomReference.fromRoomID(roomID))} - Error: {error.mostRelevantElaboration}</summary>
<summary>{renderRoomPill(MatrixRoomReference.fromRoomID(roomID))} - {renderOutcome(false)}: {error.mostRelevantElaboration}</summary>
{renderDetailsNotice(error)}
{renderElaborationTrail(error)}
{renderExceptionTrail(error)}
Expand Down
19 changes: 11 additions & 8 deletions src/capabilities/ServerACLConsequencesRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,37 +26,40 @@ class StandardServerConsequencesRenderer implements ServerConsequences {
public readonly requiredPermissions = this.capability.requiredPermissions;
public async consequenceForServerInRoom(roomID: StringRoomID, revision: PolicyListRevision): Promise<ActionResult<void>> {
const capabilityResult = await this.capability.consequenceForServerInRoom(roomID, revision);
const title = <fragment>
Setting server ACL in {Permalinks.forRoom(roomID)} as it is out of sync with watched policies.
</fragment>;
if (isError(capabilityResult)) {
this.messageCollector.addMessage(this.description, renderFailedSingularConsequence(this.description, capabilityResult.error))
this.messageCollector.addMessage(this.description, renderFailedSingularConsequence(this.description, title, capabilityResult.error))
return capabilityResult;
}
this.messageCollector.addOneliner(this.description, <fragment>
Setting server ACL in {Permalinks.forRoom(roomID)} as it is out of sync with watched policies.
</fragment>)
this.messageCollector.addOneliner(this.description, title);
return Ok(undefined);
}
public async consequenceForServerInRoomSet(revision: PolicyListRevision): Promise<ActionResult<RoomSetResult>> {
const capabilityResult = await this.capability.consequenceForServerInRoomSet(revision);
const title = <fragment>Updating server ACL in protected rooms.</fragment>;
if (isError(capabilityResult)) {
this.messageCollector.addMessage(this.description, renderFailedSingularConsequence(this.description, capabilityResult.error))
this.messageCollector.addMessage(this.description, renderFailedSingularConsequence(this.description, title, capabilityResult.error))
return capabilityResult;
}
this.messageCollector.addMessage(
this.description, renderRoomSetResult(capabilityResult.ok, {
summary: <fragment><code>{this.description.name}</code>: Updating server ACL in protected rooms.</fragment>
summary: <fragment><code>{this.description.name}</code>: {title}</fragment>
})
);
return capabilityResult;
}
public async unbanServerFromRoomSet(serverName: string, reason: string): Promise<ActionResult<RoomSetResult>> {
const capabilityResult = await this.capability.unbanServerFromRoomSet(serverName, reason);
const title = <fragment>Removing {serverName} from denied servers in protected rooms.</fragment>;
if (isError(capabilityResult)) {
this.messageCollector.addMessage(this.description, renderFailedSingularConsequence(this.description, capabilityResult.error));
this.messageCollector.addMessage(this.description, renderFailedSingularConsequence(this.description, title, capabilityResult.error));
return capabilityResult;
}
this.messageCollector.addMessage(
this.description, renderRoomSetResult(capabilityResult.ok, {
summary: <fragment><code>{this.description.name}</code>: Removing {serverName} from denied servers in protected rooms.</fragment>
summary: <fragment><code>{this.description.name}</code>: {title}</fragment>
})
);
return capabilityResult;
Expand Down
5 changes: 3 additions & 2 deletions src/capabilities/StandardEventConsequencesRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@ class StandardEventConsequencesRenderer implements EventConsequences {
public readonly requiredPermissions = this.capability.requiredPermissions;
public async consequenceForEvent(roomID: StringRoomID, eventID: StringEventID, reason: string): Promise<ActionResult<void>> {
const capabilityResult = await this.capability.consequenceForEvent(roomID, eventID, reason);
const title = <fragment>Redacting {Permalinks.forEvent(roomID, eventID)}.</fragment>;
if (isError(capabilityResult)) {
this.messageCollector.addOneliner(this.description, renderFailedSingularConsequence(this.description, capabilityResult.error))
this.messageCollector.addOneliner(this.description, renderFailedSingularConsequence(this.description, title, capabilityResult.error))
return capabilityResult;
}
this.messageCollector.addOneliner(this.description, <fragment>Redacting {Permalinks.forEvent(roomID, eventID)}.</fragment>)
this.messageCollector.addOneliner(this.description, title)
return capabilityResult;
}
}
Expand Down
69 changes: 47 additions & 22 deletions src/capabilities/StandardUserConsequencesRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@
// </text>

import { JSXFactory } from "../commands/interface-manager/JSXFactory";
import { ActionResult, Capability, DescriptionMeta, Ok, Permalinks, PolicyListRevision, ResultForUserInSetMap, StandardUserConsequencesContext, StringRoomID, StringUserID, UserConsequences, describeCapabilityContextGlue, describeCapabilityRenderer, isError } from "matrix-protection-suite";
import { ActionResult, Capability, DescriptionMeta, Ok, Permalinks, PolicyListRevision, ResultForUsersInSet, RoomSetResult, StandardUserConsequencesContext, StringRoomID, StringUserID, UserConsequences, describeCapabilityContextGlue, describeCapabilityRenderer, isError } from "matrix-protection-suite";
import { RendererMessageCollector } from "./RendererMessageCollector";
import { renderFailedSingularConsequence, renderRoomSetResult } from "./CommonRenderers";
import { renderFailedSingularConsequence, renderOutcome, renderRoomSetResult } from "./CommonRenderers";
import { DocumentNode } from "../commands/interface-manager/DeadDocument";
import { Draupnir } from "../Draupnir";

// yeah i know this is a bit insane but whatever, it can be our secret.
function renderResultForUserInSetMap(usersInSetMap: ResultForUserInSetMap, {
function renderResultForUserInSetMap(usersInSetMap: ResultForUsersInSet, {
ingword,
nnedword,
description
Expand All @@ -26,13 +26,34 @@ function renderResultForUserInSetMap(usersInSetMap: ResultForUserInSetMap, {
description: DescriptionMeta,
}): DocumentNode {
return <details>
<summary><code>{description.name}</code>: {ingword} {usersInSetMap.size} {usersInSetMap.size === 1 ? 'user' : 'users'} from protected rooms.</summary>
{[...usersInSetMap.entries()].map(([userID, roomResults]) => {
return renderRoomSetResult(roomResults, { summary: <fragment>{userID} will be {nnedword} from {roomResults.map.size} rooms.</fragment> })
})}
<summary>
<code>{description.name}</code>: {ingword} {usersInSetMap.map.size} &#32;
{usersInSetMap.map.size === 1 ? 'user' : 'users'} from protected rooms - &#32;
{renderOutcome(usersInSetMap.isEveryResultOk)}.
</summary>
{[...usersInSetMap.map.entries()].map(([userID, roomResults]) =>
renderRoomSetResultForUser(roomResults, userID, nnedword, {}))}
</details>
}

function renderRoomSetResultForUser(
roomResults: RoomSetResult,
userID: StringUserID,
nnedword: string,
{ description }: { description?: DescriptionMeta }
): DocumentNode {
return renderRoomSetResult(
roomResults,
{
summary: <fragment>
{description === undefined ? '' : <fragment><code>{description.name}</code>:</fragment>}
{userID} will be {nnedword} from {roomResults.map.size} rooms - &#32;
{renderOutcome(roomResults.isEveryResultOk)}.
</fragment>
}
)
}


class StandardUserConsequencesRenderer implements UserConsequences {
constructor(
Expand All @@ -47,24 +68,26 @@ class StandardUserConsequencesRenderer implements UserConsequences {

public async consequenceForUserInRoom(roomID: StringRoomID, userID: StringUserID, reason: string): Promise<ActionResult<void>> {
const capabilityResult = await this.capability.consequenceForUserInRoom(roomID, userID, reason);
const title = <fragment>
Banning user {userID} in {Permalinks.forRoom(roomID)} for {reason}.
</fragment>;
if (isError(capabilityResult)) {
this.messageCollector.addMessage(this.description, renderFailedSingularConsequence(this.description, capabilityResult.error))
this.messageCollector.addMessage(this.description, renderFailedSingularConsequence(this.description, title, capabilityResult.error))
return capabilityResult;
}
this.messageCollector.addOneliner(this.description, <fragment>
Banning user {userID} in {Permalinks.forRoom(roomID)} for {reason}.
</fragment>)
this.messageCollector.addOneliner(this.description, title)
return Ok(undefined);

}
public async consequenceForUserInRoomSet(revision: PolicyListRevision): Promise<ActionResult<ResultForUserInSetMap>> {
public async consequenceForUserInRoomSet(revision: PolicyListRevision): Promise<ActionResult<ResultForUsersInSet>> {
const capabilityResult = await this.capability.consequenceForUserInRoomSet(revision);
if (isError(capabilityResult)) {
this.messageCollector.addMessage(this.description, renderFailedSingularConsequence(this.description, capabilityResult.error))
const title = <fragment>Applying policy revision to protected rooms</fragment>
this.messageCollector.addMessage(this.description, renderFailedSingularConsequence(this.description, title, capabilityResult.error))
return capabilityResult;
}
const usersInSetMap = capabilityResult.ok;
if (usersInSetMap.size === 0) {
if (usersInSetMap.map.size === 0) {
return capabilityResult;
}
this.messageCollector.addMessage(this.description, renderResultForUserInSetMap(usersInSetMap, {
Expand All @@ -75,21 +98,23 @@ class StandardUserConsequencesRenderer implements UserConsequences {
return capabilityResult;

}
public async unbanUserFromRoomSet(userID: StringUserID, reason: string): Promise<ActionResult<ResultForUserInSetMap>> {
public async unbanUserFromRoomSet(userID: StringUserID, reason: string): Promise<ActionResult<RoomSetResult>> {
const capabilityResult = await this.capability.unbanUserFromRoomSet(userID, reason);
if (isError(capabilityResult)) {
this.messageCollector.addMessage(this.description, renderFailedSingularConsequence(this.description, capabilityResult.error))
const title = <fragment>Unbanning {userID} from protected rooms</fragment>
this.messageCollector.addMessage(this.description, renderFailedSingularConsequence(this.description, title, capabilityResult.error))
return capabilityResult;
}
const usersInSetMap = capabilityResult.ok;
if (usersInSetMap.size === 0) {
if (usersInSetMap.map.size === 0) {
return capabilityResult;
}
this.messageCollector.addMessage(this.description, renderResultForUserInSetMap(usersInSetMap, {
ingword: 'Unbanning',
nnedword: 'unbanned',
description: this.description,
}));
this.messageCollector.addMessage(this.description, renderRoomSetResultForUser(
usersInSetMap,
userID,
'unbanned',
{ description: this.description },
));
return capabilityResult;
}

Expand Down
2 changes: 1 addition & 1 deletion src/commands/interface-manager/DeadDocumentHtml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,5 @@ HTML_RENDERER.registerRenderer<FringeLeafRenderFunction<TransactionalOutputConte
staticString('<summary>'),
staticString('</summary>')
).registerInnerNode(NodeTag.Span,
staticString('<span>'),
attributableNode('span'),
staticString('</span>'));
18 changes: 9 additions & 9 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2505,15 +2505,15 @@ matrix-appservice@^2.0.0:
request-promise "^4.2.6"
sanitize-html "^2.8.0"

"matrix-protection-suite-for-matrix-bot-sdk@npm:@gnuxie/matrix-protection-suite-for-matrix-bot-sdk@0.17.1":
version "0.17.1"
resolved "https://registry.yarnpkg.com/@gnuxie/matrix-protection-suite-for-matrix-bot-sdk/-/matrix-protection-suite-for-matrix-bot-sdk-0.17.1.tgz#925363e0282879156c9f9b7673a8e6acd78e1a71"
integrity sha512-8vIu51ZLlVDUqRgz6K7bQMSjp/DEY+q1AO2mqvO/cSnHly/XKaflszwxN9zySAj6JjFXgPt+z1WkqV5omWE9NA==

"matrix-protection-suite@npm:@gnuxie/matrix-protection-suite@0.17.1":
version "0.17.1"
resolved "https://registry.yarnpkg.com/@gnuxie/matrix-protection-suite/-/matrix-protection-suite-0.17.1.tgz#7c4330a029461652d61d89ba5461c99324cfc3a1"
integrity sha512-3p9OqHf1JKymD1igceA5qy008Bqf9hSXC6mhPlLPqL7JGLFyE5FHa3eJcJJorZAfq54TH+KVmgpL0Es+E/wxfQ==
"matrix-protection-suite-for-matrix-bot-sdk@npm:@gnuxie/matrix-protection-suite-for-matrix-bot-sdk@0.18.0":
version "0.18.0"
resolved "https://registry.yarnpkg.com/@gnuxie/matrix-protection-suite-for-matrix-bot-sdk/-/matrix-protection-suite-for-matrix-bot-sdk-0.18.0.tgz#b08994638fad6d0f668d405f8bcd2760c641a569"
integrity sha512-Py6KNAYE0DZ/68xBEBdQVXOfyjUgHLS93vxoV+91d9sMyUuvfUmmjxvaPOzOUHoOeB6GLGAIc3lWkr3opU+upQ==

"matrix-protection-suite@npm:@gnuxie/matrix-protection-suite@0.18.0":
version "0.18.0"
resolved "https://registry.yarnpkg.com/@gnuxie/matrix-protection-suite/-/matrix-protection-suite-0.18.0.tgz#68f7898974f7a60530926c4af83999680b95706b"
integrity sha512-3tCKGatmMkyKOfbnG+VSYqs59F2S2ttuptlMC6XpmAFfaSVuR2v7ThAXp3OCVAKUykG3EY+8ypnhmtsV0JuMsQ==
dependencies:
await-lock "^2.2.2"
crypto-js "^4.1.1"
Expand Down

0 comments on commit 3d02c72

Please sign in to comment.