whatsapp-python 3.1.5__py3-none-any.whl → 3.3.5.dev0__py3-none-any.whl
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.
- whatsapp/__init__.py +386 -275
- whatsapp/constants.py +4 -4
- whatsapp/ext/_buttons.py +82 -82
- whatsapp/ext/_media.py +135 -135
- whatsapp/ext/_message.py +124 -103
- whatsapp/ext/_property.py +5 -5
- whatsapp/ext/_send_media.py +267 -267
- whatsapp/ext/_send_others.py +86 -86
- whatsapp/ext/_static.py +329 -329
- {whatsapp_python-3.1.5.dist-info → whatsapp_python-3.3.5.dev0.dist-info}/METADATA +3 -1
- whatsapp_python-3.3.5.dev0.dist-info/RECORD +13 -0
- {whatsapp_python-3.1.5.dist-info → whatsapp_python-3.3.5.dev0.dist-info}/licenses/LICENSE +21 -21
- whatsapp_python-3.1.5.dist-info/RECORD +0 -13
- {whatsapp_python-3.1.5.dist-info → whatsapp_python-3.3.5.dev0.dist-info}/WHEEL +0 -0
whatsapp/__init__.py
CHANGED
|
@@ -1,275 +1,386 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Unofficial Python wrapper for the WhatsApp Cloud API.
|
|
3
|
-
"""
|
|
4
|
-
from __future__ import annotations
|
|
5
|
-
|
|
6
|
-
import requests
|
|
7
|
-
import logging
|
|
8
|
-
from
|
|
9
|
-
from
|
|
10
|
-
from
|
|
11
|
-
from .
|
|
12
|
-
from .ext.
|
|
13
|
-
from .ext.
|
|
14
|
-
from .ext.
|
|
15
|
-
from .ext.
|
|
16
|
-
from .ext.
|
|
17
|
-
from .ext.
|
|
18
|
-
import
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
logging.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
self.
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
self.
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
self.
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
self.
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
self.
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
self.
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
1
|
+
"""
|
|
2
|
+
Unofficial Python wrapper for the WhatsApp Cloud API.
|
|
3
|
+
"""
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
import logging
|
|
8
|
+
from typing import Union
|
|
9
|
+
from fastapi import FastAPI, HTTPException, Request
|
|
10
|
+
from uvicorn import run as _run
|
|
11
|
+
from .constants import VERSION
|
|
12
|
+
from .ext._property import authorized
|
|
13
|
+
from .ext._send_others import send_custom_json, send_contacts
|
|
14
|
+
from .ext._message import send_template
|
|
15
|
+
from .ext._send_media import send_image, send_video, send_audio, send_location, send_sticker, send_document
|
|
16
|
+
from .ext._media import upload_media, query_media_url, download_media, delete_media
|
|
17
|
+
from .ext._buttons import send_button, create_button, send_reply_button
|
|
18
|
+
from .ext._static import is_message, get_mobile, get_author, get_name, get_message, get_message_id, get_message_type, get_message_timestamp, get_audio, get_delivery, get_document, get_image, get_sticker, get_interactive_response, get_location, get_video, changed_field
|
|
19
|
+
import json
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class WhatsApp(object):
|
|
23
|
+
def __init__(self, token: str = "", phone_number_id: Union[str, dict] = "", logger: bool = True, update_check: bool = True, verify_token: str = "", debug: bool = True):
|
|
24
|
+
"""
|
|
25
|
+
Initialize the WhatsApp Object
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
token[str]: Token for the WhatsApp cloud API obtained from the Facebook developer portal
|
|
29
|
+
phone_number_id[str]: Phone number id for the WhatsApp cloud API obtained from the developer portal
|
|
30
|
+
logger[bool]: Whether to enable logging or not (default: True)
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
# Check if the version is up to date
|
|
34
|
+
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
|
35
|
+
|
|
36
|
+
self.l = phone_number_id
|
|
37
|
+
print(self.l)
|
|
38
|
+
|
|
39
|
+
if isinstance(phone_number_id, dict):
|
|
40
|
+
# use first phone number id as default
|
|
41
|
+
phone_number_id = phone_number_id[list(phone_number_id.keys())[0]]
|
|
42
|
+
print(phone_number_id)
|
|
43
|
+
|
|
44
|
+
elif phone_number_id == "":
|
|
45
|
+
logging.error("Phone number ID not provided")
|
|
46
|
+
raise ValueError(
|
|
47
|
+
"Phone number ID not provided but required")
|
|
48
|
+
elif isinstance(phone_number_id, str):
|
|
49
|
+
logging.critical(
|
|
50
|
+
"The phone number ID should be a dictionary of phone numbers and their IDs. Using strings is deprecated and will be removed in the next version.")
|
|
51
|
+
print(phone_number_id)
|
|
52
|
+
else:
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
self.VERSION = VERSION
|
|
56
|
+
if update_check is True:
|
|
57
|
+
latest = str(requests.get(
|
|
58
|
+
"https://pypi.org/pypi/whatsapp-python/json").json()["info"]["version"])
|
|
59
|
+
if self.VERSION != latest:
|
|
60
|
+
try:
|
|
61
|
+
version_int = int(self.VERSION.replace(".", ""))
|
|
62
|
+
except:
|
|
63
|
+
version_int = 0
|
|
64
|
+
latest_int = int(latest.replace(".", ""))
|
|
65
|
+
# this is to avoid the case where the version is 1.0.10 and the latest is 1.0.2 (possible if user is using the github version)
|
|
66
|
+
if version_int < latest_int:
|
|
67
|
+
if version_int == 0:
|
|
68
|
+
logging.critical(
|
|
69
|
+
f"There was an error while checking for updates, please update the package manually or report the issue on GitHub.")
|
|
70
|
+
else:
|
|
71
|
+
logging.critical(
|
|
72
|
+
f"Whatsapp-python is out of date. Please update to the latest version {latest}. READ THE CHANGELOG BEFORE UPDATING. NEW VERSIONS MAY BREAK YOUR CODE IF NOT PROPERLY UPDATED.")
|
|
73
|
+
|
|
74
|
+
if token == "":
|
|
75
|
+
logging.error("Token not provided")
|
|
76
|
+
raise ValueError("Token not provided but required")
|
|
77
|
+
if phone_number_id == "":
|
|
78
|
+
logging.error("Phone number ID not provided")
|
|
79
|
+
raise ValueError(
|
|
80
|
+
"Phone number ID not provided but required")
|
|
81
|
+
self.token = token
|
|
82
|
+
self.phone_number_id = phone_number_id
|
|
83
|
+
self.base_url = "https://graph.facebook.com/v18.0"
|
|
84
|
+
self.url = f"{self.base_url}/{phone_number_id}/messages"
|
|
85
|
+
self.verify_token = verify_token
|
|
86
|
+
|
|
87
|
+
async def base(*args):
|
|
88
|
+
pass
|
|
89
|
+
self.message_handler = base
|
|
90
|
+
self.other_handler = base
|
|
91
|
+
self.verification_handler = base
|
|
92
|
+
self.headers = {
|
|
93
|
+
"Content-Type": "application/json",
|
|
94
|
+
"Authorization": f"Bearer {self.token}"
|
|
95
|
+
}
|
|
96
|
+
if logger is False:
|
|
97
|
+
logging.disable(logging.INFO)
|
|
98
|
+
logging.disable(logging.ERROR)
|
|
99
|
+
if debug is False:
|
|
100
|
+
logging.disable(logging.DEBUG)
|
|
101
|
+
logging.disable(logging.ERROR)
|
|
102
|
+
|
|
103
|
+
self.app = FastAPI()
|
|
104
|
+
|
|
105
|
+
# Verification handler has 1 argument: challenge (str | bool): str if verification is successful, False if not
|
|
106
|
+
|
|
107
|
+
@self.app.get("/")
|
|
108
|
+
async def verify_endpoint(r: Request):
|
|
109
|
+
if r.query_params.get("hub.verify_token") == self.verify_token:
|
|
110
|
+
logging.debug("Webhook verified successfully")
|
|
111
|
+
challenge = r.query_params.get("hub.challenge")
|
|
112
|
+
self.verification_handler(challenge)
|
|
113
|
+
self.other_handler(challenge)
|
|
114
|
+
return int(challenge)
|
|
115
|
+
logging.error("Webhook Verification failed - token mismatch")
|
|
116
|
+
await self.verification_handler(False)
|
|
117
|
+
await self.other_handler(False)
|
|
118
|
+
return {"success": False}
|
|
119
|
+
|
|
120
|
+
@self.app.post("/")
|
|
121
|
+
async def hook(r: Request):
|
|
122
|
+
try:
|
|
123
|
+
# Handle Webhook Subscriptions
|
|
124
|
+
data = await r.json()
|
|
125
|
+
if data is None:
|
|
126
|
+
return {"success": False}
|
|
127
|
+
data_str = json.dumps(data, indent=4)
|
|
128
|
+
# log the data received only if the log level is debug
|
|
129
|
+
logging.debug(f"Received webhook data: {data_str}")
|
|
130
|
+
|
|
131
|
+
changed_field = self.changed_field(data)
|
|
132
|
+
if changed_field == "messages":
|
|
133
|
+
new_message = self.is_message(data)
|
|
134
|
+
if new_message:
|
|
135
|
+
msg = Message(instance=self, data=data)
|
|
136
|
+
await self.message_handler(msg)
|
|
137
|
+
await self.other_handler(msg)
|
|
138
|
+
return {"success": True}
|
|
139
|
+
except Exception as e:
|
|
140
|
+
logging.error(f"Error parsing message: {e}")
|
|
141
|
+
raise HTTPException(status_code=500, detail={
|
|
142
|
+
"success": False,
|
|
143
|
+
"error": str(e)
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
# all the files starting with _ are imported here, and should not be imported directly.
|
|
147
|
+
|
|
148
|
+
is_message = staticmethod(is_message)
|
|
149
|
+
get_mobile = staticmethod(get_mobile)
|
|
150
|
+
get_name = staticmethod(get_name)
|
|
151
|
+
get_message = staticmethod(get_message)
|
|
152
|
+
get_message_id = staticmethod(get_message_id)
|
|
153
|
+
get_message_type = staticmethod(get_message_type)
|
|
154
|
+
get_message_timestamp = staticmethod(get_message_timestamp)
|
|
155
|
+
get_audio = staticmethod(get_audio)
|
|
156
|
+
get_delivery = staticmethod(get_delivery)
|
|
157
|
+
get_document = staticmethod(get_document)
|
|
158
|
+
get_image = staticmethod(get_image)
|
|
159
|
+
get_sticker = staticmethod(get_sticker)
|
|
160
|
+
get_interactive_response = staticmethod(get_interactive_response)
|
|
161
|
+
get_location = staticmethod(get_location)
|
|
162
|
+
get_video = staticmethod(get_video)
|
|
163
|
+
changed_field = staticmethod(changed_field)
|
|
164
|
+
get_author = staticmethod(get_author)
|
|
165
|
+
|
|
166
|
+
send_button = send_button
|
|
167
|
+
create_button = create_button
|
|
168
|
+
send_reply_button = send_reply_button
|
|
169
|
+
send_image = send_image
|
|
170
|
+
send_video = send_video
|
|
171
|
+
send_audio = send_audio
|
|
172
|
+
send_location = send_location
|
|
173
|
+
send_sticker = send_sticker
|
|
174
|
+
send_document = send_document
|
|
175
|
+
upload_media = upload_media
|
|
176
|
+
query_media_url = query_media_url
|
|
177
|
+
download_media = download_media
|
|
178
|
+
delete_media = delete_media
|
|
179
|
+
send_template = send_template
|
|
180
|
+
send_custom_json = send_custom_json
|
|
181
|
+
send_contacts = send_contacts
|
|
182
|
+
|
|
183
|
+
authorized = property(authorized)
|
|
184
|
+
|
|
185
|
+
def create_message(self, **kwargs) -> Message:
|
|
186
|
+
"""
|
|
187
|
+
Create a message object
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
data[dict]: The message data
|
|
191
|
+
content[str]: The message content
|
|
192
|
+
to[str]: The recipient
|
|
193
|
+
rec_type[str]: The recipient type (individual/group)
|
|
194
|
+
"""
|
|
195
|
+
return Message(**kwargs, instance=self)
|
|
196
|
+
|
|
197
|
+
def on_message(self, handler: function):
|
|
198
|
+
"""
|
|
199
|
+
Set the handler for incoming messages
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
handler[function]: The handler function
|
|
203
|
+
"""
|
|
204
|
+
self.message_handler = handler
|
|
205
|
+
|
|
206
|
+
def on_event(self, handler: function):
|
|
207
|
+
"""
|
|
208
|
+
Set the handler for other events
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
handler[function]: The handler function
|
|
212
|
+
"""
|
|
213
|
+
self.other_handler = handler
|
|
214
|
+
|
|
215
|
+
def on_verification(self, handler: function):
|
|
216
|
+
"""
|
|
217
|
+
Set the handler for verification
|
|
218
|
+
|
|
219
|
+
Args:
|
|
220
|
+
handler[function]: The handler function
|
|
221
|
+
"""
|
|
222
|
+
self.verification_handler = handler
|
|
223
|
+
|
|
224
|
+
def run(self, host: str = "localhost", port: int = 5000, **options):
|
|
225
|
+
_run(self.app, host=host, port=port, **options)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
class Message(object):
|
|
229
|
+
# type: ignore
|
|
230
|
+
def __init__(self, id: int = None, data: dict = {}, instance: WhatsApp = None, content: str = "", to: str = "", rec_type: str = "individual"):
|
|
231
|
+
self.instance = instance
|
|
232
|
+
self.url = self.instance.url
|
|
233
|
+
self.headers = self.instance.headers
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
try:
|
|
237
|
+
self.id = instance.get_message_id(data)
|
|
238
|
+
except:
|
|
239
|
+
self.id = id
|
|
240
|
+
try:
|
|
241
|
+
self.type = self.instance.get_message_type(data)
|
|
242
|
+
except:
|
|
243
|
+
self.type = "text"
|
|
244
|
+
self.data = data
|
|
245
|
+
self.rec = rec_type
|
|
246
|
+
self.to = to
|
|
247
|
+
try:
|
|
248
|
+
self.content = content if content != "" else self.instance.get_message(
|
|
249
|
+
data)
|
|
250
|
+
except:
|
|
251
|
+
self.content = content
|
|
252
|
+
try:
|
|
253
|
+
self.name = self.instance.get_name(data)
|
|
254
|
+
except:
|
|
255
|
+
self.name = None
|
|
256
|
+
|
|
257
|
+
if self.type == "image":
|
|
258
|
+
try:
|
|
259
|
+
self.image = self.instance.get_image(data)
|
|
260
|
+
except:
|
|
261
|
+
self.image = None
|
|
262
|
+
if self.type == "sticker":
|
|
263
|
+
try:
|
|
264
|
+
self.sticker = self.instance.get_sticker(data)
|
|
265
|
+
except:
|
|
266
|
+
self.sticker = None
|
|
267
|
+
elif self.type == "video":
|
|
268
|
+
try:
|
|
269
|
+
self.video = self.instance.get_video(data)
|
|
270
|
+
except:
|
|
271
|
+
self.video = None
|
|
272
|
+
elif self.type == "audio":
|
|
273
|
+
try:
|
|
274
|
+
self.audio = self.instance.get_audio(data)
|
|
275
|
+
except:
|
|
276
|
+
pass
|
|
277
|
+
elif self.type == "document":
|
|
278
|
+
try:
|
|
279
|
+
self.document = self.instance.get_document(data)
|
|
280
|
+
except:
|
|
281
|
+
pass
|
|
282
|
+
elif self.type == "location":
|
|
283
|
+
try:
|
|
284
|
+
self.location = self.instance.get_location(data)
|
|
285
|
+
except:
|
|
286
|
+
pass
|
|
287
|
+
elif self.type == "interactive":
|
|
288
|
+
try:
|
|
289
|
+
self.interactive = self.instance.get_interactive_response(data)
|
|
290
|
+
except:
|
|
291
|
+
pass
|
|
292
|
+
|
|
293
|
+
def reply(self, reply_text: str = "", preview_url: bool = True) -> dict:
|
|
294
|
+
if self.data == {}:
|
|
295
|
+
return {"error": "No data provided"}
|
|
296
|
+
author = self.instance.get_author(self.data)
|
|
297
|
+
payload = {
|
|
298
|
+
"messaging_product": "whatsapp",
|
|
299
|
+
"recipient_type": "individual",
|
|
300
|
+
"to": str(author),
|
|
301
|
+
"type": "text",
|
|
302
|
+
"context": {"message_id": self.id},
|
|
303
|
+
"text": {"preview_url": preview_url, "body": reply_text},
|
|
304
|
+
}
|
|
305
|
+
logging.info(f"Replying to {self.id}")
|
|
306
|
+
r = requests.post(self.url, headers=self.headers, json=payload)
|
|
307
|
+
if r.status_code == 200:
|
|
308
|
+
logging.info(f"Message sent to {
|
|
309
|
+
self.instance.get_author(self.data)}")
|
|
310
|
+
return r.json()
|
|
311
|
+
logging.info(f"Message not sent to {
|
|
312
|
+
self.instance.get_author(self.data)}")
|
|
313
|
+
logging.info(f"Status code: {r.status_code}")
|
|
314
|
+
logging.error(f"Response: {r.json()}")
|
|
315
|
+
return r.json()
|
|
316
|
+
|
|
317
|
+
def mark_as_read(self) -> dict:
|
|
318
|
+
|
|
319
|
+
payload = {
|
|
320
|
+
"messaging_product": "whatsapp",
|
|
321
|
+
"status": "read",
|
|
322
|
+
"message_id": self.id,
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
response = requests.post(
|
|
326
|
+
f"{self.instance.url}", headers=self.instance.headers, json=payload)
|
|
327
|
+
if response.status_code == 200:
|
|
328
|
+
logging.info(response.json())
|
|
329
|
+
return response.json()
|
|
330
|
+
else:
|
|
331
|
+
logging.error(response.json())
|
|
332
|
+
return response.json()
|
|
333
|
+
|
|
334
|
+
def send(self,sender = None, preview_url: bool = True) -> dict:
|
|
335
|
+
|
|
336
|
+
try:
|
|
337
|
+
sender = dict(self.instance.l)[sender]
|
|
338
|
+
print(self.instance.l)
|
|
339
|
+
print(sender)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
print(12)
|
|
343
|
+
|
|
344
|
+
except:
|
|
345
|
+
print(22)
|
|
346
|
+
sender = self.instance.phone_number_id
|
|
347
|
+
|
|
348
|
+
if sender == None:
|
|
349
|
+
sender = self.instance.phone_number_id
|
|
350
|
+
|
|
351
|
+
url = f"https://graph.facebook.com/v18.0/{sender}/messages"
|
|
352
|
+
data = {
|
|
353
|
+
"messaging_product": "whatsapp",
|
|
354
|
+
"recipient_type": self.rec,
|
|
355
|
+
"to": self.to,
|
|
356
|
+
"type": "text",
|
|
357
|
+
"text": {"preview_url": preview_url, "body": self.content},
|
|
358
|
+
}
|
|
359
|
+
logging.info(f"Sending message to {self.to}")
|
|
360
|
+
print(url)
|
|
361
|
+
r = requests.post(url, headers=self.headers, json=data)
|
|
362
|
+
if r.status_code == 200:
|
|
363
|
+
logging.info(f"Message sent to {self.to}")
|
|
364
|
+
return r.json()
|
|
365
|
+
logging.info(f"Message not sent to {self.to}")
|
|
366
|
+
logging.info(f"Status code: {r.status_code}")
|
|
367
|
+
logging.error(f"Response: {r.json()}")
|
|
368
|
+
return r.json()
|
|
369
|
+
|
|
370
|
+
def react(self, emoji: str) -> dict:
|
|
371
|
+
data = {
|
|
372
|
+
"messaging_product": "whatsapp",
|
|
373
|
+
"recipient_type": "individual",
|
|
374
|
+
"to": self.to,
|
|
375
|
+
"type": "reaction",
|
|
376
|
+
"reaction": {"message_id": self.id, "emoji": emoji},
|
|
377
|
+
}
|
|
378
|
+
logging.info(f"Reacting to {self.id}")
|
|
379
|
+
r = requests.post(self.url, headers=self.headers, json=data)
|
|
380
|
+
if r.status_code == 200:
|
|
381
|
+
logging.info(f"Reaction sent to {self.to}")
|
|
382
|
+
return r.json()
|
|
383
|
+
logging.info(f"Reaction not sent to {self.to}")
|
|
384
|
+
logging.info(f"Status code: {r.status_code}")
|
|
385
|
+
logging.debug(f"Response: {r.json()}")
|
|
386
|
+
return r.json()
|