Compare commits

...
10 Commits
Author SHA1 Message Date
allburov 6af547d2af [core] Quick fix for webjs engine.
Release / deploy-docker (push) Waiting to run
Fix #46
2023-01-15 14:52:17 +07:00
allburov d72b1822cb [core][2023.1] Add checkNumberStatus for webjs engine 2023-01-15 14:37:15 +07:00
allburov d34df18da8 [core][2023.1] Add contacts endpoints 2023-01-15 14:37:14 +07:00
allburov 27cb247760 [core][docs] Add contact api changelog 2023-01-09 09:31:00 +07:00
allburov 7a66d6fccd [core][docs] Add changelog.md 2023-01-09 09:31:00 +07:00
allburov f1cb372339 [core][docs] Add contacts page 2023-01-09 09:31:00 +07:00
allburov 46d65e6fc0 [core][docs] Reorder guides 2023-01-09 09:31:00 +07:00
allburov 6168298b5e [core][docs] Move engines doc to config 2023-01-09 09:31:00 +07:00
allburov d5fef413ca [core] Add swagger authentication to changelog 2022-12-19 12:35:36 +07:00
allburov 0802ee6106 [core][docs] Add GET /messages request. Fix #31 2022-12-19 12:32:55 +07:00
23 changed files with 358 additions and 66 deletions

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
# Changelog
You'll find changelog on [the changelog page](https://waha.devlike.pro/docs/help/changelog/)
+1
View File
@@ -56,6 +56,7 @@
- Multiple WhatsApp account running inside one container
## Security
- Swagger panel authentication
- API authentication
## Updates
@@ -12,6 +12,20 @@ menu:
weight: 600
toc: true
---
## 2021.1
- Added [contacts API]({{< relref "/docs/how-to/contacts" >}})
- Get all contacts
- Get a contact
- Get contact "about" (status)
- Get contact profile picture
- Check number exists (is registered in WhatsApp) - works even if the number is not in the contact list
- Block and unblock contact
## 2022.12
- Added `GET /messages/` endpoint to get chat messages [#31](https://github.com/devlikeapro/whatsapp-http-api/issues/31)
### Security ![](/images/versions/plus.png)
- Added `WHATSAPP_SWAGGER_USERNAME` and `WHATSAPP_SWAGGER_PASSWORD` to hide and protect swagger panel.
## 2022.11
**Please test changes in test environment before update production!!**
@@ -6,7 +6,7 @@ date: 2020-10-06T08:48:45+00:00
lastmod: 2020-10-06T08:48:45+00:00
draft: false
images: []
weight: 400
weight: 800
---
You can configure WhatsApp HTTP API behaviour via environment variables, by adding `-e WHATSAPP_VARNAME=value` at the
begging of the command line or by using [other options](https://docs.docker.com/engine/reference/commandline/run/)
@@ -17,21 +17,42 @@ docker run -it -e WHATSAPP_HOOK_EVENTS=* -e WHATSAPP_HOOK_URL=https://httpbin.or
## Environment variables
### Common
- `DEBUG=1` - show debug and verbose logs, set in any value
- `WHATSAPP_API_PORT=3000` - listen port for HTTP server (default: `3000`)
- `WHATSAPP_API_HOSTNAME=localhost` - Hostname for HTTP server (default: `localhost`)
- `WHATSAPP_API_KEY=mysecret` - protect the api with a secret code. If you set it - add `X-Api-Key: mysecret` to all
requests.
- `WHATSAPP_SWAGGER_USERNAME=admin` + `WHATSAPP_SWAGGER_PASSWORD=admin` - protect the Swagger panel with `admin / admin` credentials. It doesn't affect api access!
- `WHATSAPP_SWAGGER_USERNAME=admin` + `WHATSAPP_SWAGGER_PASSWORD=admin` - protect the Swagger panel with `admin / admin`
credentials. It doesn't affect api access!
- `WHATSAPP_START_SESSION=default` - start session with the name right after launching the app
-
## File storage ![](/images/versions/plus.png)
- `WHATSAPP_FILES_MIMETYPES` - download only these mimetypes from messages (download all files be default). Mimetypes
must be separated by a comma, without spaces: `audio,image/png,image/gif`. In order to choose type use prefix (
like `audio,image`).
- `WHATSAPP_FILES_LIFETIME`- to keep free space files will be removed after this time (default: `180`, in seconds)
- `WHATSAPP_FILES_FOLDER` - folder where will be stored files from chats (images, voice messages) (
default: `/tmp/whatsapp-files`)
## Engines
Under the hood **WAHA** allows you to use two different engines. You can control what you want to run by settings
`WHATSAPP_DEFAULT_ENGINE` environment variables.
If you have any problems with one engine - try another!
{{< alert icon="👉" text="API responses and webhook payloads may differ significantly! We do our best to keep requests body stable between engines." />}}
### WhatsApp WebJS ![](/images/versions/core.png)
**WAHA** uses **WhatsApp WebJS** engine by default
- https://github.com/pedroslopez/whatsapp-web.js
- `WHATSAPP_DEFAULT_ENGINE=WEBJS`
### Venom ![](/images/versions/core.png)
- https://github.com/orkestral/venom
- `WHATSAPP_DEFAULT_ENGINE=VENOM`
@@ -0,0 +1,101 @@
---
title : "Contacts"
description: "Contacts"
lead: ""
date: 2020-10-06T08:48:45+00:00
lastmod: 2020-10-06T08:48:45+00:00
draft: false
images: []
weight: 130
---
Methods for contacts.
{{< alert icon="👉" text="WhatsApp Web does not support adding contacts, so the API doesn't support it too." />}}
## Get all contacts
Get your contacts - `GET /api/contacts/all`
```json
[
{
"id": "11231231231@c.us",
"number": "11231231231",
"name": "Contact Name",
"pushname": "Pushname",
"shortName": "Shortname",
"isMe": true,
"isGroup": false,
"isWAContact": true,
"isMyContact": true,
"isBlocked": false
}
]
```
## Get contact
Get contact
- `GET /api/contacts?contactId=11231231231&session=default`
- `GET /api/contacts?contactId=11231231231@c.us&session=default`
```json
{
"id": "11231231231@c.us",
"number": "11231231231",
"name": "Contact Name",
"pushname": "Pushname",
"shortName": "Shortname",
"isMe": true,
"isGroup": false,
"isWAContact": true,
"isMyContact": true,
"isBlocked": false
}
```
## Check phone number exists
If you want to check if phone number is registered in WhatsApp (even if the number is not in your contact list) - use
this endpoint for that.
- `GET /api/contacts/check-exists?phone=11231231231&session=default`
```json
{
"numberExists": true
}
```
## Get "about" contact
- `GET /api/contacts/about?contactId=11231231231&session=default`
```json
{
"about": "Hi, I use WhatsApp!"
}
```
## Get contact profile picture
- `GET /api/contacts/profile-picture?contactId=11231231231&session=default`
```json
{
"profilePictureURL": "https://example.com/profile.jpg"
}
```
## Block (unblock) contact
- To block contact - `POST /api/contacts/block`
- To unblock contact - `POST /api/contacts/unblock`
Request:
```json
{
"contactId": "11231231231",
"session": "default"
}
```
@@ -1,27 +0,0 @@
---
title : "Engines"
description: "Engines"
lead: ""
date: 2020-10-06T08:48:45+00:00
lastmod: 2020-10-06T08:48:45+00:00
draft: false
images: []
weight: 700
---
Under the hood **WAHA** allows you to use two different engines. You can control what you want to run by settings
`WHATSAPP_DEFAULT_ENGINE` environment variables.
If you have any problems with one engine - try another!
{{< alert icon="👉" text="API responses and webhook payloads may differ significantly! We do our best to keep requests body stable between engines." />}}
## WhatsApp WebJS ![](/images/versions/core.png)
**WAHA** uses **WhatsApp WebJS** engine by default
- https://github.com/pedroslopez/whatsapp-web.js
- `WHATSAPP_DEFAULT_ENGINE=WEBJS`
## Venom ![](/images/versions/core.png)
- https://github.com/orkestral/venom
- `WHATSAPP_DEFAULT_ENGINE=VENOM`
@@ -6,7 +6,7 @@ date: 2020-10-06T08:48:45+00:00
lastmod: 2020-10-06T08:48:45+00:00
draft: false
images: []
weight: 300
weight: 120
---
The project uses [Webhooks](https://en.wikipedia.org/wiki/Webhook) to send the messages or events from WhatsApp to your
@@ -193,3 +193,12 @@ To configure the url you can use environment variables `WHATSAPP_API_HOSTNAME` a
## Webhook retries ![](/images/versions/plus.png)
**WAHA** retries to reach your webhook URL 15 times and with 2 seconds delay between attempts.
## Get messages
You can read messages from the history by using `GET /api/messages` endpoint.
```bash
curl -X 'GET' \
'http://localhost:3000/api/messages?chatId=11111111111%40c.us&limit=1000&session=default' \
-H 'accept: application/json'
```
@@ -6,7 +6,7 @@ date: 2020-10-06T08:48:45+00:00
lastmod: 2020-10-06T08:48:45+00:00
draft: false
images: []
weight: 800
weight: 700
---
{{< alert icon="💡" text="Do not expose WhatsApp HTTP API on public networks!" />}}
@@ -6,7 +6,7 @@ date: 2020-10-06T08:48:45+00:00
lastmod: 2020-10-06T08:48:45+00:00
draft: false
images: []
weight: 200
weight: 110
---
On your swagger documentation [http://localhost:3000/](http://localhost:3000/)
or in [the example swagger](/swagger) you can find:
@@ -55,7 +55,7 @@ WAHA does not support reply with files (images, voice, etc). If you're intereste
## Add a reaction ![](/images/versions/core.png) ![](/images/versions/plus.png)
Use `PUT /api/reaction` method to set reaction to a message.
{{< alert icon="👉" text="Reactoin API uses PUT, not POST request! Please make sure you send right request." />}}
{{< alert icon="👉" text="Reaction API uses PUT, not POST request! Please make sure you send right request." />}}
```json
{
@@ -6,7 +6,7 @@ date: 2020-10-06T08:48:45+00:00
lastmod: 2020-10-06T08:48:45+00:00
draft: false
images: []
weight: 800
weight: 200
---
## Saving session ![](/images/versions/plus.png)
+1 -1
View File
@@ -1 +1 @@
{"openapi":"3.0.0","paths":{"/api/sessions/start":{"post":{"operationId":"SessionsController_start","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionStartRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionDTO"}}}}},"tags":["sessions"],"security":[{"api_key":[]}]}},"/api/sessions/stop":{"post":{"operationId":"SessionsController_stop","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionStopRequest"}}}},"responses":{"201":{"description":""}},"tags":["sessions"],"security":[{"api_key":[]}]}},"/api/sessions":{"get":{"operationId":"SessionsController_list","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SessionDTO"}}}}}},"tags":["sessions"],"security":[{"api_key":[]}]}},"/api/checkNumberStatus":{"get":{"operationId":"ChattingController_checkNumberStatus","summary":"Check number status","parameters":[{"name":"phone","required":true,"in":"query","schema":{"type":"string"}},{"name":"session","required":true,"in":"query","schema":{"default":"default","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WANumberExistResult"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendContactVcard":{"post":{"operationId":"ChattingController_sendContactVcard","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageContactVcardRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendText":{"get":{"operationId":"ChattingController_sendTextGet","summary":"Send a text message","parameters":[{"name":"phone","required":true,"in":"query","schema":{"type":"string"}},{"name":"text","required":true,"in":"query","schema":{"type":"string"}},{"name":"session","required":true,"in":"query","schema":{"default":"default","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]},"post":{"operationId":"ChattingController_sendText","summary":"Send a text message","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageTextRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WAMessage"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendTextButtons":{"post":{"operationId":"ChattingController_sendTextButtons","summary":"Send a text message with buttons","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageTextButtonsRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendLocation":{"post":{"operationId":"ChattingController_sendLocation","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageLocationRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendLinkPreview":{"post":{"operationId":"ChattingController_sendLinkPreview","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageLinkPreviewRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendImage":{"post":{"operationId":"ChattingController_sendImage","summary":"Send an image. Either from an URL or base64 data - look at the request schemas for details.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageImageRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendFile":{"post":{"operationId":"ChattingController_sendFile","summary":"Send a file. Either from an URL or base64 data - look at the request schemas for details.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageFileRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendVoice":{"post":{"operationId":"ChattingController_sendVoice","summary":"Send an voice message. Either from an URL or basLine truncated
{"openapi":"3.0.0","paths":{"/api/sessions/start":{"post":{"operationId":"SessionsController_start","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionStartRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionDTO"}}}}},"tags":["sessions"],"security":[{"api_key":[]}]}},"/api/sessions/stop":{"post":{"operationId":"SessionsController_stop","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionStopRequest"}}}},"responses":{"201":{"description":""}},"tags":["sessions"],"security":[{"api_key":[]}]}},"/api/sessions":{"get":{"operationId":"SessionsController_list","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SessionDTO"}}}}}},"tags":["sessions"],"security":[{"api_key":[]}]}},"/api/checkNumberStatus":{"get":{"operationId":"ChattingController_checkNumberStatus","summary":"Check number status","parameters":[{"name":"phone","required":true,"in":"query","schema":{"type":"string"}},{"name":"session","required":true,"in":"query","schema":{"default":"default","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WANumberExistResult"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendContactVcard":{"post":{"operationId":"ChattingController_sendContactVcard","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageContactVcardRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendText":{"get":{"operationId":"ChattingController_sendTextGet","summary":"Send a text message","parameters":[{"name":"phone","required":true,"in":"query","schema":{"type":"string"}},{"name":"text","required":true,"in":"query","schema":{"type":"string"}},{"name":"session","required":true,"in":"query","schema":{"default":"default","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]},"post":{"operationId":"ChattingController_sendText","summary":"Send a text message","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageTextRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WAMessage"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendTextButtons":{"post":{"operationId":"ChattingController_sendTextButtons","summary":"Send a text message with buttons","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageTextButtonsRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendLocation":{"post":{"operationId":"ChattingController_sendLocation","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageLocationRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendLinkPreview":{"post":{"operationId":"ChattingController_sendLinkPreview","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageLinkPreviewRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendImage":{"post":{"operationId":"ChattingController_sendImage","summary":"Send an image. Either from an URL or base64 data - look at the request schemas for details.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageImageRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendFile":{"post":{"operationId":"ChattingController_sendFile","summary":"Send a file. Either from an URL or base64 data - look at the request schemas for details.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageFileRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendVoice":{"post":{"operationId":"ChattingController_sendVoice","summary":"Send an voice message. Either from an URL or basLine truncated
+5 -6
View File
@@ -30,7 +30,7 @@
"rxjs": "^7.1.0",
"swagger-ui-express": "^4.1.4",
"venom-bot": "^4.3.7",
"whatsapp-web.js": "^1.18.4"
"whatsapp-web.js": "github:wictornogueira/whatsapp-web.js#fix_legacyphonefeatures"
},
"devDependencies": {
"@nestjs/cli": "^9.0.0",
@@ -17712,8 +17712,8 @@
},
"node_modules/whatsapp-web.js": {
"version": "1.18.4",
"resolved": "https://registry.npmjs.org/whatsapp-web.js/-/whatsapp-web.js-1.18.4.tgz",
"integrity": "sha512-Dqu6Q37tDDAcVJ44aMdRE76sI/9rBCUG+NTz1Kxh2w4obX2WtpoRetilxqgx1r4+pFUl58Lf21wGOEwPZ1pT/A==",
"resolved": "git+ssh://git@github.com/wictornogueira/whatsapp-web.js.git#ccf9438a0c46f0387ad2c65604314f53b0b07e84",
"license": "Apache-2.0",
"dependencies": {
"@pedroslopez/moduleraid": "^5.0.2",
"fluent-ffmpeg": "^2.1.2",
@@ -32112,9 +32112,8 @@
"dev": true
},
"whatsapp-web.js": {
"version": "1.18.4",
"resolved": "https://registry.npmjs.org/whatsapp-web.js/-/whatsapp-web.js-1.18.4.tgz",
"integrity": "sha512-Dqu6Q37tDDAcVJ44aMdRE76sI/9rBCUG+NTz1Kxh2w4obX2WtpoRetilxqgx1r4+pFUl58Lf21wGOEwPZ1pT/A==",
"version": "git+ssh://git@github.com/wictornogueira/whatsapp-web.js.git#ccf9438a0c46f0387ad2c65604314f53b0b07e84",
"from": "whatsapp-web.js@github:wictornogueira/whatsapp-web.js#fix_legacyphonefeatures",
"requires": {
"@pedroslopez/moduleraid": "^5.0.2",
"archiver": "^5.3.1",
+1 -1
View File
@@ -43,7 +43,7 @@
"rxjs": "^7.1.0",
"swagger-ui-express": "^4.1.4",
"venom-bot": "^4.3.7",
"whatsapp-web.js": "^1.18.4"
"whatsapp-web.js": "github:wictornogueira/whatsapp-web.js#fix_legacyphonefeatures"
},
"devDependencies": {
"@nestjs/cli": "^9.0.0",
+63
View File
@@ -0,0 +1,63 @@
import {Body, Controller, Get, Post, Query} from '@nestjs/common';
import {ApiOperation, ApiSecurity, ApiTags} from "@nestjs/swagger";
import {SessionManager} from "../core/abc/manager.abc";
import {ContactQuery, ContactRequest} from "../structures/contacts.dto";
import {SessionQuery} from "../structures/base.dto";
import {CheckNumberStatusQuery} from "../structures/chatting.dto";
import {WANumberExistResult} from "../structures/responses.dto";
@ApiSecurity('api_key')
@Controller('api/contacts')
@ApiTags('contacts')
export class ContactsController {
constructor(private manager: SessionManager) {
}
@Get('/')
@ApiOperation({summary: 'Get contact basic info. The method always return result, even if the phone number is not registered in WhatsApp. For that - use /check-exists endpoint below.'})
get(@Query() query: ContactQuery) {
const whatsapp = this.manager.getSession(query.session)
return whatsapp.getContact(query)
}
@Get('/all')
@ApiOperation({summary: 'Get all contacts'})
getAll(@Query() query: SessionQuery) {
const whatsapp = this.manager.getSession(query.session)
return whatsapp.getContacts()
}
@Get('/check-exists')
@ApiOperation({summary: 'Check phone number is registered in WhatsApp.'})
async checkExists(@Query() request: CheckNumberStatusQuery): Promise<WANumberExistResult> {
const whatsapp = this.manager.getSession(request.session)
return whatsapp.checkNumberStatus(request)
}
@Get('/about')
@ApiOperation({summary: 'Gets the Contact\'s current "about" info. Returns null if you don\'t have permission to read their status.'})
getAbout(@Query() query: ContactQuery) {
const whatsapp = this.manager.getSession(query.session)
return whatsapp.getContactAbout(query)
}
@Get('/profile-picture')
@ApiOperation({summary: 'Returns the contact\'s profile picture URL, if privacy settings allow it.'})
getProfilePicture(@Query() query: ContactQuery) {
const whatsapp = this.manager.getSession(query.session)
return whatsapp.getContactProfilePicture(query)
}
@Post('/block')
@ApiOperation({summary:"Block contact"})
block(@Body() request: ContactRequest) {
const whatsapp = this.manager.getSession(request.session)
return whatsapp.blockContact(request)
}
@Post('/unblock')
@ApiOperation({summary:"Unblock contact"})
unblock(@Body() request: ContactRequest) {
const whatsapp = this.manager.getSession(request.session)
return whatsapp.unblockContact(request)
}
}
+1 -1
View File
@@ -2,8 +2,8 @@ import {Controller, Get, Query, Res} from '@nestjs/common';
import {ApiSecurity, ApiTags} from "@nestjs/swagger";
import {Readable} from "stream";
import {Response} from 'express';
import {SessionQuery} from "../structures/chatting.dto";
import {SessionManager} from "../core/abc/manager.abc";
import {SessionQuery} from "../structures/base.dto";
@ApiSecurity('api_key')
+31 -1
View File
@@ -16,6 +16,8 @@ import {
} from "../../structures/chatting.dto";
import {MediaStorage} from "./storage.abc";
import {MessageId} from "whatsapp-web.js";
import {ContactQuery, ContactRequest} from "../../structures/contacts.dto";
import {NotImplementedByEngineError} from "../exceptions";
export abstract class WhatsappSession {
public status: WhatsappStatus;
@@ -26,7 +28,7 @@ export abstract class WhatsappSession {
this.log = log
}
getBrowserExecutablePath(){
getBrowserExecutablePath() {
return "/usr/bin/google-chrome-stable"
}
@@ -103,6 +105,34 @@ export abstract class WhatsappSession {
abstract setReaction(request: MessageReactionRequest)
/**
* Contacts methods
*/
public getContact(query: ContactQuery) {
throw new NotImplementedByEngineError()
}
public getContacts() {
throw new NotImplementedByEngineError()
}
public getContactAbout(query: ContactQuery) {
throw new NotImplementedByEngineError()
}
public getContactProfilePicture(query: ContactQuery) {
throw new NotImplementedByEngineError()
}
public blockContact(request: ContactRequest) {
throw new NotImplementedByEngineError()
}
public unblockContact(request: ContactRequest) {
throw new NotImplementedByEngineError()
}
/**
* END - Methods for API
*/
+2
View File
@@ -5,6 +5,7 @@ import {WhatsappConfigService} from "../config.service";
import {ServeStaticModule} from "@nestjs/serve-static";
import {SessionsController} from "../api/sessions.controller";
import {ChattingController} from "../api/chatting.controller";
import {ContactsController} from "../api/contacts.controller";
import {VersionController} from "../api/version.controller";
import {PassportModule} from "@nestjs/passport";
import {SessionManager} from "./abc/manager.abc";
@@ -30,6 +31,7 @@ export const IMPORTS = [
export const CONTROLLERS = [
SessionsController,
ChattingController,
ContactsController,
ScreenshotController,
VersionController,
]
+1
View File
@@ -20,6 +20,7 @@ import {NotImplementedByEngineError} from "./exceptions";
import {MediaStorage} from "./abc/storage.abc";
import {UnprocessableEntityException} from "@nestjs/common/exceptions/unprocessable-entity.exception";
import {ConsoleLogger} from "@nestjs/common";
import {ContactQuery} from "../structures/contacts.dto";
class QR {
private base64: string;
+43 -4
View File
@@ -1,5 +1,5 @@
import {UnprocessableEntityException} from "@nestjs/common/exceptions/unprocessable-entity.exception";
import {Buttons, Chat, Client, Events, Message} from "whatsapp-web.js";
import {Buttons, Chat, Client, Contact, Events, Message} from "whatsapp-web.js";
import {Message as MessageInstance} from "whatsapp-web.js/src/structures"
import {WAEvents, WhatsappStatus} from "../structures/enums.dto";
import {WhatsappSession} from "./abc/session.abc";
@@ -19,6 +19,7 @@ import {
MessageVoiceRequest
} from "../structures/chatting.dto";
import {AvailableInPlusVersion, NotImplementedByEngineError} from "./exceptions";
import {ContactQuery, ContactRequest} from "../structures/contacts.dto";
// eslint-disable-next-line @typescript-eslint/no-var-requires
const qrcode = require('qrcode-terminal');
@@ -73,8 +74,9 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
return await this.whatsapp.pupPage.screenshot()
}
checkNumberStatus(request: CheckNumberStatusQuery): Promise<WANumberExistResult> {
throw new NotImplementedByEngineError()
async checkNumberStatus(request: CheckNumberStatusQuery): Promise<WANumberExistResult> {
const exist = await this.whatsapp.isRegisteredUser(this.ensureSuffix(request.phone))
return {numberExists: exist}
}
sendText(request: MessageTextRequest) {
@@ -144,6 +146,38 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
return message.react(request.reaction)
}
/**
* Contacts methods
*/
getContact(query: ContactQuery) {
return this.whatsapp.getContactById(this.ensureSuffix(query.contactId)).then(this.toWAContact)
}
getContacts() {
return this.whatsapp.getContacts().then(contacts => contacts.map(this.toWAContact))
}
public async getContactAbout(query: ContactQuery) {
const contact = await this.whatsapp.getContactById(this.ensureSuffix(query.contactId))
return {"about": await contact.getAbout()}
}
public async getContactProfilePicture(query: ContactQuery) {
const contact = await this.whatsapp.getContactById(this.ensureSuffix(query.contactId))
return {"profilePictureURL": await contact.getProfilePicUrl()}
}
public async blockContact(request: ContactRequest) {
const contact = await this.whatsapp.getContactById(this.ensureSuffix(request.contactId))
await contact.block()
}
public async unblockContact(request: ContactRequest) {
const contact = await this.whatsapp.getContactById(this.ensureSuffix(request.contactId))
await contact.unblock()
}
/**
* END - Methods for API
*/
@@ -192,6 +226,12 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
})
}
protected toWAContact(contact: Contact) {
// @ts-ignore
contact.id = contact.id._serialized
return contact
}
protected async downloadMedia(message: Message) {
if (!message.hasMedia) {
return message
@@ -202,6 +242,5 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
return message
}
}
+10 -3
View File
@@ -3,7 +3,7 @@ import {INestApplication} from "@nestjs/common";
import {VERSION} from "../version";
export class SwaggerModuleCore {
configure(app: INestApplication){
configure(app: INestApplication) {
this.setUpAuth(app)
const options = new DocumentBuilder()
@@ -11,10 +11,16 @@ export class SwaggerModuleCore {
.setDescription('WhatsApp HTTP API that you can configure in a click!')
.setExternalDoc("Documentation", "https://waha.devlike.pro/")
.setVersion(VERSION.version)
.addTag('sessions', 'Control your WhatsApp sessions')
.addTag('sessions', 'Control WhatsApp sessions')
.addTag('screenshot', 'Get screenshot of WhatsApp and show QR code')
.addTag('chatting', 'Chat methods')
.addTag('other', 'Other endpoints')
.addTag(
'contacts',
`Contacts methods.<br>
Use phone number (without +) or phone number and \`@c.us\` at the end as \`contactId\`.<br>
'E.g: \`12312312310\` OR \`12312312310@c.us\`<br>`
)
.addTag('other', 'Other methods')
.addApiKey({
type: 'apiKey',
description: 'Your secret api key',
@@ -27,6 +33,7 @@ export class SwaggerModuleCore {
SwaggerModule.setup('', app, document);
}
protected setUpAuth(app: INestApplication) {
return undefined
}
+19
View File
@@ -0,0 +1,19 @@
import {IsNotEmpty} from "class-validator";
export const WHATSAPP_DEFAULT_SESSION_NAME = "default"
/**
* Queries
*/
export class SessionQuery {
@IsNotEmpty()
session: string = WHATSAPP_DEFAULT_SESSION_NAME;
}
/**
* Requests
*/
export class SessionBaseRequest {
session = WHATSAPP_DEFAULT_SESSION_NAME
}
+1 -12
View File
@@ -1,17 +1,11 @@
import {IsNotEmpty, IsString} from "class-validator";
import {ApiExtraModels, ApiProperty, getSchemaPath} from "@nestjs/swagger";
export const WHATSAPP_DEFAULT_SESSION_NAME = "default"
import {SessionBaseRequest, SessionQuery} from "./base.dto";
/**
* Queries
*/
export class SessionQuery {
@IsNotEmpty()
session: string = WHATSAPP_DEFAULT_SESSION_NAME;
}
export class CheckNumberStatusQuery extends SessionQuery {
@IsString()
phone: string
@@ -28,11 +22,6 @@ export class MessageTextQuery extends SessionQuery {
/**
* Requests
*/
export class SessionBaseRequest {
session = WHATSAPP_DEFAULT_SESSION_NAME
}
export class ChatRequest extends SessionBaseRequest {
@ApiProperty({
example: '11111111111@c.us',
+22
View File
@@ -0,0 +1,22 @@
import {IsString} from "class-validator";
import {SessionBaseRequest, SessionQuery, WHATSAPP_DEFAULT_SESSION_NAME} from "./base.dto";
/**
* Queries
*/
export class ContactQuery extends SessionQuery {
@IsString()
contactId: string
}
/**
* Requests
*/
export class ContactRequest extends SessionBaseRequest {
@IsString()
contactId: string
}