From 7f19794da4809fa2fe36769b59f9c13bc0924030 Mon Sep 17 00:00:00 2001 From: Murtaza Patrawala <34130764+murtaza98@users.noreply.github.com> Date: Fri, 3 Jun 2022 18:28:43 +0530 Subject: [PATCH 1/6] Chore: Fix incorrect checksum for agenda package (cause of breaking develop builds) (#25741) --- yarn.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index b9e6dd612091..36a479e08a40 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8634,7 +8634,7 @@ __metadata: human-interval: ~1.0.0 moment-timezone: ~0.5.27 mongodb: ~3.5.0 - checksum: f5f68008298f9482631f1f494e392cd6b8ba7971a3b0ece81ae2abe60f53d67973ff4476156fa5c9c41b8b58c4ccd284e95c545e0523996dfd05f9a80b843e07 + checksum: acb4ebb7e7356f6e53e810d821eb6aa3d88bbfb9e85183e707517bee6d1eea1f189f38bdf0dd2b91360492ab7643134d510c320d2523d86596498ab98e59735b languageName: node linkType: hard From 08b7b2221ba72534f59b5d64359d3457ce4a6761 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Fri, 3 Jun 2022 12:58:16 -0300 Subject: [PATCH 2/6] Chore: command's endpoints (#25630) --- .vscode/settings.json | 2 +- apps/meteor/app/api/server/api.d.ts | 2 +- .../server/v1/{commands.js => commands.ts} | 179 +++++++++--------- .../app/apps/server/bridges/commands.ts | 13 +- .../app/slashcommand-asciiarts/lib/gimme.ts | 4 +- .../app/slashcommand-asciiarts/lib/lenny.ts | 4 +- .../app/slashcommand-asciiarts/lib/shrug.ts | 23 +-- .../slashcommand-asciiarts/lib/tableflip.ts | 23 +-- .../app/slashcommand-asciiarts/lib/unflip.ts | 23 +-- .../server/server.ts | 101 +++++----- .../app/slashcommands-bridge/server/index.ts | 61 +++--- .../app/slashcommands-create/server/server.ts | 103 +++++----- .../app/slashcommands-help/server/server.ts | 103 +++++----- .../app/slashcommands-hide/server/hide.ts | 109 +++++------ .../app/slashcommands-invite/server/server.ts | 132 ++++++------- .../slashcommands-inviteall/server/server.ts | 6 +- .../app/slashcommands-join/server/server.ts | 87 ++++----- .../app/slashcommands-kick/server/server.ts | 83 ++++---- .../app/slashcommands-leave/server/leave.ts | 6 +- apps/meteor/app/slashcommands-me/server/me.ts | 3 +- .../app/slashcommands-msg/server/server.ts | 81 ++++---- .../app/slashcommands-mute/server/mute.ts | 79 ++++---- .../app/slashcommands-mute/server/unmute.ts | 79 ++++---- .../app/slashcommands-open/client/client.ts | 65 +++---- .../app/slashcommands-status/client/status.ts | 33 ++-- .../app/slashcommands-status/server/status.ts | 47 ++--- .../app/slashcommands-topic/client/topic.ts | 43 +++-- .../app/slashcommands-topic/server/topic.ts | 33 ++-- .../server/server.ts | 97 +++++----- apps/meteor/app/utils/lib/slashCommand.ts | 66 ++----- apps/meteor/package.json | 1 + .../core-typings/src/SlashCommands/index.ts | 50 +++++ packages/core-typings/src/index.ts | 1 + packages/core-typings/src/utils.ts | 2 + packages/rest-typings/src/index.ts | 2 + packages/rest-typings/src/v1/commands.ts | 42 ++++ yarn.lock | 8 + 37 files changed, 941 insertions(+), 855 deletions(-) rename apps/meteor/app/api/server/v1/{commands.js => commands.ts} (74%) create mode 100644 packages/core-typings/src/SlashCommands/index.ts create mode 100644 packages/rest-typings/src/v1/commands.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 3d13987bf7ec..4bc6251d4020 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,5 +10,5 @@ } ], "typescript.tsdk": "./node_modules/typescript/lib", - "cSpell.words": ["photoswipe"] + "cSpell.words": ["photoswipe", "tmid"] } diff --git a/apps/meteor/app/api/server/api.d.ts b/apps/meteor/app/api/server/api.d.ts index fc9519b87ea5..98fcefe501e1 100644 --- a/apps/meteor/app/api/server/api.d.ts +++ b/apps/meteor/app/api/server/api.d.ts @@ -98,7 +98,7 @@ type ActionThis; - getLoggedInUser(): IUser | undefined; + getLoggedInUser(): TOptions extends { authRequired: true } ? IUser : IUser | undefined; getPaginationItems(): { readonly offset: number; readonly count: number; diff --git a/apps/meteor/app/api/server/v1/commands.js b/apps/meteor/app/api/server/v1/commands.ts similarity index 74% rename from apps/meteor/app/api/server/v1/commands.js rename to apps/meteor/app/api/server/v1/commands.ts index 9a5cde50ef00..75423636a1bf 100644 --- a/apps/meteor/app/api/server/v1/commands.js +++ b/apps/meteor/app/api/server/v1/commands.ts @@ -29,10 +29,22 @@ API.v1.addRoute( }, ); -// TODO: replace with something like client/lib/minimongo -const processQueryOptionsOnResult = (result, options = {}) => { +/* @deprecated */ +const processQueryOptionsOnResult = , F extends keyof T>( + result: T[], + options: { + fields?: { + [key in F]?: 1 | 0; + }; + sort?: { + [key: string]: 1 | -1; + }; + limit?: number; + skip?: number; + } = {}, +): Pick[] => { if (result === undefined || result === null) { - return undefined; + return []; } if (Array.isArray(result)) { @@ -74,66 +86,50 @@ const processQueryOptionsOnResult = (result, options = {}) => { } } - if (!options.fields) { - options.fields = {}; - } - - const fieldsToRemove = []; - const fieldsToGet = []; + const fieldsToRemove: F[] = []; + const fieldsToGet: F[] = []; - for (const field in options.fields) { - if (options.fields.hasOwnProperty(field)) { - if (options.fields[field] === 0) { - fieldsToRemove.push(field); - } else if (options.fields[field] === 1) { - fieldsToGet.push(field); + if (options.fields) { + for (const field in Object.keys(options.fields)) { + if (options.fields.hasOwnProperty(field as F)) { + if (options.fields[field as F] === 0) { + fieldsToRemove.push(field as F); + } else if (options.fields[field as F] === 1) { + fieldsToGet.push(field as F); + } } } } - if (fieldsToRemove.length > 0 && fieldsToGet.length > 0) { - console.warn("Can't mix remove and get fields"); - fieldsToRemove.splice(0, fieldsToRemove.length); - } - - if (fieldsToGet.length > 0 && fieldsToGet.indexOf('_id') === -1) { - fieldsToGet.push('_id'); + if (fieldsToGet.length > 0 && fieldsToGet.indexOf('_id' as F) === -1) { + fieldsToGet.push('_id' as F); } - const pickFields = (obj, fields) => { - const picked = {}; - fields.forEach((field) => { - if (field.indexOf('.') !== -1) { - objectPath.set(picked, field, objectPath.get(obj, field)); + const pickFields = (obj: T, fields: F[]): Pick => { + const picked: Partial = {}; + fields.forEach((field: F) => { + if (String(field).indexOf('.') !== -1) { + objectPath.set(picked, String(field), objectPath.get(obj, String(field))); } else { picked[field] = obj[field]; } }); - return picked; + return picked as Pick; }; - if (fieldsToRemove.length > 0 || fieldsToGet.length > 0) { - if (Array.isArray(result)) { - result = result.map((record) => { - if (fieldsToRemove.length > 0) { - return Object.fromEntries(Object.entries(record).filter(([key]) => !fieldsToRemove.includes(key))); - } - - if (fieldsToGet.length > 0) { - return pickFields(record, fieldsToGet); - } + if (fieldsToRemove.length > 0 && fieldsToGet.length > 0) { + console.warn("Can't mix remove and get fields"); + fieldsToRemove.splice(0, fieldsToRemove.length); + } - return null; - }); - } else { + if (fieldsToRemove.length > 0 || fieldsToGet.length > 0) { + return result.map((record) => { if (fieldsToRemove.length > 0) { - return Object.fromEntries(Object.entries(result).filter(([key]) => !fieldsToRemove.includes(key))); + return Object.fromEntries(Object.entries(record).filter(([key]) => !fieldsToRemove.includes(key as F))) as Pick; } - if (fieldsToGet.length > 0) { - return pickFields(result, fieldsToGet); - } - } + return pickFields(record, fieldsToGet); + }); } return result; @@ -149,20 +145,23 @@ API.v1.addRoute( let commands = Object.values(slashCommands.commands); - if (query && query.command) { + if (query?.command) { commands = commands.filter((command) => command.command === query.command); } const totalCount = commands.length; - commands = processQueryOptionsOnResult(commands, { - sort: sort || { name: 1 }, - skip: offset, - limit: count, - fields, - }); + + if (fields) { + console.warn('commands.list -> fields is deprecated and will be removed in 5.0.0'); + } return API.v1.success({ - commands, + commands: processQueryOptionsOnResult(commands, { + sort: sort || { name: 1 }, + skip: offset, + limit: count, + fields, + }), offset, count: commands.length, total: totalCount, @@ -178,7 +177,6 @@ API.v1.addRoute( { post() { const body = this.bodyParams; - const user = this.getLoggedInUser(); if (typeof body.command !== 'string') { return API.v1.failure('You must provide a command to run.'); @@ -201,28 +199,28 @@ API.v1.addRoute( return API.v1.failure('The command provided does not exist (or is disabled).'); } - if (!canAccessRoomId(body.roomId, user._id)) { + if (!canAccessRoomId(body.roomId, this.userId)) { return API.v1.unauthorized(); } const params = body.params ? body.params : ''; - const message = { - _id: Random.id(), - rid: body.roomId, - msg: `/${cmd} ${params}`, - }; - - if (body.tmid) { + if (typeof body.tmid === 'string') { const thread = Messages.findOneById(body.tmid); if (!thread || thread.rid !== body.roomId) { return API.v1.failure('Invalid thread.'); } - message.tmid = body.tmid; } + const message = { + _id: Random.id(), + rid: body.roomId, + msg: `/${cmd} ${params}`, + ...(body.tmid && { tmid: body.tmid }), + }; + const { triggerId } = body; - const result = Meteor.runAsUser(user._id, () => slashCommands.run(cmd, params, message, triggerId)); + const result = slashCommands.run(cmd, params, message, triggerId); return API.v1.success({ result }); }, @@ -234,7 +232,7 @@ API.v1.addRoute( { authRequired: true }, { // Expects these query params: command: 'giphy', params: 'mine', roomId: 'value' - get() { + async get() { const query = this.queryParams; const user = this.getLoggedInUser(); @@ -261,21 +259,18 @@ API.v1.addRoute( const params = query.params ? query.params : ''; - let preview; - Meteor.runAsUser(user._id, () => { - preview = Meteor.call('getSlashCommandPreviews', { - cmd, - params, - msg: { rid: query.roomId }, - }); + const preview = Meteor.call('getSlashCommandPreviews', { + cmd, + params, + msg: { rid: query.roomId }, }); return API.v1.success({ preview }); }, + // Expects a body format of: { command: 'giphy', params: 'mine', roomId: 'value', tmid: 'value', triggerId: 'value', previewItem: { id: 'sadf8' type: 'image', value: 'https://dev.null/gif' } } post() { const body = this.bodyParams; - const user = this.getLoggedInUser(); if (typeof body.command !== 'string') { return API.v1.failure('You must provide a command to run the preview item on.'); @@ -310,35 +305,33 @@ API.v1.addRoute( return API.v1.failure('The command provided does not exist (or is disabled).'); } - if (!canAccessRoomId(body.roomId, user._id)) { + if (!canAccessRoomId(body.roomId, this.userId)) { return API.v1.unauthorized(); } - const params = body.params ? body.params : ''; - const message = { - rid: body.roomId, - }; - + const { params = '' } = body; if (body.tmid) { const thread = Messages.findOneById(body.tmid); if (!thread || thread.rid !== body.roomId) { return API.v1.failure('Invalid thread.'); } - message.tmid = body.tmid; } - Meteor.runAsUser(user._id, () => { - Meteor.call( - 'executeSlashCommandPreview', - { - cmd, - params, - msg: { rid: body.roomId, tmid: body.tmid }, - }, - body.previewItem, - body.triggerId, - ); - }); + const msg = { + rid: body.roomId, + ...(body.tmid && { tmid: body.tmid }), + }; + + Meteor.call( + 'executeSlashCommandPreview', + { + cmd, + params, + msg, + }, + body.previewItem, + body.triggerId, + ); return API.v1.success(); }, diff --git a/apps/meteor/app/apps/server/bridges/commands.ts b/apps/meteor/app/apps/server/bridges/commands.ts index 8a6726e3925a..9f6448794e4d 100644 --- a/apps/meteor/app/apps/server/bridges/commands.ts +++ b/apps/meteor/app/apps/server/bridges/commands.ts @@ -1,7 +1,7 @@ import { Meteor } from 'meteor/meteor'; import { SlashCommandContext, ISlashCommand, ISlashCommandPreviewItem } from '@rocket.chat/apps-engine/definition/slashcommands'; import { CommandBridge } from '@rocket.chat/apps-engine/server/bridges/CommandBridge'; -import type { IMessage } from '@rocket.chat/core-typings'; +import type { IMessage, RequiredField, SlashCommand } from '@rocket.chat/core-typings'; import { slashCommands } from '../../../utils/server'; import { Utilities } from '../../lib/misc/Utilities'; @@ -114,7 +114,7 @@ export class AppCommandsBridge extends CommandBridge { previewCallback: (!command.executePreviewItem ? undefined : this._appCommandPreviewExecutor.bind(this)) as | typeof slashCommands.commands[string]['previewCallback'] | undefined, - }; + } as SlashCommand; slashCommands.commands[command.command.toLowerCase()] = item; this.orch.getNotifier().commandAdded(command.command.toLowerCase()); @@ -160,7 +160,12 @@ export class AppCommandsBridge extends CommandBridge { } } - private _appCommandExecutor(command: string, parameters: any, message: IMessage, triggerId: string): void { + private _appCommandExecutor( + command: string, + parameters: any, + message: RequiredField, 'rid'>, + triggerId?: string, + ): void { const user = this.orch.getConverters()?.get('users').convertById(Meteor.userId()); const room = this.orch.getConverters()?.get('rooms').convertById(message.rid); const threadId = message.tmid; @@ -195,6 +200,6 @@ export class AppCommandsBridge extends CommandBridge { const context = new SlashCommandContext(Object.freeze(user), Object.freeze(room), Object.freeze(params), threadId, triggerId); - Promise.await(this.orch.getManager()?.getCommandManager().executePreview(command, preview, context)); + await this.orch.getManager()?.getCommandManager().executePreview(command, preview, context); } } diff --git a/apps/meteor/app/slashcommand-asciiarts/lib/gimme.ts b/apps/meteor/app/slashcommand-asciiarts/lib/gimme.ts index a057a5faa542..2f7e92cd53c8 100644 --- a/apps/meteor/app/slashcommand-asciiarts/lib/gimme.ts +++ b/apps/meteor/app/slashcommand-asciiarts/lib/gimme.ts @@ -1,5 +1,5 @@ import { Meteor } from 'meteor/meteor'; -import type { IMessage } from '@rocket.chat/core-typings'; +import type { IMessage, RequiredField } from '@rocket.chat/core-typings'; import { slashCommands } from '../../utils/lib/slashCommand'; /* @@ -7,7 +7,7 @@ import { slashCommands } from '../../utils/lib/slashCommand'; * @param {Object} message - The message object */ -function Gimme(_command: 'gimme', params: string, item: IMessage): void { +function Gimme(_command: 'gimme', params: string, item: RequiredField, 'rid'>): void { const msg = item; msg.msg = `༼ つ ◕_◕ ༽つ ${params}`; Meteor.call('sendMessage', msg); diff --git a/apps/meteor/app/slashcommand-asciiarts/lib/lenny.ts b/apps/meteor/app/slashcommand-asciiarts/lib/lenny.ts index 135090952227..01f22523e416 100644 --- a/apps/meteor/app/slashcommand-asciiarts/lib/lenny.ts +++ b/apps/meteor/app/slashcommand-asciiarts/lib/lenny.ts @@ -1,4 +1,4 @@ -import type { IMessage } from '@rocket.chat/core-typings'; +import type { IMessage, RequiredField } from '@rocket.chat/core-typings'; import { Meteor } from 'meteor/meteor'; import { slashCommands } from '../../utils/lib/slashCommand'; @@ -7,7 +7,7 @@ import { slashCommands } from '../../utils/lib/slashCommand'; * @param {Object} message - The message object */ -function LennyFace(_command: 'lennyface', params: string, item: IMessage): void { +function LennyFace(_command: 'lennyface', params: string, item: RequiredField, 'rid'>): void { const msg = item; msg.msg = `${params} ( ͡° ͜ʖ ͡°)`; Meteor.call('sendMessage', msg); diff --git a/apps/meteor/app/slashcommand-asciiarts/lib/shrug.ts b/apps/meteor/app/slashcommand-asciiarts/lib/shrug.ts index b18e1fd1b039..89d97e6da225 100644 --- a/apps/meteor/app/slashcommand-asciiarts/lib/shrug.ts +++ b/apps/meteor/app/slashcommand-asciiarts/lib/shrug.ts @@ -1,4 +1,3 @@ -import type { IMessage } from '@rocket.chat/core-typings'; import { Meteor } from 'meteor/meteor'; import { slashCommands } from '../../utils/lib/slashCommand'; @@ -7,13 +6,15 @@ import { slashCommands } from '../../utils/lib/slashCommand'; * @param {Object} message - The message object */ -function Shrug(_command: 'shrug', params: string, item: IMessage): void { - const msg = item; - msg.msg = `${params} ¯\\_(ツ)_/¯`; - Meteor.call('sendMessage', msg); -} - -slashCommands.add('shrug', Shrug, { - description: 'Slash_Shrug_Description', - params: 'your_message_optional', -}); +slashCommands.add( + 'shrug', + (_command: 'shrug', params, item): void => { + const msg = item; + msg.msg = `${params} ¯\\_(ツ)_/¯`; + Meteor.call('sendMessage', msg); + }, + { + description: 'Slash_Shrug_Description', + params: 'your_message_optional', + }, +); diff --git a/apps/meteor/app/slashcommand-asciiarts/lib/tableflip.ts b/apps/meteor/app/slashcommand-asciiarts/lib/tableflip.ts index c2663ec487b3..f71872060dc0 100644 --- a/apps/meteor/app/slashcommand-asciiarts/lib/tableflip.ts +++ b/apps/meteor/app/slashcommand-asciiarts/lib/tableflip.ts @@ -1,4 +1,3 @@ -import type { IMessage } from '@rocket.chat/core-typings'; import { Meteor } from 'meteor/meteor'; import { slashCommands } from '../../utils/lib/slashCommand'; @@ -7,13 +6,15 @@ import { slashCommands } from '../../utils/lib/slashCommand'; * @param {Object} message - The message object */ -function Tableflip(_command: 'tableflip', params: string, item: IMessage): void { - const msg = item; - msg.msg = `${params} (╯°□°)╯︵ ┻━┻`; - Meteor.call('sendMessage', msg); -} - -slashCommands.add('tableflip', Tableflip, { - description: 'Slash_Tableflip_Description', - params: 'your_message_optional', -}); +slashCommands.add( + 'tableflip', + (_command, params, item): void => { + const msg = item; + msg.msg = `${params} (╯°□°)╯︵ ┻━┻`; + Meteor.call('sendMessage', msg); + }, + { + description: 'Slash_Tableflip_Description', + params: 'your_message_optional', + }, +); diff --git a/apps/meteor/app/slashcommand-asciiarts/lib/unflip.ts b/apps/meteor/app/slashcommand-asciiarts/lib/unflip.ts index 5f66b2c8c85c..bc8525103450 100644 --- a/apps/meteor/app/slashcommand-asciiarts/lib/unflip.ts +++ b/apps/meteor/app/slashcommand-asciiarts/lib/unflip.ts @@ -1,4 +1,3 @@ -import type { IMessage } from '@rocket.chat/core-typings'; import { Meteor } from 'meteor/meteor'; import { slashCommands } from '../../utils/lib/slashCommand'; @@ -7,13 +6,15 @@ import { slashCommands } from '../../utils/lib/slashCommand'; * @param {Object} message - The message object */ -function Unflip(_command: 'unflip', params: string, item: IMessage): void { - const msg = item; - msg.msg = `${params} ┬─┬ ノ( ゜-゜ノ)`; - Meteor.call('sendMessage', msg); -} - -slashCommands.add('unflip', Unflip, { - description: 'Slash_TableUnflip_Description', - params: 'your_message_optional', -}); +slashCommands.add( + 'unflip', + (_command: 'unflip', params, item): void => { + const msg = item; + msg.msg = `${params} ┬─┬ ノ( ゜-゜ノ)`; + Meteor.call('sendMessage', msg); + }, + { + description: 'Slash_TableUnflip_Description', + params: 'your_message_optional', + }, +); diff --git a/apps/meteor/app/slashcommands-archiveroom/server/server.ts b/apps/meteor/app/slashcommands-archiveroom/server/server.ts index ae5f12ac8506..b6be536a2ce2 100644 --- a/apps/meteor/app/slashcommands-archiveroom/server/server.ts +++ b/apps/meteor/app/slashcommands-archiveroom/server/server.ts @@ -1,71 +1,72 @@ import { Meteor } from 'meteor/meteor'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import { IMessage } from '@rocket.chat/core-typings'; import { Rooms, Messages } from '../../models/server'; import { slashCommands } from '../../utils/lib/slashCommand'; import { api } from '../../../server/sdk/api'; import { settings } from '../../settings/server'; -function Archive(_command: 'archive', params: string, item: IMessage): void { - let channel = params.trim(); +slashCommands.add( + 'archive', + function Archive(_command, params, item): void { + let channel = params.trim(); - let room; + let room; - if (channel === '') { - room = Rooms.findOneById(item.rid); - channel = room.name; - } else { - channel = channel.replace('#', ''); - room = Rooms.findOneByName(channel); - } + if (channel === '') { + room = Rooms.findOneById(item.rid); + channel = room.name; + } else { + channel = channel.replace('#', ''); + room = Rooms.findOneByName(channel); + } - const userId = Meteor.userId(); + const userId = Meteor.userId(); - if (!userId) { - return; - } + if (!userId) { + return; + } - if (!room) { - api.broadcast('notify.ephemeralMessage', userId, item.rid, { - msg: TAPi18n.__('Channel_doesnt_exist', { - postProcess: 'sprintf', - sprintf: [channel], - lng: settings.get('Language') || 'en', - }), - }); - return; - } + if (!room) { + api.broadcast('notify.ephemeralMessage', userId, item.rid, { + msg: TAPi18n.__('Channel_doesnt_exist', { + postProcess: 'sprintf', + sprintf: [channel], + lng: settings.get('Language') || 'en', + }), + }); + return; + } + + // You can not archive direct messages. + if (room.t === 'd') { + return; + } - // You can not archive direct messages. - if (room.t === 'd') { - return; - } + if (room.archived) { + api.broadcast('notify.ephemeralMessage', userId, item.rid, { + msg: TAPi18n.__('Duplicate_archived_channel_name', { + postProcess: 'sprintf', + sprintf: [channel], + lng: settings.get('Language') || 'en', + }), + }); + return; + } + Meteor.call('archiveRoom', room._id); - if (room.archived) { + Messages.createRoomArchivedByRoomIdAndUser(room._id, Meteor.user()); api.broadcast('notify.ephemeralMessage', userId, item.rid, { - msg: TAPi18n.__('Duplicate_archived_channel_name', { + msg: TAPi18n.__('Channel_Archived', { postProcess: 'sprintf', sprintf: [channel], lng: settings.get('Language') || 'en', }), }); - return; - } - Meteor.call('archiveRoom', room._id); - - Messages.createRoomArchivedByRoomIdAndUser(room._id, Meteor.user()); - api.broadcast('notify.ephemeralMessage', userId, item.rid, { - msg: TAPi18n.__('Channel_Archived', { - postProcess: 'sprintf', - sprintf: [channel], - lng: settings.get('Language') || 'en', - }), - }); -} - -slashCommands.add('archive', Archive, { - description: 'Archive', - params: '#channel', - permission: 'archive-room', -}); + }, + { + description: 'Archive', + params: '#channel', + permission: 'archive-room', + }, +); diff --git a/apps/meteor/app/slashcommands-bridge/server/index.ts b/apps/meteor/app/slashcommands-bridge/server/index.ts index c364aca53720..fa1c1e9d2f9f 100644 --- a/apps/meteor/app/slashcommands-bridge/server/index.ts +++ b/apps/meteor/app/slashcommands-bridge/server/index.ts @@ -1,36 +1,37 @@ import { Meteor } from 'meteor/meteor'; import { Match } from 'meteor/check'; -import { IMessage } from '@rocket.chat/core-typings'; import { slashCommands } from '../../utils/lib/slashCommand'; import { matrixClient } from '../../federation-v2/server/matrix-client'; -function Bridge(_command: 'bridge', stringParams: string, item: IMessage): void { - if (_command !== 'bridge' || !Match.test(stringParams, String)) { - return; - } - - const [command, ...params] = stringParams.split(' '); - - const { rid: roomId } = item; - - switch (command) { - case 'invite': - // Invite a user - // Example: /bridge invite rc_helena:b.rc.allskar.com - const [userId] = params; - - const currentUserId = Meteor.userId(); - - if (currentUserId) { - Promise.await(matrixClient.user.invite(currentUserId, roomId, `@${userId.replace('@', '')}`)); - } - - break; - } -} - -slashCommands.add('bridge', Bridge, { - description: 'Invites_an_user_to_a_bridged_room', - params: '#command #user', -}); +slashCommands.add( + 'bridge', + function Bridge(_command, stringParams, item): void { + if (_command !== 'bridge' || !Match.test(stringParams, String)) { + return; + } + + const [command, ...params] = stringParams.split(' '); + + const { rid: roomId } = item; + + switch (command) { + case 'invite': + // Invite a user + // Example: /bridge invite rc_helena:b.rc.allskar.com + const [userId] = params; + + const currentUserId = Meteor.userId(); + + if (currentUserId) { + Promise.await(matrixClient.user.invite(currentUserId, roomId, `@${userId.replace('@', '')}`)); + } + + break; + } + }, + { + description: 'Invites_an_user_to_a_bridged_room', + params: '#command #user', + }, +); diff --git a/apps/meteor/app/slashcommands-create/server/server.ts b/apps/meteor/app/slashcommands-create/server/server.ts index 6d342951b0dc..d47b84da6787 100644 --- a/apps/meteor/app/slashcommands-create/server/server.ts +++ b/apps/meteor/app/slashcommands-create/server/server.ts @@ -1,61 +1,62 @@ import { Meteor } from 'meteor/meteor'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import { IMessage } from '@rocket.chat/core-typings'; import { settings } from '../../settings/server'; import { Rooms } from '../../models/server'; import { slashCommands } from '../../utils/lib/slashCommand'; import { api } from '../../../server/sdk/api'; -function Create(_command: 'create', params: string, item: IMessage): void { - function getParams(str: string): string[] { - const regex = /(--(\w+))+/g; - const result = []; - let m; - while ((m = regex.exec(str)) !== null) { - if (m.index === regex.lastIndex) { - regex.lastIndex++; +slashCommands.add( + 'create', + function Create(_command: 'create', params, item): void { + function getParams(str: string): string[] { + const regex = /(--(\w+))+/g; + const result = []; + let m; + while ((m = regex.exec(str)) !== null) { + if (m.index === regex.lastIndex) { + regex.lastIndex++; + } + result.push(m[2]); } - result.push(m[2]); + return result; } - return result; - } - - const regexp = new RegExp(settings.get('UTF8_Channel_Names_Validation') as string); - - const channel = regexp.exec(params.trim()); - - if (!channel) { - return; - } - - const channelStr: string = channel ? channel[0] : ''; - if (channelStr === '') { - return; - } - const userId = Meteor.userId() as string; - - const room = Rooms.findOneByName(channelStr); - if (room != null) { - api.broadcast('notify.ephemeralMessage', userId, item.rid, { - msg: TAPi18n.__('Channel_already_exist', { - postProcess: 'sprintf', - sprintf: [channelStr], - lng: settings.get('Language') || 'en', - }), - }); - return; - } - - if (getParams(params).indexOf('private') > -1) { - return Meteor.call('createPrivateGroup', channelStr, []); - } - - Meteor.call('createChannel', channelStr, []); -} - -slashCommands.add('create', Create, { - description: 'Create_A_New_Channel', - params: '#channel', - permission: ['create-c', 'create-p'], -}); + + const regexp = new RegExp(settings.get('UTF8_Channel_Names_Validation') as string); + + const channel = regexp.exec(params.trim()); + + if (!channel) { + return; + } + + const channelStr: string = channel ? channel[0] : ''; + if (channelStr === '') { + return; + } + const userId = Meteor.userId() as string; + + const room = Rooms.findOneByName(channelStr); + if (room != null) { + api.broadcast('notify.ephemeralMessage', userId, item.rid, { + msg: TAPi18n.__('Channel_already_exist', { + postProcess: 'sprintf', + sprintf: [channelStr], + lng: settings.get('Language') || 'en', + }), + }); + return; + } + + if (getParams(params).indexOf('private') > -1) { + return Meteor.call('createPrivateGroup', channelStr, []); + } + + Meteor.call('createChannel', channelStr, []); + }, + { + description: 'Create_A_New_Channel', + params: '#channel', + permission: ['create-c', 'create-p'], + }, +); diff --git a/apps/meteor/app/slashcommands-help/server/server.ts b/apps/meteor/app/slashcommands-help/server/server.ts index b1d6fea68969..00bd14934e9d 100644 --- a/apps/meteor/app/slashcommands-help/server/server.ts +++ b/apps/meteor/app/slashcommands-help/server/server.ts @@ -1,6 +1,5 @@ import { Meteor } from 'meteor/meteor'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import type { IMessage } from '@rocket.chat/core-typings'; import { settings } from '../../settings/server'; import { slashCommands } from '../../utils/lib/slashCommand'; @@ -17,55 +16,57 @@ interface IHelpCommand { command: string; } -function Help(_command: 'help', _params: string, item: IMessage): void { - const userId = Meteor.userId() as string; - const user = Users.findOneById(userId); +slashCommands.add( + 'help', + function Help(_command, _params, item): void { + const userId = Meteor.userId() as string; + const user = Users.findOneById(userId); - const keys: IHelpCommand[] = [ - { - key: 'Open_channel_user_search', - command: 'Command (or Ctrl) + p OR Command (or Ctrl) + k', - }, - { - key: 'Mark_all_as_read', - command: 'Shift (or Ctrl) + ESC', - }, - { - key: 'Edit_previous_message', - command: 'Up Arrow', - }, - { - key: 'Move_beginning_message', - command: 'Command (or Alt) + Left Arrow', - }, - { - key: 'Move_beginning_message', - command: 'Command (or Alt) + Up Arrow', - }, - { - key: 'Move_end_message', - command: 'Command (or Alt) + Right Arrow', - }, - { - key: 'Move_end_message', - command: 'Command (or Alt) + Down Arrow', - }, - { - key: 'New_line_message_compose_input', - command: 'Shift + Enter', - }, - ]; - keys.forEach((key) => { - api.broadcast('notify.ephemeralMessage', userId, item.rid, { - msg: TAPi18n.__(key.key, { - postProcess: 'sprintf', - sprintf: [key.command], - lng: user?.language || settings.get('Language') || 'en', - }), + const keys: IHelpCommand[] = [ + { + key: 'Open_channel_user_search', + command: 'Command (or Ctrl) + p OR Command (or Ctrl) + k', + }, + { + key: 'Mark_all_as_read', + command: 'Shift (or Ctrl) + ESC', + }, + { + key: 'Edit_previous_message', + command: 'Up Arrow', + }, + { + key: 'Move_beginning_message', + command: 'Command (or Alt) + Left Arrow', + }, + { + key: 'Move_beginning_message', + command: 'Command (or Alt) + Up Arrow', + }, + { + key: 'Move_end_message', + command: 'Command (or Alt) + Right Arrow', + }, + { + key: 'Move_end_message', + command: 'Command (or Alt) + Down Arrow', + }, + { + key: 'New_line_message_compose_input', + command: 'Shift + Enter', + }, + ]; + keys.forEach((key) => { + api.broadcast('notify.ephemeralMessage', userId, item.rid, { + msg: TAPi18n.__(key.key, { + postProcess: 'sprintf', + sprintf: [key.command], + lng: user?.language || settings.get('Language') || 'en', + }), + }); }); - }); -} - -slashCommands.add('help', Help, { - description: 'Show_the_keyboard_shortcut_list', -}); + }, + { + description: 'Show_the_keyboard_shortcut_list', + }, +); diff --git a/apps/meteor/app/slashcommands-hide/server/hide.ts b/apps/meteor/app/slashcommands-hide/server/hide.ts index 203f304c050d..398344a8c70e 100644 --- a/apps/meteor/app/slashcommands-hide/server/hide.ts +++ b/apps/meteor/app/slashcommands-hide/server/hide.ts @@ -1,6 +1,5 @@ import { Meteor } from 'meteor/meteor'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import type { IMessage } from '@rocket.chat/core-typings'; import { settings } from '../../settings/server'; import { Rooms, Subscriptions, Users } from '../../models/server'; @@ -12,63 +11,65 @@ import { api } from '../../../server/sdk/api'; * @param {Object} message - The message object */ -function Hide(_command: 'hide', param: string, item: IMessage): void { - const room = param.trim(); - const userId = Meteor.userId(); - if (!userId) { - return; - } +slashCommands.add( + 'hide', + (_command: 'hide', param, item): void => { + const room = param.trim(); + const userId = Meteor.userId(); + if (!userId) { + return; + } - const user = Users.findOneById(userId); + const user = Users.findOneById(userId); - if (!user) { - return; - } + if (!user) { + return; + } - const lng = user.language || settings.get('Language') || 'en'; + const lng = user.language || settings.get('Language') || 'en'; - // if there is not a param, hide the current room - let { rid } = item; - if (room !== '') { - const [strippedRoom] = room.replace(/#|@/, '').split(' '); + // if there is not a param, hide the current room + let { rid } = item; + if (room !== '') { + const [strippedRoom] = room.replace(/#|@/, '').split(' '); - const [type] = room; + const [type] = room; - const roomObject = - type === '#' - ? Rooms.findOneByName(strippedRoom) - : Rooms.findOne({ - t: 'd', - usernames: { $all: [user.username, strippedRoom] }, - }); - if (!roomObject) { - api.broadcast('notify.ephemeralMessage', user._id, item.rid, { - msg: TAPi18n.__('Channel_doesnt_exist', { - postProcess: 'sprintf', - sprintf: [room], - lng, - }), - }); + const roomObject = + type === '#' + ? Rooms.findOneByName(strippedRoom) + : Rooms.findOne({ + t: 'd', + usernames: { $all: [user.username, strippedRoom] }, + }); + if (!roomObject) { + api.broadcast('notify.ephemeralMessage', user._id, item.rid, { + msg: TAPi18n.__('Channel_doesnt_exist', { + postProcess: 'sprintf', + sprintf: [room], + lng, + }), + }); + } + if (!Subscriptions.findOneByRoomIdAndUserId(roomObject._id, user._id, { fields: { _id: 1 } })) { + api.broadcast('notify.ephemeralMessage', user._id, item.rid, { + msg: TAPi18n.__('error-logged-user-not-in-room', { + postProcess: 'sprintf', + sprintf: [room], + lng, + }), + }); + return; + } + rid = roomObject._id; } - if (!Subscriptions.findOneByRoomIdAndUserId(roomObject._id, user._id, { fields: { _id: 1 } })) { - api.broadcast('notify.ephemeralMessage', user._id, item.rid, { - msg: TAPi18n.__('error-logged-user-not-in-room', { - postProcess: 'sprintf', - sprintf: [room], - lng, - }), - }); - return; - } - rid = roomObject._id; - } - Meteor.call('hideRoom', rid, (error: string) => { - if (error) { - return api.broadcast('notify.ephemeralMessage', user._id, item.rid, { - msg: TAPi18n.__(error, { lng }), - }); - } - }); -} - -slashCommands.add('hide', Hide, { description: 'Hide_room', params: '#room' }); + Meteor.call('hideRoom', rid, (error: string) => { + if (error) { + return api.broadcast('notify.ephemeralMessage', user._id, item.rid, { + msg: TAPi18n.__(error, { lng }), + }); + } + }); + }, + { description: 'Hide_room', params: '#room' }, +); diff --git a/apps/meteor/app/slashcommands-invite/server/server.ts b/apps/meteor/app/slashcommands-invite/server/server.ts index d54b319646a8..1bc427536e83 100644 --- a/apps/meteor/app/slashcommands-invite/server/server.ts +++ b/apps/meteor/app/slashcommands-invite/server/server.ts @@ -1,6 +1,5 @@ import { Meteor } from 'meteor/meteor'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import { IMessage } from '@rocket.chat/core-typings'; import { settings } from '../../settings/server'; import { slashCommands } from '../../utils/lib/slashCommand'; @@ -11,74 +10,75 @@ import { api } from '../../../server/sdk/api'; * Invite is a named function that will replace /invite commands * @param {Object} message - The message object */ - -function Invite(_command: 'invite', params: string, item: IMessage): void { - const usernames = params - .split(/[\s,]/) - .map((username) => username.replace(/(^@)|( @)/, '')) - .filter((a) => a !== ''); - if (usernames.length === 0) { - return; - } - const users = Meteor.users.find({ - username: { - $in: usernames, - }, - }); - const userId = Meteor.userId() as string; - if (users.count() === 0) { - api.broadcast('notify.ephemeralMessage', userId, item.rid, { - msg: TAPi18n.__('User_doesnt_exist', { - postProcess: 'sprintf', - sprintf: [usernames.join(' @')], - lng: settings.get('Language') || 'en', - }), - }); - return; - } - const usersFiltered = users.fetch().filter(function (user) { - const subscription = Subscriptions.findOneByRoomIdAndUserId(item.rid, user._id, { - fields: { _id: 1 }, - }); - if (subscription == null) { - return true; +slashCommands.add( + 'invite', + (_command: 'invite', params, item): void => { + const usernames = params + .split(/[\s,]/) + .map((username) => username.replace(/(^@)|( @)/, '')) + .filter((a) => a !== ''); + if (usernames.length === 0) { + return; } - const usernameStr = user.username as string; - api.broadcast('notify.ephemeralMessage', userId, item.rid, { - msg: TAPi18n.__('Username_is_already_in_here', { - postProcess: 'sprintf', - sprintf: [usernameStr], - lng: settings.get('Language') || 'en', - }), + const users = Meteor.users.find({ + username: { + $in: usernames, + }, }); - return false; - }); - - usersFiltered.forEach(function (user) { - try { - return Meteor.call('addUserToRoom', { - rid: item.rid, - username: user.username, + const userId = Meteor.userId() as string; + if (users.count() === 0) { + api.broadcast('notify.ephemeralMessage', userId, item.rid, { + msg: TAPi18n.__('User_doesnt_exist', { + postProcess: 'sprintf', + sprintf: [usernames.join(' @')], + lng: settings.get('Language') || 'en', + }), }); - } catch ({ error }) { - if (typeof error !== 'string') { - return; + return; + } + const usersFiltered = users.fetch().filter(function (user) { + const subscription = Subscriptions.findOneByRoomIdAndUserId(item.rid, user._id, { + fields: { _id: 1 }, + }); + if (subscription == null) { + return true; } - if (error === 'cant-invite-for-direct-room') { - api.broadcast('notify.ephemeralMessage', userId, item.rid, { - msg: TAPi18n.__('Cannot_invite_users_to_direct_rooms', { lng: settings.get('Language') || 'en' }), - }); - } else { - api.broadcast('notify.ephemeralMessage', userId, item.rid, { - msg: TAPi18n.__(error, { lng: settings.get('Language') || 'en' }), + const usernameStr = user.username as string; + api.broadcast('notify.ephemeralMessage', userId, item.rid, { + msg: TAPi18n.__('Username_is_already_in_here', { + postProcess: 'sprintf', + sprintf: [usernameStr], + lng: settings.get('Language') || 'en', + }), + }); + return false; + }); + + usersFiltered.forEach(function (user) { + try { + return Meteor.call('addUserToRoom', { + rid: item.rid, + username: user.username, }); + } catch ({ error }) { + if (typeof error !== 'string') { + return; + } + if (error === 'cant-invite-for-direct-room') { + api.broadcast('notify.ephemeralMessage', userId, item.rid, { + msg: TAPi18n.__('Cannot_invite_users_to_direct_rooms', { lng: settings.get('Language') || 'en' }), + }); + } else { + api.broadcast('notify.ephemeralMessage', userId, item.rid, { + msg: TAPi18n.__(error, { lng: settings.get('Language') || 'en' }), + }); + } } - } - }); -} - -slashCommands.add('invite', Invite, { - description: 'Invite_user_to_join_channel', - params: '@username', - permission: 'add-user-to-joined-room', -}); + }); + }, + { + description: 'Invite_user_to_join_channel', + params: '@username', + permission: 'add-user-to-joined-room', + }, +); diff --git a/apps/meteor/app/slashcommands-inviteall/server/server.ts b/apps/meteor/app/slashcommands-inviteall/server/server.ts index a56b2c83c769..4c05b3e1b19e 100644 --- a/apps/meteor/app/slashcommands-inviteall/server/server.ts +++ b/apps/meteor/app/slashcommands-inviteall/server/server.ts @@ -5,15 +5,15 @@ import { Meteor } from 'meteor/meteor'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import type { IMessage, ISubscription } from '@rocket.chat/core-typings'; +import type { ISubscription, SlashCommand } from '@rocket.chat/core-typings'; import { Rooms, Subscriptions, Users } from '../../models/server'; import { slashCommands } from '../../utils/lib/slashCommand'; import { settings } from '../../settings/server'; import { api } from '../../../server/sdk/api'; -function inviteAll(type: string): typeof slashCommands.commands[string]['callback'] { - return function inviteAll(command: string, params: string, item: IMessage): void { +function inviteAll(type: T): SlashCommand['callback'] { + return function inviteAll(command: T, params: string, item): void { if (!/invite\-all-(to|from)/.test(command)) { return; } diff --git a/apps/meteor/app/slashcommands-join/server/server.ts b/apps/meteor/app/slashcommands-join/server/server.ts index 25737a969dd4..1d65feb1f979 100644 --- a/apps/meteor/app/slashcommands-join/server/server.ts +++ b/apps/meteor/app/slashcommands-join/server/server.ts @@ -1,53 +1,54 @@ import { Meteor } from 'meteor/meteor'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import { IMessage } from '@rocket.chat/core-typings'; import { Rooms, Subscriptions } from '../../models/server'; import { settings } from '../../settings/server'; import { slashCommands } from '../../utils/lib/slashCommand'; import { api } from '../../../server/sdk/api'; -function Join(_command: 'join', params: string, item: IMessage): void { - let channel = params.trim(); - if (channel === '') { - return; - } - - channel = channel.replace('#', ''); - - const userId = Meteor.userId() as string; - const user = Meteor.users.findOne(userId); - const room = Rooms.findOneByNameAndType(channel, 'c'); - - if (!user) { - return; - } - - if (!room) { - api.broadcast('notify.ephemeralMessage', userId, item.rid, { - msg: TAPi18n.__('Channel_doesnt_exist', { - postProcess: 'sprintf', - sprintf: [channel], - lng: settings.get('Language') || 'en', - }), +slashCommands.add( + 'join', + (_command: 'join', params, item): void => { + let channel = params.trim(); + if (channel === '') { + return; + } + + channel = channel.replace('#', ''); + + const userId = Meteor.userId() as string; + const user = Meteor.users.findOne(userId); + const room = Rooms.findOneByNameAndType(channel, 'c'); + + if (!user) { + return; + } + + if (!room) { + api.broadcast('notify.ephemeralMessage', userId, item.rid, { + msg: TAPi18n.__('Channel_doesnt_exist', { + postProcess: 'sprintf', + sprintf: [channel], + lng: settings.get('Language') || 'en', + }), + }); + } + + const subscription = Subscriptions.findOneByRoomIdAndUserId(room._id, user._id, { + fields: { _id: 1 }, }); - } - const subscription = Subscriptions.findOneByRoomIdAndUserId(room._id, user._id, { - fields: { _id: 1 }, - }); - - if (subscription) { - throw new Meteor.Error('error-user-already-in-room', 'You are already in the channel', { - method: 'slashCommands', - }); - } - - Meteor.call('joinRoom', room._id); -} - -slashCommands.add('join', Join, { - description: 'Join_the_given_channel', - params: '#channel', - permission: 'view-c-room', -}); + if (subscription) { + throw new Meteor.Error('error-user-already-in-room', 'You are already in the channel', { + method: 'slashCommands', + }); + } + + Meteor.call('joinRoom', room._id); + }, + { + description: 'Join_the_given_channel', + params: '#channel', + permission: 'view-c-room', + }, +); diff --git a/apps/meteor/app/slashcommands-kick/server/server.ts b/apps/meteor/app/slashcommands-kick/server/server.ts index 5a08e53fbacd..70d7c44db543 100644 --- a/apps/meteor/app/slashcommands-kick/server/server.ts +++ b/apps/meteor/app/slashcommands-kick/server/server.ts @@ -1,54 +1,55 @@ // Kick is a named function that will replace /kick commands import { Meteor } from 'meteor/meteor'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import type { IMessage } from '@rocket.chat/core-typings'; import { Users, Subscriptions } from '../../models/server'; import { settings } from '../../settings/server'; import { slashCommands } from '../../utils/lib/slashCommand'; import { api } from '../../../server/sdk/api'; -const Kick = function (_command: 'kick', params: string, item: IMessage): void { - const username = params.trim().replace('@', ''); - if (username === '') { - return; - } - const userId = Meteor.userId() as string; - const user = Users.findOneById(userId); - const lng = user?.language || settings.get('Language') || 'en'; +slashCommands.add( + 'kick', + function (_command: 'kick', params, item): void { + const username = params.trim().replace('@', ''); + if (username === '') { + return; + } + const userId = Meteor.userId() as string; + const user = Users.findOneById(userId); + const lng = user?.language || settings.get('Language') || 'en'; - const kickedUser = Users.findOneByUsernameIgnoringCase(username); + const kickedUser = Users.findOneByUsernameIgnoringCase(username); - if (kickedUser == null) { - api.broadcast('notify.ephemeralMessage', userId, item.rid, { - msg: TAPi18n.__('Username_doesnt_exist', { - postProcess: 'sprintf', - sprintf: [username], - lng, - }), - }); - return; - } + if (kickedUser == null) { + api.broadcast('notify.ephemeralMessage', userId, item.rid, { + msg: TAPi18n.__('Username_doesnt_exist', { + postProcess: 'sprintf', + sprintf: [username], + lng, + }), + }); + return; + } - const subscription = Subscriptions.findOneByRoomIdAndUserId(item.rid, userId, { - fields: { _id: 1 }, - }); - if (!subscription) { - api.broadcast('notify.ephemeralMessage', userId, item.rid, { - msg: TAPi18n.__('Username_is_not_in_this_room', { - postProcess: 'sprintf', - sprintf: [username], - lng, - }), + const subscription = Subscriptions.findOneByRoomIdAndUserId(item.rid, userId, { + fields: { _id: 1 }, }); - return; - } - const { rid } = item; - Meteor.call('removeUserFromRoom', { rid, username }); -}; - -slashCommands.add('kick', Kick, { - description: 'Remove_someone_from_room', - params: '@username', - permission: 'remove-user', -}); + if (!subscription) { + api.broadcast('notify.ephemeralMessage', userId, item.rid, { + msg: TAPi18n.__('Username_is_not_in_this_room', { + postProcess: 'sprintf', + sprintf: [username], + lng, + }), + }); + return; + } + const { rid } = item; + Meteor.call('removeUserFromRoom', { rid, username }); + }, + { + description: 'Remove_someone_from_room', + params: '@username', + permission: 'remove-user', + }, +); diff --git a/apps/meteor/app/slashcommands-leave/server/leave.ts b/apps/meteor/app/slashcommands-leave/server/leave.ts index 21aed9574caf..d99def1db777 100644 --- a/apps/meteor/app/slashcommands-leave/server/leave.ts +++ b/apps/meteor/app/slashcommands-leave/server/leave.ts @@ -1,6 +1,6 @@ import { Meteor } from 'meteor/meteor'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import type { IMessage } from '@rocket.chat/core-typings'; +import type { SlashCommand } from '@rocket.chat/core-typings'; import { slashCommands } from '../../utils/lib/slashCommand'; import { settings } from '../../settings/server'; @@ -11,7 +11,7 @@ import { Users } from '../../models/server'; * Leave is a named function that will replace /leave commands * @param {Object} message - The message object */ -function Leave(_command: string, _params: string, item: IMessage): void { +const Leave: SlashCommand<'leave'>['callback'] = function Leave(_command, _params, item): void { try { Meteor.call('leaveRoom', item.rid); } catch ({ error }) { @@ -24,7 +24,7 @@ function Leave(_command: string, _params: string, item: IMessage): void { msg: TAPi18n.__(error, { lng: user?.language || settings.get('Language') || 'en' }), }); } -} +}; slashCommands.add('leave', Leave, { description: 'Leave_the_current_channel', diff --git a/apps/meteor/app/slashcommands-me/server/me.ts b/apps/meteor/app/slashcommands-me/server/me.ts index 300be2ad353a..9907474dbf15 100644 --- a/apps/meteor/app/slashcommands-me/server/me.ts +++ b/apps/meteor/app/slashcommands-me/server/me.ts @@ -1,6 +1,5 @@ import { Meteor } from 'meteor/meteor'; import s from 'underscore.string'; -import { IMessage } from '@rocket.chat/core-typings'; import { slashCommands } from '../../utils/lib/slashCommand'; @@ -10,7 +9,7 @@ import { slashCommands } from '../../utils/lib/slashCommand'; */ slashCommands.add( 'me', - function Me(_command: 'me', params: string, item: IMessage): void { + function Me(_command: 'me', params, item): void { if (s.trim(params)) { const msg = item; msg.msg = `_${params}_`; diff --git a/apps/meteor/app/slashcommands-msg/server/server.ts b/apps/meteor/app/slashcommands-msg/server/server.ts index bea98e24e2ca..d1d4cc60ede0 100644 --- a/apps/meteor/app/slashcommands-msg/server/server.ts +++ b/apps/meteor/app/slashcommands-msg/server/server.ts @@ -1,7 +1,6 @@ import { Meteor } from 'meteor/meteor'; import { Random } from 'meteor/random'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import type { IMessage } from '@rocket.chat/core-typings'; import { slashCommands } from '../../utils/lib/slashCommand'; import { settings } from '../../settings/server'; @@ -12,42 +11,44 @@ import { api } from '../../../server/sdk/api'; * Msg is a named function that will replace /msg commands */ -function Msg(_command: 'msg', params: string, item: IMessage): void { - const trimmedParams = params.trim(); - const separator = trimmedParams.indexOf(' '); - const userId = Meteor.userId() as string; - if (separator === -1) { - api.broadcast('notify.ephemeralMessage', userId, item.rid, { - msg: TAPi18n.__('Username_and_message_must_not_be_empty', { lng: settings.get('Language') || 'en' }), - }); - return; - } - const message = trimmedParams.slice(separator + 1); - const targetUsernameOrig = trimmedParams.slice(0, separator); - const targetUsername = targetUsernameOrig.replace('@', ''); - const targetUser = Users.findOneByUsernameIgnoringCase(targetUsername); - if (targetUser == null) { - const user = Users.findOneById(userId, { fields: { language: 1 } }); - api.broadcast('notify.ephemeralMessage', userId, item.rid, { - msg: TAPi18n.__('Username_doesnt_exist', { - postProcess: 'sprintf', - sprintf: [targetUsernameOrig], - lng: user?.language || settings.get('Language') || 'en', - }), - }); - return; - } - const { rid } = Meteor.call('createDirectMessage', targetUsername); - const msgObject = { - _id: Random.id(), - rid, - msg: message, - }; - Meteor.call('sendMessage', msgObject); -} - -slashCommands.add('msg', Msg, { - description: 'Direct_message_someone', - params: '@username ', - permission: 'create-d', -}); +slashCommands.add( + 'msg', + function Msg(_command: 'msg', params, item): void { + const trimmedParams = params.trim(); + const separator = trimmedParams.indexOf(' '); + const userId = Meteor.userId() as string; + if (separator === -1) { + api.broadcast('notify.ephemeralMessage', userId, item.rid, { + msg: TAPi18n.__('Username_and_message_must_not_be_empty', { lng: settings.get('Language') || 'en' }), + }); + return; + } + const message = trimmedParams.slice(separator + 1); + const targetUsernameOrig = trimmedParams.slice(0, separator); + const targetUsername = targetUsernameOrig.replace('@', ''); + const targetUser = Users.findOneByUsernameIgnoringCase(targetUsername); + if (targetUser == null) { + const user = Users.findOneById(userId, { fields: { language: 1 } }); + api.broadcast('notify.ephemeralMessage', userId, item.rid, { + msg: TAPi18n.__('Username_doesnt_exist', { + postProcess: 'sprintf', + sprintf: [targetUsernameOrig], + lng: user?.language || settings.get('Language') || 'en', + }), + }); + return; + } + const { rid } = Meteor.call('createDirectMessage', targetUsername); + const msgObject = { + _id: Random.id(), + rid, + msg: message, + }; + Meteor.call('sendMessage', msgObject); + }, + { + description: 'Direct_message_someone', + params: '@username ', + permission: 'create-d', + }, +); diff --git a/apps/meteor/app/slashcommands-mute/server/mute.ts b/apps/meteor/app/slashcommands-mute/server/mute.ts index ed4fd5312893..0353337a162d 100644 --- a/apps/meteor/app/slashcommands-mute/server/mute.ts +++ b/apps/meteor/app/slashcommands-mute/server/mute.ts @@ -1,6 +1,5 @@ import { Meteor } from 'meteor/meteor'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import { IMessage } from '@rocket.chat/core-typings'; import { slashCommands } from '../../utils/lib/slashCommand'; import { settings } from '../../settings/server'; @@ -11,44 +10,46 @@ import { api } from '../../../server/sdk/api'; * Mute is a named function that will replace /mute commands */ -function Mute(_command: 'mute', params: string, item: IMessage): void { - const username = params.trim().replace('@', ''); - if (username === '') { - return; - } +slashCommands.add( + 'mute', + function Mute(_command: 'mute', params, item): void { + const username = params.trim().replace('@', ''); + if (username === '') { + return; + } - const userId = Meteor.userId() as string; - const mutedUser = Users.findOneByUsernameIgnoringCase(username); - if (mutedUser == null) { - api.broadcast('notify.ephemeralMessage', userId, item.rid, { - msg: TAPi18n.__('Username_doesnt_exist', { - postProcess: 'sprintf', - sprintf: [username], - lng: settings.get('Language') || 'en', - }), + const userId = Meteor.userId() as string; + const mutedUser = Users.findOneByUsernameIgnoringCase(username); + if (mutedUser == null) { + api.broadcast('notify.ephemeralMessage', userId, item.rid, { + msg: TAPi18n.__('Username_doesnt_exist', { + postProcess: 'sprintf', + sprintf: [username], + lng: settings.get('Language') || 'en', + }), + }); + } + const subscription = Subscriptions.findOneByRoomIdAndUserId(item.rid, mutedUser._id, { + fields: { _id: 1 }, }); - } - const subscription = Subscriptions.findOneByRoomIdAndUserId(item.rid, mutedUser._id, { - fields: { _id: 1 }, - }); - if (!subscription) { - api.broadcast('notify.ephemeralMessage', userId, item.rid, { - msg: TAPi18n.__('Username_is_not_in_this_room', { - postProcess: 'sprintf', - sprintf: [username], - lng: settings.get('Language') || 'en', - }), + if (!subscription) { + api.broadcast('notify.ephemeralMessage', userId, item.rid, { + msg: TAPi18n.__('Username_is_not_in_this_room', { + postProcess: 'sprintf', + sprintf: [username], + lng: settings.get('Language') || 'en', + }), + }); + return; + } + Meteor.call('muteUserInRoom', { + rid: item.rid, + username, }); - return; - } - Meteor.call('muteUserInRoom', { - rid: item.rid, - username, - }); -} - -slashCommands.add('mute', Mute, { - description: 'Mute_someone_in_room', - params: '@username', - permission: 'mute-user', -}); + }, + { + description: 'Mute_someone_in_room', + params: '@username', + permission: 'mute-user', + }, +); diff --git a/apps/meteor/app/slashcommands-mute/server/unmute.ts b/apps/meteor/app/slashcommands-mute/server/unmute.ts index 38e9229b95d0..82d513302478 100644 --- a/apps/meteor/app/slashcommands-mute/server/unmute.ts +++ b/apps/meteor/app/slashcommands-mute/server/unmute.ts @@ -1,6 +1,5 @@ import { Meteor } from 'meteor/meteor'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import { IMessage } from '@rocket.chat/core-typings'; import { slashCommands } from '../../utils/lib/slashCommand'; import { Users, Subscriptions } from '../../models/server'; @@ -11,43 +10,45 @@ import { api } from '../../../server/sdk/api'; * Unmute is a named function that will replace /unmute commands */ -function Unmute(_command: 'unmute', params: string, item: IMessage): void | Promise { - const username = params.trim().replace('@', ''); - if (username === '') { - return; - } - const userId = Meteor.userId() as string; - const unmutedUser = Users.findOneByUsernameIgnoringCase(username); - if (unmutedUser == null) { - return api.broadcast('notify.ephemeralMessage', userId, item.rid, { - msg: TAPi18n.__('Username_doesnt_exist', { - postProcess: 'sprintf', - sprintf: [username], - lng: settings.get('Language') || 'en', - }), - }); - } +slashCommands.add( + 'unmute', + function Unmute(_command, params, item): void | Promise { + const username = params.trim().replace('@', ''); + if (username === '') { + return; + } + const userId = Meteor.userId() as string; + const unmutedUser = Users.findOneByUsernameIgnoringCase(username); + if (unmutedUser == null) { + return api.broadcast('notify.ephemeralMessage', userId, item.rid, { + msg: TAPi18n.__('Username_doesnt_exist', { + postProcess: 'sprintf', + sprintf: [username], + lng: settings.get('Language') || 'en', + }), + }); + } - const subscription = Subscriptions.findOneByRoomIdAndUserId(item.rid, unmutedUser._id, { - fields: { _id: 1 }, - }); - if (!subscription) { - return api.broadcast('notify.ephemeralMessage', userId, item.rid, { - msg: TAPi18n.__('Username_is_not_in_this_room', { - postProcess: 'sprintf', - sprintf: [username], - lng: settings.get('Language') || 'en', - }), + const subscription = Subscriptions.findOneByRoomIdAndUserId(item.rid, unmutedUser._id, { + fields: { _id: 1 }, }); - } - Meteor.call('unmuteUserInRoom', { - rid: item.rid, - username, - }); -} - -slashCommands.add('unmute', Unmute, { - description: 'Unmute_someone_in_room', - params: '@username', - permission: 'mute-user', -}); + if (!subscription) { + return api.broadcast('notify.ephemeralMessage', userId, item.rid, { + msg: TAPi18n.__('Username_is_not_in_this_room', { + postProcess: 'sprintf', + sprintf: [username], + lng: settings.get('Language') || 'en', + }), + }); + } + Meteor.call('unmuteUserInRoom', { + rid: item.rid, + username, + }); + }, + { + description: 'Unmute_someone_in_room', + params: '@username', + permission: 'mute-user', + }, +); diff --git a/apps/meteor/app/slashcommands-open/client/client.ts b/apps/meteor/app/slashcommands-open/client/client.ts index ce0342b20c6b..14dd0ff9fb09 100644 --- a/apps/meteor/app/slashcommands-open/client/client.ts +++ b/apps/meteor/app/slashcommands-open/client/client.ts @@ -1,46 +1,47 @@ import { Meteor } from 'meteor/meteor'; import { FlowRouter } from 'meteor/kadira:flow-router'; -import type { IMessage } from '@rocket.chat/core-typings'; import { roomCoordinator } from '../../../client/lib/rooms/roomCoordinator'; import { slashCommands } from '../../utils/lib/slashCommand'; import { Subscriptions, ChatSubscription } from '../../models/client'; -function Open(_command: 'open', params: string, _item: IMessage): void { - const dict: Record = { - '#': ['c', 'p'], - '@': ['d'], - }; +slashCommands.add( + 'open', + function Open(_command, params): void { + const dict: Record = { + '#': ['c', 'p'], + '@': ['d'], + }; - const room = params.trim().replace(/#|@/, ''); - const type = dict[params.trim()[0]] || []; + const room = params.trim().replace(/#|@/, ''); + const type = dict[params.trim()[0]] || []; - const query = { - name: room, - ...(type && { t: { $in: type } }), - }; + const query = { + name: room, + ...(type && { t: { $in: type } }), + }; - const subscription = ChatSubscription.findOne(query); + const subscription = ChatSubscription.findOne(query); - if (subscription) { - roomCoordinator.openRouteLink(subscription.t, subscription, FlowRouter.current().queryParams); - } + if (subscription) { + roomCoordinator.openRouteLink(subscription.t, subscription, FlowRouter.current().queryParams); + } - if (type && type.indexOf('d') === -1) { - return; - } - return Meteor.call('createDirectMessage', room, function (err: Meteor.Error) { - if (err) { + if (type && type.indexOf('d') === -1) { return; } - const subscription = Subscriptions.findOne(query); - roomCoordinator.openRouteLink(subscription.t, subscription, FlowRouter.current().queryParams); - }); -} - -slashCommands.add('open', Open, { - description: 'Opens_a_channel_group_or_direct_message', - params: 'room_name', - clientOnly: true, - permission: ['view-c-room', 'view-c-room', 'view-d-room', 'view-joined-room', 'create-d'], -}); + return Meteor.call('createDirectMessage', room, function (err: Meteor.Error) { + if (err) { + return; + } + const subscription = Subscriptions.findOne(query); + roomCoordinator.openRouteLink(subscription.t, subscription, FlowRouter.current().queryParams); + }); + }, + { + description: 'Opens_a_channel_group_or_direct_message', + params: 'room_name', + clientOnly: true, + permission: ['view-c-room', 'view-c-room', 'view-d-room', 'view-joined-room', 'create-d'], + }, +); diff --git a/apps/meteor/app/slashcommands-status/client/status.ts b/apps/meteor/app/slashcommands-status/client/status.ts index 69b1dd11241e..2a47886488af 100644 --- a/apps/meteor/app/slashcommands-status/client/status.ts +++ b/apps/meteor/app/slashcommands-status/client/status.ts @@ -1,26 +1,27 @@ import { Meteor } from 'meteor/meteor'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import type { IMessage } from '@rocket.chat/core-typings'; import { slashCommands } from '../../utils/lib/slashCommand'; import { settings } from '../../settings/server'; import { api } from '../../../server/sdk/api'; import { handleError } from '../../../client/lib/utils/handleError'; -function Status(_command: 'status', params: string, item: IMessage): void { - const userId = Meteor.userId() as string; +slashCommands.add( + 'status', + function Status(_command, params, item): void { + const userId = Meteor.userId() as string; - Meteor.call('setUserStatus', null, params, (err: Meteor.Error) => { - if (err) { - return handleError(err); - } - api.broadcast('notify.ephemeralMessage', userId, item.rid, { - msg: TAPi18n.__('StatusMessage_Changed_Successfully', { lng: settings.get('Language') || 'en' }), + Meteor.call('setUserStatus', null, params, (err: Meteor.Error) => { + if (err) { + return handleError(err); + } + api.broadcast('notify.ephemeralMessage', userId, item.rid, { + msg: TAPi18n.__('StatusMessage_Changed_Successfully', { lng: settings.get('Language') || 'en' }), + }); }); - }); -} - -slashCommands.add('status', Status, { - description: 'Slash_Status_Description', - params: 'Slash_Status_Params', -}); + }, + { + description: 'Slash_Status_Description', + params: 'Slash_Status_Params', + }, +); diff --git a/apps/meteor/app/slashcommands-status/server/status.ts b/apps/meteor/app/slashcommands-status/server/status.ts index 5bbee67baf8c..33ae7f77e1e8 100644 --- a/apps/meteor/app/slashcommands-status/server/status.ts +++ b/apps/meteor/app/slashcommands-status/server/status.ts @@ -1,36 +1,37 @@ import { Meteor } from 'meteor/meteor'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import type { IMessage } from '@rocket.chat/core-typings'; import { slashCommands } from '../../utils/lib/slashCommand'; import { settings } from '../../settings/server'; import { api } from '../../../server/sdk/api'; import { Users } from '../../models/server'; -function Status(_command: 'status', params: string, item: IMessage): void { - const userId = Meteor.userId() as string; +slashCommands.add( + 'status', + function Status(_command: 'status', params, item): void { + const userId = Meteor.userId() as string; - Meteor.call('setUserStatus', null, params, (err: Meteor.Error) => { - const user = userId && Users.findOneById(userId, { fields: { language: 1 } }); - const lng = user?.language || settings.get('Language') || 'en'; + Meteor.call('setUserStatus', null, params, (err: Meteor.Error) => { + const user = userId && Users.findOneById(userId, { fields: { language: 1 } }); + const lng = user?.language || settings.get('Language') || 'en'; - if (err) { - if (err.error === 'error-not-allowed') { + if (err) { + if (err.error === 'error-not-allowed') { + api.broadcast('notify.ephemeralMessage', userId, item.rid, { + msg: TAPi18n.__('StatusMessage_Change_Disabled', { lng }), + }); + } + + throw err; + } else { api.broadcast('notify.ephemeralMessage', userId, item.rid, { - msg: TAPi18n.__('StatusMessage_Change_Disabled', { lng }), + msg: TAPi18n.__('StatusMessage_Changed_Successfully', { lng }), }); } - - throw err; - } else { - api.broadcast('notify.ephemeralMessage', userId, item.rid, { - msg: TAPi18n.__('StatusMessage_Changed_Successfully', { lng }), - }); - } - }); -} - -slashCommands.add('status', Status, { - description: 'Slash_Status_Description', - params: 'Slash_Status_Params', -}); + }); + }, + { + description: 'Slash_Status_Description', + params: 'Slash_Status_Params', + }, +); diff --git a/apps/meteor/app/slashcommands-topic/client/topic.ts b/apps/meteor/app/slashcommands-topic/client/topic.ts index 8b0e121ee013..3c30011fb6ea 100644 --- a/apps/meteor/app/slashcommands-topic/client/topic.ts +++ b/apps/meteor/app/slashcommands-topic/client/topic.ts @@ -1,5 +1,4 @@ import { Meteor } from 'meteor/meteor'; -import type { IMessage } from '@rocket.chat/core-typings'; import { slashCommands } from '../../utils/lib/slashCommand'; import { ChatRoom } from '../../models/client/models/ChatRoom'; @@ -7,25 +6,27 @@ import { callbacks } from '../../../lib/callbacks'; import { hasPermission } from '../../authorization/client'; import { handleError } from '../../../client/lib/utils/handleError'; -function Topic(_command: 'topic', params: string, item: IMessage): void { - if (Meteor.isClient && hasPermission('edit-room', item.rid)) { - Meteor.call('saveRoomSettings', item.rid, 'roomTopic', params, (err: Meteor.Error) => { - if (err) { - if (Meteor.isClient) { - handleError(err); +slashCommands.add( + 'topic', + function Topic(_command: 'topic', params, item): void { + if (Meteor.isClient && hasPermission('edit-room', item.rid)) { + Meteor.call('saveRoomSettings', item.rid, 'roomTopic', params, (err: Meteor.Error) => { + if (err) { + if (Meteor.isClient) { + handleError(err); + } + throw err; } - throw err; - } - - if (Meteor.isClient) { - callbacks.run('roomTopicChanged', ChatRoom.findOne(item.rid)); - } - }); - } -} -slashCommands.add('topic', Topic, { - description: 'Slash_Topic_Description', - params: 'Slash_Topic_Params', - permission: 'edit-room', -}); + if (Meteor.isClient) { + callbacks.run('roomTopicChanged', ChatRoom.findOne(item.rid)); + } + }); + } + }, + { + description: 'Slash_Topic_Description', + params: 'Slash_Topic_Params', + permission: 'edit-room', + }, +); diff --git a/apps/meteor/app/slashcommands-topic/server/topic.ts b/apps/meteor/app/slashcommands-topic/server/topic.ts index 763861d2d20b..0256b6bb7fae 100644 --- a/apps/meteor/app/slashcommands-topic/server/topic.ts +++ b/apps/meteor/app/slashcommands-topic/server/topic.ts @@ -1,21 +1,22 @@ import { Meteor } from 'meteor/meteor'; -import type { IMessage } from '@rocket.chat/core-typings'; import { slashCommands } from '../../utils/lib/slashCommand'; import { hasPermission } from '../../authorization/server/functions/hasPermission'; -function Topic(_command: 'topic', params: string, item: IMessage): void { - if (Meteor.isServer && hasPermission(Meteor.userId() as string, 'edit-room', item.rid)) { - Meteor.call('saveRoomSettings', item.rid, 'roomTopic', params, (err: Meteor.Error) => { - if (err) { - throw err; - } - }); - } -} - -slashCommands.add('topic', Topic, { - description: 'Slash_Topic_Description', - params: 'Slash_Topic_Params', - permission: 'edit-room', -}); +slashCommands.add( + 'topic', + function Topic(_command: 'topic', params, item): void { + if (Meteor.isServer && hasPermission(Meteor.userId() as string, 'edit-room', item.rid)) { + Meteor.call('saveRoomSettings', item.rid, 'roomTopic', params, (err: Meteor.Error) => { + if (err) { + throw err; + } + }); + } + }, + { + description: 'Slash_Topic_Description', + params: 'Slash_Topic_Params', + permission: 'edit-room', + }, +); diff --git a/apps/meteor/app/slashcommands-unarchiveroom/server/server.ts b/apps/meteor/app/slashcommands-unarchiveroom/server/server.ts index ad3c999f7b38..2bc7318d75aa 100644 --- a/apps/meteor/app/slashcommands-unarchiveroom/server/server.ts +++ b/apps/meteor/app/slashcommands-unarchiveroom/server/server.ts @@ -1,6 +1,5 @@ import { Meteor } from 'meteor/meteor'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import { IMessage } from '@rocket.chat/core-typings'; import { Rooms, Messages } from '../../models/server'; import { slashCommands } from '../../utils/lib/slashCommand'; @@ -9,61 +8,63 @@ import { api } from '../../../server/sdk/api'; import { roomCoordinator } from '../../../server/lib/rooms/roomCoordinator'; import { RoomMemberActions } from '../../../definition/IRoomTypeConfig'; -function Unarchive(_command: 'unarchive', params: string, item: IMessage): void { - let channel = params.trim(); - let room; +slashCommands.add( + 'unarchive', + function Unarchive(_command: 'unarchive', params, item): void { + let channel = params.trim(); + let room; - if (channel === '') { - room = Rooms.findOneById(item.rid); - channel = room.name; - } else { - channel = channel.replace('#', ''); - room = Rooms.findOneByName(channel); - } + if (channel === '') { + room = Rooms.findOneById(item.rid); + channel = room.name; + } else { + channel = channel.replace('#', ''); + room = Rooms.findOneByName(channel); + } - const userId = Meteor.userId() as string; + const userId = Meteor.userId() as string; - if (!room) { - api.broadcast('notify.ephemeralMessage', userId, item.rid, { - msg: TAPi18n.__('Channel_doesnt_exist', { - postProcess: 'sprintf', - sprintf: [channel], - lng: settings.get('Language') || 'en', - }), - }); - return; - } + if (!room) { + api.broadcast('notify.ephemeralMessage', userId, item.rid, { + msg: TAPi18n.__('Channel_doesnt_exist', { + postProcess: 'sprintf', + sprintf: [channel], + lng: settings.get('Language') || 'en', + }), + }); + return; + } - // You can not archive direct messages. - if (!roomCoordinator.getRoomDirectives(room.t)?.allowMemberAction(room, RoomMemberActions.ARCHIVE)) { - return; - } + // You can not archive direct messages. + if (!roomCoordinator.getRoomDirectives(room.t)?.allowMemberAction(room, RoomMemberActions.ARCHIVE)) { + return; + } - if (!room.archived) { + if (!room.archived) { + api.broadcast('notify.ephemeralMessage', userId, item.rid, { + msg: TAPi18n.__('Channel_already_Unarchived', { + postProcess: 'sprintf', + sprintf: [channel], + lng: settings.get('Language') || 'en', + }), + }); + return; + } + + Meteor.call('unarchiveRoom', room._id); + + Messages.createRoomUnarchivedByRoomIdAndUser(room._id, Meteor.user()); api.broadcast('notify.ephemeralMessage', userId, item.rid, { - msg: TAPi18n.__('Channel_already_Unarchived', { + msg: TAPi18n.__('Channel_Unarchived', { postProcess: 'sprintf', sprintf: [channel], lng: settings.get('Language') || 'en', }), }); - return; - } - - Meteor.call('unarchiveRoom', room._id); - - Messages.createRoomUnarchivedByRoomIdAndUser(room._id, Meteor.user()); - api.broadcast('notify.ephemeralMessage', userId, item.rid, { - msg: TAPi18n.__('Channel_Unarchived', { - postProcess: 'sprintf', - sprintf: [channel], - lng: settings.get('Language') || 'en', - }), - }); -} - -slashCommands.add('unarchive', Unarchive, { - description: 'Unarchive', - params: '#channel', - permission: 'unarchive-room', -}); + }, + { + description: 'Unarchive', + params: '#channel', + permission: 'unarchive-room', + }, +); diff --git a/apps/meteor/app/utils/lib/slashCommand.ts b/apps/meteor/app/utils/lib/slashCommand.ts index ef8175d9c5d0..9c1ed3b2741d 100644 --- a/apps/meteor/app/utils/lib/slashCommand.ts +++ b/apps/meteor/app/utils/lib/slashCommand.ts @@ -1,59 +1,23 @@ import { Meteor } from 'meteor/meteor'; -import type { IMessage } from '@rocket.chat/core-typings'; - -type SlashCommandCallback = (command: T, params: string, message: IMessage, triggerId: string) => void; - -type SlashCommandPreviewItem = { - id: string; - type: 'image' | 'video' | 'audio' | 'text' | 'other'; - value: string; -}; - -type SlashCommandPreviews = { - i18nTitle: string; - items: SlashCommandPreviewItem[]; -}; - -type SlashCommandPreviewer = (command: string, params: string, message: IMessage) => SlashCommandPreviews | undefined; - -type SlashCommandPreviewCallback = ( - command: string, - params: string, - message: IMessage, - preview: SlashCommandPreviewItem, - triggerId: string, -) => void; - -type SlashCommandOptions = { - params?: string; - description?: string; - permission?: string | string[]; - clientOnly?: boolean; -}; - -type SlashCommand = { - command: T; - callback?: SlashCommandCallback; - params: SlashCommandOptions['params']; - description: SlashCommandOptions['description']; - permission: SlashCommandOptions['permission']; - clientOnly?: SlashCommandOptions['clientOnly']; - result?: (err: Meteor.Error, result: never, data: { cmd: T; params: string; msg: IMessage }) => void; - providesPreview: boolean; - previewer?: SlashCommandPreviewer; - previewCallback?: SlashCommandPreviewCallback; -}; +import type { + IMessage, + SlashCommand, + SlashCommandOptions, + RequiredField, + SlashCommandPreviewItem, + SlashCommandPreviews, +} from '@rocket.chat/core-typings'; export const slashCommands = { - commands: {} as Record>, + commands: {} as Record, add( - command: T, + command: string, callback?: SlashCommand['callback'], options: SlashCommandOptions = {}, - result?: SlashCommand['result'], + result?: SlashCommand['result'], providesPreview = false, - previewer?: SlashCommand['previewer'], - previewCallback?: SlashCommand['previewCallback'], + previewer?: SlashCommand['previewer'], + previewCallback?: SlashCommand['previewCallback'], ): void { this.commands[command] = { command, @@ -66,9 +30,9 @@ export const slashCommands = { providesPreview, previewer, previewCallback, - } as SlashCommand; + } as SlashCommand; }, - run(command: string, params: string, message: IMessage, triggerId: string): void { + run(command: string, params: string, message: RequiredField, 'rid'>, triggerId?: string | undefined): void { const cmd = this.commands[command]; if (typeof cmd?.callback !== 'function') { return; diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 7aa3c80937be..7a9c64e9ca61 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -209,6 +209,7 @@ "@types/cookie": "^0.5.1", "@types/lodash": "^4.14.182", "@types/lodash.debounce": "^4.0.6", + "@types/object-path": "^0.11.1", "@types/proxy-from-env": "^1.0.1", "@types/speakeasy": "^2.0.7", "adm-zip": "0.5.9", diff --git a/packages/core-typings/src/SlashCommands/index.ts b/packages/core-typings/src/SlashCommands/index.ts new file mode 100644 index 000000000000..b8e0d5d9a7f9 --- /dev/null +++ b/packages/core-typings/src/SlashCommands/index.ts @@ -0,0 +1,50 @@ +import type { IMessage } from '../IMessage'; +import type { RequiredField } from '../utils'; + +type SlashCommandCallback = ( + command: T, + params: string, + message: RequiredField, 'rid'>, + triggerId?: string, +) => void; + +export type SlashCommandPreviewItem = { + id: string; + type: 'image' | 'video' | 'audio' | 'text' | 'other'; + value: string; +}; + +export type SlashCommandPreviews = { + i18nTitle: string; + items: SlashCommandPreviewItem[]; +}; + +type SlashCommandPreviewer = (command: string, params: string, message: IMessage) => SlashCommandPreviews | undefined; + +type SlashCommandPreviewCallback = ( + command: string, + params: string, + message: IMessage, + preview: SlashCommandPreviewItem, + triggerId: string, +) => void; + +export type SlashCommandOptions = { + params?: string; + description?: string; + permission?: string | string[]; + clientOnly?: boolean; +}; + +export type SlashCommand = { + command: string; + callback?: SlashCommandCallback; + params: SlashCommandOptions['params']; + description: SlashCommandOptions['description']; + permission: SlashCommandOptions['permission']; + clientOnly?: SlashCommandOptions['clientOnly']; + result?: (err: Meteor.Error, result: never, data: { cmd: string; params: string; msg: IMessage }) => void; + providesPreview: boolean; + previewer?: SlashCommandPreviewer; + previewCallback?: SlashCommandPreviewCallback; +}; diff --git a/packages/core-typings/src/index.ts b/packages/core-typings/src/index.ts index 99c80fb49721..44045c4613d4 100644 --- a/packages/core-typings/src/index.ts +++ b/packages/core-typings/src/index.ts @@ -27,6 +27,7 @@ export * from './IServerEvent'; export * from './ICronJobs'; export * from './IPushToken'; export * from './IPushNotificationConfig'; +export * from './SlashCommands'; export * from './IUserDataFile'; export * from './IUserSession'; diff --git a/packages/core-typings/src/utils.ts b/packages/core-typings/src/utils.ts index 40c11706d8e3..2f4eb3981324 100644 --- a/packages/core-typings/src/utils.ts +++ b/packages/core-typings/src/utils.ts @@ -21,3 +21,5 @@ export type Jsonify = T extends Date : T; export type AtLeast = Partial & Pick; + +export type RequiredField = T & Required>; diff --git a/packages/rest-typings/src/index.ts b/packages/rest-typings/src/index.ts index 04b4a05c0b4a..a8dfe71b3cf0 100644 --- a/packages/rest-typings/src/index.ts +++ b/packages/rest-typings/src/index.ts @@ -34,6 +34,7 @@ import type { VoipEndpoints } from './v1/voip'; import type { EmailInboxEndpoints } from './v1/email-inbox'; import type { WebdavEndpoints } from './v1/webdav'; import type { OAuthAppsEndpoint } from './v1/oauthapps'; +import type { CommandsEndpoints } from './v1/commands'; // eslint-disable-next-line @typescript-eslint/no-empty-interface, @typescript-eslint/interface-name-prefix export interface Endpoints @@ -41,6 +42,7 @@ export interface Endpoints BannersEndpoints, ChatEndpoints, CloudEndpoints, + CommandsEndpoints, CustomUserStatusEndpoints, DmEndpoints, DnsEndpoints, diff --git a/packages/rest-typings/src/v1/commands.ts b/packages/rest-typings/src/v1/commands.ts new file mode 100644 index 000000000000..32e14b1c0393 --- /dev/null +++ b/packages/rest-typings/src/v1/commands.ts @@ -0,0 +1,42 @@ +import type { SlashCommand, SlashCommandPreviews } from '../../../core-typings/dist'; +import type { PaginatedRequest } from '../helpers/PaginatedRequest'; +import type { PaginatedResult } from '../helpers/PaginatedResult'; + +export type CommandsEndpoints = { + 'commands.get': { + GET: (params: { command: string }) => { + command: SlashCommand; + }; + }; + 'commands.list': { + GET: ( + params: PaginatedRequest<{ + fields?: string; + }>, + ) => PaginatedResult<{ + commands: SlashCommand[]; + }>; + }; + 'commands.run': { + POST: (params: { command: string; params?: string; roomId: string; tmid?: string; triggerId: string }) => { + result: unknown; + }; + }; + 'commands.preview': { + GET: (params: { command: string; params?: string; roomId: string }) => { + preview: SlashCommandPreviews; + }; + POST: (params: { + command: string; + params?: string; + roomId: string; + previewItem: { + id: string; + type: string; + value: string; + }; + triggerId: string; + tmid?: string; + }) => void; + }; +}; diff --git a/yarn.lock b/yarn.lock index 36a479e08a40..c3570d34a32f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4815,6 +4815,7 @@ __metadata: "@types/node": ^14.18.15 "@types/node-rsa": ^1.1.1 "@types/nodemailer": ^6.4.4 + "@types/object-path": ^0.11.1 "@types/parseurl": ^1.3.1 "@types/photoswipe": ^4.1.2 "@types/proxy-from-env": ^1.0.1 @@ -7543,6 +7544,13 @@ __metadata: languageName: node linkType: hard +"@types/object-path@npm:^0.11.1": + version: 0.11.1 + resolution: "@types/object-path@npm:0.11.1" + checksum: 007e819d1d9dc830491b60023b1502ef1e421416d9953d6fefcda7d06eb91548eef8ee30073a9cfb6a834ac977042f6e1a761cde2d6a7973b06ddca753be91e3 + languageName: node + linkType: hard + "@types/overlayscrollbars@npm:^1.12.0": version: 1.12.1 resolution: "@types/overlayscrollbars@npm:1.12.1" From aa7d71696e696d60fc9e76b9fadc1c921654ce1f Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Fri, 3 Jun 2022 15:43:44 -0300 Subject: [PATCH 3/6] Chore: remove duplicated NotFoundPage.js (#25749) --- .../client/views/notFound/NotFoundPage.js | 63 ------------------- 1 file changed, 63 deletions(-) delete mode 100644 apps/meteor/client/views/notFound/NotFoundPage.js diff --git a/apps/meteor/client/views/notFound/NotFoundPage.js b/apps/meteor/client/views/notFound/NotFoundPage.js deleted file mode 100644 index fd78d24879c1..000000000000 --- a/apps/meteor/client/views/notFound/NotFoundPage.js +++ /dev/null @@ -1,63 +0,0 @@ -import { Box, Button, ButtonGroup, Flex, Margins } from '@rocket.chat/fuselage'; -import { useRoute, useTranslation } from '@rocket.chat/ui-contexts'; -import React from 'react'; - -function NotFoundPage() { - const t = useTranslation(); - const homeRoute = useRoute('home'); - - const handleGoToPreviousPageClick = () => { - window.history.back(); - }; - - const handleGoHomeClick = () => { - homeRoute.push(); - }; - - return ( - - - - - - - 404 - - - - {t('Oops_page_not_found')} - - - - {t('Sorry_page_you_requested_does_not_exist_or_was_deleted')} - - - - - - - - - - - - ); -} - -export default NotFoundPage; From 9317fe9dcef95373403de75aad7dcc418d5e47db Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Fri, 3 Jun 2022 16:26:55 -0300 Subject: [PATCH 4/6] Update CODEOWNERS --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 534f23be0100..a3ae6a000b42 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -9,3 +9,4 @@ /_templates/ @RocketChat/chat-engine /apps/meteor/client/ @RocketChat/frontend /apps/meteor/tests/ @RocketChat/chat-engine +/apps/meteor/app/apps/ @RocketChat/apps From 7e8d6d24081669f109a9e24b387cb350f4a9297b Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Fri, 3 Jun 2022 17:43:16 -0300 Subject: [PATCH 5/6] Update package.json (#25755) --- apps/meteor/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 7a9c64e9ca61..39ddbbd81a67 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -28,7 +28,7 @@ "obj:dev": "TEST_MODE=true yarn dev", "stylelint": "stylelint \"app/**/*.css\" \"client/**/*.css\" \"app/**/*.less\" \"client/**/*.less\" \"ee/**/*.less\"", "stylelint:fix": "stylelint --fix \"app/**/*.css\" \"client/**/*.css\" \"app/**/*.less\" \"client/**/*.less\" \"ee/**/*.less\"", - "typecheck": "cross-env NODE_OPTIONS=\"--max-old-space-size=4092\" tsc --noEmit --skipLibCheck", + "typecheck": "cross-env NODE_OPTIONS=\"--max-old-space-size=8184\" tsc --noEmit --skipLibCheck", "deploy": "npm run build && pm2 startOrRestart pm2.json", "coverage": "nyc -r html mocha --config ./.mocharc.js", "testci": "node .scripts/start.js", From 0b1073ecde996288d75f0274de7a6c614b180c51 Mon Sep 17 00:00:00 2001 From: Felipe <84182706+felipe-rod123@users.noreply.github.com> Date: Fri, 3 Jun 2022 17:57:34 -0300 Subject: [PATCH 6/6] Chore: add Ajv JSON Schema to api/v1 (#25601) --- apps/meteor/app/api/server/v1/im.ts | 11 +- .../imports/server/rest/departments.ts | 7 +- .../Omnichannel/hooks/useDepartmentsList.ts | 5 +- .../omnichannel/directory/calls/CallTable.tsx | 4 +- .../omnichannel/queueList/hooks/useQuery.ts | 6 +- .../tests/end-to-end/api/04-direct-message.js | 1 - packages/rest-typings/src/index.ts | 2 + packages/rest-typings/src/v1/banners.ts | 86 +- packages/rest-typings/src/v1/chat.ts | 420 ++++++++- packages/rest-typings/src/v1/cloud.ts | 72 +- packages/rest-typings/src/v1/customSounds.ts | 37 +- .../rest-typings/src/v1/customUserStatus.ts | 34 +- packages/rest-typings/src/v1/directory.ts | 40 +- .../rest-typings/src/v1/dm/DmCloseProps.ts | 20 + .../rest-typings/src/v1/dm/DmHistoryProps.ts | 56 ++ .../rest-typings/src/v1/dm/DmKickProps.ts | 24 + .../rest-typings/src/v1/dm/DmLeaveProps.ts | 20 + packages/rest-typings/src/v1/dm/im.ts | 22 +- packages/rest-typings/src/v1/dns.ts | 44 +- packages/rest-typings/src/v1/e2e.ts | 96 +- packages/rest-typings/src/v1/email-inbox.ts | 181 +++- packages/rest-typings/src/v1/emojiCustom.ts | 43 +- packages/rest-typings/src/v1/groups.ts | 356 +++++++- packages/rest-typings/src/v1/invites.ts | 43 +- packages/rest-typings/src/v1/ldap.ts | 25 +- packages/rest-typings/src/v1/licenses.ts | 24 +- packages/rest-typings/src/v1/oauthapps.ts | 4 +- packages/rest-typings/src/v1/omnichannel.ts | 854 ++++++++++++++++-- packages/rest-typings/src/v1/permissions.ts | 30 +- packages/rest-typings/src/v1/push.ts | 56 +- packages/rest-typings/src/v1/roles.ts | 68 +- packages/rest-typings/src/v1/rooms.ts | 451 +++++++-- packages/rest-typings/src/v1/statistics.ts | 59 +- packages/rest-typings/src/v1/users.ts | 126 ++- .../rest-typings/src/v1/videoConference.ts | 28 +- packages/rest-typings/src/v1/voip.ts | 518 ++++++++++- 36 files changed, 3577 insertions(+), 296 deletions(-) create mode 100644 packages/rest-typings/src/v1/dm/DmCloseProps.ts create mode 100644 packages/rest-typings/src/v1/dm/DmHistoryProps.ts create mode 100644 packages/rest-typings/src/v1/dm/DmKickProps.ts create mode 100644 packages/rest-typings/src/v1/dm/DmLeaveProps.ts diff --git a/apps/meteor/app/api/server/v1/im.ts b/apps/meteor/app/api/server/v1/im.ts index 76542f1e5582..5795f9601ac2 100644 --- a/apps/meteor/app/api/server/v1/im.ts +++ b/apps/meteor/app/api/server/v1/im.ts @@ -2,7 +2,14 @@ * Docs: https://github.com/RocketChat/developer-docs/blob/master/reference/api/rest-api/endpoints/team-collaboration-endpoints/im-endpoints */ import type { IMessage, IRoom, ISetting, ISubscription, IUpload, IUser } from '@rocket.chat/core-typings'; -import { isDmDeleteProps, isDmFileProps, isDmMemberProps, isDmMessagesProps, isDmCreateProps } from '@rocket.chat/rest-typings'; +import { + isDmDeleteProps, + isDmFileProps, + isDmMemberProps, + isDmMessagesProps, + isDmCreateProps, + isDmHistoryProps, +} from '@rocket.chat/rest-typings'; import { Meteor } from 'meteor/meteor'; import { Match, check } from 'meteor/check'; @@ -240,7 +247,7 @@ API.v1.addRoute( API.v1.addRoute( ['dm.history', 'im.history'], - { authRequired: true }, + { authRequired: true, validateParams: isDmHistoryProps }, { async get() { const { offset = 0, count = 20 } = this.getPaginationItems(); diff --git a/apps/meteor/app/livechat/imports/server/rest/departments.ts b/apps/meteor/app/livechat/imports/server/rest/departments.ts index ab8ee8a66e42..e501782744d4 100644 --- a/apps/meteor/app/livechat/imports/server/rest/departments.ts +++ b/apps/meteor/app/livechat/imports/server/rest/departments.ts @@ -1,3 +1,4 @@ +import { isLivechatDepartmentProps } from '@rocket.chat/rest-typings'; import { Match, check } from 'meteor/check'; import { API } from '../../../../api/server'; @@ -14,9 +15,9 @@ import { API.v1.addRoute( 'livechat/department', - { authRequired: true }, + { authRequired: true, validateParams: isLivechatDepartmentProps }, { - get() { + async get() { const { offset, count } = this.getPaginationItems(); const { sort } = this.parseJsonQuery(); @@ -26,7 +27,7 @@ API.v1.addRoute( findDepartments({ userId: this.userId, text, - enabled, + enabled: enabled === 'true', onlyMyDepartments: onlyMyDepartments === 'true', excludeDepartmentId, pagination: { diff --git a/apps/meteor/client/components/Omnichannel/hooks/useDepartmentsList.ts b/apps/meteor/client/components/Omnichannel/hooks/useDepartmentsList.ts index a80ea72447ab..1d87a9f6e6da 100644 --- a/apps/meteor/client/components/Omnichannel/hooks/useDepartmentsList.ts +++ b/apps/meteor/client/components/Omnichannel/hooks/useDepartmentsList.ts @@ -27,9 +27,8 @@ export const useDepartmentsList = ( const t = useTranslation(); const [itemsList, setItemsList] = useState(() => new RecordList()); const reload = useCallback(() => setItemsList(new RecordList()), []); - const endpoint = 'livechat/department'; - const getDepartments = useEndpoint('GET', endpoint); + const getDepartments = useEndpoint('GET', 'livechat/department'); useComponentDidUpdate(() => { options && reload(); @@ -44,7 +43,7 @@ export const useDepartmentsList = ( count: end + start, sort: `{ "name": 1 }`, excludeDepartmentId: options.excludeDepartmentId, - enabled: options.enabled, + enabled: options.enabled ? 'true' : 'false', }); const items = departments diff --git a/apps/meteor/client/views/omnichannel/directory/calls/CallTable.tsx b/apps/meteor/client/views/omnichannel/directory/calls/CallTable.tsx index 2c9485b74e4d..7d964af4c16a 100644 --- a/apps/meteor/client/views/omnichannel/directory/calls/CallTable.tsx +++ b/apps/meteor/client/views/omnichannel/directory/calls/CallTable.tsx @@ -22,7 +22,7 @@ const useQuery = ( userIdLoggedIn: string | null, ): { sort: string; - open: boolean; + open: 'false'; roomName: string; agents: string[]; count?: number; @@ -31,7 +31,7 @@ const useQuery = ( useMemo( () => ({ sort: JSON.stringify({ [column]: direction === 'asc' ? 1 : -1 }), - open: false, + open: 'false', roomName: text || '', agents: userIdLoggedIn ? [userIdLoggedIn] : [], ...(itemsPerPage && { count: itemsPerPage }), diff --git a/apps/meteor/client/views/omnichannel/queueList/hooks/useQuery.ts b/apps/meteor/client/views/omnichannel/queueList/hooks/useQuery.ts index 880c157455d4..76a5fe26dfcb 100644 --- a/apps/meteor/client/views/omnichannel/queueList/hooks/useQuery.ts +++ b/apps/meteor/client/views/omnichannel/queueList/hooks/useQuery.ts @@ -12,7 +12,7 @@ type useQueryType = ( debouncedSort: [string, 'asc' | 'desc'], ) => { agentId?: ILivechatAgent['_id']; - includeOfflineAgents?: boolean; + includeOfflineAgents?: 'true' | 'false'; departmentId?: ILivechatAgent['_id']; offset: number; count: number; @@ -25,7 +25,7 @@ export const useQuery: useQueryType = ({ servedBy, status, departmentId, itemsPe useMemo(() => { const query: { agentId?: string; - includeOflineAgents?: boolean; + includeOflineAgents?: 'true' | 'false'; departmentId?: string; sort: string; count: number; @@ -39,7 +39,7 @@ export const useQuery: useQueryType = ({ servedBy, status, departmentId, itemsPe }; if (status !== 'online') { - query.includeOflineAgents = true; + query.includeOflineAgents = 'true'; } if (servedBy) { query.agentId = servedBy; diff --git a/apps/meteor/tests/end-to-end/api/04-direct-message.js b/apps/meteor/tests/end-to-end/api/04-direct-message.js index d1f6e82dc75e..9eb450539ab9 100644 --- a/apps/meteor/tests/end-to-end/api/04-direct-message.js +++ b/apps/meteor/tests/end-to-end/api/04-direct-message.js @@ -170,7 +170,6 @@ describe('[Direct Messages]', function () { .set(credentials) .query({ roomId: directMessage._id, - userId: 'rocket.cat', }) .expect('Content-Type', 'application/json') .expect(200) diff --git a/packages/rest-typings/src/index.ts b/packages/rest-typings/src/index.ts index a8dfe71b3cf0..75274d973509 100644 --- a/packages/rest-typings/src/index.ts +++ b/packages/rest-typings/src/index.ts @@ -157,7 +157,9 @@ export * from './v1/channels/ChannelsConvertToTeamProps'; export * from './v1/channels/ChannelsSetReadOnlyProps'; export * from './v1/channels/ChannelsDeleteProps'; export * from './v1/dm'; +export * from './v1/dm/DmHistoryProps'; export * from './v1/integrations'; +export * from './v1/omnichannel'; export * from './v1/oauthapps'; export * from './helpers/PaginatedRequest'; export * from './helpers/PaginatedResult'; diff --git a/packages/rest-typings/src/v1/banners.ts b/packages/rest-typings/src/v1/banners.ts index 2af16f69620d..7045e2383a14 100644 --- a/packages/rest-typings/src/v1/banners.ts +++ b/packages/rest-typings/src/v1/banners.ts @@ -1,26 +1,104 @@ +import Ajv from 'ajv'; import type { BannerPlatform, IBanner } from '@rocket.chat/core-typings'; +const ajv = new Ajv({ + coerceTypes: true, +}); + +type BannersGetNew = { + platform: BannerPlatform; + bid: IBanner['_id']; +}; + +const BannersGetNewSchema = { + type: 'object', + properties: { + platform: { + type: 'string', + enum: ['1', '2'], + }, + bid: { + type: 'string', + }, + }, + required: ['platform', 'bid'], + additionalProperties: false, +}; + +export const isBannersGetNewProps = ajv.compile(BannersGetNewSchema); + +type BannersId = { + platform: BannerPlatform; +}; + +const BannersIdSchema = { + type: 'object', + properties: { + platform: { + type: 'string', + }, + }, + required: ['platform'], + additionalProperties: false, +}; + +export const isBannersIdProps = ajv.compile(BannersIdSchema); + +type Banners = { + platform: BannerPlatform; +}; + +const BannersSchema = { + type: 'object', + properties: { + platform: { + type: 'string', + }, + }, + required: ['platform'], + additionalProperties: false, +}; + +export const isBannersProps = ajv.compile(BannersSchema); + +type BannersDismiss = { + bannerId: string; +}; + +const BannersDismissSchema = { + type: 'object', + properties: { + bannerId: { + type: 'string', + }, + }, + required: ['bannerId'], + additionalProperties: false, +}; + +export const isBannersDismissProps = ajv.compile(BannersDismissSchema); + export type BannersEndpoints = { /* @deprecated */ 'banners.getNew': { - GET: (params: { platform: BannerPlatform; bid: IBanner['_id'] }) => { + GET: (params: BannersGetNew) => { banners: IBanner[]; }; }; 'banners/:id': { - GET: (params: { platform: BannerPlatform }) => { + GET: (params: BannersId) => { banners: IBanner[]; }; }; 'banners': { - GET: (params: { platform: BannerPlatform }) => { + GET: (params: Banners) => { banners: IBanner[]; }; }; 'banners.dismiss': { - POST: (params: { bannerId: string }) => void; + POST: (params: BannersDismiss) => void; }; }; diff --git a/packages/rest-typings/src/v1/chat.ts b/packages/rest-typings/src/v1/chat.ts index e22ab320c99f..1754c302f5a9 100644 --- a/packages/rest-typings/src/v1/chat.ts +++ b/packages/rest-typings/src/v1/chat.ts @@ -1,46 +1,432 @@ import type { IMessage, IRoom, ReadReceipt } from '@rocket.chat/core-typings'; +import Ajv from 'ajv'; + +const ajv = new Ajv({ + coerceTypes: true, +}); + +type ChatFollowMessage = { + mid: IMessage['_id']; +}; + +const chatFollowMessageSchema = { + type: 'object', + properties: { + mid: { + type: 'string', + }, + }, + required: ['mid'], + additionalProperties: false, +}; + +export const isChatFollowMessageProps = ajv.compile(chatFollowMessageSchema); + +type ChatUnfollowMessage = { + mid: IMessage['_id']; +}; + +const chatUnfollowMessageSchema = { + type: 'object', + properties: { + mid: { + type: 'string', + }, + }, + required: ['mid'], + additionalProperties: false, +}; + +export const isChatUnfollowMessageProps = ajv.compile(chatUnfollowMessageSchema); + +type ChatGetMessage = { + msgId: IMessage['_id']; +}; + +const ChatGetMessageSchema = { + type: 'object', + properties: { + msgId: { + type: 'string', + }, + }, + required: ['msgId'], + additionalProperties: false, +}; + +export const isChatGetMessageProps = ajv.compile(ChatGetMessageSchema); + +type ChatStarMessage = { + msgId: IMessage['_id']; +}; + +const ChatStarMessageSchema = { + type: 'object', + properties: { + msgId: { + type: 'string', + }, + }, + required: ['msgId'], + additionalProperties: false, +}; + +export const isChatStarMessageProps = ajv.compile(ChatStarMessageSchema); + +type ChatUnstarMessage = { + msgId: IMessage['_id']; +}; + +const ChatUnstarMessageSchema = { + type: 'object', + properties: { + msgId: { + type: 'string', + }, + }, + required: ['msgId'], + additionalProperties: false, +}; + +export const isChatUnstarMessageProps = ajv.compile(ChatUnstarMessageSchema); + +type ChatPinMessage = { + msgId: IMessage['_id']; +}; + +const ChatPinMessageSchema = { + type: 'object', + properties: { + msgId: { + type: 'string', + }, + }, + required: ['msgId'], + additionalProperties: false, +}; + +export const isChatPinMessageProps = ajv.compile(ChatPinMessageSchema); + +type ChatUnpinMessage = { + messageId: IMessage['_id']; +}; + +const ChatUnpinMessageSchema = { + type: 'object', + properties: { + messageId: { + type: 'string', + }, + }, + required: ['messageId'], + additionalProperties: false, +}; + +export const isChatUnpinMessageProps = ajv.compile(ChatUnpinMessageSchema); + +type ChatGetDiscussions = { + roomId: IRoom['_id']; + text?: string; + offset: number; + count: number; +}; + +const ChatGetDiscussionsSchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + text: { + type: 'string', + nullable: true, + }, + offset: { + type: 'number', + }, + count: { + type: 'number', + }, + }, + required: ['roomId', 'offset', 'count'], + additionalProperties: false, +}; + +export const isChatGetDiscussionsProps = ajv.compile(ChatGetDiscussionsSchema); + +type ChatReportMessage = { + messageId: IMessage['_id']; + description: string; +}; + +const ChatReportMessageSchema = { + type: 'object', + properties: { + messageId: { + type: 'string', + }, + description: { + type: 'string', + }, + }, + required: ['messageId', 'description'], + additionalProperties: false, +}; + +export const isChatReportMessageProps = ajv.compile(ChatReportMessageSchema); + +type ChatGetThreadsList = { + rid: IRoom['_id']; + type: 'unread' | 'following' | 'all'; + text?: string; + offset: number; + count: number; +}; + +const ChatGetThreadsListSchema = { + type: 'object', + properties: { + rid: { + type: 'string', + }, + type: { + type: 'string', + }, + text: { + type: 'string', + nullable: true, + }, + offset: { + type: 'number', + }, + count: { + type: 'number', + }, + }, + required: ['rid', 'type', 'offset', 'count'], + additionalProperties: false, +}; + +export const isChatGetThreadsListProps = ajv.compile(ChatGetThreadsListSchema); + +type ChatSyncThreadsList = { + rid: IRoom['_id']; + updatedSince: string; +}; + +const ChatSyncThreadsListSchema = { + type: 'object', + properties: { + rid: { + type: 'string', + }, + updatedSince: { + type: 'string', + }, + }, + required: ['rid', 'updatedSince'], + additionalProperties: false, +}; + +export const isChatSyncThreadsListProps = ajv.compile(ChatSyncThreadsListSchema); + +type ChatDelete = { + msgId: IMessage['_id']; + roomId: IRoom['_id']; +}; + +const ChatDeleteSchema = { + type: 'object', + properties: { + msgId: { + type: 'string', + }, + roomId: { + type: 'string', + }, + }, + required: ['msgId', 'roomId'], + additionalProperties: false, +}; + +export const isChatDeleteProps = ajv.compile(ChatDeleteSchema); + +type ChatReact = { emoji: string; messageId: IMessage['_id'] } | { reaction: string; messageId: IMessage['_id'] }; + +const ChatReactSchema = { + oneOf: [ + { + type: 'object', + properties: { + emoji: { + type: 'string', + }, + messageId: { + type: 'string', + }, + }, + required: ['emoji', 'messageId'], + additionalProperties: false, + }, + { + type: 'object', + properties: { + reaction: { + type: 'string', + }, + messageId: { + type: 'string', + }, + }, + required: ['reaction', 'messageId'], + additionalProperties: false, + }, + ], +}; + +export const isChatReactProps = ajv.compile(ChatReactSchema); + +/** + * The param `ignore` cannot be boolean, since this is a GET method. Use strings 'true' or 'false' instead. + * @param {string} ignore + */ +type ChatIgnoreUser = { + rid: string; + userId: string; + ignore: string; +}; + +const ChatIgnoreUserSchema = { + type: 'object', + properties: { + rid: { + type: 'string', + }, + userId: { + type: 'string', + }, + ignore: { + type: 'string', + }, + }, + required: ['rid', 'userId', 'ignore'], + additionalProperties: false, +}; + +export const isChatIgnoreUserProps = ajv.compile(ChatIgnoreUserSchema); + +type ChatSearch = { + roomId: IRoom['_id']; + searchText: string; + count: number; + offset: number; +}; + +const ChatSearchSchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + searchText: { + type: 'string', + }, + count: { + type: 'number', + }, + offset: { + type: 'number', + }, + }, + required: ['roomId', 'searchText', 'count', 'offset'], + additionalProperties: false, +}; + +export const isChatSearchProps = ajv.compile(ChatSearchSchema); + +type ChatUpdate = { + roomId: IRoom['_id']; + msgId: string; + text: string; +}; + +const ChatUpdateSchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + msgId: { + type: 'string', + }, + text: { + type: 'string', + }, + }, + required: ['roomId', 'msgId', 'text'], + additionalProperties: false, +}; + +export const isChatUpdateProps = ajv.compile(ChatUpdateSchema); + +type ChatGetMessageReadReceipts = { + messageId: IMessage['_id']; +}; + +const ChatGetMessageReadReceiptsSchema = { + type: 'object', + properties: { + messageId: { + type: 'string', + }, + }, + required: ['messageId'], + additionalProperties: false, +}; + +export const isChatGetMessageReadReceiptsProps = ajv.compile(ChatGetMessageReadReceiptsSchema); export type ChatEndpoints = { 'chat.getMessage': { - GET: (params: { msgId: IMessage['_id'] }) => { + GET: (params: ChatGetMessage) => { message: IMessage; }; }; 'chat.followMessage': { - POST: (params: { mid: IMessage['_id'] }) => void; + POST: (params: ChatFollowMessage) => void; }; 'chat.unfollowMessage': { - POST: (params: { mid: IMessage['_id'] }) => void; + POST: (params: ChatUnfollowMessage) => void; }; 'chat.starMessage': { - POST: (params: { messageId: IMessage['_id'] }) => void; + POST: (params: ChatStarMessage) => void; }; 'chat.unStarMessage': { - POST: (params: { messageId: IMessage['_id'] }) => void; + POST: (params: ChatUnstarMessage) => void; }; 'chat.pinMessage': { - POST: (params: { messageId: IMessage['_id'] }) => void; + POST: (params: ChatPinMessage) => void; }; 'chat.unPinMessage': { - POST: (params: { messageId: IMessage['_id'] }) => void; + POST: (params: ChatUnpinMessage) => void; }; 'chat.reportMessage': { - POST: (params: { messageId: IMessage['_id']; description: string }) => void; + POST: (params: ChatReportMessage) => void; }; 'chat.getDiscussions': { - GET: (params: { roomId: IRoom['_id']; text?: string; offset: number; count: number }) => { + GET: (params: ChatGetDiscussions) => { messages: IMessage[]; total: number; }; }; 'chat.getThreadsList': { - GET: (params: { rid: IRoom['_id']; type: 'unread' | 'following' | 'all'; text?: string; offset: number; count: number }) => { + GET: (params: ChatGetThreadsList) => { threads: IMessage[]; total: number; }; }; 'chat.syncThreadsList': { - GET: (params: { rid: IRoom['_id']; updatedSince: string }) => { + GET: (params: ChatSyncThreadsList) => { threads: { update: IMessage[]; remove: IMessage[]; @@ -48,29 +434,29 @@ export type ChatEndpoints = { }; }; 'chat.delete': { - POST: (params: { msgId: string; roomId: string }) => { + POST: (params: ChatDelete) => { _id: string; ts: string; message: Pick; }; }; 'chat.react': { - POST: (params: { emoji: string; messageId: string } | { reaction: string; messageId: string }) => void; + POST: (params: ChatReact) => void; }; 'chat.ignoreUser': { - GET: (params: { rid: string; userId: string; ignore: boolean }) => {}; + GET: (params: ChatIgnoreUser) => {}; }; 'chat.search': { - GET: (params: { roomId: IRoom['_id']; searchText: string; count: number; offset: number }) => { + GET: (params: ChatSearch) => { messages: IMessage[]; }; }; 'chat.update': { - POST: (params: { roomId: IRoom['_id']; msgId: string; text: string }) => { + POST: (params: ChatUpdate) => { messages: IMessage; }; }; 'chat.getMessageReadReceipts': { - GET: (params: { messageId: string }) => { receipts: ReadReceipt[] }; + GET: (params: ChatGetMessageReadReceipts) => { receipts: ReadReceipt[] }; }; }; diff --git a/packages/rest-typings/src/v1/cloud.ts b/packages/rest-typings/src/v1/cloud.ts index c5f56e26f097..e27289566711 100644 --- a/packages/rest-typings/src/v1/cloud.ts +++ b/packages/rest-typings/src/v1/cloud.ts @@ -1,16 +1,82 @@ import type { CloudRegistrationIntentData, CloudConfirmationPollData, CloudRegistrationStatus } from '@rocket.chat/core-typings'; +import Ajv from 'ajv'; + +const ajv = new Ajv({ + coerceTypes: true, +}); + +type CloudManualRegister = { + cloudBlob: string; +}; + +const CloudManualRegisterSchema = { + type: 'object', + properties: { + cloudBlob: { + type: 'string', + }, + }, + required: ['cloudBlob'], + additionalProperties: false, +}; + +export const isCloudManualRegisterProps = ajv.compile(CloudManualRegisterSchema); + +type CloudCreateRegistrationIntent = { + resend: boolean; + email: string; +}; + +const CloudCreateRegistrationIntentSchema = { + type: 'object', + properties: { + resend: { + type: 'boolean', + }, + email: { + type: 'string', + }, + }, + required: ['resend', 'email'], + additionalProperties: false, +}; + +export const isCloudCreateRegistrationIntentProps = ajv.compile(CloudCreateRegistrationIntentSchema); + +type CloudConfirmationPoll = { + deviceCode: string; + resend?: string; +}; + +const CloudConfirmationPollSchema = { + type: 'object', + properties: { + deviceCode: { + type: 'string', + }, + resend: { + type: 'string', + nullable: true, + }, + }, + required: ['deviceCode'], + optionalProperties: ['resend'], + additionalProperties: false, +}; + +export const isCloudConfirmationPollProps = ajv.compile(CloudConfirmationPollSchema); export type CloudEndpoints = { 'cloud.manualRegister': { - POST: (params: { cloudBlob: string }) => void; + POST: (params: CloudManualRegister) => void; }; 'cloud.createRegistrationIntent': { - POST: (params: { resend: boolean; email: string }) => { + POST: (params: CloudCreateRegistrationIntent) => { intentData: CloudRegistrationIntentData; }; }; 'cloud.confirmationPoll': { - GET: (params: { deviceCode: string; resend?: boolean }) => { + GET: (params: CloudConfirmationPoll) => { pollData: CloudConfirmationPollData; }; }; diff --git a/packages/rest-typings/src/v1/customSounds.ts b/packages/rest-typings/src/v1/customSounds.ts index 1f39263abb67..84efd66ecb60 100644 --- a/packages/rest-typings/src/v1/customSounds.ts +++ b/packages/rest-typings/src/v1/customSounds.ts @@ -1,10 +1,43 @@ -import type { ICustomSound } from '../../../core-typings/dist'; +import type { ICustomSound } from '@rocket.chat/core-typings'; +import Ajv from 'ajv'; + import type { PaginatedRequest } from '../helpers/PaginatedRequest'; import type { PaginatedResult } from '../helpers/PaginatedResult'; +const ajv = new Ajv({ + coerceTypes: true, +}); + +type CustomSoundsList = PaginatedRequest<{ query: string }>; + +const CustomSoundsListSchema = { + type: 'object', + properties: { + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + query: { + type: 'string', + }, + }, + required: ['query'], + additionalProperties: false, +}; + +export const isCustomSoundsListProps = ajv.compile(CustomSoundsListSchema); + export type CustomSoundEndpoint = { 'custom-sounds.list': { - GET: (params: PaginatedRequest<{ query: string }>) => PaginatedResult<{ + GET: (params: CustomSoundsList) => PaginatedResult<{ sounds: ICustomSound[]; }>; }; diff --git a/packages/rest-typings/src/v1/customUserStatus.ts b/packages/rest-typings/src/v1/customUserStatus.ts index 943aebb9fdca..dfd30aa9a117 100644 --- a/packages/rest-typings/src/v1/customUserStatus.ts +++ b/packages/rest-typings/src/v1/customUserStatus.ts @@ -1,11 +1,43 @@ import type { ICustomUserStatus, IUserStatus } from '@rocket.chat/core-typings'; +import Ajv from 'ajv'; import type { PaginatedRequest } from '../helpers/PaginatedRequest'; import type { PaginatedResult } from '../helpers/PaginatedResult'; +const ajv = new Ajv({ + coerceTypes: true, +}); + +type CustomUserStatusListProps = PaginatedRequest<{ query: string }>; + +const CustomUserStatusListSchema = { + type: 'object', + properties: { + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + query: { + type: 'string', + }, + }, + required: ['query'], + additionalProperties: false, +}; + +export const isCustomUserStatusListProps = ajv.compile(CustomUserStatusListSchema); + export type CustomUserStatusEndpoints = { 'custom-user-status.list': { - GET: (params: PaginatedRequest<{ query: string }>) => PaginatedResult<{ + GET: (params: CustomUserStatusListProps) => PaginatedResult<{ statuses: IUserStatus[]; }>; }; diff --git a/packages/rest-typings/src/v1/directory.ts b/packages/rest-typings/src/v1/directory.ts index fda67ddf9810..af0ad5be6d8d 100644 --- a/packages/rest-typings/src/v1/directory.ts +++ b/packages/rest-typings/src/v1/directory.ts @@ -1,14 +1,42 @@ import type { IRoom } from '@rocket.chat/core-typings'; +import Ajv from 'ajv'; +import type { PaginatedRequest } from '../helpers/PaginatedRequest'; import type { PaginatedResult } from '../helpers/PaginatedResult'; +const ajv = new Ajv({ + coerceTypes: true, +}); + +type DirectoryProps = PaginatedRequest<{}>; + +const DirectorySchema = { + type: 'object', + properties: { + query: { + type: 'string', + nullable: true, + }, + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + }, + additionalProperties: false, +}; + +export const isDirectoryProps = ajv.compile(DirectorySchema); + export type DirectoryEndpoint = { directory: { - GET: (params: { - query: { [key: string]: string }; - count: number; - offset: number; - sort: { [key: string]: number }; - }) => PaginatedResult<{ result: IRoom[] }>; + GET: (params: DirectoryProps) => PaginatedResult<{ result: IRoom[] }>; }; }; diff --git a/packages/rest-typings/src/v1/dm/DmCloseProps.ts b/packages/rest-typings/src/v1/dm/DmCloseProps.ts new file mode 100644 index 000000000000..1a1ea759680a --- /dev/null +++ b/packages/rest-typings/src/v1/dm/DmCloseProps.ts @@ -0,0 +1,20 @@ +import Ajv, { JSONSchemaType } from 'ajv'; + +const ajv = new Ajv(); + +export type DmCloseProps = { + roomId: string; +}; + +const DmClosePropsSchema: JSONSchemaType = { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + }, + required: ['roomId'], + additionalProperties: false, +}; + +export const isDmCloseProps = ajv.compile(DmClosePropsSchema); diff --git a/packages/rest-typings/src/v1/dm/DmHistoryProps.ts b/packages/rest-typings/src/v1/dm/DmHistoryProps.ts new file mode 100644 index 000000000000..0a836961f366 --- /dev/null +++ b/packages/rest-typings/src/v1/dm/DmHistoryProps.ts @@ -0,0 +1,56 @@ +import type { PaginatedRequest } from '@rocket.chat/rest-typings/src/helpers/PaginatedRequest'; +import Ajv from 'ajv'; + +const ajv = new Ajv(); + +export type DmHistoryProps = PaginatedRequest<{ + roomId: string; + latest?: string; + oldest?: string; + inclusive?: 'false' | 'true'; + unreads?: 'true' | 'false'; + showThreadMessages?: 'false' | 'true'; +}>; + +const DmHistoryPropsSchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + minLength: 1, + }, + latest: { + type: 'string', + minLength: 1, + }, + showThreadMessages: { + type: 'string', + enum: ['false', 'true'], + }, + oldest: { + type: 'string', + minLength: 1, + }, + inclusive: { + type: 'string', + enum: ['false', 'true'], + }, + unreads: { + type: 'string', + enum: ['true', 'false'], + }, + count: { + type: 'number', + }, + offset: { + type: 'number', + }, + sort: { + type: 'string', + }, + }, + required: ['roomId'], + additionalProperties: false, +}; + +export const isDmHistoryProps = ajv.compile(DmHistoryPropsSchema); diff --git a/packages/rest-typings/src/v1/dm/DmKickProps.ts b/packages/rest-typings/src/v1/dm/DmKickProps.ts new file mode 100644 index 000000000000..beca20ef5dc8 --- /dev/null +++ b/packages/rest-typings/src/v1/dm/DmKickProps.ts @@ -0,0 +1,24 @@ +import Ajv, { JSONSchemaType } from 'ajv'; + +const ajv = new Ajv(); + +type DmKickProps = { + roomId: string; + userId: string; +}; + +const DmKickPropsSchema: JSONSchemaType = { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + userId: { + type: 'string', + }, + }, + required: ['roomId', 'userId'], + additionalProperties: false, +}; + +export const isDmKickProps = ajv.compile(DmKickPropsSchema); diff --git a/packages/rest-typings/src/v1/dm/DmLeaveProps.ts b/packages/rest-typings/src/v1/dm/DmLeaveProps.ts new file mode 100644 index 000000000000..a91ee8ba9a91 --- /dev/null +++ b/packages/rest-typings/src/v1/dm/DmLeaveProps.ts @@ -0,0 +1,20 @@ +import Ajv, { JSONSchemaType } from 'ajv'; + +const ajv = new Ajv(); + +export type DmLeaveProps = { + roomId: string; +}; + +const DmLeavePropsSchema: JSONSchemaType = { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + }, + required: ['roomId'], + additionalProperties: false, +}; + +export const isDmLeaveProps = ajv.compile(DmLeavePropsSchema); diff --git a/packages/rest-typings/src/v1/dm/im.ts b/packages/rest-typings/src/v1/dm/im.ts index 927f7ac3458f..87c4adfe4fa7 100644 --- a/packages/rest-typings/src/v1/dm/im.ts +++ b/packages/rest-typings/src/v1/dm/im.ts @@ -2,9 +2,12 @@ import type { IMessage, IRoom, IUser, IUpload } from '@rocket.chat/core-typings' import type { PaginatedRequest } from '../../helpers/PaginatedRequest'; import type { PaginatedResult } from '../../helpers/PaginatedResult'; +import type { DmCloseProps } from './DmCloseProps'; import type { DmCreateProps } from './DmCreateProps'; import type { DmDeleteProps } from './DmDeleteProps'; import type { DmFileProps } from './DmFileProps'; +import type { DmHistoryProps } from './DmHistoryProps'; +import type { DmLeaveProps } from './DmLeaveProps'; import type { DmMemberProps } from './DmMembersProps'; import type { DmMessagesProps } from './DmMessagesProps'; @@ -18,7 +21,13 @@ export type ImEndpoints = { POST: (params: DmDeleteProps) => void; }; 'im.close': { - POST: (params: { roomId: string }) => void; + POST: (params: DmCloseProps) => void; + }; + 'im.kick': { + POST: (params: DmCloseProps) => void; + }; + 'im.leave': { + POST: (params: DmLeaveProps) => void; }; 'im.counters': { GET: (params: { roomId: string; userId?: string }) => { @@ -37,16 +46,7 @@ export type ImEndpoints = { }>; }; 'im.history': { - GET: ( - params: PaginatedRequest<{ - roomId: string; - latest?: string; - oldest?: string; - inclusive?: string; - unreads?: string; - showThreadMessages?: string; - }>, - ) => { + GET: (params: DmHistoryProps) => { messages: Pick[]; }; }; diff --git a/packages/rest-typings/src/v1/dns.ts b/packages/rest-typings/src/v1/dns.ts index b2d553e036f2..28a630ea3352 100644 --- a/packages/rest-typings/src/v1/dns.ts +++ b/packages/rest-typings/src/v1/dns.ts @@ -1,11 +1,51 @@ +import Ajv from 'ajv'; + +const ajv = new Ajv({ + coerceTypes: true, +}); + +type DnsResolveTxtProps = { + url: string; +}; + +const dnsResolveTxtPropsSchema = { + type: 'object', + properties: { + url: { + type: 'string', + }, + }, + required: ['url'], + additionalProperties: false, +}; + +export const isDnsResolveTxtProps = ajv.compile(dnsResolveTxtPropsSchema); + +type DnsResolveSrvProps = { + url: string; +}; + +const DnsResolveSrvSchema = { + type: 'object', + properties: { + url: { + type: 'string', + }, + }, + required: ['url'], + additionalProperties: false, +}; + +export const isDnsResolveSrvProps = ajv.compile(DnsResolveSrvSchema); + export type DnsEndpoints = { 'dns.resolve.srv': { - GET: (params: { url: string }) => { + GET: (params: DnsResolveSrvProps) => { resolved: Record; }; }; 'dns.resolve.txt': { - POST: (params: { url: string }) => { + POST: (params: DnsResolveTxtProps) => { resolved: string; // resolved: Record; }; diff --git a/packages/rest-typings/src/v1/e2e.ts b/packages/rest-typings/src/v1/e2e.ts index d8bf5f77312c..62ce4110ddbb 100644 --- a/packages/rest-typings/src/v1/e2e.ts +++ b/packages/rest-typings/src/v1/e2e.ts @@ -1,19 +1,107 @@ +/* eslint-disable @typescript-eslint/camelcase */ import type { IUser } from '@rocket.chat/core-typings'; +import Ajv from 'ajv'; + +const ajv = new Ajv({ + coerceTypes: true, +}); + +type E2eSetUserPublicAndPrivateKeysProps = { + public_key: string; + private_key: string; +}; + +const E2eSetUserPublicAndPrivateKeysSchema = { + type: 'object', + properties: { + public_key: { + type: 'string', + }, + private_key: { + type: 'string', + }, + }, + required: ['public_key', 'private_key'], + additionalProperties: false, +}; + +export const isE2eSetUserPublicAndPrivateKeysProps = ajv.compile(E2eSetUserPublicAndPrivateKeysSchema); + +type E2eGetUsersOfRoomWithoutKeyProps = { rid: string }; + +const E2eGetUsersOfRoomWithoutKeySchema = { + type: 'object', + properties: { + rid: { + type: 'string', + }, + }, + required: ['rid'], + additionalProperties: false, +}; + +export const isE2eGetUsersOfRoomWithoutKeyProps = ajv.compile(E2eGetUsersOfRoomWithoutKeySchema); + +type E2eUpdateGroupKeyProps = { + uid: string; + rid: string; + key: string; +}; + +const E2eUpdateGroupKeySchema = { + type: 'object', + properties: { + uid: { + type: 'string', + }, + rid: { + type: 'string', + }, + key: { + type: 'string', + }, + }, + required: ['uid', 'rid', 'key'], + additionalProperties: false, +}; + +export const isE2eUpdateGroupKeyProps = ajv.compile(E2eUpdateGroupKeySchema); + +type E2eSetRoomKeyIdProps = { + rid: string; + keyID: string; +}; + +const E2eSetRoomKeyIdSchema = { + type: 'object', + properties: { + rid: { + type: 'string', + }, + keyID: { + type: 'string', + }, + }, + required: ['rid', 'keyID'], + additionalProperties: false, +}; + +export const isE2eSetRoomKeyIdProps = ajv.compile(E2eSetRoomKeyIdSchema); export type E2eEndpoints = { 'e2e.setUserPublicAndPrivateKeys': { - POST: (params: { public_key: string; private_key: string }) => void; + POST: (params: E2eSetUserPublicAndPrivateKeysProps) => void; }; 'e2e.getUsersOfRoomWithoutKey': { - GET: (params: { rid: string }) => { + GET: (params: E2eGetUsersOfRoomWithoutKeyProps) => { users: Pick[]; }; }; 'e2e.updateGroupKey': { - POST: (params: { uid: string; rid: string; key: string }) => {}; + POST: (params: E2eUpdateGroupKeyProps) => {}; }; 'e2e.setRoomKeyID': { - POST: (params: { rid: string; keyID: string }) => {}; + POST: (params: E2eSetRoomKeyIdProps) => {}; }; 'e2e.fetchMyKeys': { GET: () => { public_key: string; private_key: string }; diff --git a/packages/rest-typings/src/v1/email-inbox.ts b/packages/rest-typings/src/v1/email-inbox.ts index afa4745ed86d..d0347fe7e829 100644 --- a/packages/rest-typings/src/v1/email-inbox.ts +++ b/packages/rest-typings/src/v1/email-inbox.ts @@ -1,43 +1,174 @@ import type { IEmailInbox } from '@rocket.chat/core-typings'; +import Ajv from 'ajv'; import type { PaginatedRequest } from '../helpers/PaginatedRequest'; import type { PaginatedResult } from '../helpers/PaginatedResult'; +const ajv = new Ajv({ + coerceTypes: true, +}); + +type EmailInboxListProps = PaginatedRequest<{ query?: string }>; + +const EmailInboxListPropsSchema = { + type: 'object', + properties: { + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + query: { + type: 'string', + nullable: true, + }, + }, + required: [], + additionalProperties: false, +}; + +export const isEmailInboxList = ajv.compile(EmailInboxListPropsSchema); + +type EmailInboxProps = { + _id?: string; + name: string; + email: string; + active: boolean; // POST method + description: string; + senderInfo: string; + department: string; + smtp: { + password: string; + port: number; + secure: boolean; + server: string; + username: string; + }; + imap: { + password: string; + port: number; + secure: boolean; + server: string; + username: string; + }; +}; + +const EmailInboxPropsSchema = { + type: 'object', + properties: { + _id: { + type: 'string', + nullable: true, + }, + name: { + type: 'string', + }, + email: { + type: 'string', + }, + active: { + type: 'boolean', + }, + description: { + type: 'string', + }, + senderInfo: { + type: 'string', + }, + department: { + type: 'string', + }, + + smtp: { + type: 'object', + properties: { + password: { + type: 'string', + }, + port: { + type: 'number', + }, + secure: { + type: 'boolean', + }, + server: { + type: 'string', + }, + username: { + type: 'string', + }, + }, + required: ['password', 'port', 'secure', 'server', 'username'], + additionalProperties: false, + }, + + imap: { + type: 'object', + properties: { + password: { + type: 'string', + }, + port: { + type: 'number', + }, + secure: { + type: 'boolean', + }, + server: { + type: 'string', + }, + username: { + type: 'string', + }, + }, + required: ['password', 'port', 'secure', 'server', 'username'], + additionalProperties: false, + }, + }, + + required: ['name', 'email', 'active', 'description', 'senderInfo', 'department', 'smtp', 'imap'], + additionalProperties: false, +}; + +export const isEmailInbox = ajv.compile(EmailInboxPropsSchema); + +type EmailInboxSearchProps = { + email: string; +}; + +const EmailInboxSearchPropsSchema = { + type: 'object', + properties: { + email: { + type: 'string', + }, + }, + required: ['email'], + additionalProperties: false, +}; + +export const isEmailInboxSearch = ajv.compile(EmailInboxSearchPropsSchema); + export type EmailInboxEndpoints = { 'email-inbox.list': { - GET: (params: PaginatedRequest<{ query?: string }>) => PaginatedResult<{ emailInboxes: IEmailInbox[] }>; + GET: (params: EmailInboxListProps) => PaginatedResult<{ emailInboxes: IEmailInbox[] }>; }; 'email-inbox': { - POST: (params: { - _id?: string; - name: string; - email: string; - active: boolean; - description: string; - senderInfo: string; - department: string; - smtp: { - password: string; - port: number; - secure: boolean; - server: string; - username: string; - }; - imap: { - password: string; - port: number; - secure: boolean; - server: string; - username: string; - }; - }) => { _id: string }; + POST: (params: EmailInboxProps) => { _id: string }; }; 'email-inbox/:_id': { GET: (params: void) => IEmailInbox | null; DELETE: (params: void) => { _id: string }; }; 'email-inbox.search': { - GET: (params: { email: string }) => { emailInbox: IEmailInbox | null }; + GET: (params: EmailInboxSearchProps) => { emailInbox: IEmailInbox | null }; }; 'email-inbox.send-test/:_id': { POST: (params: void) => { _id: string }; diff --git a/packages/rest-typings/src/v1/emojiCustom.ts b/packages/rest-typings/src/v1/emojiCustom.ts index 0a52dddc940e..2532879dd9a9 100644 --- a/packages/rest-typings/src/v1/emojiCustom.ts +++ b/packages/rest-typings/src/v1/emojiCustom.ts @@ -1,8 +1,47 @@ import type { ICustomEmojiDescriptor } from '@rocket.chat/core-typings'; +import Ajv from 'ajv'; import type { PaginatedRequest } from '../helpers/PaginatedRequest'; import type { PaginatedResult } from '../helpers/PaginatedResult'; +const ajv = new Ajv({ + coerceTypes: true, +}); + +type emojiCustomDeleteProps = { + emojiId: ICustomEmojiDescriptor['_id']; +}; + +const emojiCustomDeletePropsSchema = { + type: 'object', + properties: { + emojiId: { + type: 'string', + }, + }, + required: ['emojiId'], + additionalProperties: false, +}; + +export const isEmojiCustomDelete = ajv.compile(emojiCustomDeletePropsSchema); + +type emojiCustomList = { + query: string; +}; + +const emojiCustomListSchema = { + type: 'object', + properties: { + query: { + type: 'string', + }, + }, + required: ['query'], + additionalProperties: false, +}; + +export const isemojiCustomList = ajv.compile(emojiCustomListSchema); + export type EmojiCustomEndpoints = { 'emoji-custom.all': { GET: (params: PaginatedRequest<{ query: string }, 'name'>) => { @@ -10,13 +49,13 @@ export type EmojiCustomEndpoints = { } & PaginatedResult; }; 'emoji-custom.list': { - GET: (params: { query: string }) => { + GET: (params: emojiCustomList) => { emojis?: { update: ICustomEmojiDescriptor[]; }; }; }; 'emoji-custom.delete': { - POST: (params: { emojiId: ICustomEmojiDescriptor['_id'] }) => void; + POST: (params: emojiCustomDeleteProps) => void; }; }; diff --git a/packages/rest-typings/src/v1/groups.ts b/packages/rest-typings/src/v1/groups.ts index 5cb5db378ffc..10540a3ecd62 100644 --- a/packages/rest-typings/src/v1/groups.ts +++ b/packages/rest-typings/src/v1/groups.ts @@ -1,16 +1,330 @@ import type { IMessage, IRoom, ITeam, IGetRoomRoles, IUser, IUpload } from '@rocket.chat/core-typings'; +import Ajv from 'ajv'; import type { PaginatedRequest } from '../helpers/PaginatedRequest'; import type { PaginatedResult } from '../helpers/PaginatedResult'; +const ajv = new Ajv({ + coerceTypes: true, +}); + +type GroupsFilesProps = { + roomId: IRoom['_id']; + count: number; + sort: string; + query: string; +}; + +const GroupsFilesPropsSchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + count: { + type: 'number', + }, + sort: { + type: 'string', + }, + query: { + type: 'string', + }, + }, + required: ['roomId', 'count', 'sort', 'query'], + additionalProperties: false, +}; + +export const isGroupsFilesProps = ajv.compile(GroupsFilesPropsSchema); + +type GroupsMembersProps = { + roomId: IRoom['_id']; + offset?: number; + count?: number; + filter?: string; + status?: string[]; +}; + +const GroupsMembersPropsSchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + offset: { + type: 'number', + nullable: true, + }, + count: { + type: 'number', + nullable: true, + }, + filter: { + type: 'string', + nullable: true, + }, + status: { + type: 'array', + items: { type: 'string' }, + nullable: true, + }, + }, + required: ['roomId'], + additionalProperties: false, +}; + +export const isGroupsMembersProps = ajv.compile(GroupsMembersPropsSchema); + +type GroupsArchiveProps = { + roomId: IRoom['_id']; +}; + +const GroupsArchivePropsSchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + }, + required: ['roomId'], + additionalProperties: false, +}; + +export const isGroupsArchiveProps = ajv.compile(GroupsArchivePropsSchema); + +type GroupsUnarchiveProps = { + roomId: IRoom['_id']; +}; + +const GroupsUnarchivePropsSchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + }, + required: ['roomId'], + additionalProperties: false, +}; + +export const isGroupsUnarchiveProps = ajv.compile(GroupsUnarchivePropsSchema); + +type GroupsCreateProps = { + name: string; + members: string[]; + readOnly: boolean; + extraData: { + broadcast: boolean; + encrypted: boolean; + teamId?: string; + }; +}; + +const GroupsCreatePropsSchema = { + type: 'object', + properties: { + name: { + type: 'string', + }, + members: { + type: 'array', + items: { type: 'string' }, + }, + readOnly: { + type: 'boolean', + }, + extraData: { + type: 'object', + properties: { + broadcast: { + type: 'boolean', + }, + encrypted: { + type: 'boolean', + }, + teamId: { + type: 'string', + nullable: true, + }, + }, + required: ['broadcast', 'encrypted'], + additionalProperties: false, + }, + }, + required: ['name', 'members', 'readOnly', 'extraData'], + additionalProperties: false, +}; + +export const isGroupsCreateProps = ajv.compile(GroupsCreatePropsSchema); + +type GroupsConvertToTeamProps = { + roomId: string; + roomName: string; +}; + +const GroupsConvertToTeamPropsSchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + roomName: { + type: 'string', + }, + }, + required: ['roomId', 'roomName'], + additionalProperties: false, +}; + +export const isGroupsConvertToTeamProps = ajv.compile(GroupsConvertToTeamPropsSchema); + +type GroupsCountersProps = { + roomId: string; +}; + +const GroupsCountersPropsSchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + }, + required: ['roomId'], + additionalProperties: false, +}; + +export const isGroupsCountersProps = ajv.compile(GroupsCountersPropsSchema); + +type GroupsCloseProps = { + roomId: string; +}; + +const GroupsClosePropsSchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + }, + required: ['roomId'], + additionalProperties: false, +}; + +export const isGroupsCloseProps = ajv.compile(GroupsClosePropsSchema); + +type GroupsDeleteProps = { + roomId: string; +}; + +const GroupsDeletePropsSchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + }, + required: ['roomId'], + additionalProperties: false, +}; + +export const isGroupsDeleteProps = ajv.compile(GroupsDeletePropsSchema); + +type GroupsLeaveProps = { + roomId: string; +}; + +const GroupsLeavePropsSchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + }, + required: ['roomId'], + additionalProperties: false, +}; + +export const isGroupsLeaveProps = ajv.compile(GroupsLeavePropsSchema); + +type GroupsRolesProps = { + roomId: string; +}; + +const GroupsRolesPropsSchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + }, + required: ['roomId'], + additionalProperties: false, +}; + +export const isGroupsRolesProps = ajv.compile(GroupsRolesPropsSchema); + +type GroupsKickProps = { + roomId: string; + userId: string; +}; + +const GroupsKickPropsSchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + userId: { + type: 'string', + }, + }, + required: ['roomId', 'userId'], + additionalProperties: false, +}; + +export const isGroupsKickProps = ajv.compile(GroupsKickPropsSchema); + +type GroupsMessageProps = PaginatedRequest<{ + roomId: IRoom['_id']; +}>; + +const GroupsMessagePropsSchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + query: { + type: 'string', + nullable: true, + }, + }, + required: ['roomId'], + additionalProperties: false, +}; + +export const isGroupsMessageProps = ajv.compile(GroupsMessagePropsSchema); + export type GroupsEndpoints = { 'groups.files': { - GET: (params: PaginatedRequest<{ roomId: IRoom['_id']; query: string }>) => PaginatedResult<{ + GET: (params: GroupsFilesProps) => PaginatedResult<{ files: IUpload[]; }>; }; 'groups.members': { - GET: (params: { roomId: IRoom['_id']; offset?: number; count?: number; filter?: string; status?: string[] }) => { + GET: (params: GroupsMembersProps) => { count: number; offset: number; members: IUser[]; @@ -23,30 +337,21 @@ export type GroupsEndpoints = { }>; }; 'groups.archive': { - POST: (params: { roomId: string }) => void; + POST: (params: GroupsArchiveProps) => void; }; 'groups.unarchive': { - POST: (params: { roomId: string }) => void; + POST: (params: GroupsUnarchiveProps) => void; }; 'groups.create': { - POST: (params: { - name: string; - members: string[]; - readOnly: boolean; - extraData: { - broadcast: boolean; - encrypted: boolean; - teamId?: string; - }; - }) => { + POST: (params: GroupsCreateProps) => { group: Partial; }; }; 'groups.convertToTeam': { - POST: (params: { roomId: string; roomName: string }) => { team: ITeam }; + POST: (params: GroupsConvertToTeamProps) => { team: ITeam }; }; 'groups.counters': { - GET: (params: { roomId: string }) => { + GET: (params: GroupsCountersProps) => { joined: boolean; members: number; unreads: number; @@ -57,28 +362,23 @@ export type GroupsEndpoints = { }; }; 'groups.close': { - POST: (params: { roomId: string }) => {}; + POST: (params: GroupsCloseProps) => {}; }; 'groups.kick': { - POST: (params: { roomId: string; userId: string }) => {}; + POST: (params: GroupsKickProps) => {}; }; 'groups.delete': { - POST: (params: { roomId: string }) => {}; + POST: (params: GroupsDeleteProps) => {}; }; 'groups.leave': { - POST: (params: { roomId: string }) => {}; + POST: (params: GroupsLeaveProps) => {}; }; 'groups.roles': { - GET: (params: { roomId: string }) => { roles: IGetRoomRoles[] }; + GET: (params: GroupsRolesProps) => { roles: IGetRoomRoles[] }; }; 'groups.messages': { - GET: (params: { - roomId: IRoom['_id']; - query: { 'mentions._id': { $in: string[] } } | { 'starred._id': { $in: string[] } } | { pinned: boolean }; - offset: number; - sort: { ts: number }; - }) => { + GET: (params: GroupsMessageProps) => PaginatedResult<{ messages: IMessage[]; - }; + }>; }; }; diff --git a/packages/rest-typings/src/v1/invites.ts b/packages/rest-typings/src/v1/invites.ts index 200302c99711..fda658af2267 100644 --- a/packages/rest-typings/src/v1/invites.ts +++ b/packages/rest-typings/src/v1/invites.ts @@ -1,4 +1,43 @@ import type { IInvite, IRoom } from '@rocket.chat/core-typings'; +import Ajv from 'ajv'; + +const ajv = new Ajv({ + coerceTypes: true, +}); + +type v1UseInviteTokenProps = { + token: string; +}; + +const v1UseInviteTokenPropsSchema = { + type: 'object', + properties: { + token: { + type: 'string', + }, + }, + required: ['token'], + additionalProperties: false, +}; + +export const isV1UseInviteTokenProps = ajv.compile(v1UseInviteTokenPropsSchema); + +type v1ValidateInviteTokenProps = { + token: string; +}; + +const v1ValidateInviteTokenPropsSchema = { + type: 'object', + properties: { + token: { + type: 'string', + }, + }, + required: ['token'], + additionalProperties: false, +}; + +export const isV1ValidateInviteTokenProps = ajv.compile(v1ValidateInviteTokenPropsSchema); export type InvitesEndpoints = { 'listInvites': { @@ -8,7 +47,7 @@ export type InvitesEndpoints = { DELETE: () => void; }; '/v1/useInviteToken': { - POST: (params: { token: string }) => { + POST: (params: v1UseInviteTokenProps) => { room: { rid: IRoom['_id']; prid: IRoom['prid']; @@ -19,6 +58,6 @@ export type InvitesEndpoints = { }; }; '/v1/validateInviteToken': { - POST: (params: { token: string }) => { valid: boolean }; + POST: (params: v1ValidateInviteTokenProps) => { valid: boolean }; }; }; diff --git a/packages/rest-typings/src/v1/ldap.ts b/packages/rest-typings/src/v1/ldap.ts index 45c482c0957d..3fd343cf4c03 100644 --- a/packages/rest-typings/src/v1/ldap.ts +++ b/packages/rest-typings/src/v1/ldap.ts @@ -1,3 +1,26 @@ +import Ajv from 'ajv'; + +const ajv = new Ajv({ + coerceTypes: true, +}); + +type ldapTestSearchProps = { + username: string; +}; + +const ldapTestSearchPropsSchema = { + type: 'object', + properties: { + username: { + type: 'string', + }, + }, + required: ['username'], + additionalProperties: false, +}; + +export const isLdapTestSearch = ajv.compile(ldapTestSearchPropsSchema); + export type LDAPEndpoints = { 'ldap.testConnection': { POST: () => { @@ -5,7 +28,7 @@ export type LDAPEndpoints = { }; }; 'ldap.testSearch': { - POST: (params: { username: string }) => { + POST: (params: ldapTestSearchProps) => { message: string; }; }; diff --git a/packages/rest-typings/src/v1/licenses.ts b/packages/rest-typings/src/v1/licenses.ts index f1bb124a956b..de477d37a813 100644 --- a/packages/rest-typings/src/v1/licenses.ts +++ b/packages/rest-typings/src/v1/licenses.ts @@ -1,11 +1,33 @@ import type { ILicense } from '@rocket.chat/core-typings'; +import Ajv from 'ajv'; + +const ajv = new Ajv({ + coerceTypes: true, +}); + +type licensesAddProps = { + license: string; +}; + +const licensesAddPropsSchema = { + type: 'object', + properties: { + license: { + type: 'string', + }, + }, + required: ['license'], + additionalProperties: false, +}; + +export const isLicensesAddProps = ajv.compile(licensesAddPropsSchema); export type LicensesEndpoints = { 'licenses.get': { GET: () => { licenses: Array }; }; 'licenses.add': { - POST: (params: { license: string }) => void; + POST: (params: licensesAddProps) => void; }; 'licenses.maxActiveUsers': { GET: () => { maxActiveUsers: number | null; activeUsers: number }; diff --git a/packages/rest-typings/src/v1/oauthapps.ts b/packages/rest-typings/src/v1/oauthapps.ts index 89f993d50b21..4928257efd1e 100644 --- a/packages/rest-typings/src/v1/oauthapps.ts +++ b/packages/rest-typings/src/v1/oauthapps.ts @@ -1,7 +1,9 @@ import type { IOAuthApps, IUser } from '@rocket.chat/core-typings'; import Ajv from 'ajv'; -const ajv = new Ajv(); +const ajv = new Ajv({ + coerceTypes: true, +}); export type OauthAppsGetParams = { clientId: string } | { appId: string }; diff --git a/packages/rest-typings/src/v1/omnichannel.ts b/packages/rest-typings/src/v1/omnichannel.ts index 3b29ad0b9274..fc2ab9e23fd9 100644 --- a/packages/rest-typings/src/v1/omnichannel.ts +++ b/packages/rest-typings/src/v1/omnichannel.ts @@ -13,12 +13,770 @@ import type { IRoom, ISetting, } from '@rocket.chat/core-typings'; +import Ajv from 'ajv'; import type { PaginatedRequest } from '../helpers/PaginatedRequest'; import type { PaginatedResult } from '../helpers/PaginatedResult'; type booleanString = 'true' | 'false'; +const ajv = new Ajv({ + coerceTypes: true, +}); + +type LivechatVisitorsInfo = { + visitorId: string; +}; + +const LivechatVisitorsInfoSchema = { + type: 'object', + properties: { + visitorId: { + type: 'string', + }, + }, + required: ['visitorId'], + additionalProperties: false, +}; + +export const isLivechatVisitorsInfoProps = ajv.compile(LivechatVisitorsInfoSchema); + +type LivechatRoomOnHold = { + roomId: IRoom['_id']; +}; + +const LivechatRoomOnHoldSchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + }, + required: ['roomId'], + additionalProperties: false, +}; + +export const isLivechatRoomOnHoldProps = ajv.compile(LivechatRoomOnHoldSchema); + +type LivechatDepartmentId = { + onlyMyDepartments?: booleanString; + includeAgents?: booleanString; +}; + +const LivechatDepartmentIdSchema = { + type: 'object', + properties: { + onlyMyDepartments: { + type: 'string', + nullable: true, + }, + includeAgents: { + type: 'string', + nullable: true, + }, + }, + additionalProperties: false, +}; + +export const isLivechatDepartmentIdProps = ajv.compile(LivechatDepartmentIdSchema); + +type LivechatDepartmentAutocomplete = { + selector: string; + onlyMyDepartments: booleanString; +}; + +const LivechatDepartmentAutocompleteSchema = { + type: 'object', + properties: { + selector: { + type: 'string', + }, + onlyMyDepartments: { + type: 'string', + }, + }, + required: ['selector', 'onlyMyDepartments'], + additionalProperties: false, +}; + +export const isLivechatDepartmentAutocompleteProps = ajv.compile(LivechatDepartmentAutocompleteSchema); + +type LivechatDepartmentDepartmentIdAgentsGET = { + sort: string; +}; + +const LivechatDepartmentDepartmentIdAgentsGETSchema = { + type: 'object', + properties: { + sort: { + type: 'string', + }, + }, + required: ['sort'], + additionalProperties: false, +}; + +export const isLivechatDepartmentDepartmentIdAgentsGETProps = ajv.compile( + LivechatDepartmentDepartmentIdAgentsGETSchema, +); + +type LivechatDepartmentDepartmentIdAgentsPOST = { + upsert: string[]; + remove: string[]; +}; + +const LivechatDepartmentDepartmentIdAgentsPOSTSchema = { + type: 'object', + properties: { + upsert: { + type: 'array', + items: { + type: 'string', + }, + }, + remove: { + type: 'array', + items: { + type: 'string', + }, + }, + }, + required: ['upsert', 'remove'], + additionalProperties: false, +}; + +export const isLivechatDepartmentDepartmentIdAgentsPOSTProps = ajv.compile( + LivechatDepartmentDepartmentIdAgentsPOSTSchema, +); + +type LivechatVisitorTokenGet = { + token: string; +}; + +const LivechatVisitorTokenGetSchema = { + type: 'object', + properties: { + token: { + type: 'string', + }, + }, + required: ['token'], + additionalProperties: false, +}; + +export const isLivechatVisitorTokenGetProps = ajv.compile(LivechatVisitorTokenGetSchema); + +type LivechatVisitorTokenDelete = { + token: string; +}; + +const LivechatVisitorTokenDeleteSchema = { + type: 'object', + properties: { + token: { + type: 'string', + }, + }, + required: ['token'], + additionalProperties: false, +}; + +export const isLivechatVisitorTokenDeleteProps = ajv.compile(LivechatVisitorTokenDeleteSchema); + +type LivechatVisitorTokenRoom = { + token: string; +}; + +const LivechatVisitorTokenRoomSchema = { + type: 'object', + properties: { + token: { + type: 'string', + }, + }, + required: ['token'], + additionalProperties: false, +}; + +export const isLivechatVisitorTokenRoomProps = ajv.compile(LivechatVisitorTokenRoomSchema); + +type LivechatVisitorCallStatus = { + token: string; + callStatus: string; + rid: string; + callId: string; +}; + +const LivechatVisitorCallStatusSchema = { + type: 'object', + properties: { + token: { + type: 'string', + }, + callStatus: { + type: 'string', + }, + rid: { + type: 'string', + }, + callId: { + type: 'string', + }, + }, + required: ['token', 'callStatus', 'rid', 'callId'], + additionalProperties: false, +}; + +export const isLivechatVisitorCallStatusProps = ajv.compile(LivechatVisitorCallStatusSchema); + +type LivechatVisitorStatus = { + token: string; + status: string; +}; + +const LivechatVisitorStatusSchema = { + type: 'object', + properties: { + token: { + type: 'string', + }, + status: { + type: 'string', + }, + }, + required: ['token', 'status'], + additionalProperties: false, +}; + +export const isLivechatVisitorStatusProps = ajv.compile(LivechatVisitorStatusSchema); + +type LiveChatRoomJoin = { + roomId: string; +}; + +const LiveChatRoomJoinSchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + }, + required: ['roomId'], + additionalProperties: false, +}; + +export const isLiveChatRoomJoinProps = ajv.compile(LiveChatRoomJoinSchema); + +type LivechatMonitorsListProps = PaginatedRequest<{ text: string }>; + +const LivechatMonitorsListSchema = { + type: 'object', + properties: { + text: { + type: 'string', + }, + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + query: { + type: 'string', + nullable: true, + }, + }, + required: ['text'], + additionalProperties: false, +}; + +export const isLivechatMonitorsListProps = ajv.compile(LivechatMonitorsListSchema); + +type LivechatTagsListProps = PaginatedRequest<{ text: string }, 'name'>; + +const LivechatTagsListSchema = { + type: 'object', + properties: { + text: { + type: 'string', + }, + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + query: { + type: 'string', + nullable: true, + }, + }, + required: ['text'], + additionalProperties: false, +}; + +export const isLivechatTagsListProps = ajv.compile(LivechatTagsListSchema); + +type LivechatDepartmentProps = PaginatedRequest<{ + text: string; + onlyMyDepartments?: booleanString; + enabled?: booleanString; + excludeDepartmentId?: string; +}>; + +const LivechatDepartmentSchema = { + type: 'object', + properties: { + text: { + type: 'string', + nullable: true, + }, + onlyMyDepartments: { + type: 'string', + enum: ['true', 'false'], + nullable: true, + }, + enabled: { + type: 'string', + nullable: true, + }, + excludeDepartmentId: { + type: 'string', + nullable: true, + }, + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + query: { + type: 'string', + nullable: true, + }, + fields: { + type: 'string', + nullable: true, + }, + }, + additionalProperties: false, +}; + +export const isLivechatDepartmentProps = ajv.compile(LivechatDepartmentSchema); + +type LivechatDepartmentsAvailableByUnitIdProps = PaginatedRequest<{ text: string }>; + +const LivechatDepartmentsAvailableByUnitIdSchema = { + type: 'object', + properties: { + text: { + type: 'string', + }, + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + query: { + type: 'string', + nullable: true, + }, + }, + required: ['text'], + additionalProperties: false, +}; + +export const isLivechatDepartmentsAvailableByUnitIdProps = ajv.compile( + LivechatDepartmentsAvailableByUnitIdSchema, +); + +type LivechatDepartmentsByUnitProps = PaginatedRequest<{ text: string }>; + +const LivechatDepartmentsByUnitSchema = { + type: 'object', + properties: { + text: { + type: 'string', + }, + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + query: { + type: 'string', + nullable: true, + }, + }, + required: ['text'], + additionalProperties: false, +}; + +export const isLivechatDepartmentsByUnitProps = ajv.compile(LivechatDepartmentsByUnitSchema); + +type LivechatDepartmentsByUnitIdProps = PaginatedRequest<{ text: string }>; + +const LivechatDepartmentsByUnitIdSchema = { + type: 'object', + properties: { + text: { + type: 'string', + }, + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + query: { + type: 'string', + nullable: true, + }, + }, + required: ['text'], + additionalProperties: false, +}; + +export const isLivechatDepartmentsByUnitIdProps = ajv.compile(LivechatDepartmentsByUnitIdSchema); + +type LivechatUsersManagerGETProps = PaginatedRequest<{ text?: string }>; + +const LivechatUsersManagerGETSchema = { + type: 'object', + properties: { + text: { + type: 'string', + nullable: true, + }, + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + query: { + type: 'string', + nullable: true, + }, + }, + required: [], + additionalProperties: false, +}; + +export const isLivechatUsersManagerGETProps = ajv.compile(LivechatUsersManagerGETSchema); + +type LivechatUsersManagerPOSTProps = PaginatedRequest<{ username: string }>; + +const LivechatUsersManagerPOSTSchema = { + type: 'object', + properties: { + username: { + type: 'string', + }, + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + query: { + type: 'string', + nullable: true, + }, + }, + required: ['username'], + additionalProperties: false, +}; + +export const isLivechatUsersManagerPOSTProps = ajv.compile(LivechatUsersManagerPOSTSchema); + +type LivechatQueueProps = { + agentId?: string; + includeOfflineAgents?: booleanString; + departmentId?: string; + offset: number; + count: number; + sort: string; +}; + +const LivechatQueuePropsSchema = { + type: 'object', + properties: { + agentId: { + type: 'string', + nullable: true, + }, + includeOfflineAgents: { + type: 'string', + nullable: true, + }, + departmentId: { + type: 'string', + nullable: true, + }, + count: { + type: 'number', + }, + offset: { + type: 'number', + }, + sort: { + type: 'string', + }, + }, + required: ['count', 'offset', 'sort'], + additionalProperties: false, +}; + +export const isLivechatQueueProps = ajv.compile(LivechatQueuePropsSchema); + +type CannedResponsesProps = PaginatedRequest<{ + scope?: string; + departmentId?: string; + text?: string; +}>; + +const CannedResponsesPropsSchema = { + type: 'object', + properties: { + scope: { + type: 'string', + nullable: true, + }, + departmentId: { + type: 'string', + nullable: true, + }, + text: { + type: 'string', + nullable: true, + }, + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + query: { + type: 'string', + nullable: true, + }, + }, + additionalProperties: false, +}; + +export const isCannedResponsesProps = ajv.compile(CannedResponsesPropsSchema); + +type LivechatCustomFieldsProps = PaginatedRequest<{ text: string }>; + +const LivechatCustomFieldsSchema = { + type: 'object', + properties: { + text: { + type: 'string', + }, + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + query: { + type: 'string', + nullable: true, + }, + }, + required: ['text'], + additionalProperties: false, +}; + +export const isLivechatCustomFieldsProps = ajv.compile(LivechatCustomFieldsSchema); + +type LivechatRoomsProps = { + guest: string; + fname: string; + servedBy: string[]; + status: string; + department: string; + from: string; + to: string; + customFields: any; + current: number; + itemsPerPage: number; + tags: string[]; +}; + +const LivechatRoomsSchema = { + type: 'object', + properties: { + guest: { + type: 'string', + }, + fname: { + type: 'string', + }, + servedBy: { + type: 'array', + items: { + type: 'string', + }, + }, + status: { + type: 'string', + }, + department: { + type: 'string', + }, + from: { + type: 'string', + }, + to: { + type: 'string', + }, + customFields: { + type: 'object', + nullable: true, + }, + current: { + type: 'number', + }, + itemsPerPage: { + type: 'number', + }, + tags: { + type: 'array', + items: { + type: 'string', + }, + }, + }, + required: ['guest', 'fname', 'servedBy', 'status', 'department', 'from', 'to', 'current', 'itemsPerPage'], + additionalProperties: false, +}; + +export const isLivechatRoomsProps = ajv.compile(LivechatRoomsSchema); + +type LivechatRidMessagesProps = PaginatedRequest<{ query: string }>; + +const LivechatRidMessagesSchema = { + type: 'object', + properties: { + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + query: { + type: 'string', + }, + }, + required: ['query'], + additionalProperties: false, +}; + +export const isLivechatRidMessagesProps = ajv.compile(LivechatRidMessagesSchema); + +type LivechatUsersAgentProps = PaginatedRequest<{ text?: string }>; + +const LivechatUsersAgentSchema = { + type: 'object', + properties: { + text: { + type: 'string', + nullable: true, + }, + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + query: { + type: 'string', + nullable: true, + }, + }, + required: [], + additionalProperties: false, +}; + +export const isLivechatUsersAgentProps = ajv.compile(LivechatUsersAgentSchema); + export type OmnichannelEndpoints = { 'livechat/appearance': { GET: () => { @@ -26,7 +784,7 @@ export type OmnichannelEndpoints = { }; }; 'livechat/visitors.info': { - GET: (params: { visitorId: string }) => { + GET: (params: LivechatVisitorsInfo) => { visitor: { visitorEmails: Array<{ address: string; @@ -35,30 +793,23 @@ export type OmnichannelEndpoints = { }; }; 'livechat/room.onHold': { - POST: (params: { roomId: IRoom['_id'] }) => void; + POST: (params: LivechatRoomOnHold) => void; }; 'livechat/room.join': { - GET: (params: { roomId: IRoom['_id'] }) => { success: boolean }; + GET: (params: LiveChatRoomJoin) => { success: boolean }; }; 'livechat/monitors.list': { - GET: (params: PaginatedRequest<{ text: string }>) => PaginatedResult<{ + GET: (params: LivechatMonitorsListProps) => PaginatedResult<{ monitors: ILivechatMonitor[]; }>; }; 'livechat/tags.list': { - GET: (params: PaginatedRequest<{ text: string }, 'name'>) => PaginatedResult<{ + GET: (params: LivechatTagsListProps) => PaginatedResult<{ tags: ILivechatTag[]; }>; }; 'livechat/department': { - GET: ( - params: PaginatedRequest<{ - text: string; - onlyMyDepartments?: booleanString; - enabled?: boolean; - excludeDepartmentId?: string; - }>, - ) => PaginatedResult<{ + GET: (params: LivechatDepartmentProps) => PaginatedResult<{ departments: ILivechatDepartment[]; }>; POST: (params: { department: Partial; agents: string[] }) => { @@ -67,7 +818,7 @@ export type OmnichannelEndpoints = { }; }; 'livechat/department/:_id': { - GET: (params: { onlyMyDepartments?: booleanString; includeAgents?: booleanString }) => { + GET: (params: LivechatDepartmentId) => { department: ILivechatDepartmentRecord | null; agents?: ILivechatDepartmentAgents[]; }; @@ -78,27 +829,27 @@ export type OmnichannelEndpoints = { DELETE: () => void; }; 'livechat/department.autocomplete': { - GET: (params: { selector: string; onlyMyDepartments: booleanString }) => { + GET: (params: LivechatDepartmentAutocomplete) => { items: ILivechatDepartment[]; }; }; 'livechat/department/:departmentId/agents': { - GET: (params: { sort: string }) => PaginatedResult<{ agents: ILivechatDepartmentAgents[] }>; - POST: (params: { upsert: string[]; remove: string[] }) => void; + GET: (params: LivechatDepartmentDepartmentIdAgentsGET) => PaginatedResult<{ agents: ILivechatDepartmentAgents[] }>; + POST: (params: LivechatDepartmentDepartmentIdAgentsPOST) => void; }; 'livechat/departments.available-by-unit/:id': { - GET: (params: PaginatedRequest<{ text: string }>) => PaginatedResult<{ + GET: (params: LivechatDepartmentsAvailableByUnitIdProps) => PaginatedResult<{ departments: ILivechatDepartment[]; }>; }; 'livechat/departments.by-unit/': { - GET: (params: PaginatedRequest<{ text: string }>) => PaginatedResult<{ + GET: (params: LivechatDepartmentsByUnitProps) => PaginatedResult<{ departments: ILivechatDepartment[]; }>; }; 'livechat/departments.by-unit/:id': { - GET: (params: PaginatedRequest<{ text: string }>) => PaginatedResult<{ + GET: (params: LivechatDepartmentsByUnitIdProps) => PaginatedResult<{ departments: ILivechatDepartment[]; }>; }; @@ -110,7 +861,7 @@ export type OmnichannelEndpoints = { }; 'livechat/custom-fields': { - GET: (params: PaginatedRequest<{ text: string }>) => PaginatedResult<{ + GET: (params: LivechatCustomFieldsProps) => PaginatedResult<{ customFields: [ { _id: string; @@ -120,28 +871,23 @@ export type OmnichannelEndpoints = { }>; }; 'livechat/rooms': { - GET: (params: { - guest: string; - fname: string; - servedBy: string[]; - status: string; - department: string; - from: string; - to: string; - customFields: any; - current: number; - itemsPerPage: number; - tags: string[]; - }) => PaginatedResult<{ + GET: (params: LivechatRoomsProps) => PaginatedResult<{ rooms: IOmnichannelRoom[]; }>; }; 'livechat/:rid/messages': { - GET: (params: PaginatedRequest<{ query: string }>) => PaginatedResult<{ + GET: (params: LivechatRidMessagesProps) => PaginatedResult<{ messages: IMessage[]; }>; }; + 'livechat/users/manager': { + GET: (params: LivechatUsersManagerGETProps) => PaginatedResult<{ + users: ILivechatAgent[]; + }>; + POST: (params: { username: string }) => { success: boolean }; + }; + 'livechat/users/manager/:_id': { GET: ( params: PaginatedRequest<{ @@ -151,11 +897,11 @@ export type OmnichannelEndpoints = { DELETE: () => void; }; - 'livechat/users/manager': { + 'livechat/users/agent': { GET: (params: PaginatedRequest<{ text?: string }>) => PaginatedResult<{ users: ILivechatAgent[]; }>; - POST: (params: { username: string }) => { success: boolean }; + POST: (params: LivechatUsersManagerPOSTProps) => { success: boolean }; }; 'livechat/users/agent/:_id': { @@ -167,13 +913,6 @@ export type OmnichannelEndpoints = { DELETE: () => { success: boolean }; }; - 'livechat/users/agent': { - GET: (params: PaginatedRequest<{ text?: string }>) => PaginatedResult<{ - users: ILivechatAgent[]; - }>; - POST: (params: { username: string }) => { success: boolean }; - }; - 'livechat/visitor': { POST: (params: { visitor: ILivechatVisitorDTO }) => { visitor: ILivechatVisitor; @@ -181,39 +920,32 @@ export type OmnichannelEndpoints = { }; 'livechat/visitor/:token': { - GET: (params: { token: string }) => { visitor: ILivechatVisitor }; - DELETE: (params: { token: string }) => { + GET: (params: LivechatVisitorTokenGet) => { visitor: ILivechatVisitor }; + DELETE: (params: LivechatVisitorTokenDelete) => { visitor: { _id: string; ts: string }; }; }; 'livechat/visitor/:token/room': { - GET: (params: { token: string }) => { rooms: IOmnichannelRoom[] }; + GET: (params: LivechatVisitorTokenRoom) => { rooms: IOmnichannelRoom[] }; }; 'livechat/visitor.callStatus': { - POST: (params: { token: string; callStatus: string; rid: string; callId: string }) => { + POST: (params: LivechatVisitorCallStatus) => { token: string; callStatus: string; }; }; 'livechat/visitor.status': { - POST: (params: { token: string; status: string }) => { + POST: (params: LivechatVisitorStatus) => { token: string; status: string; }; }; 'livechat/queue': { - GET: (params: { - agentId?: ILivechatAgent['_id']; - includeOfflineAgents?: boolean; - departmentId?: ILivechatAgent['_id']; - offset: number; - count: number; - sort: string; - }) => { + GET: (params: LivechatQueueProps) => { queue: { chats: number; department: { _id: string; name: string }; @@ -229,13 +961,7 @@ export type OmnichannelEndpoints = { }; 'canned-responses': { - GET: ( - params: PaginatedRequest<{ - scope?: string; - departmentId?: string; - text?: string; - }>, - ) => PaginatedResult<{ + GET: (params: CannedResponsesProps) => PaginatedResult<{ cannedResponses: IOmnichannelCannedResponse[]; }>; }; diff --git a/packages/rest-typings/src/v1/permissions.ts b/packages/rest-typings/src/v1/permissions.ts index 85506bf1aff8..3128db4ec259 100644 --- a/packages/rest-typings/src/v1/permissions.ts +++ b/packages/rest-typings/src/v1/permissions.ts @@ -1,13 +1,33 @@ -import Ajv, { JSONSchemaType } from 'ajv'; +import Ajv from 'ajv'; import type { IPermission } from '@rocket.chat/core-typings'; -const ajv = new Ajv(); +const ajv = new Ajv({ + coerceTypes: true, +}); + +type PermissionsListAllProps = { + updatedSince?: string; +}; + +const permissionListAllSchema = { + type: 'object', + properties: { + updatedSince: { + type: 'string', + nullable: true, + }, + }, + required: [], + additionalProperties: false, +}; + +export const isPermissionsListAll = ajv.compile(permissionListAllSchema); type PermissionsUpdateProps = { permissions: { _id: string; roles: string[] }[]; }; -const permissionUpdatePropsSchema: JSONSchemaType = { +const permissionUpdatePropsSchema = { type: 'object', properties: { permissions: { @@ -31,11 +51,11 @@ const permissionUpdatePropsSchema: JSONSchemaType = { additionalProperties: false, }; -export const isBodyParamsValidPermissionUpdate = ajv.compile(permissionUpdatePropsSchema); +export const isBodyParamsValidPermissionUpdate = ajv.compile(permissionUpdatePropsSchema); export type PermissionsEndpoints = { 'permissions.listAll': { - GET: (params: { updatedSince?: string }) => { + GET: (params: PermissionsListAllProps) => { update: IPermission[]; remove: IPermission[]; }; diff --git a/packages/rest-typings/src/v1/push.ts b/packages/rest-typings/src/v1/push.ts index d0b07c6afbca..54568328bc42 100644 --- a/packages/rest-typings/src/v1/push.ts +++ b/packages/rest-typings/src/v1/push.ts @@ -1,12 +1,64 @@ import type { IMessage, IPushNotificationConfig, IPushTokenTypes, IPushToken } from '@rocket.chat/core-typings'; +import Ajv from 'ajv'; + +const ajv = new Ajv({ + coerceTypes: true, +}); + +type PushTokenProps = { + id?: string; + type: IPushTokenTypes; + value: string; + appName: string; +}; + +const PushTokenPropsSchema = { + type: 'object', + properties: { + id: { + type: 'string', + nullable: true, + }, + type: { + type: 'string', + }, + value: { + type: 'string', + }, + appName: { + type: 'string', + }, + }, + required: ['type', 'value', 'appName'], + additionalProperties: false, +}; + +export const isPushTokenProps = ajv.compile(PushTokenPropsSchema); + +type PushGetProps = { + id: string; +}; + +const PushGetPropsSchema = { + type: 'object', + properties: { + id: { + type: 'string', + }, + }, + required: ['id'], + additionalProperties: false, +}; + +export const isPushGetProps = ajv.compile(PushGetPropsSchema); export type PushEndpoints = { 'push.token': { - POST: (payload: { id?: string; type: IPushTokenTypes; value: string; appName: string }) => { result: IPushToken }; + POST: (payload: PushTokenProps) => { result: IPushToken }; DELETE: (payload: { token: string }) => void; }; 'push.get': { - GET: (params: { id: string }) => { + GET: (params: PushGetProps) => { data: { message: IMessage; notification: IPushNotificationConfig; diff --git a/packages/rest-typings/src/v1/roles.ts b/packages/rest-typings/src/v1/roles.ts index 6e3d729a0222..8c4135fc4b5b 100644 --- a/packages/rest-typings/src/v1/roles.ts +++ b/packages/rest-typings/src/v1/roles.ts @@ -1,11 +1,15 @@ -import Ajv, { JSONSchemaType } from 'ajv'; +import Ajv from 'ajv'; import type { RocketChatRecordDeleted, IRole, IUserInRole } from '@rocket.chat/core-typings'; -const ajv = new Ajv(); +import type { PaginatedRequest } from '../helpers/PaginatedRequest'; + +const ajv = new Ajv({ + coerceTypes: true, +}); type RoleCreateProps = Pick & Partial>; -const roleCreatePropsSchema: JSONSchemaType = { +const roleCreatePropsSchema = { type: 'object', properties: { name: { @@ -29,14 +33,14 @@ const roleCreatePropsSchema: JSONSchemaType = { additionalProperties: false, }; -export const isRoleCreateProps = ajv.compile(roleCreatePropsSchema); +export const isRoleCreateProps = ajv.compile(roleCreatePropsSchema); type RoleUpdateProps = { roleId: IRole['_id']; name: IRole['name']; } & Partial; -const roleUpdatePropsSchema: JSONSchemaType = { +const roleUpdatePropsSchema = { type: 'object', properties: { roleId: { @@ -63,11 +67,11 @@ const roleUpdatePropsSchema: JSONSchemaType = { additionalProperties: false, }; -export const isRoleUpdateProps = ajv.compile(roleUpdatePropsSchema); +export const isRoleUpdateProps = ajv.compile(roleUpdatePropsSchema); type RoleDeleteProps = { roleId: IRole['_id'] }; -const roleDeletePropsSchema: JSONSchemaType = { +const roleDeletePropsSchema = { type: 'object', properties: { roleId: { @@ -78,7 +82,7 @@ const roleDeletePropsSchema: JSONSchemaType = { additionalProperties: false, }; -export const isRoleDeleteProps = ajv.compile(roleDeletePropsSchema); +export const isRoleDeleteProps = ajv.compile(roleDeletePropsSchema); type RoleAddUserToRoleProps = { username: string; @@ -88,7 +92,7 @@ type RoleAddUserToRoleProps = { roomId?: string; }; -const roleAddUserToRolePropsSchema: JSONSchemaType = { +const roleAddUserToRolePropsSchema = { type: 'object', properties: { username: { @@ -111,7 +115,7 @@ const roleAddUserToRolePropsSchema: JSONSchemaType = { additionalProperties: false, }; -export const isRoleAddUserToRoleProps = ajv.compile(roleAddUserToRolePropsSchema); +export const isRoleAddUserToRoleProps = ajv.compile(roleAddUserToRolePropsSchema); type RoleRemoveUserFromRoleProps = { username: string; @@ -122,7 +126,7 @@ type RoleRemoveUserFromRoleProps = { scope?: string; }; -const roleRemoveUserFromRolePropsSchema: JSONSchemaType = { +const roleRemoveUserFromRolePropsSchema = { type: 'object', properties: { username: { @@ -149,7 +153,45 @@ const roleRemoveUserFromRolePropsSchema: JSONSchemaType(roleRemoveUserFromRolePropsSchema); + +type RolesGetUsersInRoleProps = PaginatedRequest<{ + roomId?: string; + role: string; +}>; + +const RolesGetUsersInRolePropsSchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + nullable: true, + }, + role: { + type: 'string', + }, + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + query: { + type: 'string', + nullable: true, + }, + }, + required: ['role'], + additionalProperties: false, +}; + +export const isRolesGetUsersInRoleProps = ajv.compile(RolesGetUsersInRolePropsSchema); type RoleSyncProps = { updatedSince?: string; @@ -182,7 +224,7 @@ export type RolesEndpoints = { }; 'roles.getUsersInRole': { - GET: (params: { roomId?: string; role: string; offset?: number; count?: number }) => { + GET: (params: RolesGetUsersInRoleProps) => { users: IUserInRole[]; total: number; }; diff --git a/packages/rest-typings/src/v1/rooms.ts b/packages/rest-typings/src/v1/rooms.ts index 647127c4b469..aca408dc1109 100644 --- a/packages/rest-typings/src/v1/rooms.ts +++ b/packages/rest-typings/src/v1/rooms.ts @@ -1,16 +1,406 @@ +/* eslint-disable @typescript-eslint/camelcase */ import type { IMessage, IRoom, IUser, RoomAdminFieldsType } from '@rocket.chat/core-typings'; +import Ajv from 'ajv'; import type { PaginatedRequest } from '../helpers/PaginatedRequest'; import type { PaginatedResult } from '../helpers/PaginatedResult'; +const ajv = new Ajv({ + coerceTypes: true, +}); + +type RoomsAutoCompleteChannelAndPrivateProps = { selector: string }; + +const RoomsAutoCompleteChannelAndPrivateSchema = { + type: 'object', + properties: { + selector: { + type: 'string', + }, + }, + required: ['selector'], + additionalProperties: false, +}; + +export const isRoomsAutoCompleteChannelAndPrivateProps = ajv.compile( + RoomsAutoCompleteChannelAndPrivateSchema, +); + +type RoomsAutocompleteChannelAndPrivateWithPaginationProps = PaginatedRequest<{ selector: string }>; + +const RoomsAutocompleteChannelAndPrivateWithPaginationSchema = { + type: 'object', + properties: { + selector: { + type: 'string', + }, + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + query: { + type: 'string', + nullable: true, + }, + }, + required: ['selector'], + additionalProperties: false, +}; + +export const isRoomsAutocompleteChannelAndPrivateWithPaginationProps = ajv.compile( + RoomsAutocompleteChannelAndPrivateWithPaginationSchema, +); + +type RoomsAutocompleteAvailableForTeamsProps = { name: string }; + +const RoomsAutocompleteAvailableForTeamsSchema = { + type: 'object', + properties: { + name: { + type: 'string', + }, + }, + required: ['name'], + additionalProperties: false, +}; + +export const isRoomsAutocompleteAvailableForTeamsProps = ajv.compile( + RoomsAutocompleteAvailableForTeamsSchema, +); + +type RoomsInfoProps = { roomId: string } | { roomName: string }; + +const RoomsInfoSchema = { + oneOf: [ + { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + }, + required: ['roomId'], + additionalProperties: false, + }, + { + type: 'object', + properties: { + roomName: { + type: 'string', + }, + }, + required: ['roomName'], + additionalProperties: false, + }, + ], +}; + +export const isRoomsInfoProps = ajv.compile(RoomsInfoSchema); + +type RoomsCreateDiscussionProps = { + prid: IRoom['_id']; + pmid?: IMessage['_id']; + t_name: string; // IRoom['fname'] + users?: IUser['username'][]; + encrypted?: boolean; + reply?: string; +}; + +const RoomsCreateDiscussionSchema = { + type: 'object', + properties: { + prid: { + type: 'string', + }, + pmid: { + type: 'string', + nullable: true, + }, + t_name: { + type: 'string', + nullable: true, + }, + users: { + type: 'array', + items: { + type: 'string', + }, + nullable: true, + }, + encrypted: { + type: 'boolean', + nullable: true, + }, + reply: { + type: 'string', + nullable: true, + }, + }, + required: ['prid', 't_name'], + additionalProperties: false, +}; + +export const isRoomsCreateDiscussionProps = ajv.compile(RoomsCreateDiscussionSchema); + +type RoomsExportProps = { + rid: IRoom['_id']; + type: 'email' | 'file'; + toUsers?: IUser['username'][]; + toEmails?: string[]; + additionalEmails?: string; + subject?: string; + messages?: IMessage['_id'][]; + dateFrom?: string; + dateTo?: string; + format?: 'html' | 'json'; +}; + +const RoomsExportSchema = { + type: 'object', + properties: { + rid: { + type: 'string', + }, + type: { + type: 'string', + nullable: true, + }, + toUsers: { + type: 'array', + items: { + type: 'string', + }, + nullable: true, + }, + toEmails: { + type: 'array', + items: { + type: 'string', + }, + nullable: true, + }, + additionalEmails: { + type: 'string', + nullable: true, + }, + subject: { + type: 'string', + nullable: true, + }, + messages: { + type: 'array', + items: { + type: 'string', + }, + nullable: true, + }, + dateFrom: { + type: 'string', + nullable: true, + }, + dateTo: { + type: 'string', + nullable: true, + }, + format: { + type: 'string', + nullable: true, + }, + }, + required: ['rid'], + additionalProperties: false, +}; + +export const isRoomsExportProps = ajv.compile(RoomsExportSchema); + +type RoomsAdminRoomsProps = PaginatedRequest<{ + filter?: string; + types?: string[]; +}>; + +const RoomsAdminRoomsSchema = { + type: 'object', + properties: { + filter: { + type: 'string', + nullable: true, + }, + types: { + type: 'array', + items: { + type: 'string', + }, + nullable: true, + }, + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + query: { + type: 'string', + nullable: true, + }, + }, + required: [], + additionalProperties: false, +}; + +export const isRoomsAdminRoomsProps = ajv.compile(RoomsAdminRoomsSchema); + +type RoomsAdminRoomsGetRoomProps = { rid?: string }; + +const RoomsAdminRoomsGetRoomSchema = { + type: 'object', + properties: { + rid: { + type: 'string', + nullable: true, + }, + }, + required: [], + additionalProperties: false, +}; + +export const isRoomsAdminRoomsGetRoomProps = ajv.compile(RoomsAdminRoomsGetRoomSchema); + +type RoomsChangeArchivationStateProps = { rid: string; action?: string }; + +const RoomsChangeArchivationStateSchema = { + type: 'object', + properties: { + rid: { + type: 'string', + }, + action: { + type: 'string', + nullable: true, + }, + }, + required: ['rid'], + additionalProperties: false, +}; + +export const isRoomsChangeArchivationStateProps = ajv.compile(RoomsChangeArchivationStateSchema); + +type RoomsSaveRoomSettingsProps = { + rid: string; + roomAvatar?: string; + featured?: boolean; + roomName?: string; + roomTopic?: string; + roomAnnouncement?: string; + roomDescription?: string; + roomType?: IRoom['t']; + readOnly?: boolean; + reactWhenReadOnly?: boolean; + default?: boolean; + tokenpass?: string; + encrypted?: boolean; + favorite?: { + defaultValue?: boolean; + favorite?: boolean; + }; +}; + +const RoomsSaveRoomSettingsSchema = { + type: 'object', + properties: { + rid: { + type: 'string', + }, + roomAvatar: { + type: 'string', + nullable: true, + }, + featured: { + type: 'boolean', + nullable: true, + }, + roomName: { + type: 'string', + nullable: true, + }, + roomTopic: { + type: 'string', + nullable: true, + }, + roomAnnouncement: { + type: 'string', + nullable: true, + }, + roomDescription: { + type: 'string', + nullable: true, + }, + roomType: { + type: 'string', + nullable: true, + }, + readOnly: { + type: 'boolean', + nullable: true, + }, + reactWhenReadOnly: { + type: 'boolean', + nullable: true, + }, + default: { + type: 'boolean', + nullable: true, + }, + tokenpass: { + type: 'string', + nullable: true, + }, + encrypted: { + type: 'boolean', + nullable: true, + }, + favorite: { + type: 'object', + properties: { + defaultValue: { + type: 'boolean', + nullable: true, + }, + favorite: { + type: 'boolean', + nullable: true, + }, + }, + nullable: true, + }, + }, + required: ['rid'], + additionalProperties: false, +}; + +export const isRoomsSaveRoomSettingsProps = ajv.compile(RoomsSaveRoomSettingsSchema); + export type RoomsEndpoints = { 'rooms.autocomplete.channelAndPrivate': { - GET: (params: { selector: string }) => { + GET: (params: RoomsAutoCompleteChannelAndPrivateProps) => { items: IRoom[]; }; }; 'rooms.autocomplete.channelAndPrivate.withPagination': { - GET: (params: { selector: string; offset?: number; count?: number; sort?: string }) => { + GET: (params: RoomsAutocompleteChannelAndPrivateWithPaginationProps) => { items: IRoom[]; count: number; offset: number; @@ -18,81 +408,40 @@ export type RoomsEndpoints = { }; }; 'rooms.autocomplete.availableForTeams': { - GET: (params: { name: string }) => { + GET: (params: RoomsAutocompleteAvailableForTeamsProps) => { items: IRoom[]; }; }; 'rooms.info': { - GET: (params: { roomId: string } | { roomName: string }) => { + GET: (params: RoomsInfoProps) => { room: IRoom; }; }; 'rooms.createDiscussion': { - POST: (params: { - prid: IRoom['_id']; - pmid?: IMessage['_id']; - t_name: IRoom['fname']; - users?: IUser['username'][]; - encrypted?: boolean; - reply?: string; - }) => { + POST: (params: RoomsCreateDiscussionProps) => { discussion: IRoom; }; }; 'rooms.export': { - POST: (params: { - rid: IRoom['_id']; - type: 'email' | 'file'; - toUsers?: IUser['username'][]; - toEmails?: string[]; - additionalEmails?: string; - subject?: string; - messages?: IMessage['_id'][]; - dateFrom?: string; - dateTo?: string; - format?: 'html' | 'json'; - }) => { + POST: (params: RoomsExportProps) => { missing?: []; success: boolean; }; }; 'rooms.adminRooms': { - GET: ( - params: PaginatedRequest<{ - filter?: string; - types?: string[]; - }>, - ) => PaginatedResult<{ rooms: Pick[] }>; + GET: (params: RoomsAdminRoomsProps) => PaginatedResult<{ rooms: Pick[] }>; }; 'rooms.adminRooms.getRoom': { - GET: (params: { rid?: string }) => Pick; + GET: (params: RoomsAdminRoomsGetRoomProps) => Pick; }; 'rooms.saveRoomSettings': { - POST: (params: { - rid: string; - roomAvatar?: string; - featured?: boolean; - roomName?: string; - roomTopic?: string; - roomAnnouncement?: string; - roomDescription?: string; - roomType?: IRoom['t']; - readOnly?: boolean; - reactWhenReadOnly?: boolean; - default?: boolean; - tokenpass?: string; - encrypted?: boolean; - favorite?: { - defaultValue?: boolean; - favorite?: boolean; - }; - }) => { + POST: (params: RoomsSaveRoomSettingsProps) => { success: boolean; rid: string; }; }; 'rooms.changeArchivationState': { - POST: (params: { rid: string; action?: string }) => { + POST: (params: RoomsChangeArchivationStateProps) => { success: boolean; }; }; diff --git a/packages/rest-typings/src/v1/statistics.ts b/packages/rest-typings/src/v1/statistics.ts index b3fd2fb723c3..837bbf1afa0e 100644 --- a/packages/rest-typings/src/v1/statistics.ts +++ b/packages/rest-typings/src/v1/statistics.ts @@ -1,4 +1,7 @@ import type { IStats } from '@rocket.chat/core-typings'; +import Ajv from 'ajv'; + +import type { PaginatedRequest } from '../helpers/PaginatedRequest'; type OTREnded = { rid: string }; @@ -18,12 +21,64 @@ export type TelemetryPayload = { params: Param[]; }; +const ajv = new Ajv({ + coerceTypes: true, +}); + +type StatisticsProps = { refresh?: 'true' | 'false' }; + +const StatisticsSchema = { + type: 'object', + properties: { + refresh: { + type: 'string', + nullable: true, + }, + }, + required: [], + additionalProperties: false, +}; + +export const isStatisticsProps = ajv.compile(StatisticsSchema); + +type StatisticsListProps = PaginatedRequest<{ fields?: string }>; + +const StatisticsListSchema = { + type: 'object', + properties: { + fields: { + type: 'string', + nullable: true, + }, + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + query: { + type: 'string', + nullable: true, + }, + }, + required: [], + additionalProperties: false, +}; + +export const isStatisticsListProps = ajv.compile(StatisticsListSchema); + export type StatisticsEndpoints = { 'statistics': { - GET: (params: { refresh?: 'true' | 'false' }) => IStats; + GET: (params: StatisticsProps) => IStats; }; 'statistics.list': { - GET: (params: { offset?: number; count?: number; sort?: string; fields?: string; query?: string }) => { + GET: (params: StatisticsListProps) => { statistics: IStats[]; count: number; offset: number; diff --git a/packages/rest-typings/src/v1/users.ts b/packages/rest-typings/src/v1/users.ts index 0f9951f4dfec..4b311d1af3d2 100644 --- a/packages/rest-typings/src/v1/users.ts +++ b/packages/rest-typings/src/v1/users.ts @@ -1,26 +1,140 @@ import type { ITeam, IUser } from '@rocket.chat/core-typings'; +import Ajv from 'ajv'; + +const ajv = new Ajv({ + coerceTypes: true, +}); + +type UsersInfo = { userId?: IUser['_id']; userName?: IUser['username'] }; + +const UsersInfoSchema = { + type: 'object', + properties: { + userId: { + type: 'string', + nullable: true, + }, + userName: { + type: 'string', + nullable: true, + }, + }, + required: [], + additionalProperties: false, +}; + +export const isUsersInfoProps = ajv.compile(UsersInfoSchema); + +type Users2faSendEmailCode = { emailOrUsername: string }; + +const Users2faSendEmailCodeSchema = { + type: 'object', + properties: { + emailOrUsername: { + type: 'string', + }, + }, + required: ['emailOrUsername'], + additionalProperties: false, +}; + +export const isUsers2faSendEmailCodeProps = ajv.compile(Users2faSendEmailCodeSchema); + +type UsersAutocomplete = { selector: string }; + +const UsersAutocompleteSchema = { + type: 'object', + properties: { + selector: { + type: 'string', + }, + }, + required: ['selector'], + additionalProperties: false, +}; + +export const isUsersAutocompleteProps = ajv.compile(UsersAutocompleteSchema); + +type UsersListTeams = { userId: IUser['_id'] }; + +const UsersListTeamsSchema = { + type: 'object', + properties: { + userId: { + type: 'string', + }, + }, + required: ['userId'], + additionalProperties: false, +}; + +export const isUsersListTeamsProps = ajv.compile(UsersListTeamsSchema); + +type UsersSetAvatar = { userId?: IUser['_id']; username?: IUser['username']; avatarUrl?: string }; + +const UsersSetAvatarSchema = { + type: 'object', + properties: { + userId: { + type: 'string', + nullable: true, + }, + username: { + type: 'string', + nullable: true, + }, + avatarUrl: { + type: 'string', + nullable: true, + }, + }, + required: [], + additionalProperties: false, +}; + +export const isUsersSetAvatarProps = ajv.compile(UsersSetAvatarSchema); + +type UsersResetAvatar = { userId?: IUser['_id']; username?: IUser['username'] }; + +const UsersResetAvatarSchema = { + type: 'object', + properties: { + userId: { + type: 'string', + nullable: true, + }, + username: { + type: 'string', + nullable: true, + }, + }, + required: [], + additionalProperties: false, +}; + +export const isUsersResetAvatarProps = ajv.compile(UsersResetAvatarSchema); export type UsersEndpoints = { 'users.info': { - GET: (params: { userId?: IUser['_id']; userName?: IUser['username'] }) => { + GET: (params: UsersInfo) => { user: IUser; }; }; 'users.2fa.sendEmailCode': { - POST: (params: { emailOrUsername: string }) => void; + POST: (params: Users2faSendEmailCode) => void; }; 'users.autocomplete': { - GET: (params: { selector: string }) => { + GET: (params: UsersAutocomplete) => { items: Required>[]; }; }; 'users.listTeams': { - GET: (params: { userId: IUser['_id'] }) => { teams: Array }; + GET: (params: UsersListTeams) => { teams: Array }; }; 'users.setAvatar': { - POST: (params: { userId?: IUser['_id']; username?: IUser['username']; avatarUrl?: string }) => void; + POST: (params: UsersSetAvatar) => void; }; 'users.resetAvatar': { - POST: (params: { userId?: IUser['_id']; username?: IUser['username'] }) => void; + POST: (params: UsersResetAvatar) => void; }; }; diff --git a/packages/rest-typings/src/v1/videoConference.ts b/packages/rest-typings/src/v1/videoConference.ts index 4030043e2f02..c314e43deb6c 100644 --- a/packages/rest-typings/src/v1/videoConference.ts +++ b/packages/rest-typings/src/v1/videoConference.ts @@ -1,8 +1,34 @@ import type { IRoom } from '@rocket.chat/core-typings'; +import Ajv from 'ajv'; + +const ajv = new Ajv({ + coerceTypes: true, +}); + +type VideoConferenceJitsiUpdateTimeout = { roomId: IRoom['_id']; joiningNow?: boolean }; + +const VideoConferenceJitsiUpdateTimeoutSchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + }, + joiningNow: { + type: 'boolean', + nullable: true, + }, + }, + required: ['roomId'], + additionalProperties: false, +}; + +export const isVideoConferenceJitsiUpdateTimeoutProps = ajv.compile( + VideoConferenceJitsiUpdateTimeoutSchema, +); export type VideoConferenceEndpoints = { 'video-conference/jitsi.update-timeout': { - POST: (params: { roomId: IRoom['_id']; joiningNow?: boolean }) => { + POST: (params: VideoConferenceJitsiUpdateTimeout) => { jitsiTimeout: number; }; }; diff --git a/packages/rest-typings/src/v1/voip.ts b/packages/rest-typings/src/v1/voip.ts index 5398586927a3..fbdeafc23fef 100644 --- a/packages/rest-typings/src/v1/voip.ts +++ b/packages/rest-typings/src/v1/voip.ts @@ -8,72 +8,534 @@ import type { IVoipExtensionWithAgentInfo, IManagementServerConnectionStatus, IRegistrationInfo, - VoipClientEvents, } from '@rocket.chat/core-typings'; +import { VoipClientEvents } from '@rocket.chat/core-typings'; +import Ajv, { JSONSchemaType } from 'ajv'; import type { PaginatedRequest } from '../helpers/PaginatedRequest'; import type { PaginatedResult } from '../helpers/PaginatedResult'; +const ajv = new Ajv({ + coerceTypes: true, +}); + +/** *************************************************/ +type CustomSoundsList = PaginatedRequest<{ query: string }>; + +const CustomSoundsListSchema: JSONSchemaType = { + type: 'object', + properties: { + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + query: { + type: 'string', + nullable: true, + }, + }, + required: [], + additionalProperties: false, +}; + +export const isCustomSoundsListProps = ajv.compile(CustomSoundsListSchema); + +type ConnectorExtensionGetRegistrationInfoByUserId = { id: string }; + +const ConnectorExtensionGetRegistrationInfoByUserIdSchema: JSONSchemaType = { + type: 'object', + properties: { + id: { + type: 'string', + }, + }, + required: ['id'], + additionalProperties: false, +}; + +export const isConnectorExtensionGetRegistrationInfoByUserIdProps = ajv.compile( + ConnectorExtensionGetRegistrationInfoByUserIdSchema, +); + +type VoipQueuesGetQueuedCallsForThisExtension = { extension: string }; + +const VoipQueuesGetQueuedCallsForThisExtensionSchema: JSONSchemaType = { + type: 'object', + properties: { + extension: { + type: 'string', + }, + }, + required: ['extension'], + additionalProperties: false, +}; + +export const isVoipQueuesGetQueuedCallsForThisExtensionProps = ajv.compile( + VoipQueuesGetQueuedCallsForThisExtensionSchema, +); + +type VoipQueuesGetMembershipSubscription = { extension: string }; + +const VoipQueuesGetMembershipSubscriptionSchema: JSONSchemaType = { + type: 'object', + properties: { + extension: { + type: 'string', + }, + }, + required: ['extension'], + additionalProperties: false, +}; + +export const isVoipQueuesGetMembershipSubscriptionProps = ajv.compile( + VoipQueuesGetMembershipSubscriptionSchema, +); + +type OmnichannelExtensions = PaginatedRequest<{ + status?: string; + agentId?: string; + queues?: string[]; + extension?: string; +}>; + +const OmnichannelExtensionsSchema: JSONSchemaType = { + type: 'object', + properties: { + status: { + type: 'string', + nullable: true, + }, + agentId: { + type: 'string', + nullable: true, + }, + queues: { + type: 'array', + items: { + type: 'string', + }, + nullable: true, + }, + extension: { + type: 'string', + nullable: true, + }, + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + query: { + type: 'string', + nullable: true, + }, + }, + required: [], + additionalProperties: false, +}; + +export const isOmnichannelExtensionsProps = ajv.compile(OmnichannelExtensionsSchema); + +type OmnichannelExtension = + | { + userId: string; + type: 'free' | 'allocated' | 'available'; + } + | { + username: string; + type: 'free' | 'allocated' | 'available'; + }; + +const OmnichannelExtensionSchema: JSONSchemaType = { + oneOf: [ + { + type: 'object', + properties: { + userId: { + type: 'string', + }, + type: { + type: 'string', + enum: ['free', 'allocated', 'available'], + }, + }, + required: ['userId', 'type'], + additionalProperties: false, + }, + { + type: 'object', + properties: { + username: { + type: 'string', + }, + type: { + type: 'string', + enum: ['free', 'allocated', 'available'], + }, + }, + required: ['username', 'type'], + additionalProperties: false, + }, + ], +}; + +export const isOmnichannelExtensionProps = ajv.compile(OmnichannelExtensionSchema); + +type OmnichannelAgentExtensionGET = { username: string }; + +const OmnichannelAgentExtensionGETSchema: JSONSchemaType = { + type: 'object', + properties: { + username: { + type: 'string', + }, + }, + required: ['username'], + additionalProperties: false, +}; + +export const isOmnichannelAgentExtensionGETProps = ajv.compile(OmnichannelAgentExtensionGETSchema); + +type OmnichannelAgentExtensionPOST = { userId: string; extension: string } | { username: string; extension: string }; + +const OmnichannelAgentExtensionPOSTSchema: JSONSchemaType = { + oneOf: [ + { + type: 'object', + properties: { + userId: { + type: 'string', + }, + extension: { + type: 'string', + }, + }, + required: ['userId', 'extension'], + additionalProperties: false, + }, + { + type: 'object', + properties: { + username: { + type: 'string', + }, + extension: { + type: 'string', + }, + }, + required: ['username', 'extension'], + additionalProperties: false, + }, + ], +}; + +export const isOmnichannelAgentExtensionPOSTProps = ajv.compile(OmnichannelAgentExtensionPOSTSchema); + +type OmnichannelAgentExtensionDELETE = { username: string }; + +const OmnichannelAgentExtensionDELETESchema: JSONSchemaType = { + type: 'object', + properties: { + username: { + type: 'string', + }, + }, + required: ['username'], + additionalProperties: false, +}; + +export const isOmnichannelAgentExtensionDELETEProps = ajv.compile(OmnichannelAgentExtensionDELETESchema); + +type OmnichannelAgentsAvailable = PaginatedRequest<{ text?: string; includeExtension?: string }>; + +const OmnichannelAgentsAvailableSchema: JSONSchemaType = { + type: 'object', + properties: { + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + query: { + type: 'string', + nullable: true, + }, + text: { + type: 'string', + nullable: true, + }, + includeExtension: { + type: 'string', + nullable: true, + }, + }, + required: [], + additionalProperties: false, +}; + +export const isOmnichannelAgentsAvailableProps = ajv.compile(OmnichannelAgentsAvailableSchema); + +type VoipEvents = { event: VoipClientEvents; rid: string; comment?: string }; + +const VoipEventsSchema: JSONSchemaType = { + type: 'object', + properties: { + event: { + type: 'string', + enum: Object.values(VoipClientEvents), + }, + rid: { + type: 'string', + }, + comment: { + type: 'string', + nullable: true, + }, + }, + required: ['event', 'rid'], + additionalProperties: false, +}; + +export const isVoipEventsProps = ajv.compile(VoipEventsSchema); + +type VoipRoom = { token: string; agentId: ILivechatAgent['_id'] } | { rid: string; token: string }; + +const VoipRoomSchema: JSONSchemaType = { + oneOf: [ + { + type: 'object', + properties: { + token: { + type: 'string', + }, + agentId: { + type: 'string', + }, + }, + required: ['token', 'agentId'], + additionalProperties: false, + }, + { + type: 'object', + properties: { + rid: { + type: 'string', + }, + token: { + type: 'string', + }, + }, + required: ['rid', 'token'], + additionalProperties: false, + }, + ], +}; + +export const isVoipRoomProps = ajv.compile(VoipRoomSchema); + +type VoipManagementServerCheckConnection = { host: string; port: string; username: string; password: string }; + +const VoipManagementServerCheckConnectionSchema: JSONSchemaType = { + type: 'object', + properties: { + host: { + type: 'string', + }, + port: { + type: 'string', + }, + username: { + type: 'string', + }, + password: { + type: 'string', + }, + }, + required: ['host', 'port', 'username', 'password'], + additionalProperties: false, +}; + +export const isVoipManagementServerCheckConnectionProps = ajv.compile( + VoipManagementServerCheckConnectionSchema, +); + +type VoipCallServerCheckConnection = { websocketUrl: string; host: string; port: string; path: string }; + +const VoipCallServerCheckConnectionSchema: JSONSchemaType = { + type: 'object', + properties: { + websocketUrl: { + type: 'string', + }, + host: { + type: 'string', + }, + port: { + type: 'string', + }, + path: { + type: 'string', + }, + }, + required: ['websocketUrl', 'host', 'port', 'path'], + additionalProperties: false, +}; + +export const isVoipCallServerCheckConnectionProps = ajv.compile(VoipCallServerCheckConnectionSchema); + +type VoipRooms = { + agents?: string[]; + open?: 'true' | 'false'; + createdAt?: string; + closedAt?: string; + tags?: string[]; + queue?: string; + visitorId?: string; +}; + +const VoipRoomsSchema: JSONSchemaType = { + type: 'object', + properties: { + agents: { + type: 'array', + items: { + type: 'string', + }, + nullable: true, + }, + open: { + type: 'string', + enum: ['true', 'false'], + nullable: true, + }, + createdAt: { + type: 'string', + nullable: true, + }, + closedAt: { + type: 'string', + nullable: true, + }, + tags: { + type: 'array', + items: { + type: 'string', + }, + nullable: true, + }, + queue: { + type: 'string', + nullable: true, + }, + visitorId: { + type: 'string', + nullable: true, + }, + }, + required: [], + additionalProperties: false, +}; + +export const isVoipRoomsProps = ajv.compile(VoipRoomsSchema); + +type VoipRoomClose = { rid: string; token: string; comment: string; tags?: string[] }; + +const VoipRoomCloseSchema: JSONSchemaType = { + type: 'object', + properties: { + rid: { + type: 'string', + }, + token: { + type: 'string', + }, + comment: { + type: 'string', + }, + tags: { + type: 'array', + items: { + type: 'string', + }, + nullable: true, + }, + }, + required: ['rid', 'token', 'comment'], + additionalProperties: false, +}; + +export const isVoipRoomCloseProps = ajv.compile(VoipRoomCloseSchema); + export type VoipEndpoints = { 'connector.extension.getRegistrationInfoByUserId': { - GET: (params: { id: string }) => IRegistrationInfo | { result: string }; + GET: (params: ConnectorExtensionGetRegistrationInfoByUserId) => IRegistrationInfo | { result: string }; }; 'voip/queues.getSummary': { GET: () => { summary: IQueueSummary[] }; }; 'voip/queues.getQueuedCallsForThisExtension': { - GET: (params: { extension: string }) => IQueueMembershipDetails; + GET: (params: VoipQueuesGetQueuedCallsForThisExtension) => IQueueMembershipDetails; }; 'voip/queues.getMembershipSubscription': { - GET: (params: { extension: string }) => IQueueMembershipSubscription; + GET: (params: VoipQueuesGetMembershipSubscription) => IQueueMembershipSubscription; }; 'omnichannel/extensions': { - GET: ( - params: PaginatedRequest<{ status?: string; agentId?: string; queues?: string[]; extension?: string }>, - ) => PaginatedResult<{ extensions: IVoipExtensionWithAgentInfo[] }>; + GET: (params: OmnichannelExtensions) => PaginatedResult<{ extensions: IVoipExtensionWithAgentInfo[] }>; }; 'omnichannel/extension': { - GET: ( - params: { userId: string; type: 'free' | 'allocated' | 'available' } | { username: string; type: 'free' | 'allocated' | 'available' }, - ) => { + GET: (params: OmnichannelExtension) => { extensions: string[]; }; }; 'omnichannel/agent/extension': { - GET: (params: { username: string }) => { extension: Pick }; - POST: (params: { userId: string; extension: string } | { username: string; extension: string }) => void; - DELETE: (params: { username: string }) => void; + GET: (params: OmnichannelAgentExtensionGET) => { extension: Pick }; + POST: (params: OmnichannelAgentExtensionPOST) => void; + DELETE: (params: OmnichannelAgentExtensionDELETE) => void; }; 'omnichannel/agents/available': { - GET: (params: PaginatedRequest<{ text?: string; includeExtension?: string }>) => PaginatedResult<{ agents: ILivechatAgent[] }>; + GET: (params: OmnichannelAgentsAvailable) => PaginatedResult<{ agents: ILivechatAgent[] }>; }; 'voip/events': { - POST: (params: { event: VoipClientEvents; rid: string; comment?: string }) => void; + POST: (params: VoipEvents) => void; }; 'voip/room': { - GET: (params: { token: string; agentId: ILivechatAgent['_id'] } | { rid: string; token: string }) => { + GET: (params: VoipRoom) => { room: IVoipRoom; newRoom: boolean; }; }; 'voip/managementServer/checkConnection': { - GET: (params: { host: string; port: string; username: string; password: string }) => IManagementServerConnectionStatus; + GET: (params: VoipManagementServerCheckConnection) => IManagementServerConnectionStatus; }; 'voip/callServer/checkConnection': { - GET: (params: { websocketUrl: string; host: string; port: string; path: string }) => IManagementServerConnectionStatus; + GET: (params: VoipCallServerCheckConnection) => IManagementServerConnectionStatus; }; 'voip/rooms': { - GET: (params: { - agents?: string[]; - open?: boolean; - createdAt?: string; - closedAt?: string; - tags?: string[]; - queue?: string; - visitorId?: string; - }) => PaginatedResult<{ rooms: IVoipRoom[] }>; + GET: (params: VoipRooms) => PaginatedResult<{ rooms: IVoipRoom[] }>; }; 'voip/room.close': { - POST: (params: { rid: string; token: string; comment: string; tags?: string[] }) => { rid: string }; + POST: (params: VoipRoomClose) => { rid: string }; }; };