Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better help menu #33

Merged
merged 9 commits into from
Mar 7, 2023
2 changes: 1 addition & 1 deletion src/appservice/bot/AppserviceCommandHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { AppserviceBotEmitter } from './AppserviceBotEmitter';
const helpCommand = defineInterfaceCommand({
parameters: parameters([]),
table: "appservice bot",
command: async function() { return CommandResult.Ok(findCommandTable("appservice bot").getCommands()) },
command: async function() { return CommandResult.Ok(findCommandTable("appservice bot").getAllCommands()) },
designator: ["help"],
summary: "Display this message"
})
Expand Down
70 changes: 51 additions & 19 deletions src/commands/AddRemoveRoomFromDirectoryCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,30 +26,62 @@ limitations under the License.
*/

import { Mjolnir } from "../Mjolnir";
import { RichReply } from "matrix-bot-sdk";
import { defineInterfaceCommand, findTableCommand } from "./interface-manager/InterfaceCommand";
import { MjolnirContext } from "./CommandHandler";
import { tickCrossRenderer } from "./interface-manager/MatrixHelpRenderer";
import { defineMatrixInterfaceAdaptor } from "./interface-manager/MatrixInterfaceAdaptor";
import { parameters, findPresentationType, ParsedKeywords } from "./interface-manager/ParameterParsing";
import { CommandResult, CommandError } from "./interface-manager/Validation";
import { MatrixRoomReference } from "./interface-manager/MatrixRoomReference";

async function addRemoveFromDirectory(inRoomId: string, event: any, mjolnir: Mjolnir, roomRef: string, visibility: "public" | "private") {
async function addRemoveFromDirectory(mjolnir: Mjolnir, roomRef: MatrixRoomReference, visibility: "public" | "private"): Promise<CommandResult<void>> {
const isAdmin = await mjolnir.isSynapseAdmin();
if (!isAdmin) {
const message = "I am not a Synapse administrator, or the endpoint is blocked";
const reply = RichReply.createFor(inRoomId, event, message, message);
reply['msgtype'] = "m.notice";
mjolnir.client.sendMessage(inRoomId, reply);
return;
return CommandError.Result('I am not a Synapse administrator, or the endpoint to remove/add to the room directory is blocked');
}

const targetRoomId = await mjolnir.client.resolveRoom(roomRef);
const targetRoomId = (await roomRef.resolve(mjolnir.client)).toRoomIdOrAlias();
await mjolnir.client.setDirectoryVisibility(targetRoomId, visibility);

await mjolnir.client.unstableApis.addReactionToEvent(inRoomId, event['event_id'], '✅');
return CommandResult.Ok(undefined);
}

// !mjolnir directory add <room>
export async function execAddRoomToDirectoryCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
await addRemoveFromDirectory(roomId, event, mjolnir, parts[3], "public");
}
// Note: While synapse admin API is not required for these endpoints,
// I believe they were added to manage rooms other than the ones you are admin in.
defineInterfaceCommand({
table: "synapse admin",
designator: ["directory", "add"],
summary: "Publishes a room in the server's room directory.",
parameters: parameters([
{
name: 'room',
acceptor: findPresentationType("MatrixRoomReference"),
}
]),
command: async function (this: MjolnirContext, _keywords: ParsedKeywords, targetRoom: MatrixRoomReference): Promise<CommandResult<void, CommandError>> {
return await addRemoveFromDirectory(this.mjolnir, targetRoom, "public");
},
})

// !mjolnir directory remove <room>
export async function execRemoveRoomFromDirectoryCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
await addRemoveFromDirectory(roomId, event, mjolnir, parts[3], "private");
}
defineMatrixInterfaceAdaptor({
interfaceCommand: findTableCommand("synapse admin", "directory", "add"),
renderer: tickCrossRenderer,
})

defineInterfaceCommand({
table: "synapse admin",
designator: ["directory", "remove"],
summary: "Removes a room from the server's room directory.",
parameters: parameters([
{
name: 'room',
acceptor: findPresentationType("MatrixRoomReference"),
}
]),
command: async function (this: MjolnirContext, _keywords: ParsedKeywords, targetRoom: MatrixRoomReference): Promise<CommandResult<void, CommandError>> {
return await addRemoveFromDirectory(this.mjolnir, targetRoom, "private");
},
})

defineMatrixInterfaceAdaptor({
interfaceCommand: findTableCommand("synapse admin", "directory", "remove"),
renderer: tickCrossRenderer,
})
177 changes: 102 additions & 75 deletions src/commands/AliasCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,78 +25,105 @@ limitations under the License.
* are NOT distributed, contributed, committed, or licensed under the Apache License.
*/

import { Mjolnir } from "../Mjolnir";
import { RichReply } from "matrix-bot-sdk";
import { htmlEscape } from "../utils";

// !mjolnir move <alias> <new room ID>
export async function execMoveAliasCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
const movingAlias = parts[2];
const targetRoom = parts[3];

const isAdmin = await mjolnir.isSynapseAdmin();
if (!isAdmin) {
const message = "I am not a Synapse administrator, or the endpoint is blocked";
const reply = RichReply.createFor(roomId, event, message, message);
reply['msgtype'] = "m.notice";
mjolnir.client.sendMessage(roomId, reply);
return;
}

await mjolnir.client.deleteRoomAlias(movingAlias);
const newRoomId = await mjolnir.client.resolveRoom(targetRoom);
await mjolnir.client.createRoomAlias(movingAlias, newRoomId);

await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
}

// !mjolnir alias add <alias> <target room>
export async function execAddAliasCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
const aliasToAdd = parts[3];
const targetRoom = parts[4];

