wazzapi 0.1.2__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {wazzapi-0.1.2 → wazzapi-0.3.0}/PKG-INFO +19 -3
- {wazzapi-0.1.2 → wazzapi-0.3.0}/README.md +17 -1
- wazzapi-0.3.0/examples/list_devices.py +15 -0
- {wazzapi-0.1.2 → wazzapi-0.3.0}/pyproject.toml +2 -2
- {wazzapi-0.1.2 → wazzapi-0.3.0}/tests/smoke_test.py +1 -1
- {wazzapi-0.1.2 → wazzapi-0.3.0}/tests/test_client.py +1 -0
- wazzapi-0.3.0/tests/test_groups.py +285 -0
- {wazzapi-0.1.2 → wazzapi-0.3.0}/tests/test_resources.py +56 -0
- {wazzapi-0.1.2 → wazzapi-0.3.0}/wazzapi/__init__.py +1 -1
- {wazzapi-0.1.2 → wazzapi-0.3.0}/wazzapi/client.py +3 -1
- {wazzapi-0.1.2 → wazzapi-0.3.0}/wazzapi/models/__init__.py +14 -1
- wazzapi-0.3.0/wazzapi/models/devices.py +42 -0
- wazzapi-0.3.0/wazzapi/models/groups.py +165 -0
- wazzapi-0.3.0/wazzapi/resources/__init__.py +13 -0
- wazzapi-0.3.0/wazzapi/resources/devices.py +40 -0
- wazzapi-0.3.0/wazzapi/resources/groups.py +266 -0
- wazzapi-0.1.2/wazzapi/resources/__init__.py +0 -5
- {wazzapi-0.1.2 → wazzapi-0.3.0}/.gitignore +0 -0
- {wazzapi-0.1.2 → wazzapi-0.3.0}/examples/create_template.py +0 -0
- {wazzapi-0.1.2 → wazzapi-0.3.0}/examples/list_contacts.py +0 -0
- {wazzapi-0.1.2 → wazzapi-0.3.0}/examples/preview_template.py +0 -0
- {wazzapi-0.1.2 → wazzapi-0.3.0}/examples/send_message.py +0 -0
- {wazzapi-0.1.2 → wazzapi-0.3.0}/examples/verify_webhook.py +0 -0
- {wazzapi-0.1.2 → wazzapi-0.3.0}/tests/test_media.py +0 -0
- {wazzapi-0.1.2 → wazzapi-0.3.0}/tests/test_webhooks.py +0 -0
- {wazzapi-0.1.2 → wazzapi-0.3.0}/wazzapi/errors.py +0 -0
- {wazzapi-0.1.2 → wazzapi-0.3.0}/wazzapi/media.py +0 -0
- {wazzapi-0.1.2 → wazzapi-0.3.0}/wazzapi/models/base.py +0 -0
- {wazzapi-0.1.2 → wazzapi-0.3.0}/wazzapi/models/contacts.py +0 -0
- {wazzapi-0.1.2 → wazzapi-0.3.0}/wazzapi/models/media.py +0 -0
- {wazzapi-0.1.2 → wazzapi-0.3.0}/wazzapi/models/messages.py +0 -0
- {wazzapi-0.1.2 → wazzapi-0.3.0}/wazzapi/models/templates.py +0 -0
- {wazzapi-0.1.2 → wazzapi-0.3.0}/wazzapi/models/webhooks.py +0 -0
- {wazzapi-0.1.2 → wazzapi-0.3.0}/wazzapi/py.typed +0 -0
- {wazzapi-0.1.2 → wazzapi-0.3.0}/wazzapi/resources/base.py +0 -0
- {wazzapi-0.1.2 → wazzapi-0.3.0}/wazzapi/resources/contacts.py +0 -0
- {wazzapi-0.1.2 → wazzapi-0.3.0}/wazzapi/resources/messages.py +0 -0
- {wazzapi-0.1.2 → wazzapi-0.3.0}/wazzapi/resources/templates.py +0 -0
- {wazzapi-0.1.2 → wazzapi-0.3.0}/wazzapi/webhooks.py +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wazzapi
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Typed Python SDK for WazzAPI
|
|
5
|
-
Project-URL: Homepage, https://github.com/wazzapihq/wazzapi-py
|
|
6
5
|
Project-URL: API, https://api.wazzapi.com
|
|
6
|
+
Project-URL: Homepage, https://github.com/wazzapihq/wazzapi-py
|
|
7
7
|
Keywords: api,sdk,wazzapi,webhook,whatsapp
|
|
8
8
|
Classifier: Development Status :: 4 - Beta
|
|
9
9
|
Classifier: Intended Audience :: Developers
|
|
@@ -26,11 +26,12 @@ Description-Content-Type: text/markdown
|
|
|
26
26
|
|
|
27
27
|
Official Python SDK for WazzAPI.
|
|
28
28
|
|
|
29
|
-
Use it to send messages, manage contacts and templates, and verify incoming webhooks with a simple typed client.
|
|
29
|
+
Use it to send messages, inspect WhatsApp devices, manage contacts and templates, and verify incoming webhooks with a simple typed client.
|
|
30
30
|
|
|
31
31
|
## What you can do with this SDK
|
|
32
32
|
|
|
33
33
|
- send direct WhatsApp messages
|
|
34
|
+
- list and inspect WhatsApp devices
|
|
34
35
|
- list, create, update, and delete contacts
|
|
35
36
|
- manage message templates and preview rendered content
|
|
36
37
|
- verify and parse incoming WazzAPI webhooks
|
|
@@ -118,6 +119,19 @@ with WazzapiClient(api_key="your-api-key") as client:
|
|
|
118
119
|
|
|
119
120
|
for contact in response.contacts:
|
|
120
121
|
print(contact.model_dump())
|
|
122
|
+
|
|
123
|
+
### List devices
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
from wazzapi import WazzapiClient
|
|
127
|
+
|
|
128
|
+
with WazzapiClient(api_key="your-api-key") as client:
|
|
129
|
+
response = client.devices.list(limit=20, status="connected")
|
|
130
|
+
|
|
131
|
+
for device in response.devices:
|
|
132
|
+
print(device.name, device.session_name, device.status)
|
|
133
|
+
```
|
|
134
|
+
|
|
121
135
|
```
|
|
122
136
|
|
|
123
137
|
### Create a template
|
|
@@ -182,6 +196,7 @@ Supported webhook event families:
|
|
|
182
196
|
|
|
183
197
|
Ready-to-run examples live in `examples/`:
|
|
184
198
|
|
|
199
|
+
- `examples/list_devices.py`
|
|
185
200
|
- `examples/list_contacts.py`
|
|
186
201
|
- `examples/send_message.py`
|
|
187
202
|
- `examples/create_template.py`
|
|
@@ -192,6 +207,7 @@ Run them with:
|
|
|
192
207
|
|
|
193
208
|
```bash
|
|
194
209
|
uv run python examples/list_contacts.py
|
|
210
|
+
uv run python examples/list_devices.py
|
|
195
211
|
uv run python examples/send_message.py
|
|
196
212
|
uv run python examples/create_template.py
|
|
197
213
|
uv run python examples/preview_template.py
|
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
Official Python SDK for WazzAPI.
|
|
4
4
|
|
|
5
|
-
Use it to send messages, manage contacts and templates, and verify incoming webhooks with a simple typed client.
|
|
5
|
+
Use it to send messages, inspect WhatsApp devices, manage contacts and templates, and verify incoming webhooks with a simple typed client.
|
|
6
6
|
|
|
7
7
|
## What you can do with this SDK
|
|
8
8
|
|
|
9
9
|
- send direct WhatsApp messages
|
|
10
|
+
- list and inspect WhatsApp devices
|
|
10
11
|
- list, create, update, and delete contacts
|
|
11
12
|
- manage message templates and preview rendered content
|
|
12
13
|
- verify and parse incoming WazzAPI webhooks
|
|
@@ -94,6 +95,19 @@ with WazzapiClient(api_key="your-api-key") as client:
|
|
|
94
95
|
|
|
95
96
|
for contact in response.contacts:
|
|
96
97
|
print(contact.model_dump())
|
|
98
|
+
|
|
99
|
+
### List devices
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from wazzapi import WazzapiClient
|
|
103
|
+
|
|
104
|
+
with WazzapiClient(api_key="your-api-key") as client:
|
|
105
|
+
response = client.devices.list(limit=20, status="connected")
|
|
106
|
+
|
|
107
|
+
for device in response.devices:
|
|
108
|
+
print(device.name, device.session_name, device.status)
|
|
109
|
+
```
|
|
110
|
+
|
|
97
111
|
```
|
|
98
112
|
|
|
99
113
|
### Create a template
|
|
@@ -158,6 +172,7 @@ Supported webhook event families:
|
|
|
158
172
|
|
|
159
173
|
Ready-to-run examples live in `examples/`:
|
|
160
174
|
|
|
175
|
+
- `examples/list_devices.py`
|
|
161
176
|
- `examples/list_contacts.py`
|
|
162
177
|
- `examples/send_message.py`
|
|
163
178
|
- `examples/create_template.py`
|
|
@@ -168,6 +183,7 @@ Run them with:
|
|
|
168
183
|
|
|
169
184
|
```bash
|
|
170
185
|
uv run python examples/list_contacts.py
|
|
186
|
+
uv run python examples/list_devices.py
|
|
171
187
|
uv run python examples/send_message.py
|
|
172
188
|
uv run python examples/create_template.py
|
|
173
189
|
uv run python examples/preview_template.py
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
from wazzapi import WazzapiClient
|
|
6
|
+
|
|
7
|
+
api_key = os.environ["WAZZAPI_API_KEY"]
|
|
8
|
+
|
|
9
|
+
with WazzapiClient(api_key=api_key) as client:
|
|
10
|
+
response = client.devices.list(limit=20, status="connected")
|
|
11
|
+
|
|
12
|
+
for device in response.devices:
|
|
13
|
+
print(device.model_dump())
|
|
14
|
+
|
|
15
|
+
print({"total": response.total, "limit": response.limit, "offset": response.offset})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "wazzapi"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.0"
|
|
4
4
|
description = "Typed Python SDK for WazzAPI"
|
|
5
5
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
6
6
|
requires-python = ">=3.10"
|
|
@@ -25,8 +25,8 @@ dependencies = [
|
|
|
25
25
|
]
|
|
26
26
|
|
|
27
27
|
[project.urls]
|
|
28
|
-
Homepage = "https://github.com/wazzapihq/wazzapi-py"
|
|
29
28
|
API = "https://api.wazzapi.com"
|
|
29
|
+
Homepage = "https://github.com/wazzapihq/wazzapi-py"
|
|
30
30
|
|
|
31
31
|
[dependency-groups]
|
|
32
32
|
dev = [
|
|
@@ -15,6 +15,7 @@ def test_client_formats_bearer_auth_header() -> None:
|
|
|
15
15
|
assert client.http.headers["Authorization"] == "Bearer plain-token"
|
|
16
16
|
assert client.http.headers["Accept"] == "application/json"
|
|
17
17
|
assert client.http.headers["Content-Type"] == "application/json"
|
|
18
|
+
assert client.devices is not None
|
|
18
19
|
finally:
|
|
19
20
|
client.close()
|
|
20
21
|
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from collections.abc import Callable
|
|
5
|
+
|
|
6
|
+
import httpx
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
from wazzapi import WazzapiClient, models
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@pytest.mark.parametrize(
|
|
13
|
+
("call_factory", "expected_method", "expected_path", "expected_response_type", "response_json"),
|
|
14
|
+
[
|
|
15
|
+
(
|
|
16
|
+
lambda client: client.groups.list(session_name="main", limit=25),
|
|
17
|
+
"GET",
|
|
18
|
+
"/api/v1/groups",
|
|
19
|
+
models.GroupListResponse,
|
|
20
|
+
{"groups": [], "total": 0},
|
|
21
|
+
),
|
|
22
|
+
(
|
|
23
|
+
lambda client: client.groups.get("123@g.us", session_name="main"),
|
|
24
|
+
"GET",
|
|
25
|
+
"/api/v1/groups/123@g.us",
|
|
26
|
+
models.GroupDetailResponse,
|
|
27
|
+
{"id": "123@g.us", "name": "Test Group"},
|
|
28
|
+
),
|
|
29
|
+
(
|
|
30
|
+
lambda client: client.groups.get_participants("123@g.us", session_name="main"),
|
|
31
|
+
"GET",
|
|
32
|
+
"/api/v1/groups/123@g.us/participants",
|
|
33
|
+
models.GroupParticipantsResponse,
|
|
34
|
+
{"participants": [{"id": "6281234567890@s.whatsapp.net", "is_admin": True}]},
|
|
35
|
+
),
|
|
36
|
+
(
|
|
37
|
+
lambda client: client.groups.create({"session_name": "main", "name": "New Group", "participants": ["6281234567890"]}),
|
|
38
|
+
"POST",
|
|
39
|
+
"/api/v1/groups/create",
|
|
40
|
+
models.CreateGroupResponseModel,
|
|
41
|
+
{"success": True, "jid": "456@g.us", "name": "New Group"},
|
|
42
|
+
),
|
|
43
|
+
(
|
|
44
|
+
lambda client: client.groups.send_text({"session_name": "main", "group_jid": "123@g.us", "text": "hello"}),
|
|
45
|
+
"POST",
|
|
46
|
+
"/api/v1/groups/send",
|
|
47
|
+
models.SendGroupResponse,
|
|
48
|
+
{"success": True, "message_id": "msg_1", "status": "queued"},
|
|
49
|
+
),
|
|
50
|
+
(
|
|
51
|
+
lambda client: client.groups.send_media({
|
|
52
|
+
"session_name": "main",
|
|
53
|
+
"group_jid": "123@g.us",
|
|
54
|
+
"media_url": "https://example.com/img.jpg",
|
|
55
|
+
"media_type": "image",
|
|
56
|
+
}),
|
|
57
|
+
"POST",
|
|
58
|
+
"/api/v1/groups/send/media",
|
|
59
|
+
models.SendGroupResponse,
|
|
60
|
+
{"success": True, "message_id": "msg_2", "status": "queued"},
|
|
61
|
+
),
|
|
62
|
+
(
|
|
63
|
+
lambda client: client.groups.update_participants({
|
|
64
|
+
"session_name": "main",
|
|
65
|
+
"group_jid": "123@g.us",
|
|
66
|
+
"action": "promote",
|
|
67
|
+
"participants": ["6281234567890@s.whatsapp.net"],
|
|
68
|
+
}),
|
|
69
|
+
"POST",
|
|
70
|
+
"/api/v1/groups/participants",
|
|
71
|
+
models.GroupOperationResponseModel,
|
|
72
|
+
{"success": True, "details": "done"},
|
|
73
|
+
),
|
|
74
|
+
(
|
|
75
|
+
lambda client: client.groups.add_participant("123@g.us", session_name="main", participant_jid="6281234567890@s.whatsapp.net"),
|
|
76
|
+
"POST",
|
|
77
|
+
"/api/v1/groups/123@g.us/participants/add",
|
|
78
|
+
models.GroupOperationResponseModel,
|
|
79
|
+
{"success": True, "details": "added"},
|
|
80
|
+
),
|
|
81
|
+
(
|
|
82
|
+
lambda client: client.groups.remove_participant("123@g.us", session_name="main", participant_jid="6281234567890@s.whatsapp.net"),
|
|
83
|
+
"POST",
|
|
84
|
+
"/api/v1/groups/123@g.us/participants/remove",
|
|
85
|
+
models.GroupOperationResponseModel,
|
|
86
|
+
{"success": True, "details": "removed"},
|
|
87
|
+
),
|
|
88
|
+
(
|
|
89
|
+
lambda client: client.groups.get_invite_link("123@g.us", session_name="main"),
|
|
90
|
+
"POST",
|
|
91
|
+
"/api/v1/groups/123@g.us/invite-link",
|
|
92
|
+
models.GroupInviteLinkResponseModel,
|
|
93
|
+
{"success": True, "invite_link": "https://chat.whatsapp.com/abc"},
|
|
94
|
+
),
|
|
95
|
+
(
|
|
96
|
+
lambda client: client.groups.get_invite_info({"session_name": "main", "invite_link": "https://chat.whatsapp.com/abc"}),
|
|
97
|
+
"POST",
|
|
98
|
+
"/api/v1/groups/invite-info",
|
|
99
|
+
models.GroupInviteInfoResponseModel,
|
|
100
|
+
{"success": True, "jid": "789@g.us", "name": "Invited Group"},
|
|
101
|
+
),
|
|
102
|
+
(
|
|
103
|
+
lambda client: client.groups.join({"session_name": "main", "invite_link": "https://chat.whatsapp.com/abc"}),
|
|
104
|
+
"POST",
|
|
105
|
+
"/api/v1/groups/join",
|
|
106
|
+
models.GroupOperationResponseModel,
|
|
107
|
+
{"success": True, "details": "joined"},
|
|
108
|
+
),
|
|
109
|
+
(
|
|
110
|
+
lambda client: client.groups.leave("123@g.us", session_name="main"),
|
|
111
|
+
"POST",
|
|
112
|
+
"/api/v1/groups/123@g.us/leave",
|
|
113
|
+
models.GroupOperationResponseModel,
|
|
114
|
+
{"success": True, "details": "left"},
|
|
115
|
+
),
|
|
116
|
+
(
|
|
117
|
+
lambda client: client.groups.set_name("123@g.us", {"session_name": "main", "name": "Renamed"}),
|
|
118
|
+
"POST",
|
|
119
|
+
"/api/v1/groups/123@g.us/name",
|
|
120
|
+
models.GroupOperationResponseModel,
|
|
121
|
+
{"success": True, "details": "name updated"},
|
|
122
|
+
),
|
|
123
|
+
(
|
|
124
|
+
lambda client: client.groups.set_topic("123@g.us", {"session_name": "main", "topic": "new topic"}),
|
|
125
|
+
"POST",
|
|
126
|
+
"/api/v1/groups/123@g.us/topic",
|
|
127
|
+
models.GroupOperationResponseModel,
|
|
128
|
+
{"success": True, "details": "topic updated"},
|
|
129
|
+
),
|
|
130
|
+
(
|
|
131
|
+
lambda client: client.groups.set_photo("123@g.us", {"session_name": "main", "image_data_uri": "data:image/png;base64,abc"}),
|
|
132
|
+
"POST",
|
|
133
|
+
"/api/v1/groups/123@g.us/photo",
|
|
134
|
+
models.GroupOperationResponseModel,
|
|
135
|
+
{"success": True, "details": "photo updated"},
|
|
136
|
+
),
|
|
137
|
+
(
|
|
138
|
+
lambda client: client.groups.set_announce("123@g.us", {"session_name": "main", "announce": True}),
|
|
139
|
+
"POST",
|
|
140
|
+
"/api/v1/groups/123@g.us/announce",
|
|
141
|
+
models.GroupOperationResponseModel,
|
|
142
|
+
{"success": True, "details": "announce set"},
|
|
143
|
+
),
|
|
144
|
+
(
|
|
145
|
+
lambda client: client.groups.set_locked("123@g.us", {"session_name": "main", "locked": True}),
|
|
146
|
+
"POST",
|
|
147
|
+
"/api/v1/groups/123@g.us/locked",
|
|
148
|
+
models.GroupOperationResponseModel,
|
|
149
|
+
{"success": True, "details": "locked set"},
|
|
150
|
+
),
|
|
151
|
+
(
|
|
152
|
+
lambda client: client.groups.set_ephemeral("123@g.us", {"session_name": "main", "duration": "24h"}),
|
|
153
|
+
"POST",
|
|
154
|
+
"/api/v1/groups/123@g.us/ephemeral",
|
|
155
|
+
models.GroupOperationResponseModel,
|
|
156
|
+
{"success": True, "details": "ephemeral set"},
|
|
157
|
+
),
|
|
158
|
+
],
|
|
159
|
+
)
|
|
160
|
+
def test_groups_methods_hit_expected_routes(
|
|
161
|
+
call_factory: Callable[[WazzapiClient], object],
|
|
162
|
+
expected_method: str,
|
|
163
|
+
expected_path: str,
|
|
164
|
+
expected_response_type: type[object],
|
|
165
|
+
response_json: dict[str, object],
|
|
166
|
+
) -> None:
|
|
167
|
+
seen: dict[str, object] = {}
|
|
168
|
+
|
|
169
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
170
|
+
seen["method"] = request.method
|
|
171
|
+
seen["path"] = request.url.path
|
|
172
|
+
seen["query"] = dict(request.url.params)
|
|
173
|
+
seen["body"] = json.loads(request.content.decode("utf-8")) if request.content else None
|
|
174
|
+
status_code = 201 if request.method == "POST" else 200
|
|
175
|
+
return httpx.Response(status_code, json=response_json)
|
|
176
|
+
|
|
177
|
+
transport = httpx.MockTransport(handler)
|
|
178
|
+
with WazzapiClient(base_url="https://api.example.com", transport=transport) as client:
|
|
179
|
+
result = call_factory(client)
|
|
180
|
+
|
|
181
|
+
assert seen["method"] == expected_method
|
|
182
|
+
assert seen["path"] == expected_path
|
|
183
|
+
assert isinstance(result, expected_response_type)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def test_groups_remove_photo_returns_operation_response() -> None:
|
|
187
|
+
seen: dict[str, object] = {}
|
|
188
|
+
|
|
189
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
190
|
+
seen["method"] = request.method
|
|
191
|
+
seen["path"] = request.url.path
|
|
192
|
+
seen["query"] = dict(request.url.params)
|
|
193
|
+
return httpx.Response(
|
|
194
|
+
200,
|
|
195
|
+
json={"success": True, "details": "photo removed"},
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
transport = httpx.MockTransport(handler)
|
|
199
|
+
with WazzapiClient(base_url="https://api.example.com", transport=transport) as client:
|
|
200
|
+
result = client.groups.remove_photo("123@g.us", session_name="main")
|
|
201
|
+
|
|
202
|
+
assert seen["method"] == "DELETE"
|
|
203
|
+
assert seen["path"] == "/api/v1/groups/123@g.us/photo"
|
|
204
|
+
assert seen["query"] == {"session_name": "main"}
|
|
205
|
+
assert isinstance(result, models.GroupOperationResponseModel)
|
|
206
|
+
assert result.success is True
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def test_groups_list_sends_query_params() -> None:
|
|
210
|
+
seen: dict[str, object] = {}
|
|
211
|
+
|
|
212
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
213
|
+
seen["query"] = dict(request.url.params)
|
|
214
|
+
return httpx.Response(200, json={"groups": [], "total": 0})
|
|
215
|
+
|
|
216
|
+
transport = httpx.MockTransport(handler)
|
|
217
|
+
with WazzapiClient(base_url="https://api.example.com", transport=transport) as client:
|
|
218
|
+
client.groups.list(session_name="main", limit=10, offset=5)
|
|
219
|
+
|
|
220
|
+
assert seen["query"] == {"session_name": "main", "limit": "10", "offset": "5"}
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def test_groups_get_sends_session_name_query() -> None:
|
|
224
|
+
seen: dict[str, object] = {}
|
|
225
|
+
|
|
226
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
227
|
+
seen["query"] = dict(request.url.params)
|
|
228
|
+
return httpx.Response(200, json={"id": "123@g.us", "name": "Test"})
|
|
229
|
+
|
|
230
|
+
transport = httpx.MockTransport(handler)
|
|
231
|
+
with WazzapiClient(base_url="https://api.example.com", transport=transport) as client:
|
|
232
|
+
client.groups.get("123@g.us", session_name="main")
|
|
233
|
+
|
|
234
|
+
assert seen["query"] == {"session_name": "main"}
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def test_groups_add_participant_sends_query_params() -> None:
|
|
238
|
+
seen: dict[str, object] = {}
|
|
239
|
+
|
|
240
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
241
|
+
seen["query"] = dict(request.url.params)
|
|
242
|
+
return httpx.Response(200, json={"success": True, "details": "added"})
|
|
243
|
+
|
|
244
|
+
transport = httpx.MockTransport(handler)
|
|
245
|
+
with WazzapiClient(base_url="https://api.example.com", transport=transport) as client:
|
|
246
|
+
client.groups.add_participant(
|
|
247
|
+
"123@g.us",
|
|
248
|
+
session_name="main",
|
|
249
|
+
participant_jid="6281234567890@s.whatsapp.net",
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
assert seen["query"] == {
|
|
253
|
+
"session_name": "main",
|
|
254
|
+
"participant_jid": "6281234567890@s.whatsapp.net",
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def test_groups_models_are_importable() -> None:
|
|
259
|
+
from wazzapi.models import (
|
|
260
|
+
CreateGroupRequest,
|
|
261
|
+
CreateGroupResponseModel,
|
|
262
|
+
GroupDetailResponse,
|
|
263
|
+
GroupInviteInfoResponseModel,
|
|
264
|
+
GroupInviteLinkResponseModel,
|
|
265
|
+
GroupListItem,
|
|
266
|
+
GroupListResponse,
|
|
267
|
+
GroupOperationResponseModel,
|
|
268
|
+
GroupParticipantItem,
|
|
269
|
+
GroupParticipantsResponse,
|
|
270
|
+
InviteInfoRequest,
|
|
271
|
+
JoinGroupRequest,
|
|
272
|
+
SendGroupMediaRequest,
|
|
273
|
+
SendGroupResponse,
|
|
274
|
+
SendGroupTextRequest,
|
|
275
|
+
SetGroupAnnounceRequest,
|
|
276
|
+
SetGroupEphemeralRequest,
|
|
277
|
+
SetGroupLockedRequest,
|
|
278
|
+
SetGroupNameRequest,
|
|
279
|
+
SetGroupPhotoRequest,
|
|
280
|
+
SetGroupTopicRequest,
|
|
281
|
+
UpdateParticipantsRequest,
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
assert GroupListItem is not None
|
|
285
|
+
assert CreateGroupResponseModel is not None
|
|
@@ -12,6 +12,18 @@ from wazzapi import WazzapiClient, models
|
|
|
12
12
|
@pytest.mark.parametrize(
|
|
13
13
|
("call_factory", "expected_method", "expected_path", "expected_response_type", "response_json"),
|
|
14
14
|
[
|
|
15
|
+
(
|
|
16
|
+
lambda client: client.devices.list(limit=25, status="connected", search="main"),
|
|
17
|
+
"GET",
|
|
18
|
+
"/api/v1/devices",
|
|
19
|
+
models.DeviceListResponse,
|
|
20
|
+
{
|
|
21
|
+
"devices": [],
|
|
22
|
+
"total": 0,
|
|
23
|
+
"limit": 25,
|
|
24
|
+
"offset": 0,
|
|
25
|
+
},
|
|
26
|
+
),
|
|
15
27
|
(
|
|
16
28
|
lambda client: client.contacts.list(limit=25, search="alice"),
|
|
17
29
|
"GET",
|
|
@@ -134,6 +146,50 @@ def test_delete_endpoints_return_none() -> None:
|
|
|
134
146
|
assert seen_paths == ["/api/v1/contacts/contact_1", "/api/v1/templates/template_1"]
|
|
135
147
|
|
|
136
148
|
|
|
149
|
+
def test_get_device_returns_typed_response() -> None:
|
|
150
|
+
seen: dict[str, object] = {}
|
|
151
|
+
|
|
152
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
153
|
+
seen["method"] = request.method
|
|
154
|
+
seen["path"] = request.url.path
|
|
155
|
+
return httpx.Response(
|
|
156
|
+
200,
|
|
157
|
+
json={
|
|
158
|
+
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
|
|
159
|
+
"name": "Primary Device",
|
|
160
|
+
"session_name": "main",
|
|
161
|
+
"status": "connected",
|
|
162
|
+
"is_primary": True,
|
|
163
|
+
"auto_warmer_enabled": True,
|
|
164
|
+
"total_messages_sent": 123,
|
|
165
|
+
"total_messages_received": 45,
|
|
166
|
+
"contacts_synced_count": 900,
|
|
167
|
+
"created_at": "2026-05-01T00:00:00Z",
|
|
168
|
+
"updated_at": "2026-05-02T00:00:00Z",
|
|
169
|
+
"timezone": "Asia/Jakarta",
|
|
170
|
+
"connection_attempts": 2,
|
|
171
|
+
"daily_message_limit": 1000,
|
|
172
|
+
"message_delay_ms": 500,
|
|
173
|
+
"phone_number": "6281234567890",
|
|
174
|
+
"last_connected_at": "2026-05-02T00:00:00Z",
|
|
175
|
+
"last_health_check_at": "2026-05-02T01:00:00Z",
|
|
176
|
+
"last_contact_sync_at": "2026-05-02T02:00:00Z",
|
|
177
|
+
"last_contact_sync_status": "completed",
|
|
178
|
+
"backend_id": "7a5d6343-1dd1-429a-8d83-25c9bf06c878",
|
|
179
|
+
},
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
transport = httpx.MockTransport(handler)
|
|
183
|
+
with WazzapiClient(base_url="https://api.example.com", transport=transport) as client:
|
|
184
|
+
result = client.devices.get("3c90c3cc-0d44-4b50-8888-8dd25736052a")
|
|
185
|
+
|
|
186
|
+
assert seen["method"] == "GET"
|
|
187
|
+
assert seen["path"] == "/api/v1/devices/3c90c3cc-0d44-4b50-8888-8dd25736052a"
|
|
188
|
+
assert isinstance(result, models.DeviceResponse)
|
|
189
|
+
assert result.session_name == "main"
|
|
190
|
+
assert result.timezone == "Asia/Jakarta"
|
|
191
|
+
|
|
192
|
+
|
|
137
193
|
def test_sync_status_returns_typed_list() -> None:
|
|
138
194
|
def handler(_: httpx.Request) -> httpx.Response:
|
|
139
195
|
return httpx.Response(
|
|
@@ -7,7 +7,7 @@ import httpx
|
|
|
7
7
|
from pydantic import BaseModel, TypeAdapter
|
|
8
8
|
|
|
9
9
|
from .errors import WazzapiAPIError
|
|
10
|
-
from .resources import ContactsResource, MessagesResource, TemplatesResource
|
|
10
|
+
from .resources import ContactsResource, DevicesResource, GroupsResource, MessagesResource, TemplatesResource
|
|
11
11
|
|
|
12
12
|
DEFAULT_BASE_URL = "https://api.wazzapi.com"
|
|
13
13
|
|
|
@@ -39,6 +39,8 @@ class WazzapiClient:
|
|
|
39
39
|
)
|
|
40
40
|
|
|
41
41
|
self.contacts = ContactsResource(self)
|
|
42
|
+
self.devices = DevicesResource(self)
|
|
43
|
+
self.groups = GroupsResource(self)
|
|
42
44
|
self.messages = MessagesResource(self)
|
|
43
45
|
self.templates = TemplatesResource(self)
|
|
44
46
|
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
from .base import WazzapiModel
|
|
2
2
|
from .contacts import *
|
|
3
3
|
from .contacts import __all__ as contacts_all
|
|
4
|
+
from .devices import *
|
|
5
|
+
from .devices import __all__ as devices_all
|
|
6
|
+
from .groups import *
|
|
7
|
+
from .groups import __all__ as groups_all
|
|
4
8
|
from .media import *
|
|
5
9
|
from .media import __all__ as media_all
|
|
6
10
|
from .messages import *
|
|
@@ -10,4 +14,13 @@ from .templates import __all__ as templates_all
|
|
|
10
14
|
from .webhooks import *
|
|
11
15
|
from .webhooks import __all__ as webhooks_all
|
|
12
16
|
|
|
13
|
-
__all__ = [
|
|
17
|
+
__all__ = [
|
|
18
|
+
"WazzapiModel",
|
|
19
|
+
*contacts_all,
|
|
20
|
+
*devices_all,
|
|
21
|
+
*groups_all,
|
|
22
|
+
*media_all,
|
|
23
|
+
*messages_all,
|
|
24
|
+
*templates_all,
|
|
25
|
+
*webhooks_all,
|
|
26
|
+
]
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
|
|
5
|
+
from .base import WazzapiModel
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DeviceItem(WazzapiModel):
|
|
9
|
+
id: str
|
|
10
|
+
name: str
|
|
11
|
+
session_name: str
|
|
12
|
+
status: str
|
|
13
|
+
is_primary: bool
|
|
14
|
+
auto_warmer_enabled: bool
|
|
15
|
+
total_messages_sent: int
|
|
16
|
+
total_messages_received: int
|
|
17
|
+
contacts_synced_count: int
|
|
18
|
+
created_at: datetime
|
|
19
|
+
updated_at: datetime
|
|
20
|
+
phone_number: str | None = None
|
|
21
|
+
last_connected_at: datetime | None = None
|
|
22
|
+
last_health_check_at: datetime | None = None
|
|
23
|
+
last_contact_sync_at: datetime | None = None
|
|
24
|
+
last_contact_sync_status: str | None = None
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class DeviceListResponse(WazzapiModel):
|
|
28
|
+
devices: list[DeviceItem]
|
|
29
|
+
total: int
|
|
30
|
+
limit: int
|
|
31
|
+
offset: int
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class DeviceResponse(DeviceItem):
|
|
35
|
+
timezone: str
|
|
36
|
+
connection_attempts: int
|
|
37
|
+
daily_message_limit: int
|
|
38
|
+
message_delay_ms: int
|
|
39
|
+
backend_id: str | None = None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
__all__ = ["DeviceItem", "DeviceListResponse", "DeviceResponse"]
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from .base import WazzapiModel
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class GroupListItem(WazzapiModel):
|
|
10
|
+
id: str
|
|
11
|
+
name: str
|
|
12
|
+
description: str | None = None
|
|
13
|
+
owner: str | None = None
|
|
14
|
+
participants_count: int = 0
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class GroupListResponse(WazzapiModel):
|
|
18
|
+
groups: list[GroupListItem]
|
|
19
|
+
total: int
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class GroupDetailResponse(WazzapiModel):
|
|
23
|
+
id: str
|
|
24
|
+
name: str
|
|
25
|
+
description: str | None = None
|
|
26
|
+
owner: str | None = None
|
|
27
|
+
participants_count: int = 0
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class GroupParticipantItem(WazzapiModel):
|
|
31
|
+
id: str
|
|
32
|
+
is_admin: bool = False
|
|
33
|
+
is_super_admin: bool = False
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class GroupParticipantsResponse(WazzapiModel):
|
|
37
|
+
participants: list[GroupParticipantItem]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class GroupOperationResponseModel(WazzapiModel):
|
|
41
|
+
success: bool
|
|
42
|
+
details: str
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class CreateGroupRequest(WazzapiModel):
|
|
46
|
+
session_name: str
|
|
47
|
+
name: str
|
|
48
|
+
participants: list[str]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class CreateGroupResponseModel(WazzapiModel):
|
|
52
|
+
success: bool
|
|
53
|
+
jid: str
|
|
54
|
+
name: str
|
|
55
|
+
owner_jid: str | None = None
|
|
56
|
+
group_created: str | None = None
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class SendGroupTextRequest(WazzapiModel):
|
|
60
|
+
session_name: str
|
|
61
|
+
group_jid: str
|
|
62
|
+
text: str
|
|
63
|
+
message_id: str | None = None
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class SendGroupMediaRequest(WazzapiModel):
|
|
67
|
+
session_name: str
|
|
68
|
+
group_jid: str
|
|
69
|
+
media_url: str
|
|
70
|
+
media_type: str
|
|
71
|
+
caption: str | None = None
|
|
72
|
+
filename: str | None = None
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class SendGroupResponse(WazzapiModel):
|
|
76
|
+
success: bool
|
|
77
|
+
message_id: str
|
|
78
|
+
status: str
|
|
79
|
+
run_id: str | None = None
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class UpdateParticipantsRequest(WazzapiModel):
|
|
83
|
+
session_name: str
|
|
84
|
+
group_jid: str
|
|
85
|
+
action: str
|
|
86
|
+
participants: list[str]
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class GroupInviteLinkResponseModel(WazzapiModel):
|
|
90
|
+
success: bool
|
|
91
|
+
invite_link: str
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class GroupInviteInfoResponseModel(WazzapiModel):
|
|
95
|
+
success: bool
|
|
96
|
+
jid: str
|
|
97
|
+
name: str
|
|
98
|
+
participants: int = 0
|
|
99
|
+
owner_jid: str | None = None
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class InviteInfoRequest(WazzapiModel):
|
|
103
|
+
session_name: str
|
|
104
|
+
invite_link: str
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class JoinGroupRequest(WazzapiModel):
|
|
108
|
+
session_name: str
|
|
109
|
+
invite_link: str
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class SetGroupNameRequest(WazzapiModel):
|
|
113
|
+
session_name: str
|
|
114
|
+
name: str
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class SetGroupTopicRequest(WazzapiModel):
|
|
118
|
+
session_name: str
|
|
119
|
+
topic: str
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class SetGroupPhotoRequest(WazzapiModel):
|
|
123
|
+
session_name: str
|
|
124
|
+
image_data_uri: str
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class SetGroupAnnounceRequest(WazzapiModel):
|
|
128
|
+
session_name: str
|
|
129
|
+
announce: bool
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class SetGroupLockedRequest(WazzapiModel):
|
|
133
|
+
session_name: str
|
|
134
|
+
locked: bool
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class SetGroupEphemeralRequest(WazzapiModel):
|
|
138
|
+
session_name: str
|
|
139
|
+
duration: str
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
__all__ = [
|
|
143
|
+
"CreateGroupRequest",
|
|
144
|
+
"CreateGroupResponseModel",
|
|
145
|
+
"GroupDetailResponse",
|
|
146
|
+
"GroupInviteInfoResponseModel",
|
|
147
|
+
"GroupInviteLinkResponseModel",
|
|
148
|
+
"GroupListItem",
|
|
149
|
+
"GroupListResponse",
|
|
150
|
+
"GroupOperationResponseModel",
|
|
151
|
+
"GroupParticipantItem",
|
|
152
|
+
"GroupParticipantsResponse",
|
|
153
|
+
"InviteInfoRequest",
|
|
154
|
+
"JoinGroupRequest",
|
|
155
|
+
"SendGroupMediaRequest",
|
|
156
|
+
"SendGroupResponse",
|
|
157
|
+
"SendGroupTextRequest",
|
|
158
|
+
"SetGroupAnnounceRequest",
|
|
159
|
+
"SetGroupEphemeralRequest",
|
|
160
|
+
"SetGroupLockedRequest",
|
|
161
|
+
"SetGroupNameRequest",
|
|
162
|
+
"SetGroupPhotoRequest",
|
|
163
|
+
"SetGroupTopicRequest",
|
|
164
|
+
"UpdateParticipantsRequest",
|
|
165
|
+
]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from .contacts import ContactsResource
|
|
2
|
+
from .devices import DevicesResource
|
|
3
|
+
from .groups import GroupsResource
|
|
4
|
+
from .messages import MessagesResource
|
|
5
|
+
from .templates import TemplatesResource
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"ContactsResource",
|
|
9
|
+
"DevicesResource",
|
|
10
|
+
"GroupsResource",
|
|
11
|
+
"MessagesResource",
|
|
12
|
+
"TemplatesResource",
|
|
13
|
+
]
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from .. import models
|
|
4
|
+
from .base import BaseResource
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class DevicesResource(BaseResource):
|
|
8
|
+
def list(
|
|
9
|
+
self,
|
|
10
|
+
*,
|
|
11
|
+
limit: int | None = None,
|
|
12
|
+
offset: int | None = None,
|
|
13
|
+
status: str | None = None,
|
|
14
|
+
search: str | None = None,
|
|
15
|
+
sort_by: str | None = None,
|
|
16
|
+
sort_order: str | None = None,
|
|
17
|
+
) -> models.DeviceListResponse:
|
|
18
|
+
return self._client._request(
|
|
19
|
+
"GET",
|
|
20
|
+
"/api/v1/devices",
|
|
21
|
+
params={
|
|
22
|
+
"limit": limit,
|
|
23
|
+
"offset": offset,
|
|
24
|
+
"status": status,
|
|
25
|
+
"search": search,
|
|
26
|
+
"sort_by": sort_by,
|
|
27
|
+
"sort_order": sort_order,
|
|
28
|
+
},
|
|
29
|
+
response_model=models.DeviceListResponse,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
def get(self, device_id: str) -> models.DeviceResponse:
|
|
33
|
+
return self._client._request(
|
|
34
|
+
"GET",
|
|
35
|
+
f"/api/v1/devices/{device_id}",
|
|
36
|
+
response_model=models.DeviceResponse,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
__all__ = ["DevicesResource"]
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from .. import models
|
|
6
|
+
from .base import BaseResource
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class GroupsResource(BaseResource):
|
|
10
|
+
def list(
|
|
11
|
+
self,
|
|
12
|
+
*,
|
|
13
|
+
session_name: str,
|
|
14
|
+
limit: int | None = None,
|
|
15
|
+
offset: int | None = None,
|
|
16
|
+
) -> models.GroupListResponse:
|
|
17
|
+
return self._client._request(
|
|
18
|
+
"GET",
|
|
19
|
+
"/api/v1/groups",
|
|
20
|
+
params={
|
|
21
|
+
"session_name": session_name,
|
|
22
|
+
"limit": limit,
|
|
23
|
+
"offset": offset,
|
|
24
|
+
},
|
|
25
|
+
response_model=models.GroupListResponse,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
def get(
|
|
29
|
+
self,
|
|
30
|
+
group_jid: str,
|
|
31
|
+
*,
|
|
32
|
+
session_name: str,
|
|
33
|
+
) -> models.GroupDetailResponse:
|
|
34
|
+
return self._client._request(
|
|
35
|
+
"GET",
|
|
36
|
+
f"/api/v1/groups/{group_jid}",
|
|
37
|
+
params={"session_name": session_name},
|
|
38
|
+
response_model=models.GroupDetailResponse,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
def get_participants(
|
|
42
|
+
self,
|
|
43
|
+
group_jid: str,
|
|
44
|
+
*,
|
|
45
|
+
session_name: str,
|
|
46
|
+
) -> models.GroupParticipantsResponse:
|
|
47
|
+
return self._client._request(
|
|
48
|
+
"GET",
|
|
49
|
+
f"/api/v1/groups/{group_jid}/participants",
|
|
50
|
+
params={"session_name": session_name},
|
|
51
|
+
response_model=models.GroupParticipantsResponse,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
def create(
|
|
55
|
+
self,
|
|
56
|
+
payload: models.CreateGroupRequest | dict[str, Any],
|
|
57
|
+
) -> models.CreateGroupResponseModel:
|
|
58
|
+
return self._client._request(
|
|
59
|
+
"POST",
|
|
60
|
+
"/api/v1/groups/create",
|
|
61
|
+
json_body=payload,
|
|
62
|
+
response_model=models.CreateGroupResponseModel,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
def send_text(
|
|
66
|
+
self,
|
|
67
|
+
payload: models.SendGroupTextRequest | dict[str, Any],
|
|
68
|
+
) -> models.SendGroupResponse:
|
|
69
|
+
return self._client._request(
|
|
70
|
+
"POST",
|
|
71
|
+
"/api/v1/groups/send",
|
|
72
|
+
json_body=payload,
|
|
73
|
+
response_model=models.SendGroupResponse,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
def send_media(
|
|
77
|
+
self,
|
|
78
|
+
payload: models.SendGroupMediaRequest | dict[str, Any],
|
|
79
|
+
) -> models.SendGroupResponse:
|
|
80
|
+
return self._client._request(
|
|
81
|
+
"POST",
|
|
82
|
+
"/api/v1/groups/send/media",
|
|
83
|
+
json_body=payload,
|
|
84
|
+
response_model=models.SendGroupResponse,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
def update_participants(
|
|
88
|
+
self,
|
|
89
|
+
payload: models.UpdateParticipantsRequest | dict[str, Any],
|
|
90
|
+
) -> models.GroupOperationResponseModel:
|
|
91
|
+
return self._client._request(
|
|
92
|
+
"POST",
|
|
93
|
+
"/api/v1/groups/participants",
|
|
94
|
+
json_body=payload,
|
|
95
|
+
response_model=models.GroupOperationResponseModel,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
def add_participant(
|
|
99
|
+
self,
|
|
100
|
+
group_jid: str,
|
|
101
|
+
*,
|
|
102
|
+
session_name: str,
|
|
103
|
+
participant_jid: str,
|
|
104
|
+
) -> models.GroupOperationResponseModel:
|
|
105
|
+
return self._client._request(
|
|
106
|
+
"POST",
|
|
107
|
+
f"/api/v1/groups/{group_jid}/participants/add",
|
|
108
|
+
params={
|
|
109
|
+
"session_name": session_name,
|
|
110
|
+
"participant_jid": participant_jid,
|
|
111
|
+
},
|
|
112
|
+
response_model=models.GroupOperationResponseModel,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
def remove_participant(
|
|
116
|
+
self,
|
|
117
|
+
group_jid: str,
|
|
118
|
+
*,
|
|
119
|
+
session_name: str,
|
|
120
|
+
participant_jid: str,
|
|
121
|
+
) -> models.GroupOperationResponseModel:
|
|
122
|
+
return self._client._request(
|
|
123
|
+
"POST",
|
|
124
|
+
f"/api/v1/groups/{group_jid}/participants/remove",
|
|
125
|
+
params={
|
|
126
|
+
"session_name": session_name,
|
|
127
|
+
"participant_jid": participant_jid,
|
|
128
|
+
},
|
|
129
|
+
response_model=models.GroupOperationResponseModel,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
def get_invite_link(
|
|
133
|
+
self,
|
|
134
|
+
group_jid: str,
|
|
135
|
+
*,
|
|
136
|
+
session_name: str,
|
|
137
|
+
) -> models.GroupInviteLinkResponseModel:
|
|
138
|
+
return self._client._request(
|
|
139
|
+
"POST",
|
|
140
|
+
f"/api/v1/groups/{group_jid}/invite-link",
|
|
141
|
+
params={"session_name": session_name},
|
|
142
|
+
response_model=models.GroupInviteLinkResponseModel,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
def get_invite_info(
|
|
146
|
+
self,
|
|
147
|
+
payload: models.InviteInfoRequest | dict[str, Any],
|
|
148
|
+
) -> models.GroupInviteInfoResponseModel:
|
|
149
|
+
return self._client._request(
|
|
150
|
+
"POST",
|
|
151
|
+
"/api/v1/groups/invite-info",
|
|
152
|
+
json_body=payload,
|
|
153
|
+
response_model=models.GroupInviteInfoResponseModel,
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
def join(
|
|
157
|
+
self,
|
|
158
|
+
payload: models.JoinGroupRequest | dict[str, Any],
|
|
159
|
+
) -> models.GroupOperationResponseModel:
|
|
160
|
+
return self._client._request(
|
|
161
|
+
"POST",
|
|
162
|
+
"/api/v1/groups/join",
|
|
163
|
+
json_body=payload,
|
|
164
|
+
response_model=models.GroupOperationResponseModel,
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
def leave(
|
|
168
|
+
self,
|
|
169
|
+
group_jid: str,
|
|
170
|
+
*,
|
|
171
|
+
session_name: str,
|
|
172
|
+
) -> models.GroupOperationResponseModel:
|
|
173
|
+
return self._client._request(
|
|
174
|
+
"POST",
|
|
175
|
+
f"/api/v1/groups/{group_jid}/leave",
|
|
176
|
+
params={"session_name": session_name},
|
|
177
|
+
response_model=models.GroupOperationResponseModel,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
def set_name(
|
|
181
|
+
self,
|
|
182
|
+
group_jid: str,
|
|
183
|
+
payload: models.SetGroupNameRequest | dict[str, Any],
|
|
184
|
+
) -> models.GroupOperationResponseModel:
|
|
185
|
+
return self._client._request(
|
|
186
|
+
"POST",
|
|
187
|
+
f"/api/v1/groups/{group_jid}/name",
|
|
188
|
+
json_body=payload,
|
|
189
|
+
response_model=models.GroupOperationResponseModel,
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
def set_topic(
|
|
193
|
+
self,
|
|
194
|
+
group_jid: str,
|
|
195
|
+
payload: models.SetGroupTopicRequest | dict[str, Any],
|
|
196
|
+
) -> models.GroupOperationResponseModel:
|
|
197
|
+
return self._client._request(
|
|
198
|
+
"POST",
|
|
199
|
+
f"/api/v1/groups/{group_jid}/topic",
|
|
200
|
+
json_body=payload,
|
|
201
|
+
response_model=models.GroupOperationResponseModel,
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
def set_photo(
|
|
205
|
+
self,
|
|
206
|
+
group_jid: str,
|
|
207
|
+
payload: models.SetGroupPhotoRequest | dict[str, Any],
|
|
208
|
+
) -> models.GroupOperationResponseModel:
|
|
209
|
+
return self._client._request(
|
|
210
|
+
"POST",
|
|
211
|
+
f"/api/v1/groups/{group_jid}/photo",
|
|
212
|
+
json_body=payload,
|
|
213
|
+
response_model=models.GroupOperationResponseModel,
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
def remove_photo(
|
|
217
|
+
self,
|
|
218
|
+
group_jid: str,
|
|
219
|
+
*,
|
|
220
|
+
session_name: str,
|
|
221
|
+
) -> models.GroupOperationResponseModel:
|
|
222
|
+
return self._client._request(
|
|
223
|
+
"DELETE",
|
|
224
|
+
f"/api/v1/groups/{group_jid}/photo",
|
|
225
|
+
params={"session_name": session_name},
|
|
226
|
+
response_model=models.GroupOperationResponseModel,
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
def set_announce(
|
|
230
|
+
self,
|
|
231
|
+
group_jid: str,
|
|
232
|
+
payload: models.SetGroupAnnounceRequest | dict[str, Any],
|
|
233
|
+
) -> models.GroupOperationResponseModel:
|
|
234
|
+
return self._client._request(
|
|
235
|
+
"POST",
|
|
236
|
+
f"/api/v1/groups/{group_jid}/announce",
|
|
237
|
+
json_body=payload,
|
|
238
|
+
response_model=models.GroupOperationResponseModel,
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
def set_locked(
|
|
242
|
+
self,
|
|
243
|
+
group_jid: str,
|
|
244
|
+
payload: models.SetGroupLockedRequest | dict[str, Any],
|
|
245
|
+
) -> models.GroupOperationResponseModel:
|
|
246
|
+
return self._client._request(
|
|
247
|
+
"POST",
|
|
248
|
+
f"/api/v1/groups/{group_jid}/locked",
|
|
249
|
+
json_body=payload,
|
|
250
|
+
response_model=models.GroupOperationResponseModel,
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
def set_ephemeral(
|
|
254
|
+
self,
|
|
255
|
+
group_jid: str,
|
|
256
|
+
payload: models.SetGroupEphemeralRequest | dict[str, Any],
|
|
257
|
+
) -> models.GroupOperationResponseModel:
|
|
258
|
+
return self._client._request(
|
|
259
|
+
"POST",
|
|
260
|
+
f"/api/v1/groups/{group_jid}/ephemeral",
|
|
261
|
+
json_body=payload,
|
|
262
|
+
response_model=models.GroupOperationResponseModel,
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
__all__ = ["GroupsResource"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|