diff --git a/apps/meteor/app/api/server/v1/im.ts b/apps/meteor/app/api/server/v1/im.ts index 76542f1e55827..5795f9601ac2f 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 ab8ee8a66e428..e501782744d4a 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 a80ea72447abe..1d87a9f6e6daa 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 2c9485b74e4dc..7d964af4c16a2 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 880c157455d4f..76a5fe26dfcbb 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/package.json b/apps/meteor/package.json index 7aa3c80937be4..30d3bca1d4bf3 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", 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 d1f6e82dc75e6..9eb450539ab95 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 04b4a05c0b4ab..49573302bed73 100644 --- a/packages/rest-typings/src/index.ts +++ b/packages/rest-typings/src/index.ts @@ -155,7 +155,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 2af16f69620d1..7045e2383a14c 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 e22ab320c99f3..1754c302f5a9e 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 c5f56e26f0974..e272895667118 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 1f39263abb673..84efd66ecb60a 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 943aebb9fdcac..dfd30aa9a117b 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 fda67ddf98101..af0ad5be6d8d4 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 0000000000000..1a1ea759680ac --- /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 0000000000000..0a836961f3665 --- /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 0000000000000..beca20ef5dc80 --- /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 0000000000000..a91ee8ba9a910 --- /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 927f7ac3458f3..87c4adfe4fa7c 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 b2d553e036f20..28a630ea3352a 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 d8bf5f77312cf..62ce4110ddbb3 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 afa4745ed86dd..d0347fe7e829f 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 0a52dddc940ec..2532879dd9a9c 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 5cb5db378ffc0..10540a3ecd624 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 200302c99711e..fda658af22672 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 45c482c0957d7..3fd343cf4c036 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 f1bb124a956bb..de477d37a8136 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 89f993d50b21d..4928257efd1e5 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 3b29ad0b9274d..fc2ab9e23fd9b 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 85506bf1aff8d..3128db4ec2590 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 d0b07c6afbcaf..54568328bc42a 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 6e3d729a02221..8c4135fc4b5b6 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 647127c4b4694..aca408dc1109d 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 b3fd2fb723c3d..837bbf1afa0e7 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 0f9951f4dfec6..4b311d1af3d24 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 4030043e2f02d..c314e43deb6c0 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 5398586927a30..fbdeafc23fef4 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 }; }; };