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