const isAdmin = await mjolnir.isSynapseAdmin();
if (!isAdmin) {
const message = "I am not a Synapse administrator, or the endpoint is blocked";
const reply = RichReply.createFor(roomId, event, message, message);
reply['msgtype'] = "m.notice";
mjolnir.client.sendMessage(roomId, reply);
return;
}

const newRoomId = await mjolnir.client.resolveRoom(targetRoom);
await mjolnir.client.createRoomAlias(aliasToAdd, newRoomId);

await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
}

// !mjolnir alias remove <alias>
export async function execRemoveAliasCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
const aliasToRemove = parts[3];

const isAdmin = await mjolnir.isSynapseAdmin();
if (!isAdmin) {
const message = "I am not a Synapse administrator, or the endpoint is blocked";
const reply = RichReply.createFor(roomId, event, message, message);
reply['msgtype'] = "m.notice";
mjolnir.client.sendMessage(roomId, reply);
return;
}

await mjolnir.client.deleteRoomAlias(aliasToRemove);

await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
}

// !mjolnir resolve <alias>
export async function execResolveCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
const toResolve = parts[2];

const resolvedRoomId = await mjolnir.client.resolveRoom(toResolve);

const message = `Room ID for ${toResolve} is ${resolvedRoomId}`;
const html = `Room ID for ${htmlEscape(toResolve)} is ${htmlEscape(resolvedRoomId)}`;
const reply = RichReply.createFor(roomId, event, message, html);
reply["msgtype"] = "m.notice";
await mjolnir.client.sendMessage(roomId, reply);
}
import { findPresentationType, parameters, ParsedKeywords } from "./interface-manager/ParameterParsing";
import { defineInterfaceCommand, findTableCommand } from "./interface-manager/InterfaceCommand";
import { MjolnirContext } from "./CommandHandler";
import { MatrixRoomAlias, MatrixRoomReference } from "./interface-manager/MatrixRoomReference";
import { CommandError, CommandResult } from "./interface-manager/Validation";
import { defineMatrixInterfaceAdaptor } from "./interface-manager/MatrixInterfaceAdaptor";
import { tickCrossRenderer } from "./interface-manager/MatrixHelpRenderer";

// TODO: we should probably add an --admin keyword to these commands
// since they don't actually need admin. Mjolnir had them as admin though.
// then we'd have to call the table "alias table" or something.

defineInterfaceCommand({
table: "synapse admin",
designator: ["alias", "move"],
summary: "Move an alias from one room to another.",
parameters: parameters([
{
name: 'alias',
acceptor: findPresentationType("MatrixRoomAlias"),
description: 'The alias that should be moved.'
},
{
name: 'new room',
acceptor: findPresentationType("MatrixRoomReference"),
description: 'The room to move the alias to.'
}
]),
command: async function (this: MjolnirContext, _keywords: ParsedKeywords, movingAlias: MatrixRoomAlias, room: MatrixRoomReference): Promise<CommandResult<void>> {
const isAdmin = await this.mjolnir.isSynapseAdmin();
if (!isAdmin) {
return CommandError.Result('I am not a Synapse administrator, or the endpoint to deactivate a user is blocked');
}
const newRoomId = await room.resolve(this.mjolnir.client);
await this.mjolnir.client.deleteRoomAlias(movingAlias.toRoomIdOrAlias());
await this.mjolnir.client.createRoomAlias(movingAlias.toRoomIdOrAlias(), newRoomId.toRoomIdOrAlias());
return CommandResult.Ok(undefined);
},
})

defineMatrixInterfaceAdaptor({
interfaceCommand: findTableCommand("synapse admin", "alias", "move"),
renderer: tickCrossRenderer,
})

defineInterfaceCommand({
table: "synapse admin",
designator: ["alias", "add"],
summary: "Add a new alias to a room.",
parameters: parameters([
{
name: 'alias',
acceptor: findPresentationType("MatrixRoomAlias"),
description: 'The alias that should be created.'
},
{
name: 'target room',
acceptor: findPresentationType("MatrixRoomReference"),
description: 'The room to add the alias to.'
}
]),
command: async function (this: MjolnirContext, _keywords: ParsedKeywords, movingAlias: MatrixRoomAlias, room: MatrixRoomReference): Promise<CommandResult<void>> {
const isAdmin = await this.mjolnir.isSynapseAdmin();
if (!isAdmin) {
return CommandError.Result('I am not a Synapse administrator, or the endpoint to deactivate a user is blocked');
}
const roomId = await room.resolve(this.mjolnir.client);
await this.mjolnir.client.createRoomAlias(movingAlias.toRoomIdOrAlias(), roomId.toRoomIdOrAlias());
return CommandResult.Ok(undefined);
},
})

defineMatrixInterfaceAdaptor({
interfaceCommand: findTableCommand("synapse admin", "alias", "add"),
renderer: tickCrossRenderer,
})

defineInterfaceCommand({
table: "synapse admin",
designator: ["alias", "remove"],
summary: "Removes an alias from a room.",
parameters: parameters([
{
name: 'alias',
acceptor: findPresentationType("MatrixRoomAlias"),
description: 'The alias that should be deleted.'
}
]),
command: async function (this: MjolnirContext, _keywords: ParsedKeywords, alias: MatrixRoomAlias): Promise<CommandResult<void>> {
const isAdmin = await this.mjolnir.isSynapseAdmin();
if (!isAdmin) {
return CommandError.Result('I am not a Synapse administrator, or the endpoint to deactivate a user is blocked');
}
await this.mjolnir.client.deleteRoomAlias(alias.toRoomIdOrAlias());
return CommandResult.Ok(undefined);
},
})

defineMatrixInterfaceAdaptor({
interfaceCommand: findTableCommand("synapse admin", "alias", "remove"),
renderer: tickCrossRenderer,
})
Loading