whatsapp-python 3.0.2.post1__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.
- examples/example_hook_obj.py +85 -0
- examples/reply_to_message_obj.py +14 -0
- examples/sending_audio.py +15 -0
- examples/sending_button.py +33 -0
- examples/sending_document.py +16 -0
- examples/sending_image.py +15 -0
- examples/sending_location.py +18 -0
- examples/sending_message.py +14 -0
- examples/sending_template_message.py +13 -0
- examples/sending_video.py +15 -0
- examples/standalone_hook.py +133 -0
- setup.py +42 -0
- whatsapp/__init__.py +238 -0
- whatsapp/constants.py +3 -0
- whatsapp/ext/_buttons.py +82 -0
- whatsapp/ext/_media.py +135 -0
- whatsapp/ext/_message.py +103 -0
- whatsapp/ext/_property.py +5 -0
- whatsapp/ext/_send_media.py +267 -0
- whatsapp/ext/_send_others.py +86 -0
- whatsapp/ext/_static.py +310 -0
- whatsapp_python-3.0.2.post1.dist-info/METADATA +105 -0
- whatsapp_python-3.0.2.post1.dist-info/RECORD +25 -0
- whatsapp_python-3.0.2.post1.dist-info/WHEEL +4 -0
- whatsapp_python-3.0.2.post1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from whatsapp import Message, Hook, WhatsApp
|
|
2
|
+
from flask import Response
|
|
3
|
+
from os import getenv
|
|
4
|
+
from dotenv import load_dotenv
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def handler(msg: Message):
|
|
8
|
+
message_type = msg.type
|
|
9
|
+
messenger = msg.instance
|
|
10
|
+
mobile = msg.sender
|
|
11
|
+
|
|
12
|
+
if message_type == "text":
|
|
13
|
+
message = msg.content
|
|
14
|
+
name = msg.name
|
|
15
|
+
m = Message(instance=messenger, to=mobile, content="Hello World")
|
|
16
|
+
m.send()
|
|
17
|
+
|
|
18
|
+
elif message_type == "interactive":
|
|
19
|
+
message_response = msg.interactive
|
|
20
|
+
if message_response is None:
|
|
21
|
+
return Response(status=400)
|
|
22
|
+
interactive_type = message_response.get("type")
|
|
23
|
+
message_id = message_response[interactive_type]["id"]
|
|
24
|
+
message_text = message_response[interactive_type]["title"]
|
|
25
|
+
# Do some action
|
|
26
|
+
|
|
27
|
+
elif message_type == "location":
|
|
28
|
+
message_location = msg.location
|
|
29
|
+
if message_location is None:
|
|
30
|
+
return Response(status=400)
|
|
31
|
+
message_latitude = message_location["latitude"]
|
|
32
|
+
message_longitude = message_location["longitude"]
|
|
33
|
+
# Do some action
|
|
34
|
+
|
|
35
|
+
elif message_type == "image":
|
|
36
|
+
image = msg.image
|
|
37
|
+
if image is None:
|
|
38
|
+
return Response(status=400)
|
|
39
|
+
image_id, mime_type = image["id"], image["mime_type"]
|
|
40
|
+
image_url = messenger.query_media_url(image_id)
|
|
41
|
+
if image_url is None:
|
|
42
|
+
return Response(status=400)
|
|
43
|
+
image_filename = messenger.download_media(image_url, mime_type)
|
|
44
|
+
# Do some action
|
|
45
|
+
|
|
46
|
+
elif message_type == "video":
|
|
47
|
+
video = msg.video
|
|
48
|
+
if video is None:
|
|
49
|
+
return Response(status=400)
|
|
50
|
+
video_id, mime_type = video["id"], video["mime_type"]
|
|
51
|
+
video_url = messenger.query_media_url(video_id)
|
|
52
|
+
if video_url is None:
|
|
53
|
+
return Response(status=400)
|
|
54
|
+
video_filename = messenger.download_media(video_url, mime_type)
|
|
55
|
+
# Do some action
|
|
56
|
+
|
|
57
|
+
elif message_type == "audio":
|
|
58
|
+
audio = msg.audio
|
|
59
|
+
if audio is None:
|
|
60
|
+
return Response(status=400)
|
|
61
|
+
audio_id, mime_type = audio["id"], audio["mime_type"]
|
|
62
|
+
audio_url = messenger.query_media_url(audio_id)
|
|
63
|
+
if audio_url is None:
|
|
64
|
+
return Response(status=400)
|
|
65
|
+
audio_filename = messenger.download_media(audio_url, mime_type)
|
|
66
|
+
# Do some action
|
|
67
|
+
|
|
68
|
+
elif message_type == "document":
|
|
69
|
+
file = msg.document
|
|
70
|
+
if file is None:
|
|
71
|
+
return Response(status=400)
|
|
72
|
+
file_id, mime_type = file["id"], file["mime_type"]
|
|
73
|
+
file_url = messenger.query_media_url(file_id)
|
|
74
|
+
if file_url is None:
|
|
75
|
+
return Response(status=400)
|
|
76
|
+
file_filename = messenger.download_media(file_url, mime_type)
|
|
77
|
+
# Do some action
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
messenger = WhatsApp(token=getenv("TOKEN"),
|
|
81
|
+
phone_number_id=getenv("PHONE_NUMBER_ID"))
|
|
82
|
+
hook = Hook(instance=messenger, handler=handler, port=5000,
|
|
83
|
+
host="0.0.0.0", verify_token=getenv("VERIFY_TOKEN"))
|
|
84
|
+
|
|
85
|
+
hook.run()
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from os import getenv
|
|
2
|
+
from whatsapp import WhatsApp, Message
|
|
3
|
+
from dotenv import load_dotenv
|
|
4
|
+
|
|
5
|
+
if __name__ == "__main__":
|
|
6
|
+
load_dotenv()
|
|
7
|
+
messenger = WhatsApp(token=getenv("TOKEN"), phone_number_id=getenv("ID"))
|
|
8
|
+
|
|
9
|
+
data = {"your": "data"}
|
|
10
|
+
|
|
11
|
+
msg = Message(data=data, instance=messenger)
|
|
12
|
+
msg.reply("lol")
|
|
13
|
+
|
|
14
|
+
print(msg)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from os import getenv
|
|
2
|
+
from whatsapp import WhatsApp
|
|
3
|
+
from dotenv import load_dotenv
|
|
4
|
+
|
|
5
|
+
if __name__ == "__main__":
|
|
6
|
+
load_dotenv()
|
|
7
|
+
messenger = WhatsApp(token=getenv("TOKEN"),
|
|
8
|
+
phone_number_id=getenv("PHONE_NUMBER_ID"))
|
|
9
|
+
|
|
10
|
+
response = messenger.send_audio(
|
|
11
|
+
audio="https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3",
|
|
12
|
+
recipient_id="255757xxxxxx",
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
print(response)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from os import getenv
|
|
2
|
+
from whatsapp import WhatsApp
|
|
3
|
+
from dotenv import load_dotenv
|
|
4
|
+
|
|
5
|
+
if __name__ == "__main__":
|
|
6
|
+
load_dotenv()
|
|
7
|
+
messenger = WhatsApp(token=getenv("TOKEN"),
|
|
8
|
+
phone_number_id=getenv("PHONE_NUMBER_ID"))
|
|
9
|
+
|
|
10
|
+
response = messenger.send_button(
|
|
11
|
+
recipient_id="255757xxxxxx",
|
|
12
|
+
button={
|
|
13
|
+
"header": "Header Testing",
|
|
14
|
+
"body": "Body Testing",
|
|
15
|
+
"footer": "Footer Testing",
|
|
16
|
+
"action": {
|
|
17
|
+
"button": "Button Testing",
|
|
18
|
+
"sections": [
|
|
19
|
+
{
|
|
20
|
+
"title": "iBank",
|
|
21
|
+
"rows": [
|
|
22
|
+
{"id": "row 1", "title": "Send Money", "description": ""},
|
|
23
|
+
{
|
|
24
|
+
"id": "row 2",
|
|
25
|
+
"title": "Withdraw money",
|
|
26
|
+
"description": "",
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from os import getenv
|
|
2
|
+
from whatsapp import WhatsApp
|
|
3
|
+
from dotenv import load_dotenv
|
|
4
|
+
|
|
5
|
+
if __name__ == "__main__":
|
|
6
|
+
load_dotenv()
|
|
7
|
+
|
|
8
|
+
messenger = WhatsApp(token=getenv("TOKEN"),
|
|
9
|
+
phone_number_id=getenv("PHONE_NUMBER_ID"))
|
|
10
|
+
|
|
11
|
+
response = messenger.send_document(
|
|
12
|
+
document="http://www.africau.edu/images/default/sample.pdf",
|
|
13
|
+
recipient_id="255757294146",
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
print(response)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from os import getenv
|
|
2
|
+
from whatsapp import WhatsApp
|
|
3
|
+
from dotenv import load_dotenv
|
|
4
|
+
|
|
5
|
+
if __name__ == "__main__":
|
|
6
|
+
load_dotenv()
|
|
7
|
+
messenger = WhatsApp(token=getenv("TOKEN"),
|
|
8
|
+
phone_number_id=getenv("PHONE_NUMBER_ID"))
|
|
9
|
+
|
|
10
|
+
response = messenger.send_image(
|
|
11
|
+
image="https://i.imgur.com/Fh7XVYY.jpeg",
|
|
12
|
+
recipient_id="255757294146",
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
print(response)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from os import getenv
|
|
2
|
+
from whatsapp import WhatsApp
|
|
3
|
+
from dotenv import load_dotenv
|
|
4
|
+
|
|
5
|
+
if __name__ == "__main__":
|
|
6
|
+
load_dotenv()
|
|
7
|
+
messenger = WhatsApp(token=getenv("TOKEN"),
|
|
8
|
+
phone_number_id=getenv("PHONE_NUMBER_ID"))
|
|
9
|
+
|
|
10
|
+
response = messenger.send_location(
|
|
11
|
+
lat=1.29,
|
|
12
|
+
long=103.85,
|
|
13
|
+
name="Singapore",
|
|
14
|
+
address="Singapore",
|
|
15
|
+
recipient_id="255757294146",
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
print(response)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from os import getenv
|
|
2
|
+
from whatsapp import WhatsApp, Message
|
|
3
|
+
from dotenv import load_dotenv
|
|
4
|
+
|
|
5
|
+
if __name__ == "__main__":
|
|
6
|
+
load_dotenv()
|
|
7
|
+
messenger = WhatsApp(token=getenv("TOKEN"),
|
|
8
|
+
phone_number_id=getenv("PHONE_NUMBER_ID"))
|
|
9
|
+
|
|
10
|
+
msg = Message(instance=messenger,
|
|
11
|
+
content="Hello World!", to="919999999999")
|
|
12
|
+
response = msg.send()
|
|
13
|
+
|
|
14
|
+
print(response)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from os import getenv
|
|
2
|
+
from whatsapp import WhatsApp
|
|
3
|
+
from dotenv import load_dotenv
|
|
4
|
+
|
|
5
|
+
if __name__ == "__main__":
|
|
6
|
+
load_dotenv()
|
|
7
|
+
messenger = WhatsApp(token=getenv("TOKEN"),
|
|
8
|
+
phone_number_id=getenv("PHONE_NUMBER_ID"))
|
|
9
|
+
|
|
10
|
+
response = messenger.send_template(
|
|
11
|
+
"hello_world", "255757xxxxxx", components=[], lang="en_US")
|
|
12
|
+
|
|
13
|
+
print(response)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from os import getenv
|
|
2
|
+
from whatsapp import WhatsApp
|
|
3
|
+
from dotenv import load_dotenv
|
|
4
|
+
|
|
5
|
+
if __name__ == "__main__":
|
|
6
|
+
load_dotenv()
|
|
7
|
+
messenger = WhatsApp(token=getenv("TOKEN"),
|
|
8
|
+
phone_number_id=getenv("PHONE_NUMBER_ID"))
|
|
9
|
+
|
|
10
|
+
response = messenger.send_video(
|
|
11
|
+
video="https://www.youtube.com/watch?v=K4TOrB7at0Y",
|
|
12
|
+
recipient_id="255757xxxxxx",
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
print(response)
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import logging
|
|
3
|
+
from whatsapp import WhatsApp, Message
|
|
4
|
+
from dotenv import load_dotenv
|
|
5
|
+
from flask import Flask, request, Response
|
|
6
|
+
|
|
7
|
+
# Initialize Flask App
|
|
8
|
+
app = Flask(__name__)
|
|
9
|
+
|
|
10
|
+
# Load .env file
|
|
11
|
+
load_dotenv("../.env")
|
|
12
|
+
messenger = WhatsApp(os.getenv("TOKEN"),
|
|
13
|
+
phone_number_id=os.getenv("ID"))
|
|
14
|
+
VERIFY_TOKEN = "30cca545-3838-48b2-80a7-9e43b1ae8ce4"
|
|
15
|
+
|
|
16
|
+
# Logging
|
|
17
|
+
logging.basicConfig(
|
|
18
|
+
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@app.get("/")
|
|
23
|
+
def verify_token():
|
|
24
|
+
if request.args.get("hub.verify_token") == VERIFY_TOKEN:
|
|
25
|
+
logging.info("Verified webhook")
|
|
26
|
+
challenge = request.args.get("hub.challenge")
|
|
27
|
+
return str(challenge)
|
|
28
|
+
logging.error("Webhook Verification failed")
|
|
29
|
+
return "Invalid verification token"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@app.post("/")
|
|
33
|
+
def hook():
|
|
34
|
+
# Handle Webhook Subscriptions
|
|
35
|
+
data = request.get_json()
|
|
36
|
+
if data is None:
|
|
37
|
+
return Response(status=200)
|
|
38
|
+
logging.info("Received webhook data: %s", data)
|
|
39
|
+
changed_field = messenger.changed_field(data)
|
|
40
|
+
if changed_field == "messages":
|
|
41
|
+
new_message = messenger.is_message(data)
|
|
42
|
+
if new_message:
|
|
43
|
+
msg = Message(instance=messenger, data=data)
|
|
44
|
+
mobile = msg.sender
|
|
45
|
+
name = msg.name
|
|
46
|
+
message_type = msg.type
|
|
47
|
+
logging.info(
|
|
48
|
+
f"New Message; sender:{mobile} name:{name} type:{message_type}"
|
|
49
|
+
)
|
|
50
|
+
if message_type == "text":
|
|
51
|
+
message = msg.content
|
|
52
|
+
name = msg.name
|
|
53
|
+
logging.info("Message: %s", message)
|
|
54
|
+
m = Message(instance=messenger, to=mobile,
|
|
55
|
+
content="Hello World")
|
|
56
|
+
m.send()
|
|
57
|
+
|
|
58
|
+
elif message_type == "interactive":
|
|
59
|
+
message_response = msg.interactive
|
|
60
|
+
if message_response is None:
|
|
61
|
+
return Response(status=400)
|
|
62
|
+
interactive_type = message_response.get("type")
|
|
63
|
+
message_id = message_response[interactive_type]["id"]
|
|
64
|
+
message_text = message_response[interactive_type]["title"]
|
|
65
|
+
logging.info(
|
|
66
|
+
f"Interactive Message; {message_id}: {message_text}")
|
|
67
|
+
|
|
68
|
+
elif message_type == "location":
|
|
69
|
+
message_location = msg.location
|
|
70
|
+
if message_location is None:
|
|
71
|
+
return Response(status=400)
|
|
72
|
+
message_latitude = message_location["latitude"]
|
|
73
|
+
message_longitude = message_location["longitude"]
|
|
74
|
+
logging.info("Location: %s, %s",
|
|
75
|
+
message_latitude, message_longitude)
|
|
76
|
+
|
|
77
|
+
elif message_type == "image":
|
|
78
|
+
image = msg.image
|
|
79
|
+
if image is None:
|
|
80
|
+
return Response(status=400)
|
|
81
|
+
image_id, mime_type = image["id"], image["mime_type"]
|
|
82
|
+
image_url = messenger.query_media_url(image_id)
|
|
83
|
+
if image_url is None:
|
|
84
|
+
return Response(status=400)
|
|
85
|
+
image_filename = messenger.download_media(image_url, mime_type)
|
|
86
|
+
logging.info(f"{mobile} sent image {image_filename}")
|
|
87
|
+
|
|
88
|
+
elif message_type == "video":
|
|
89
|
+
video = msg.video
|
|
90
|
+
if video is None:
|
|
91
|
+
return Response(status=400)
|
|
92
|
+
video_id, mime_type = video["id"], video["mime_type"]
|
|
93
|
+
video_url = messenger.query_media_url(video_id)
|
|
94
|
+
if video_url is None:
|
|
95
|
+
return Response(status=400)
|
|
96
|
+
video_filename = messenger.download_media(video_url, mime_type)
|
|
97
|
+
logging.info(f"{mobile} sent video {video_filename}")
|
|
98
|
+
|
|
99
|
+
elif message_type == "audio":
|
|
100
|
+
audio = msg.audio
|
|
101
|
+
if audio is None:
|
|
102
|
+
return Response(status=400)
|
|
103
|
+
audio_id, mime_type = audio["id"], audio["mime_type"]
|
|
104
|
+
audio_url = messenger.query_media_url(audio_id)
|
|
105
|
+
if audio_url is None:
|
|
106
|
+
return Response(status=400)
|
|
107
|
+
audio_filename = messenger.download_media(audio_url, mime_type)
|
|
108
|
+
logging.info(f"{mobile} sent audio {audio_filename}")
|
|
109
|
+
|
|
110
|
+
elif message_type == "document":
|
|
111
|
+
file = msg.document
|
|
112
|
+
if file is None:
|
|
113
|
+
return Response(status=400)
|
|
114
|
+
file_id, mime_type = file["id"], file["mime_type"]
|
|
115
|
+
file_url = messenger.query_media_url(file_id)
|
|
116
|
+
if file_url is None:
|
|
117
|
+
return Response(status=400)
|
|
118
|
+
file_filename = messenger.download_media(file_url, mime_type)
|
|
119
|
+
logging.info(f"{mobile} sent file {file_filename}")
|
|
120
|
+
else:
|
|
121
|
+
logging.info(f"{mobile} sent {message_type} ")
|
|
122
|
+
logging.info(data)
|
|
123
|
+
else:
|
|
124
|
+
delivery = messenger.get_delivery(data)
|
|
125
|
+
if delivery:
|
|
126
|
+
logging.info(f"Message : {delivery}")
|
|
127
|
+
else:
|
|
128
|
+
logging.info("No new message")
|
|
129
|
+
return "OK", 200
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
if __name__ == "__main__":
|
|
133
|
+
app.run(port=6869, debug=False)
|
setup.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from os import path
|
|
2
|
+
from setuptools import setup
|
|
3
|
+
from whatsapp.constants import VERSION
|
|
4
|
+
|
|
5
|
+
this_directory = path.abspath(path.dirname(__file__))
|
|
6
|
+
with open(path.join(this_directory, "README.md")) as f:
|
|
7
|
+
long_description = f.read()
|
|
8
|
+
|
|
9
|
+
setup(
|
|
10
|
+
name="whatsapp-python",
|
|
11
|
+
version=VERSION,
|
|
12
|
+
description="Open source Python wrapper for the WhatsApp Cloud API",
|
|
13
|
+
long_description=long_description,
|
|
14
|
+
long_description_content_type="text/markdown",
|
|
15
|
+
url="https://github.com/filipporomani/whatsapp",
|
|
16
|
+
download_url="https://github.com/filipporomani/whatsapp/releases/latest",
|
|
17
|
+
author="Filippo Romani",
|
|
18
|
+
author_email="mail@filipporomani.it",
|
|
19
|
+
license="MIT",
|
|
20
|
+
packages=["whatsapp"],
|
|
21
|
+
install_requires=["requests", "requests-toolbelt", "typing", "fastapi", "logging"],
|
|
22
|
+
keywords=[
|
|
23
|
+
"whatsapp",
|
|
24
|
+
"whatsapp-libary",
|
|
25
|
+
"WhatsApp Cloud API Wrapper",
|
|
26
|
+
"PyWhatsApp",
|
|
27
|
+
"WhatsApp API in Python",
|
|
28
|
+
],
|
|
29
|
+
python_requires=">=3.6",
|
|
30
|
+
classifiers=[
|
|
31
|
+
"Development Status :: 4 - Beta",
|
|
32
|
+
"Intended Audience :: Developers",
|
|
33
|
+
"Topic :: Software Development :: Build Tools",
|
|
34
|
+
"License :: OSI Approved :: MIT License",
|
|
35
|
+
"Programming Language :: Python :: 3.6",
|
|
36
|
+
"Programming Language :: Python :: 3.7",
|
|
37
|
+
"Programming Language :: Python :: 3.8",
|
|
38
|
+
"Programming Language :: Python :: 3.9",
|
|
39
|
+
"Programming Language :: Python :: 3.10",
|
|
40
|
+
"Programming Language :: Python :: 3.11",
|
|
41
|
+
],
|
|
42
|
+
)
|
whatsapp/__init__.py
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
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 fastapi import FastAPI, Request
|
|
9
|
+
from .constants import VERSION
|
|
10
|
+
from . import ext
|
|
11
|
+
from .ext._property import authorized
|
|
12
|
+
from .ext._send_others import send_custom_json, send_contacts
|
|
13
|
+
from .ext._message import send_template
|
|
14
|
+
from .ext._send_media import send_image, send_video, send_audio, send_location, send_sticker, send_document
|
|
15
|
+
from .ext._media import upload_media, query_media_url, download_media, delete_media
|
|
16
|
+
from .ext._buttons import send_button, create_button, send_reply_button
|
|
17
|
+
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_interactive_response, get_location, get_video, changed_field
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class WhatsApp(object):
|
|
23
|
+
def __init__(self, token: str = "", phone_number_id: str = "", logger: bool = True, update_check: 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
|
+
|
|
37
|
+
self.VERSION = VERSION
|
|
38
|
+
if update_check is True:
|
|
39
|
+
latest = str(requests.get(
|
|
40
|
+
"https://pypi.org/pypi/whatsapp-python/json").json()["info"]["version"])
|
|
41
|
+
if self.VERSION != latest:
|
|
42
|
+
version_int = int(self.VERSION.replace(".", ""))
|
|
43
|
+
latest_int = int(latest.replace(".", ""))
|
|
44
|
+
# 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)
|
|
45
|
+
if version_int < latest_int:
|
|
46
|
+
logging.critical(
|
|
47
|
+
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.")
|
|
48
|
+
if version_int > latest_int:
|
|
49
|
+
latest_beta = int(str(requests.get(
|
|
50
|
+
"https://raw.githubusercontent.com/filipporomani/whatsapp/main/.version").text).replace(".", ""))
|
|
51
|
+
if latest_beta > version_int:
|
|
52
|
+
logging.critical(
|
|
53
|
+
"A new beta version is available. Please update to the latest version. READ THE CHANGELOG BEFORE UPDATING. NEW VERSIONS MAY BREAK YOUR CODE IF NOT PROPERLY UPDATED.")
|
|
54
|
+
logging.critical(
|
|
55
|
+
f"You are using a development version of whatsapp-python. Please report any issue on GitHub.")
|
|
56
|
+
|
|
57
|
+
if token == "" or phone_number_id == "":
|
|
58
|
+
logging.error("Token or phone number id not provided")
|
|
59
|
+
raise ValueError(
|
|
60
|
+
"Token or phone number ID not provided but is required")
|
|
61
|
+
self.token = token
|
|
62
|
+
self.phone_number_id = phone_number_id
|
|
63
|
+
self.base_url = "https://graph.facebook.com/v17.0"
|
|
64
|
+
self.url = f"{self.base_url}/{phone_number_id}/messages"
|
|
65
|
+
|
|
66
|
+
async def base():
|
|
67
|
+
pass
|
|
68
|
+
self.message_handler = base
|
|
69
|
+
self.other_handler = base
|
|
70
|
+
self.verification_handler = base
|
|
71
|
+
self.headers = {
|
|
72
|
+
"Content-Type": "application/json",
|
|
73
|
+
"Authorization": f"Bearer {self.token}"
|
|
74
|
+
}
|
|
75
|
+
if logger is False:
|
|
76
|
+
logging.disable(logging.INFO)
|
|
77
|
+
logging.disable(logging.ERROR)
|
|
78
|
+
|
|
79
|
+
self.app = FastAPI()
|
|
80
|
+
|
|
81
|
+
# Verification handler has 1 argument: challenge (str | bool): str if verification is successful, False if not
|
|
82
|
+
|
|
83
|
+
@self.app.get("/")
|
|
84
|
+
async def verify_endpoint(r: Request):
|
|
85
|
+
if r.query_params.get("hub.verify_token") == self.token:
|
|
86
|
+
logging.info("Verified webhook")
|
|
87
|
+
challenge = r.query_params.get("hub.challenge")
|
|
88
|
+
self.verification_handler(challenge)
|
|
89
|
+
self.other_handler(challenge)
|
|
90
|
+
return str(challenge)
|
|
91
|
+
logging.error("Webhook Verification failed")
|
|
92
|
+
await self.verification_handler(False)
|
|
93
|
+
await self.other_handler(False)
|
|
94
|
+
return {"success": False}
|
|
95
|
+
|
|
96
|
+
@self.app.post("/")
|
|
97
|
+
async def hook(r: Request):
|
|
98
|
+
# Handle Webhook Subscriptions
|
|
99
|
+
data = await r.json()
|
|
100
|
+
if data is None:
|
|
101
|
+
return {"success": False}
|
|
102
|
+
logging.info("Received webhook data: %s", data)
|
|
103
|
+
changed_field = self.instance.changed_field(data)
|
|
104
|
+
if changed_field == "messages":
|
|
105
|
+
new_message = self.instance.is_message(data)
|
|
106
|
+
if new_message:
|
|
107
|
+
msg = Message(instance=self.instance, data=data)
|
|
108
|
+
await self.message_handler(msg)
|
|
109
|
+
await self.other_handler(msg)
|
|
110
|
+
return {"success": True}
|
|
111
|
+
|
|
112
|
+
# all the files starting with _ are imported here, and should not be imported directly.
|
|
113
|
+
|
|
114
|
+
is_message = staticmethod(is_message)
|
|
115
|
+
get_mobile = staticmethod(get_mobile)
|
|
116
|
+
get_name = staticmethod(get_name)
|
|
117
|
+
get_message = staticmethod(get_message)
|
|
118
|
+
get_message_id = staticmethod(get_message_id)
|
|
119
|
+
get_message_type = staticmethod(get_message_type)
|
|
120
|
+
get_message_timestamp = staticmethod(get_message_timestamp)
|
|
121
|
+
get_audio = staticmethod(get_audio)
|
|
122
|
+
get_delivery = staticmethod(get_delivery)
|
|
123
|
+
get_document = staticmethod(get_document)
|
|
124
|
+
get_image = staticmethod(get_image)
|
|
125
|
+
get_interactive_response = staticmethod(get_interactive_response)
|
|
126
|
+
get_location = staticmethod(get_location)
|
|
127
|
+
get_video = staticmethod(get_video)
|
|
128
|
+
changed_field = staticmethod(changed_field)
|
|
129
|
+
get_author = staticmethod(get_author)
|
|
130
|
+
|
|
131
|
+
authorized = property(authorized)
|
|
132
|
+
|
|
133
|
+
def create_message(self, **kwargs) -> Message:
|
|
134
|
+
"""
|
|
135
|
+
Create a message object
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
data[dict]: The message data
|
|
139
|
+
content[str]: The message content
|
|
140
|
+
to[str]: The recipient
|
|
141
|
+
rec_type[str]: The recipient type (individual/group)
|
|
142
|
+
"""
|
|
143
|
+
return Message(**kwargs, instance=self)
|
|
144
|
+
|
|
145
|
+
def on_message(self, handler: function):
|
|
146
|
+
"""
|
|
147
|
+
Set the handler for incoming messages
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
handler[function]: The handler function
|
|
151
|
+
"""
|
|
152
|
+
self.message_handler = handler
|
|
153
|
+
|
|
154
|
+
def on_event(self, handler: function):
|
|
155
|
+
"""
|
|
156
|
+
Set the handler for other events
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
handler[function]: The handler function
|
|
160
|
+
"""
|
|
161
|
+
self.other_handler = handler
|
|
162
|
+
|
|
163
|
+
def on_verification(self, handler: function):
|
|
164
|
+
"""
|
|
165
|
+
Set the handler for verification
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
handler[function]: The handler function
|
|
169
|
+
"""
|
|
170
|
+
self.verification_handler = handler
|
|
171
|
+
|
|
172
|
+
def run(self, host: str = "localhost", port: int = 5000, debug: bool = False, **options):
|
|
173
|
+
self.app.run(host=host, port=port, debug=debug, **options)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
class Message(object):
|
|
177
|
+
def __init__(self, data: dict = {}, instance: WhatsApp = None, content: str = "", to: str = "", rec_type: str = "individual"): # type: ignore
|
|
178
|
+
try:
|
|
179
|
+
self.id = instance.get_message_id(data)
|
|
180
|
+
except:
|
|
181
|
+
self.id = None
|
|
182
|
+
try:
|
|
183
|
+
self.type = self.instance.get_message_type(data)
|
|
184
|
+
except:
|
|
185
|
+
self.type = "text"
|
|
186
|
+
self.data = data
|
|
187
|
+
self.rec = rec_type
|
|
188
|
+
self.to = to
|
|
189
|
+
try:
|
|
190
|
+
self.content = content if content != "" else self.instance.get_message(
|
|
191
|
+
data)
|
|
192
|
+
except:
|
|
193
|
+
self.content = content
|
|
194
|
+
try:
|
|
195
|
+
self.sender = self.instance.get_mobile(data)
|
|
196
|
+
except:
|
|
197
|
+
self.sender = None
|
|
198
|
+
try:
|
|
199
|
+
self.name = self.instance.get_name(data)
|
|
200
|
+
except:
|
|
201
|
+
self.name = None
|
|
202
|
+
|
|
203
|
+
if self.type == "image":
|
|
204
|
+
try:
|
|
205
|
+
self.image = self.instance.get_image(data)
|
|
206
|
+
except:
|
|
207
|
+
self.image = None
|
|
208
|
+
elif self.type == "video":
|
|
209
|
+
try:
|
|
210
|
+
self.video = self.instance.get_video(data)
|
|
211
|
+
except:
|
|
212
|
+
self.video = None
|
|
213
|
+
elif self.type == "audio":
|
|
214
|
+
try:
|
|
215
|
+
self.audio = self.instance.get_audio(data)
|
|
216
|
+
except:
|
|
217
|
+
pass
|
|
218
|
+
elif self.type == "document":
|
|
219
|
+
try:
|
|
220
|
+
self.document = self.instance.get_document(data)
|
|
221
|
+
except:
|
|
222
|
+
pass
|
|
223
|
+
elif self.type == "location":
|
|
224
|
+
try:
|
|
225
|
+
self.location = self.instance.get_location(data)
|
|
226
|
+
except:
|
|
227
|
+
pass
|
|
228
|
+
elif self.type == "interactive":
|
|
229
|
+
try:
|
|
230
|
+
self.interactive = self.instance.get_interactive_response(data)
|
|
231
|
+
except:
|
|
232
|
+
pass
|
|
233
|
+
|
|
234
|
+
self.instance = instance
|
|
235
|
+
self.url = self.instance.url
|
|
236
|
+
self.headers = self.instance.headers
|
|
237
|
+
|
|
238
|
+
from .ext._message import send, reply, mark_as_read
|
whatsapp/constants.py
ADDED