2023-10-18 04:15:30 +02:00
|
|
|
import { MatrixClient, Room } from 'matrix-js-sdk';
|
|
|
|
import { useMemo } from 'react';
|
2024-05-31 16:19:46 +02:00
|
|
|
import { getDMRoomFor, isRoomAlias, isRoomId, isUserId } from '../utils/matrix';
|
2023-10-18 04:15:30 +02:00
|
|
|
import { hasDevices } from '../../util/matrixUtil';
|
|
|
|
import * as roomActions from '../../client/action/room';
|
2024-05-31 16:19:46 +02:00
|
|
|
import { useRoomNavigate } from './useRoomNavigate';
|
2023-10-18 04:15:30 +02:00
|
|
|
|
|
|
|
export const SHRUG = '¯\\_(ツ)_/¯';
|
|
|
|
|
|
|
|
export function parseUsersAndReason(payload: string): {
|
|
|
|
users: string[];
|
|
|
|
reason?: string;
|
|
|
|
} {
|
|
|
|
let reason: string | undefined;
|
|
|
|
let ids: string = payload;
|
|
|
|
|
|
|
|
const reasonMatch = payload.match(/\s-r\s/);
|
|
|
|
if (reasonMatch) {
|
|
|
|
ids = payload.slice(0, reasonMatch.index);
|
|
|
|
reason = payload.slice((reasonMatch.index ?? 0) + reasonMatch[0].length);
|
|
|
|
if (reason.trim() === '') reason = undefined;
|
|
|
|
}
|
|
|
|
const rawIds = ids.split(' ');
|
|
|
|
const users = rawIds.filter((id) => isUserId(id));
|
|
|
|
return {
|
|
|
|
users,
|
|
|
|
reason,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export type CommandExe = (payload: string) => Promise<void>;
|
|
|
|
|
|
|
|
export enum Command {
|
|
|
|
Me = 'me',
|
|
|
|
Notice = 'notice',
|
|
|
|
Shrug = 'shrug',
|
|
|
|
StartDm = 'startdm',
|
|
|
|
Join = 'join',
|
|
|
|
Leave = 'leave',
|
|
|
|
Invite = 'invite',
|
|
|
|
DisInvite = 'disinvite',
|
|
|
|
Kick = 'kick',
|
|
|
|
Ban = 'ban',
|
|
|
|
UnBan = 'unban',
|
|
|
|
Ignore = 'ignore',
|
|
|
|
UnIgnore = 'unignore',
|
|
|
|
MyRoomNick = 'myroomnick',
|
|
|
|
MyRoomAvatar = 'myroomavatar',
|
|
|
|
ConvertToDm = 'converttodm',
|
|
|
|
ConvertToRoom = 'converttoroom',
|
|
|
|
}
|
|
|
|
|
|
|
|
export type CommandContent = {
|
|
|
|
name: string;
|
|
|
|
description: string;
|
|
|
|
exe: CommandExe;
|
|
|
|
};
|
|
|
|
|
|
|
|
export type CommandRecord = Record<Command, CommandContent>;
|
|
|
|
|
|
|
|
export const useCommands = (mx: MatrixClient, room: Room): CommandRecord => {
|
2024-05-31 16:19:46 +02:00
|
|
|
const { navigateRoom } = useRoomNavigate();
|
|
|
|
|
2023-10-18 04:15:30 +02:00
|
|
|
const commands: CommandRecord = useMemo(
|
|
|
|
() => ({
|
|
|
|
[Command.Me]: {
|
|
|
|
name: Command.Me,
|
|
|
|
description: 'Send action message',
|
|
|
|
exe: async () => undefined,
|
|
|
|
},
|
|
|
|
[Command.Notice]: {
|
|
|
|
name: Command.Notice,
|
|
|
|
description: 'Send notice message',
|
|
|
|
exe: async () => undefined,
|
|
|
|
},
|
|
|
|
[Command.Shrug]: {
|
|
|
|
name: Command.Shrug,
|
|
|
|
description: 'Send ¯\\_(ツ)_/¯ as message',
|
|
|
|
exe: async () => undefined,
|
|
|
|
},
|
|
|
|
[Command.StartDm]: {
|
|
|
|
name: Command.StartDm,
|
|
|
|
description: 'Start direct message with user. Example: /startdm userId1',
|
|
|
|
exe: async (payload) => {
|
|
|
|
const rawIds = payload.split(' ');
|
|
|
|
const userIds = rawIds.filter((id) => isUserId(id) && id !== mx.getUserId());
|
|
|
|
if (userIds.length === 0) return;
|
|
|
|
if (userIds.length === 1) {
|
2024-05-31 16:19:46 +02:00
|
|
|
const dmRoomId = getDMRoomFor(mx, userIds[0])?.roomId;
|
2023-10-18 04:15:30 +02:00
|
|
|
if (dmRoomId) {
|
2024-05-31 16:19:46 +02:00
|
|
|
navigateRoom(dmRoomId);
|
2023-10-18 04:15:30 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2024-07-22 12:47:19 +02:00
|
|
|
const devices = await Promise.all(userIds.map(uid => hasDevices(mx, uid)));
|
2023-10-18 04:15:30 +02:00
|
|
|
const isEncrypt = devices.every((hasDevice) => hasDevice);
|
2024-07-22 12:47:19 +02:00
|
|
|
const result = await roomActions.createDM(mx, userIds, isEncrypt);
|
2024-05-31 16:19:46 +02:00
|
|
|
navigateRoom(result.room_id);
|
2023-10-18 04:15:30 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
[Command.Join]: {
|
|
|
|
name: Command.Join,
|
|
|
|
description: 'Join room with address. Example: /join address1 address2',
|
|
|
|
exe: async (payload) => {
|
|
|
|
const rawIds = payload.split(' ');
|
|
|
|
const roomIds = rawIds.filter(
|
|
|
|
(idOrAlias) => isRoomId(idOrAlias) || isRoomAlias(idOrAlias)
|
|
|
|
);
|
2024-07-22 12:47:19 +02:00
|
|
|
roomIds.map((id) => roomActions.join(mx, id));
|
2023-10-18 04:15:30 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
[Command.Leave]: {
|
|
|
|
name: Command.Leave,
|
|
|
|
description: 'Leave current room.',
|
|
|
|
exe: async (payload) => {
|
|
|
|
if (payload.trim() === '') {
|
2024-07-08 13:27:10 +02:00
|
|
|
mx.leave(room.roomId);
|
2023-10-18 04:15:30 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
const rawIds = payload.split(' ');
|
|
|
|
const roomIds = rawIds.filter((id) => isRoomId(id));
|
2024-07-08 13:27:10 +02:00
|
|
|
roomIds.map((id) => mx.leave(id));
|
2023-10-18 04:15:30 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
[Command.Invite]: {
|
|
|
|
name: Command.Invite,
|
|
|
|
description: 'Invite user to room. Example: /invite userId1 userId2 [-r reason]',
|
|
|
|
exe: async (payload) => {
|
|
|
|
const { users, reason } = parseUsersAndReason(payload);
|
2024-07-22 12:47:19 +02:00
|
|
|
users.map((id) => mx.invite(room.roomId, id, reason));
|
2023-10-18 04:15:30 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
[Command.DisInvite]: {
|
|
|
|
name: Command.DisInvite,
|
|
|
|
description: 'Disinvite user to room. Example: /disinvite userId1 userId2 [-r reason]',
|
|
|
|
exe: async (payload) => {
|
|
|
|
const { users, reason } = parseUsersAndReason(payload);
|
2024-07-22 12:47:19 +02:00
|
|
|
users.map((id) => mx.kick(room.roomId, id, reason));
|
2023-10-18 04:15:30 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
[Command.Kick]: {
|
|
|
|
name: Command.Kick,
|
|
|
|
description: 'Kick user from room. Example: /kick userId1 userId2 [-r reason]',
|
|
|
|
exe: async (payload) => {
|
|
|
|
const { users, reason } = parseUsersAndReason(payload);
|
2024-07-22 12:47:19 +02:00
|
|
|
users.map((id) => mx.kick(room.roomId, id, reason));
|
2023-10-18 04:15:30 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
[Command.Ban]: {
|
|
|
|
name: Command.Ban,
|
|
|
|
description: 'Ban user from room. Example: /ban userId1 userId2 [-r reason]',
|
|
|
|
exe: async (payload) => {
|
|
|
|
const { users, reason } = parseUsersAndReason(payload);
|
2024-07-22 12:47:19 +02:00
|
|
|
users.map((id) => mx.ban(room.roomId, id, reason));
|
2023-10-18 04:15:30 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
[Command.UnBan]: {
|
|
|
|
name: Command.UnBan,
|
|
|
|
description: 'Unban user from room. Example: /unban userId1 userId2',
|
|
|
|
exe: async (payload) => {
|
|
|
|
const rawIds = payload.split(' ');
|
|
|
|
const users = rawIds.filter((id) => isUserId(id));
|
2024-07-22 12:47:19 +02:00
|
|
|
users.map((id) => mx.unban(room.roomId, id));
|
2023-10-18 04:15:30 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
[Command.Ignore]: {
|
|
|
|
name: Command.Ignore,
|
|
|
|
description: 'Ignore user. Example: /ignore userId1 userId2',
|
|
|
|
exe: async (payload) => {
|
|
|
|
const rawIds = payload.split(' ');
|
|
|
|
const userIds = rawIds.filter((id) => isUserId(id));
|
2024-07-22 12:47:19 +02:00
|
|
|
if (userIds.length > 0) roomActions.ignore(mx, userIds);
|
2023-10-18 04:15:30 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
[Command.UnIgnore]: {
|
|
|
|
name: Command.UnIgnore,
|
|
|
|
description: 'Unignore user. Example: /unignore userId1 userId2',
|
|
|
|
exe: async (payload) => {
|
|
|
|
const rawIds = payload.split(' ');
|
|
|
|
const userIds = rawIds.filter((id) => isUserId(id));
|
2024-07-22 12:47:19 +02:00
|
|
|
if (userIds.length > 0) roomActions.unignore(mx, userIds);
|
2023-10-18 04:15:30 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
[Command.MyRoomNick]: {
|
|
|
|
name: Command.MyRoomNick,
|
|
|
|
description: 'Change nick in current room.',
|
|
|
|
exe: async (payload) => {
|
|
|
|
const nick = payload.trim();
|
|
|
|
if (nick === '') return;
|
2024-07-22 12:47:19 +02:00
|
|
|
roomActions.setMyRoomNick(mx, room.roomId, nick);
|
2023-10-18 04:15:30 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
[Command.MyRoomAvatar]: {
|
|
|
|
name: Command.MyRoomAvatar,
|
|
|
|
description: 'Change profile picture in current room. Example /myroomavatar mxc://xyzabc',
|
|
|
|
exe: async (payload) => {
|
|
|
|
if (payload.match(/^mxc:\/\/\S+$/)) {
|
2024-07-22 12:47:19 +02:00
|
|
|
roomActions.setMyRoomAvatar(mx, room.roomId, payload);
|
2023-10-18 04:15:30 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
[Command.ConvertToDm]: {
|
|
|
|
name: Command.ConvertToDm,
|
|
|
|
description: 'Convert room to direct message',
|
|
|
|
exe: async () => {
|
2024-07-22 12:47:19 +02:00
|
|
|
roomActions.convertToDm(mx, room.roomId);
|
2023-10-18 04:15:30 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
[Command.ConvertToRoom]: {
|
|
|
|
name: Command.ConvertToRoom,
|
|
|
|
description: 'Convert direct message to room',
|
|
|
|
exe: async () => {
|
2024-07-22 12:47:19 +02:00
|
|
|
roomActions.convertToRoom(mx, room.roomId);
|
2023-10-18 04:15:30 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}),
|
2024-05-31 16:19:46 +02:00
|
|
|
[mx, room, navigateRoom]
|
2023-10-18 04:15:30 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
return commands;
|
|
|
|
};
|