From 296b29bbf82602ec82b684c4f520bc9e074e5d81 Mon Sep 17 00:00:00 2001 From: Lucas Pelegrino Date: Tue, 22 Jul 2025 15:11:10 -0300 Subject: [PATCH] feat: adds new endpoint to fetch outbound provider metadata (#36424) Co-authored-by: Diego Sampaio <8591547+sampaiodiego@users.noreply.github.com> --- .changeset/giant-toes-decide.md | 5 + .../server/api/outbound.ts | 89 ++++----- .../server/outboundcomms/rest.ts | 183 +++++++++++++++++- 3 files changed, 228 insertions(+), 49 deletions(-) create mode 100644 .changeset/giant-toes-decide.md diff --git a/.changeset/giant-toes-decide.md b/.changeset/giant-toes-decide.md new file mode 100644 index 00000000000..fef7f852afb --- /dev/null +++ b/.changeset/giant-toes-decide.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": minor +--- + +Adds an endpoint to fetch a Outbound Comms Provider's metadata. diff --git a/apps/meteor/ee/app/livechat-enterprise/server/api/outbound.ts b/apps/meteor/ee/app/livechat-enterprise/server/api/outbound.ts index 12ce248e4b0..92ef41a678c 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/api/outbound.ts +++ b/apps/meteor/ee/app/livechat-enterprise/server/api/outbound.ts @@ -1,55 +1,50 @@ -import type { IOutboundProvider } from '@rocket.chat/core-typings'; -import { ajv } from '@rocket.chat/rest-typings'; - import { API } from '../../../../../app/api/server'; -import { isGETOutboundProviderParams } from '../outboundcomms/rest'; +import { + GETOutboundProvidersResponseSchema, + GETOutboundProviderParamsSchema, + GETOutboundProviderBadRequestErrorSchema, + GETOutboundProviderMetadataSchema, +} from '../outboundcomms/rest'; import { outboundMessageProvider } from './lib/outbound'; import type { ExtractRoutesFromAPI } from '../../../../../app/api/server/ApiClass'; -const outboundCommsEndpoints = API.v1.get( - 'omnichannel/outbound/providers', - { - response: { - 200: ajv.compile<{ providers: IOutboundProvider[] }>({ - type: 'object', - properties: { - providers: { - type: 'array', - items: { - type: 'object', - properties: { - providerId: { - type: 'string', - }, - providerName: { - type: 'string', - }, - supportsTemplates: { - type: 'boolean', - }, - providerType: { - type: 'string', - }, - documentationUrl: { - type: 'string', - }, - }, - }, - }, - }, - }), +const outboundCommsEndpoints = API.v1 + .get( + 'omnichannel/outbound/providers', + { + response: { + 200: GETOutboundProvidersResponseSchema, + 400: GETOutboundProviderBadRequestErrorSchema, + }, + query: GETOutboundProviderParamsSchema, + authRequired: true, }, - query: isGETOutboundProviderParams, - authRequired: true, - }, - async function action() { - const { type } = this.queryParams; + async function action() { + const { type } = this.queryParams; - const providers = outboundMessageProvider.listOutboundProviders(type); - return API.v1.success({ - providers, - }); - }, -); + const providers = outboundMessageProvider.listOutboundProviders(type); + return API.v1.success({ + providers, + }); + }, + ) + .get( + 'omnichannel/outbound/providers/:id/metadata', + { + response: { + 200: GETOutboundProviderMetadataSchema, + 400: GETOutboundProviderBadRequestErrorSchema, + }, + authRequired: true, + }, + async function action() { + const { id } = this.urlParams; + + const providerMetadata = await outboundMessageProvider.getProviderMetadata(id); + return API.v1.success({ + metadata: providerMetadata, + }); + }, + ); export type OutboundCommsEndpoints = ExtractRoutesFromAPI; diff --git a/apps/meteor/ee/app/livechat-enterprise/server/outboundcomms/rest.ts b/apps/meteor/ee/app/livechat-enterprise/server/outboundcomms/rest.ts index 5b01cdef085..e13d368bea9 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/outboundcomms/rest.ts +++ b/apps/meteor/ee/app/livechat-enterprise/server/outboundcomms/rest.ts @@ -1,4 +1,4 @@ -import type { IOutboundMessage } from '@rocket.chat/core-typings'; +import type { IOutboundMessage, IOutboundProvider, IOutboundProviderMetadata } from '@rocket.chat/core-typings'; import Ajv from 'ajv'; import type { OutboundCommsEndpoints } from '../api/outbound'; @@ -24,7 +24,49 @@ const GETOutboundProviderSchema = { required: [], additionalProperties: false, }; -export const isGETOutboundProviderParams = ajv.compile(GETOutboundProviderSchema); +export const GETOutboundProviderParamsSchema = ajv.compile(GETOutboundProviderSchema); + +const GETOutboundProvidersResponse = { + type: 'object', + properties: { + providers: { + type: 'array', + items: { + type: 'object', + properties: { + providerId: { + type: 'string', + }, + providerName: { + type: 'string', + }, + supportsTemplates: { + type: 'boolean', + }, + providerType: { + type: 'string', + }, + }, + }, + }, + }, +}; +export const GETOutboundProvidersResponseSchema = ajv.compile<{ providers: IOutboundProvider[] }>(GETOutboundProvidersResponse); + +const GETOutboundProviderBadRequestError = { + type: 'object', + properties: { + success: { + type: 'boolean', + }, + message: { + type: 'string', + }, + }, +}; +export const GETOutboundProviderBadRequestErrorSchema = ajv.compile<{ success: boolean; message: string }>( + GETOutboundProviderBadRequestError, +); type POSTOutboundMessageParams = { message: IOutboundMessage; @@ -142,3 +184,140 @@ const POSTOutboundMessageSchema = { }; export const isPOSTOutboundMessageParams = ajv.compile(POSTOutboundMessageSchema); + +const OutboundProviderMetadataSchema = { + type: 'object', + properties: { + metadata: { + type: 'object', + properties: { + providerId: { + type: 'string', + }, + providerName: { + type: 'string', + }, + supportsTemplates: { + type: 'boolean', + }, + providerType: { + type: 'string', + enum: ['phone', 'email'], + }, + templates: { + type: 'object', + additionalProperties: { + type: 'array', + items: { + type: 'object', + properties: { + id: { + type: 'string', + }, + name: { + type: 'string', + }, + language: { + type: 'string', + }, + type: { + type: 'string', + }, + category: { + type: 'string', + }, + status: { + type: 'string', + }, + qualityScore: { + type: 'object', + required: ['score', 'reasons'], + properties: { + score: { + type: 'string', + enum: ['GREEN', 'YELLOW', 'RED', 'UNKNOWN'], + }, + reasons: { + type: ['array', 'null'], + items: { + type: 'string', + }, + }, + }, + }, + components: { + type: 'array', + items: { + type: 'object', + oneOf: [ + { + properties: { + type: { const: 'HEADER' }, + format: { + type: 'string', + enum: ['TEXT', 'IMAGE', 'VIDEO', 'DOCUMENT'], + }, + text: { type: 'string' }, + example: { + type: 'object', + properties: { + headerText: { + type: 'array', + items: { type: 'string' }, + }, + }, + }, + }, + }, + { + properties: { + type: { const: 'BODY' }, + text: { type: 'string' }, + example: { + type: 'object', + properties: { + bodyText: { + type: 'array', + items: { + type: 'array', + items: { type: 'string' }, + }, + }, + }, + }, + }, + required: ['type', 'text'], + }, + { + properties: { + type: { const: 'FOOTER' }, + text: { type: 'string' }, + }, + required: ['type', 'text'], + }, + ], + }, + }, + createdAt: { type: 'string' }, + createdBy: { type: 'string' }, + modifiedAt: { type: 'string' }, + modifiedBy: { type: 'string' }, + namespace: { type: 'string' }, + wabaAccountId: { type: 'string' }, + phoneNumber: { type: 'string' }, + partnerId: { type: 'string' }, + externalId: { type: 'string' }, + updatedExternal: { type: 'string' }, + rejectedReason: { + type: ['string', 'null'], + }, + }, + }, + }, + }, + }, + }, + }, +}; + +export const GETOutboundProviderMetadataSchema = ajv.compile<{ metadata: IOutboundProviderMetadata }>(OutboundProviderMetadataSchema);