diff --git a/src/commands/Unban.ts b/src/commands/Unban.ts index 6214c35c..510ab5fe 100644 --- a/src/commands/Unban.ts +++ b/src/commands/Unban.ts @@ -27,12 +27,12 @@ limitations under the License. import { DraupnirContext } from "./CommandHandler"; import { findPresentationType, KeywordsDescription, parameters, ParsedKeywords, union } from "./interface-manager/ParameterParsing"; -import { UserID, MatrixGlob, LogLevel } from "matrix-bot-sdk"; +import { MatrixGlob, LogLevel } from "matrix-bot-sdk"; import { defineInterfaceCommand, findTableCommand } from "./interface-manager/InterfaceCommand"; import { defineMatrixInterfaceAdaptor } from "./interface-manager/MatrixInterfaceAdaptor"; import { tickCrossRenderer } from "./interface-manager/MatrixHelpRenderer"; import { Draupnir } from "../Draupnir"; -import { ActionResult, isError, isStringUserID, MatrixRoomReference, Ok, PolicyRuleType } from "matrix-protection-suite"; +import { ActionResult, isError, isStringUserID, MatrixRoomReference, Ok, PolicyRuleType, UserID } from "matrix-protection-suite"; import { resolveRoomReferenceSafe } from "matrix-protection-suite-for-matrix-bot-sdk"; import { findPolicyRoomIDFromShortcode } from "./CreateBanListCommand"; diff --git a/src/commands/interface-manager/DeadDocumentPresentation.ts b/src/commands/interface-manager/DeadDocumentPresentation.ts index cf70bb7c..c60d14a5 100644 --- a/src/commands/interface-manager/DeadDocumentPresentation.ts +++ b/src/commands/interface-manager/DeadDocumentPresentation.ts @@ -3,8 +3,9 @@ * All rights reserved. */ +import { MatrixRoomAlias, MatrixRoomID } from "matrix-protection-suite"; import { DocumentNode } from "./DeadDocument" -import { PresentationType } from "./ParameterParsing"; +import { PresentationType, findPresentationType, presentationTypeOf } from "./ParameterParsing"; type PresentationRenderer = (presentation: unknown) => DocumentNode; @@ -26,3 +27,19 @@ export function findPresentationRenderer(presentationType: PresentationType): Pr } return entry; } + +export const DeadDocumentPresentationMirror = Object.freeze({ + present(object: unknown): DocumentNode { + if (object instanceof MatrixRoomID || object instanceof MatrixRoomAlias) { + return findPresentationRenderer(findPresentationType('MatrixRoomReference'))(object) + } else { + const presentationType = presentationTypeOf(object); + if (presentationType !== undefined) { + const renderer = findPresentationRenderer(presentationType); + return renderer(object); + } else { + throw new TypeError(`Unable to present: ${object}`); + } + } + } +}) diff --git a/src/commands/interface-manager/JSXFactory.ts b/src/commands/interface-manager/JSXFactory.ts index 40f2ce04..2fd640f9 100644 --- a/src/commands/interface-manager/JSXFactory.ts +++ b/src/commands/interface-manager/JSXFactory.ts @@ -4,8 +4,7 @@ */ import { DocumentNode, LeafNode, makeDocumentNode, makeLeafNode, NodeTag, TextNode } from "./DeadDocument"; -import { findPresentationRenderer } from "./DeadDocumentPresentation"; -import { presentationTypeOf } from "./ParameterParsing"; +import { DeadDocumentPresentationMirror } from "./DeadDocumentPresentation"; type rawJSX = DocumentNode|LeafNode|string|number|Array; @@ -31,13 +30,7 @@ export function JSXFactory(tag: NodeTag, properties: unknown, ...rawChildren: (D node.addChild(rawChild); } } else { - const presentationType = presentationTypeOf(rawChild); - if (presentationType !== undefined) { - const renderer = findPresentationRenderer(presentationType); - node.addChild(renderer(rawChild)); - } else { - throw new TypeError(`Unexpected raw child ${JSON.stringify(rawChild)}`); - } + node.addChild(DeadDocumentPresentationMirror.present(rawChild)); } } rawChildren.forEach(ensureChild); diff --git a/src/commands/interface-manager/MatrixInterfaceAdaptor.ts b/src/commands/interface-manager/MatrixInterfaceAdaptor.ts index 0e6debfe..827fa53c 100644 --- a/src/commands/interface-manager/MatrixInterfaceAdaptor.ts +++ b/src/commands/interface-manager/MatrixInterfaceAdaptor.ts @@ -98,6 +98,7 @@ export class MatrixInterfaceAdaptor item instanceof MatrixRoomID || item instanceof MatrixRoomAlias), }) +definePresentationRenderer(findPresentationType('MatrixRoomReference'), function(presentation: MatrixRoomReference): DocumentNode { + return {presentation.toRoomIDOrAlias()} +}) + makePresentationType({ name: 'MatrixRoomID', validator: simpleTypeValidator('MatrixRoomID', (item: ReadItem) => item instanceof MatrixRoomID) diff --git a/src/commands/interface-manager/MatrixPromptForAccept.tsx b/src/commands/interface-manager/MatrixPromptForAccept.tsx index e3f2785d..6e623be0 100644 --- a/src/commands/interface-manager/MatrixPromptForAccept.tsx +++ b/src/commands/interface-manager/MatrixPromptForAccept.tsx @@ -13,6 +13,7 @@ import { MatrixSendClient } from "matrix-protection-suite-for-matrix-bot-sdk"; import { MatrixReactionHandler, ReactionListener } from "./MatrixReactionHandler"; import { StaticDecode, Type } from "@sinclair/typebox"; import { ReadItem, readCommand } from "./CommandReader"; +import { printReadably } from "./PrintReadably"; const log = new Logger('MatrixPromptForAccept'); @@ -150,8 +151,8 @@ export async function promptDefault( reactionMap, { command_designator: command.designator, - read_items: existingArguments.map(item => item.toString()), - default: defaultPrompt.toString() + read_items: existingArguments.map(printReadably), + default: printReadably(defaultPrompt) } ) ); @@ -173,7 +174,7 @@ export async function promptSuggestions( existingArguments: ReadItem[], ): Promise { const reactionMap = MatrixReactionHandler.createItemizedReactionMap( - suggestions.map(item => item.toString()) + suggestions.map(printReadably) ); const events = await renderMatrixAndSend( Please select one of the following options to provide as an argument for the parameter {parameter.name}: @@ -190,7 +191,7 @@ export async function promptSuggestions( ARGUMENT_PROMPT_LISTENER, reactionMap, { - read_items: existingArguments, + read_items: existingArguments.map(printReadably), command_designator: command.designator } ) diff --git a/src/commands/interface-manager/PrintReadably.ts b/src/commands/interface-manager/PrintReadably.ts new file mode 100644 index 00000000..3eaf0f5d --- /dev/null +++ b/src/commands/interface-manager/PrintReadably.ts @@ -0,0 +1,18 @@ +// SPDX-FileCopyrightText: 2024 Gnuxie +// +// SPDX-License-Identifier: AFL-3.0 + +import { MatrixEventViaAlias, MatrixEventViaRoomID, MatrixRoomAlias, MatrixRoomID, Permalinks, UserID } from "matrix-protection-suite"; +import { ReadItem } from "./CommandReader"; + +export function printReadably(item: ReadItem): string { + if (item instanceof MatrixRoomID || item instanceof MatrixRoomAlias) { + return item.toPermalink(); + } else if (item instanceof UserID) { + return item.toString(); + } else if (item instanceof MatrixEventViaAlias || item instanceof MatrixEventViaRoomID) { + return Permalinks.forEvent(item.reference.toRoomIDOrAlias(), item.eventID, item.reference.getViaServers()); + } else { + return item.toString() + } +} diff --git a/test/commands/CommandReaderTest.ts b/test/commands/CommandReaderTest.ts index bb34b2ec..35b55586 100644 --- a/test/commands/CommandReaderTest.ts +++ b/test/commands/CommandReaderTest.ts @@ -1,6 +1,6 @@ import expect from "expect"; import { Keyword, readCommand } from "../../src/commands/interface-manager/CommandReader"; -import { MatrixRoomAlias, MatrixRoomID } from "matrix-protection-suite"; +import { MatrixRoomAlias, MatrixRoomID, UserID } from "matrix-protection-suite"; describe("Can read", function() { it("Can read a simple command with only strings", function() { @@ -43,5 +43,12 @@ describe("Can read", function() { } checkMalformedRoomReference("#singasongaboutlife"); checkMalformedRoomReference("!mjolnir"); - }) + }); + it("Can parse userID's", function() { + const command = "@spam:example.com"; + const readItems = readCommand(command); + expect(readItems.at(0)).toBeInstanceOf(UserID); + const user = readItems.at(0) as UserID; + expect(user.localpart).toBe('spam'); + }); }) diff --git a/test/commands/ParseTest.ts b/test/commands/ParseTest.ts new file mode 100644 index 00000000..0d3c4701 --- /dev/null +++ b/test/commands/ParseTest.ts @@ -0,0 +1,38 @@ +import { Ok, isError } from "matrix-protection-suite"; +import { defineCommandTable, defineInterfaceCommand, findTableCommand } from "../../src/commands/interface-manager/InterfaceCommand"; +import { ArgumentStream, findPresentationType, parameters, union } from "../../src/commands/interface-manager/ParameterParsing"; +import { readCommand } from "../../src/commands/interface-manager/CommandReader"; +import "../../src/commands/interface-manager/MatrixPresentations"; + +it('A command that fookin parses mxids', async function() { + const tableName = Symbol("ParseTest"); + defineCommandTable(tableName); + defineInterfaceCommand({ + designator: ["unban"], + table: tableName, + parameters: parameters([ + { + name: "entity", + acceptor: union( + findPresentationType("UserID"), + findPresentationType("MatrixRoomReference"), + findPresentationType("string") + ) + } + ], + undefined, + ), + command: async function() { + return Ok(undefined); + }, + summary: "Mimicks the unban command" + }); + const command = findTableCommand(tableName, "unban"); + if (command === undefined) { + throw new TypeError(`Command table has gone missing this asin't good guys`); + } + const result = await command.parseThenInvoke(undefined, new ArgumentStream(readCommand("@spam:example.com"))); + if (isError(result)) { + throw new TypeError(`Not supposed to be error mate`); + } +})