Compare commits

...
3 Commits
Author SHA1 Message Date
allburov f6f09747dc [core] pin node:20-bullseye
Release / deploy-docker (push) Waiting to run
2023-07-14 10:10:28 +07:00
allburov 27a534a605 [core] add set session presence endpoint 2023-07-12 16:46:15 +07:00
allburov 3cbd940843 [core] Add swagger image at the top of quick start 2023-07-07 14:26:23 +07:00
12 changed files with 169 additions and 14 deletions

No files matched your search

+2 -2
View File
@@ -1,7 +1,7 @@
#
# Build
#
FROM node:18 as build
FROM node:20-bullseye as build
ENV PUPPETEER_SKIP_DOWNLOAD=True
# npm packages
@@ -20,7 +20,7 @@ RUN yarn build && find ./dist -name "*.d.ts" -delete
#
# Final
#
FROM node:18 as release
FROM node:20-bullseye as release
ENV PUPPETEER_SKIP_DOWNLOAD=True
ARG USE_BROWSER=chromium
@@ -12,7 +12,55 @@ weight: 801
You can get presence information (online, offline with last seen, typing status) for a contact if they share their
presence information.
{{< alert icon="👉" text="Presence endpoints and webhook is available only in **NOWEB** engine." />}}
Possible presence statuses that you can set or get for chats:
- `online`
- `offline`
- `typing`
- `recording`
- `paused` resets the chat presence after you were `typing`
## Endpoints
### Set presence
You can set your global or chat-related presence with `POST /api/{session}/presence` endpoint
Start typing to a chat (you can use `POST /startTyping` instead)
```json
{
"chatId": "111111111@c.us",
"presence": "typing"
}
```
Clear "typing" state (you can use `POST /stopTyping` instead)
```json
{
"chatId": "111111111@c.us",
"presence": "paused"
}
```
Set global "online", all contacts will see it
```json
{
"presence": "online"
}
```
💡 In the multi-device version of WhatsApp - if a desktop client is active, WhatsApp doesn't send push notifications
to the device.
If you would like to receive said notifications - you need to mark a session's presence as `offline`.
```json
{
"presence": "offline"
}
```
### Get all chats presence
{{< alert icon="👉" text="Get presence endpoints and webhook is available only in **NOWEB** engine." />}}
[Read more about engines to choose right for you ->]({{< relref "/docs/how-to/engines" >}})
Here's few notes about fields:
@@ -22,9 +70,6 @@ Here's few notes about fields:
- `lastKnownPresence` - contains the last known presence status, which can be
`offline`, `online`, `typing`, `recording`, or `paused`
## Endpoints
### Get all presence
You can get all presence information available for a session by calling `GET /api/{session}/presence/`.
It returns both groups' and personal chats' presence information.
@@ -12,6 +12,12 @@ menu:
weight: 199
toc: true
---
## 2023.8
August 2023
- Added [set presence endpoint](https://waha.devlike.pro/docs/how-to/presence)!
- With `online` presence you can show your status as online [#121](https://github.com/devlikeapro/whatsapp-http-api/issues/121)
- With `offline` presence you can get notifications for your device [#28](https://github.com/devlikeapro/whatsapp-http-api/issues/28)
## 2023.7
July 2023
- Now session can have their own [Webhooks](https://waha.devlike.pro/docs/how-to/webhooks) -
@@ -16,6 +16,8 @@ toc: true
On this page you're going to install WAHA, run it, authenticate the client using QR code and send the first text message
to WhatsApp!
![](swagger.png)
## Requirements
Only thing that you must have - installed docker. Please follow the original
+43 -2
View File
@@ -1,10 +1,21 @@
import { Controller, Get, Param, Post } from '@nestjs/common';
import {
BadRequestException,
Body,
Controller,
Get,
Param,
Post,
} from '@nestjs/common';
import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger';
import { SessionManager } from '../core/abc/manager.abc';
import { WhatsappSession } from '../core/abc/session.abc';
import { WAHAChatPresences } from '../structures/presence.dto';
import {
WAHAChatPresences,
WAHASessionPresence,
} from '../structures/presence.dto';
import { SessionApiParam, SessionParam } from './helpers';
import { WAHAPresenceStatus } from '../structures/enums.dto';
@ApiSecurity('api_key')
@Controller('api/:session/presence')
@@ -12,6 +23,36 @@ import { SessionApiParam, SessionParam } from './helpers';
export class PresenceController {
constructor(private manager: SessionManager) {}
@Post('')
@SessionApiParam
@ApiOperation({ summary: 'Set session presence' })
setPresence(
@SessionParam session: WhatsappSession,
@Body() request: WAHASessionPresence,
) {
// Validate request
const presencesWithoutChatId = [
WAHAPresenceStatus.ONLINE,
WAHAPresenceStatus.OFFLINE,
];
const requiresNoChatId = presencesWithoutChatId.includes(request.presence);
const requiresChatId = !requiresNoChatId;
if (requiresNoChatId && request.chatId) {
const msg = {
detail: `'${request.presence}' presence works on the global scope and doesn't require 'chatId' field.`,
};
throw new BadRequestException(msg);
} else if (requiresChatId && !request.chatId) {
const msg = {
detail: `'${request.presence}' presence requires 'chatId' field.`,
};
throw new BadRequestException(msg);
}
return session.setPresence(request.presence, request.chatId);
}
@Get('')
@SessionApiParam
@ApiOperation({ summary: 'Get all subscribed presence information.' })
+5
View File
@@ -22,6 +22,7 @@ import { ContactQuery, ContactRequest } from '../../structures/contacts.dto';
import {
WAHAEngine,
WAHAEvents,
WAHAPresenceStatus,
WAHASessionStatus,
} from '../../structures/enums.dto';
import {
@@ -257,6 +258,10 @@ export abstract class WhatsappSession {
throw new NotImplementedByEngineError();
}
public setPresence(presence: WAHAPresenceStatus, chatId?: string) {
throw new NotImplementedByEngineError();
}
public getPresences(): Promise<WAHAChatPresences[]> {
throw new NotImplementedByEngineError();
}
+12
View File
@@ -12,6 +12,7 @@ import { Agent } from 'https';
import * as lodash from 'lodash';
import { Message } from 'whatsapp-web.js';
import { flipObject } from '../helpers';
import {
Button,
ChatRequest,
@@ -78,6 +79,7 @@ const PresenceStatuses = {
recording: WAHAPresenceStatus.RECORDING,
paused: WAHAPresenceStatus.PAUSED,
};
const ToEnginePresenceStatus = flipObject(PresenceStatuses);
export class WhatsappSessionNoWebCore extends WhatsappSession {
engine = WAHAEngine.NOWEB;
@@ -414,6 +416,16 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
return this.sock.groupParticipantsUpdate(id, participants, 'demote');
}
public async setPresence(presence: WAHAPresenceStatus, chatId?: string) {
const enginePresence = ToEnginePresenceStatus[presence];
if (!enginePresence) {
throw new NotImplementedByEngineError(
`NOWEB engine doesn't support '${presence}' presence.`,
);
}
await this.sock.sendPresenceUpdate(enginePresence, chatId);
}
public async getPresences(): Promise<WAHAChatPresences[]> {
const result: WAHAChatPresences[] = [];
for (const remoteJid in this.store.presences) {
+29
View File
@@ -33,6 +33,7 @@ import { ContactQuery, ContactRequest } from '../structures/contacts.dto';
import {
WAHAEngine,
WAHAEvents,
WAHAPresenceStatus,
WAHASessionStatus,
} from '../structures/enums.dto';
import {
@@ -366,6 +367,34 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
return groupChat.demoteParticipants(participantIds);
}
public async setPresence(presence: WAHAPresenceStatus, chatId?: string) {
let chat: Chat;
switch (presence) {
case WAHAPresenceStatus.ONLINE:
await this.whatsapp.sendPresenceAvailable();
break;
case WAHAPresenceStatus.OFFLINE:
await this.whatsapp.sendPresenceUnavailable();
break;
case WAHAPresenceStatus.TYPING:
chat = await this.whatsapp.getChatById(chatId);
await chat.sendStateTyping();
break;
case WAHAPresenceStatus.RECORDING:
chat = await this.whatsapp.getChatById(chatId);
await chat.sendStateRecording();
break;
case WAHAPresenceStatus.PAUSED:
chat = await this.whatsapp.getChatById(chatId);
await chat.clearState();
break;
default:
throw new NotImplementedByEngineError(
`WEBJS engine doesn't support '${presence}' presence.`,
);
}
}
/**
* END - Methods for API
*/
+1 -4
View File
@@ -24,10 +24,7 @@ export class SwaggerModuleCore {
'E.g: \`12312312310\` OR \`12312312310@c.us\`<br>`,
)
.addTag('groups', `Groups methods.<br>`)
.addTag(
'presence',
`Presence information. Available in <b>NOWEB</b> engine only.<br>`,
)
.addTag('presence', `Presence information`)
.addTag('other', 'Other methods')
.addApiKey({
type: 'apiKey',
+9 -1
View File
@@ -1,4 +1,4 @@
export function parseBool(value: any): boolean {
function parseBool(value: any): boolean {
if (!value) {
return false;
}
@@ -18,3 +18,11 @@ export function parseBool(value: any): boolean {
'Error: parseBool got unexpected value - use "true" or "false" values',
);
}
function flipObject(object) {
return Object.fromEntries(
Object.entries(object).map(([key, value]) => [value, key]),
);
}
export { flipObject, parseBool };
+10
View File
@@ -22,3 +22,13 @@ export class WAHAChatPresences {
id: string;
presences: WAHAPresenceData[];
}
export class WAHASessionPresence {
presence: WAHAPresenceStatus;
@ApiProperty({
description: 'Chat ID - either group id or contact id',
example: '11111111111@c.us',
})
chatId: string;
}
+1 -1
View File
@@ -26,7 +26,7 @@ export function getWAHAVersion(): WAHAVersion {
}
export const VERSION = {
version: '2023.7.1',
version: '2023.7.12',
tier: getWAHAVersion(),
browser: getBrowserExecutablePath(),
};