diff --git a/README.md b/README.md index 95da82d8..583383b0 100644 --- a/README.md +++ b/README.md @@ -174,14 +174,13 @@ docker-compose up | | | |-----|---| | Send Text | ✔ | -| Send Buttons | ❌ | -| Send Template | ❌ | -| Send Media: audio - video - image - document - gif

base64: ```true``` | ✔ | +| Send Buttons | ✔ - only \[ios,android\] | +| Send Media: audio - video - image - document - gif

base64: ```false``` | ✔ | | Send Media File | ✔ | | Send Audio type WhatsApp | ✔ | | Send Audio type WhatsApp - File | ✔ | | Send Location | ✔ | -| Send List | ❌ | +| Send List | ✔ \[ios,android\] | | Send Link Preview | ❌ | | Send Contact | ✔ | | Send Reaction - emoji | ✔ | diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 88bf30b3..5af67715 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -55,7 +55,7 @@ info: can build stronger and more authentic relationships with their customers, generating lasting satisfaction and loyalty. [![Run in Postman](https://run.pstmn.io/button.svg)](https://www.postman.com/codechat/workspace/codechat-whatsapp-api/api/fbe06c7b-7647-4c71-81ee-841f5b2e90d8?action=share&creator=14064846) - version: 1.3.1 + version: 1.3.2 contact: name: jrCleber email: cleber@codechat.dev @@ -63,6 +63,7 @@ info: license: name: Apache License - Version 2.0, January 2004 url: https://www.exemplo.com/licenca + components: securitySchemes: apikeyAuth: @@ -73,8 +74,63 @@ components: type: http scheme: bearer bearerFormat: JWT + schemas: + Message: + type: object + properties: + id: + type: integer + example: 16262 + keyId: + type: string + example: "01J2EKS9WE0DX6HJG0ACW0NBPY" + keyFromMe: + type: boolean + example: true + keyRemoteJid: + type: string + example: "553197853327@s.whatsapp.net" + keyParticipant: + type: string + example: "" + pushName: + type: string + example: "" + messageType: + type: string + example: "viewOnceMessage" + content: + type: object + description: "Details of the content (empty object in this example)." + example: {} + messageTimestamp: + type: integer + format: int64 + description: "Unix timestamp of the message." + example: 1720624916 + instanceId: + type: integer + example: 1 + device: + type: string + example: "web" + isGroup: + type: boolean + example: false + required: + - id + - keyId + - keyFromMe + - keyRemoteJid + - messageType + - messageTimestamp + - instanceId + - device + - isGroup + security: - bearerAuth: [] + tags: - name: Instance Controller description: Controller responsible for managing the application instances. @@ -152,39 +208,6 @@ paths: responses: '201': description: Created - headers: - X-Powered-By: - schema: - type: string - example: Express - Content-Type: - schema: - type: string - example: application/json; charset=utf-8 - Content-Length: - schema: - type: integer - example: '442' - ETag: - schema: - type: string - example: W/"1ba-TGxN/leIZn7YtssW90IY6RKaHvM" - Vary: - schema: - type: string - example: Accept-Encoding - Date: - schema: - type: string - example: Mon, 04 Dec 2023 23:34:23 GMT - Connection: - schema: - type: string - example: keep-alive - Keep-Alive: - schema: - type: string - example: timeout=5 content: application/json: schema: @@ -219,39 +242,6 @@ paths: responses: '200': description: OK - headers: - X-Powered-By: - schema: - type: string - example: Express - Content-Type: - schema: - type: string - example: application/json; charset=utf-8 - Content-Length: - schema: - type: integer - example: '631' - ETag: - schema: - type: string - example: W/"277-xtshIWa2qiaPH/lRSdSpOLf18eQ" - Vary: - schema: - type: string - example: Accept-Encoding - Date: - schema: - type: string - example: Tue, 05 Dec 2023 00:42:54 GMT - Connection: - schema: - type: string - example: keep-alive - Keep-Alive: - schema: - type: string - example: timeout=5 content: application/json: schema: @@ -318,43 +308,6 @@ paths: responses: '200': description: OK - headers: - X-Powered-By: - schema: - type: string - example: Express - Content-Type: - schema: - type: string - example: application/json; charset=utf-8 - ETag: - schema: - type: string - example: W/"3080-Jq6QcOPmu0LaxEpgAfV8ikVLhos" - Vary: - schema: - type: string - example: Accept-Encoding - Content-Encoding: - schema: - type: string - example: gzip - Date: - schema: - type: string - example: Mon, 04 Dec 2023 23:52:10 GMT - Connection: - schema: - type: string - example: keep-alive - Keep-Alive: - schema: - type: string - example: timeout=5 - Transfer-Encoding: - schema: - type: string - example: chunked content: application/json: schema: @@ -429,39 +382,6 @@ paths: responses: '200': description: OK - headers: - X-Powered-By: - schema: - type: string - example: Express - Content-Type: - schema: - type: string - example: application/json; charset=utf-8 - Content-Length: - schema: - type: integer - example: '35' - ETag: - schema: - type: string - example: W/"23-nac7WzMd0OLjn7OhjfARLJe158A" - Vary: - schema: - type: string - example: Accept-Encoding - Date: - schema: - type: string - example: Tue, 05 Dec 2023 00:48:48 GMT - Connection: - schema: - type: string - example: keep-alive - Keep-Alive: - schema: - type: string - example: timeout=5 content: application/json: schema: @@ -580,39 +500,6 @@ paths: responses: '201': description: Created - headers: - X-Powered-By: - schema: - type: string - example: Express - Content-Type: - schema: - type: string - example: application/json; charset=utf-8 - Content-Length: - schema: - type: integer - example: '280' - ETag: - schema: - type: string - example: W/"118-0QNcm2pEx0oVk/6YPgCKDQyvVFw" - Vary: - schema: - type: string - example: Accept-Encoding - Date: - schema: - type: string - example: Tue, 05 Dec 2023 09:07:45 GMT - Connection: - schema: - type: string - example: keep-alive - Keep-Alive: - schema: - type: string - example: timeout=5 content: application/json: schema: @@ -738,7 +625,9 @@ paths: '200': description: Successful response content: - application/json: {} + application/json: + schema: + $ref: '#/components/schemas/Message' /message/sendMediaFile/{instanceName}: post: @@ -792,39 +681,6 @@ paths: responses: '201': description: Created - headers: - X-Powered-By: - schema: - type: string - example: Express - Content-Type: - schema: - type: string - example: application/json; charset=utf-8 - Content-Length: - schema: - type: integer - example: '932' - ETag: - schema: - type: string - example: W/"3a4-B4T6qfkbaGZZAwZru/T1JbHB9xg" - Vary: - schema: - type: string - example: Accept-Encoding - Date: - schema: - type: string - example: Tue, 05 Dec 2023 09:10:29 GMT - Connection: - schema: - type: string - example: keep-alive - Keep-Alive: - schema: - type: string - example: timeout=5 content: application/json: schema: @@ -904,7 +760,9 @@ paths: '200': description: Successful response content: - application/json: {} + application/json: + schema: + $ref: '#/components/schemas/Message' /message/sendContact/{instanceName}: post: @@ -949,7 +807,9 @@ paths: '200': description: Successful response content: - application/json: {} + application/json: + schema: + $ref: '#/components/schemas/Message' /message/sendReaction/{instanceName}: post: @@ -982,7 +842,9 @@ paths: '200': description: Successful response content: - application/json: {} + application/json: + schema: + $ref: '#/components/schemas/Message' /message/sendWhatsAppAudio/{instanceName}: post: @@ -1017,7 +879,9 @@ paths: '200': description: Successful response content: - application/json: {} + application/json: + schema: + $ref: '#/components/schemas/Message' /message/sendWhatsAppAudioFile/{instanceName}: post: @@ -1078,70 +942,196 @@ paths: '500': description: Internal Server Error - Error in processing the request. - /chat/whatsappNumbers/{instanceName}: + /message/sendButtons/{instanceName}: post: tags: - - Chat Controller - summary: WhatsApp Number - description: | - This endpoint is used to add WhatsApp numbers to a specific instance. It expects a JSON object in the request body with an array of numbers. The numbers must be provided as strings. The instance name is passed as a path parameter. + - Send Message Controller + summary: Send a buttons message + description: Sends a message with buttons to a specified number. + parameters: + - in: path + name: instanceName + required: true + schema: + type: string + description: The instance name for the messaging service. requestBody: + required: true content: application/json: schema: type: object - example: - numbers: - - - required - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: '- required' - example: 'codechat_v1' + properties: + number: + type: string + description: "The recipient's phone number." + example: "5531900000000" + options: + type: object + properties: + delay: + type: integer + description: "Delay in milliseconds before sending the message." + example: 1200 + presence: + type: string + description: "Typing presence status." + example: "composing" + buttonsMessage: + type: object + properties: + thumbnailUrl: + type: string + description: "URL of the thumbnail image (optional)." + nullable: true + title: + type: string + description: "Title of the buttons message." + description: + type: string + description: "Description of the buttons message (optional)." + nullable: true + footer: + type: string + description: "Footer text for the buttons message (optional)." + nullable: true + buttons: + type: array + items: + type: object + properties: + type: + type: string + description: "Type of the button." + displayText: + type: string + description: "Text displayed on the button." + id: + type: string + description: "Identifier for the button (optional)." + nullable: true + copyCode: + type: string + description: "Copy code for the button (only for type 'copy')." + nullable: true + url: + type: string + description: "URL for the button (only for type 'url')." + nullable: true + phoneNumber: + type: string + description: "Phone number for the button (only for type 'call')." + nullable: true responses: '200': - description: Created + description: Successful response content: application/json: schema: - type: object - example: - - jid: 123@s.whatsapp.net - exists: true - - jid: '5531988888' - exists: false - '400': - description: Bad Request + $ref: '#/components/schemas/Message' + + /message/sendList/{instanceName}: + post: + tags: + - Send Message Controller + summary: Send a list message + description: Sends a structured list message to a specified number. + parameters: + - in: path + name: instanceName + required: true + schema: + type: string + description: The instance name for the messaging service. + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + number: + type: string + example: "5531997853327" + options: + type: object + properties: + delay: + type: integer + example: 1200 + presence: + type: string + example: "composing" + listMessage: + type: object + properties: + thumbnailUrl: + type: string + nullable: true + description: "URL of the thumbnail image (optional)." + title: + type: string + description: + type: string + nullable: true + description: "Description of the list message (optional)." + footer: + type: string + nullable: true + description: "Footer text for the list message (optional)." + sections: + type: array + items: + type: object + properties: + buttonText: + type: string + list: + type: array + items: + type: object + properties: + title: + type: string + rows: + type: array + items: + type: object + properties: + header: + type: string + nullable: true + title: + type: string + description: + type: string + nullable: true + id: + type: string + nullable: true + responses: + '200': + description: Successful response content: application/json: schema: - type: object - example: - status: 400 - error: Bad Request - message: - - property: numbers[0] - message: '"numbers" must be an array of numeric strings' + $ref: '#/components/schemas/Message' - /chat/markMessageAsRead/{instanceName}: - put: + /chat/whatsappNumbers/{instanceName}: + post: tags: - Chat Controller - summary: Mark Message as Read - deprecated: true + summary: WhatsApp Number + description: | + This endpoint is used to add WhatsApp numbers to a specific instance. It expects a JSON object in the request body with an array of numbers. The numbers must be provided as strings. The instance name is passed as a path parameter. requestBody: content: application/json: schema: type: object example: - readMessages: - - remoteJid: - required - fromMe: - required - id: - required + numbers: + - - required parameters: - name: instanceName in: path @@ -1158,8 +1148,10 @@ paths: schema: type: object example: - message: Read messages - read: success + - jid: 123@s.whatsapp.net + exists: true + - jid: '5531988888' + exists: false '400': description: Bad Request content: @@ -1170,12 +1162,8 @@ paths: status: 400 error: Bad Request message: - - property: readMessages[0].fromMe - message: readMessages[0].fromMe is not of a type(s) boolean - - property: readMessages[0].fromMe - message: >- - readMessages[0].fromMe is not one of enum values: - true,false + - property: numbers[0] + message: '"numbers" must be an array of numeric strings' /chat/readMessages/{instanceName}: patch: @@ -1608,7 +1596,7 @@ paths: content: application/json: {} - /chat/findChats/{inatnceName}: + /chat/findChats/{instanceName}: get: tags: - Chat Controller diff --git a/package.json b/package.json index 3d64a1e1..1e7b68f2 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,6 @@ "@adiwajshing/keyed-db": "^0.2.4", "@hapi/boom": "^10.0.1", "@prisma/client": "^5.14.0", - "@scalar/express-api-reference": "^0.4.42", "@whiskeysockets/baileys": "6.7.5", "axios": "^1.6.2", "class-validator": "^0.14.0", @@ -69,7 +68,8 @@ "pino-pretty": "^11.0.0", "qrcode": "^1.5.1", "qrcode-terminal": "^0.12.0", - "uuid": "^10.0.0", + "swagger-ui-express": "^5.0.1", + "ulid": "^2.3.0", "ws": "^8.18.0", "yamljs": "^0.3.0" }, @@ -85,7 +85,7 @@ "@types/node": "^20.12.12", "@types/qrcode": "^1.5.5", "@types/qrcode-terminal": "^0.12.2", - "@types/uuid": "^10.0.0", + "@types/swagger-ui-express": "^4.1.6", "@types/ws": "^8.5.10", "@types/yamljs": "^0.2.34", "@typescript-eslint/eslint-plugin": "6.21.0", diff --git a/public/css/dark-theme-swagger.css b/public/css/dark-theme-swagger.css index e4bf1c8c..81b63b3a 100644 --- a/public/css/dark-theme-swagger.css +++ b/public/css/dark-theme-swagger.css @@ -5,6 +5,10 @@ body { color: #e5e5e5; } +.swagger-ui { + color: #bbbbbb; +} + .swagger-ui .topbar { background-color: #333842; } @@ -173,3 +177,19 @@ body { .swagger-ui table.headers td { color: #b5b9c3; } + +.swagger-ui .markdown code, .swagger-ui .renderedMarkdown code { + color: #ff6f6f; +} + +.swagger-ui .parameter__type { + color: #fff; +} + +.swagger-ui .prop-format { + color: #ff0000; +} + +.swagger-ui .parameter__name.required:after{ + color: #ff0000; +} \ No newline at end of file diff --git a/src/config/scala.config.ts b/src/config/scala.config.ts index 54a18b9d..2ba9cdb9 100644 --- a/src/config/scala.config.ts +++ b/src/config/scala.config.ts @@ -34,8 +34,8 @@ import { Router } from 'express'; import { join } from 'path'; import YAML from 'yamljs'; -import { apiReference } from '@scalar/express-api-reference'; import { readFileSync } from 'fs'; +import { serve, setup } from 'swagger-ui-express'; const router = Router(); @@ -51,11 +51,10 @@ if (process.env?.API_BACKEND) { export const docsRouter = router.use( '/docs', - apiReference({ - spec: { - content() { - return json; - }, - }, + serve, + setup(json, { + customSiteTitle: 'CodeChat Api V1', + customCssUrl: '/css/dark-theme-swagger.css', + customfavIcon: '/images/logo.png', }), ); diff --git a/src/middle/logger.middle.ts b/src/middle/logger.middle.ts index 8cee40f1..ab0b87bd 100644 --- a/src/middle/logger.middle.ts +++ b/src/middle/logger.middle.ts @@ -71,7 +71,9 @@ export class LoggerMiddleware { body: JSON.stringify(req?.body || {}), }, description: 'Request received', - instanceId: req?.params?.instanceId ? Number(req.params.instanceId) : undefined, + instanceId: req?.params?.instanceId + ? Number(req.params.instanceId) + : undefined, }, }) .catch((error) => logger.error(error)); diff --git a/src/validate/ulid.ts b/src/validate/ulid.ts new file mode 100644 index 00000000..c193e1cd --- /dev/null +++ b/src/validate/ulid.ts @@ -0,0 +1,49 @@ +/** + * ┌──────────────────────────────────────────────────────────────────────────────┐ + * │ @author jrCleber │ + * │ @filename ulid.ts │ + * │ Developed by: Cleber Wilson │ + * │ Creation date: Jul 17, 2022 │ + * │ Contact: contato@codechat.dev │ + * ├──────────────────────────────────────────────────────────────────────────────┤ + * │ @copyright © Cleber Wilson 2022. All rights reserved. │ + * │ Licensed under the Apache License, Version 2.0 │ + * │ │ + * │ @license "https://github.com/code-chat-br/whatsapp-api/blob/main/LICENSE" │ + * │ │ + * │ You may not use this file except in compliance with the License. │ + * │ You may obtain a copy of the License at │ + * │ │ + * │ http://www.apache.org/licenses/LICENSE-2.0 │ + * │ │ + * │ Unless required by applicable law or agreed to in writing, software │ + * │ distributed under the License is distributed on an "AS IS" BASIS, │ + * │ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │ + * │ │ + * │ See the License for the specific language governing permissions and │ + * │ limitations under the License. │ + * │ │ + * ├──────────────────────────────────────────────────────────────────────────────┤ + * │ @important │ + * │ For any future changes to the code in this file, it is recommended to │ + * │ contain, together with the modification, the information of the developer │ + * │ who changed it and the date of modification. │ + * └──────────────────────────────────────────────────────────────────────────────┘ + */ + +import { decodeTime } from 'ulid'; + +export const isValidUlid = (id: string) => { + const ulidPattern = /^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$/; + + if (!ulidPattern.test(id)) { + return false; + } + + try { + decodeTime(id); + return true; + } catch (error) { + return false; + } +}; diff --git a/src/validate/validate.schema.ts b/src/validate/validate.schema.ts index 91f5e411..c9896c2c 100644 --- a/src/validate/validate.schema.ts +++ b/src/validate/validate.schema.ts @@ -45,7 +45,7 @@ */ import { JSONSchema7, JSONSchema7Definition } from 'json-schema'; -import { v4 } from 'uuid'; +import { ulid } from 'ulid'; const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { const properties = {}; @@ -68,7 +68,7 @@ const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { // Instance Schema export const instanceNameSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { instanceName: { type: 'string', minLength: 1 }, @@ -78,7 +78,7 @@ export const instanceNameSchema: JSONSchema7 = { }; export const oldTokenSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { oldToken: { type: 'string' }, @@ -99,6 +99,7 @@ const optionsSchema: JSONSchema7 = { enum: ['unavailable', 'available', 'composing', 'recording', 'paused'], }, quotedMessageId: { type: 'integer', description: 'Enter the message id' }, + messageId: { type: 'string', description: 'Set your own id for the message.' }, }, }; @@ -109,7 +110,7 @@ const numberDefinition: JSONSchema7Definition = { }; export const textMessageSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { number: { ...numberDefinition }, @@ -127,7 +128,7 @@ export const textMessageSchema: JSONSchema7 = { }; export const mediaMessageSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { number: { ...numberDefinition }, @@ -135,7 +136,10 @@ export const mediaMessageSchema: JSONSchema7 = { mediaMessage: { type: 'object', properties: { - mediatype: { type: 'string', enum: ['image', 'document', 'video', 'audio', 'sticker'] }, + mediatype: { + type: 'string', + enum: ['image', 'document', 'video', 'audio', 'sticker'], + }, media: { type: 'string' }, fileName: { type: 'string' }, caption: { type: 'string' }, @@ -148,12 +152,15 @@ export const mediaMessageSchema: JSONSchema7 = { }; export const mediaFileMessageSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { number: { ...numberDefinition }, caption: { type: 'string' }, - mediatype: { type: 'string', enum: ['image', 'document', 'video', 'audio', 'sticker'] }, + mediatype: { + type: 'string', + enum: ['image', 'document', 'video', 'audio', 'sticker'], + }, presence: { type: 'string', enum: ['composing', 'recording'] }, delay: { type: 'string' }, }, @@ -162,7 +169,7 @@ export const mediaFileMessageSchema: JSONSchema7 = { }; export const audioMessageSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { number: { ...numberDefinition }, @@ -180,7 +187,7 @@ export const audioMessageSchema: JSONSchema7 = { }; export const audioFileMessageSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { number: { ...numberDefinition }, @@ -191,7 +198,7 @@ export const audioFileMessageSchema: JSONSchema7 = { }; export const locationMessageSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { number: { ...numberDefinition }, @@ -211,8 +218,99 @@ export const locationMessageSchema: JSONSchema7 = { required: ['number', 'locationMessage'], }; +export const buttonsMessageSchema: JSONSchema7 = { + $id: ulid(), + type: 'object', + properties: { + number: { ...numberDefinition }, + options: { ...optionsSchema }, + buttonsMessage: { + type: 'object', + properties: { + thumbnailUrl: { type: 'string' }, + title: { type: 'string' }, + description: { type: 'string' }, + footer: { type: 'string' }, + buttons: { + type: 'array', + items: { + type: 'object', + properties: { + type: { + type: 'string', + enum: ['reply', 'copy', 'url', 'call'], + }, + displayText: { type: 'string' }, + id: { type: 'string' }, + url: { type: 'string' }, + phoneNumber: { type: 'string' }, + }, + required: ['type', 'displayText'], + ...isNotEmpty('id', 'url', 'phoneNumber'), + }, + }, + }, + required: ['title', 'buttons'], + ...isNotEmpty('thumbnailUrl', 'footer', 'description'), + }, + }, + required: ['number', 'buttonsMessage'], +}; + +export const listMessageSchema: JSONSchema7 = { + $id: ulid(), + type: 'object', + properties: { + number: { ...numberDefinition }, + options: { ...optionsSchema }, + listMessage: { + type: 'object', + properties: { + thumbnailUrl: { type: 'string' }, + title: { type: 'string' }, + description: { type: 'string' }, + footer: { type: 'string' }, + sections: { + type: 'array', + items: { + type: 'object', + properties: { + buttonText: { type: 'string' }, + list: { + type: 'array', + properties: { + title: { type: 'string' }, + rows: { + type: 'array', + items: { + type: 'object', + properties: { + header: { type: 'string' }, + title: { type: 'string' }, + description: { type: 'string' }, + id: { type: 'string' }, + }, + required: ['title'], + ...isNotEmpty('header', 'description', 'id'), + }, + }, + }, + required: ['title', 'rows'], + }, + }, + required: ['buttonText', 'list'], + }, + }, + }, + required: ['title', 'sections'], + ...isNotEmpty('thumbnailUrl', 'footer', 'description'), + }, + }, + required: ['number', 'listMessage'], +}; + export const contactMessageSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { number: { ...numberDefinition }, @@ -242,7 +340,7 @@ export const contactMessageSchema: JSONSchema7 = { }; export const reactionMessageSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { reactionMessage: { @@ -269,7 +367,7 @@ export const reactionMessageSchema: JSONSchema7 = { // Chat Schema export const whatsappNumberSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { numbers: { @@ -286,7 +384,7 @@ export const whatsappNumberSchema: JSONSchema7 = { }; export const readMessageSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { readMessages: { @@ -308,7 +406,7 @@ export const readMessageSchema: JSONSchema7 = { }; export const readMessageForIdSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { ids: { @@ -324,7 +422,7 @@ export const readMessageForIdSchema: JSONSchema7 = { }; export const updatePresenceSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { presence: { @@ -337,7 +435,7 @@ export const updatePresenceSchema: JSONSchema7 = { }; export const archiveChatSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { lastMessage: { @@ -364,7 +462,7 @@ export const archiveChatSchema: JSONSchema7 = { }; export const deleteMessageSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { id: { type: 'string', pattern: '\\d+', minLength: 1 }, @@ -374,7 +472,7 @@ export const deleteMessageSchema: JSONSchema7 = { }; export const contactValidateSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { where: { @@ -388,7 +486,7 @@ export const contactValidateSchema: JSONSchema7 = { }; export const profilePictureSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { number: { type: 'string' }, @@ -397,7 +495,7 @@ export const profilePictureSchema: JSONSchema7 = { }; export const rejectCallSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { callId: { type: 'string' }, @@ -408,7 +506,7 @@ export const rejectCallSchema: JSONSchema7 = { }; export const messageValidateSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { where: { @@ -441,7 +539,7 @@ export const messageValidateSchema: JSONSchema7 = { }; export const mediaUrlSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { id: { type: 'string', pattern: '\\d+', minLength: 1 }, @@ -452,7 +550,7 @@ export const mediaUrlSchema: JSONSchema7 = { // Group Schema export const createGroupSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { subject: { type: 'string' }, @@ -475,7 +573,7 @@ export const createGroupSchema: JSONSchema7 = { }; export const groupJidSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { groupJid: { type: 'string', pattern: '^[\\d-]+@g.us$' }, @@ -485,7 +583,7 @@ export const groupJidSchema: JSONSchema7 = { }; export const updateParticipantsSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { groupJid: { type: 'string' }, @@ -510,7 +608,7 @@ export const updateParticipantsSchema: JSONSchema7 = { }; export const updateGroupPicture: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { groupJid: { type: 'string' }, @@ -522,7 +620,7 @@ export const updateGroupPicture: JSONSchema7 = { // Webhook Schema export const webhookSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { url: { type: 'string' }, @@ -559,7 +657,7 @@ export const webhookSchema: JSONSchema7 = { // MinIO Schema export const s3MediaSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { id: { type: 'integer' }, @@ -570,7 +668,7 @@ export const s3MediaSchema: JSONSchema7 = { }; export const s3MediaUrlSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { id: { type: 'string', pattern: '\\d+', minLength: 1 }, @@ -582,7 +680,7 @@ export const s3MediaUrlSchema: JSONSchema7 = { // Typebot Schema export const typebotSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { publicId: { type: 'string' }, @@ -594,7 +692,7 @@ export const typebotSchema: JSONSchema7 = { }; export const typebotUpdateSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { publicId: { type: 'string' }, @@ -605,7 +703,7 @@ export const typebotUpdateSchema: JSONSchema7 = { }; export const typebotUpdateSessionSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { sessionId: { type: 'string' }, @@ -616,7 +714,7 @@ export const typebotUpdateSessionSchema: JSONSchema7 = { }; export const typebotFindSessionSchema: JSONSchema7 = { - $id: v4(), + $id: ulid(), type: 'object', properties: { sessionId: { type: 'string' }, diff --git a/src/whatsapp/controllers/sendMessage.controller.ts b/src/whatsapp/controllers/sendMessage.controller.ts index e2987985..6b316afb 100644 --- a/src/whatsapp/controllers/sendMessage.controller.ts +++ b/src/whatsapp/controllers/sendMessage.controller.ts @@ -41,7 +41,9 @@ import { AudioMessageFileDto, MediaFileDto, SendAudioDto, + SendButtonsDto, SendContactDto, + SendListDto, SendLocationDto, SendMediaDto, SendReactionDto, @@ -123,4 +125,12 @@ export class SendMessageController { } return await this.waMonitor.waInstances.get(instanceName).reactionMessage(data); } + + public async sendButtons({ instanceName }: InstanceDto, data: SendButtonsDto) { + return await this.waMonitor.waInstances.get(instanceName).buttonsMessage(data); + } + + public async sendList({ instanceName }: InstanceDto, data: SendListDto) { + return await this.waMonitor.waInstances.get(instanceName).listButtons(data); + } } diff --git a/src/whatsapp/dto/sendMessage.dto.ts b/src/whatsapp/dto/sendMessage.dto.ts index b6b83dd0..2a2fec26 100644 --- a/src/whatsapp/dto/sendMessage.dto.ts +++ b/src/whatsapp/dto/sendMessage.dto.ts @@ -39,11 +39,13 @@ */ import { proto, WAPresence } from '@whiskeysockets/baileys'; +import { ulid } from 'ulid'; export class Options { delay?: number; presence?: WAPresence; quotedMessageId?: number; + messageId?: string; } class OptionsMessage { options: Options; @@ -118,3 +120,154 @@ class ReactionMessage { export class SendReactionDto { reactionMessage: ReactionMessage; } + +const toString = (value: any) => JSON.stringify(value); + +type TypeButton = 'reply' | 'copy' | 'url' | 'call'; + +export class Button { + type: TypeButton; + displayText: string; + id?: string; + url?: string; + copyCode?: string; + phoneNumber?: string; + + constructor(props: Partial