Skip to content

Commit 51cbad1

Browse files
committed
[user_preferences] adding support for signups
1 parent 35a4851 commit 51cbad1

6 files changed

Lines changed: 61 additions & 11 deletions

File tree

pywa/filters.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,12 +1026,12 @@ def failed_with(
10261026
"""Filter for user marketing preferences updates."""
10271027

10281028
user_marketing_preferences_stop = new(
1029-
lambda _, m: bool(m),
1029+
lambda _, m: not bool(m),
10301030
name="user_marketing_preferences_stop",
10311031
)
10321032
"""Filter for user marketing preferences updates that indicate the user has requested to stop receiving marketing messages."""
10331033
user_marketing_preferences_resume = new(
1034-
lambda _, m: not bool(m),
1034+
lambda _, m: bool(m),
10351035
name="user_marketing_preferences_resume",
10361036
)
10371037
"""Filter for user marketing preferences updates that indicate the user has requested to resume receiving marketing messages."""

pywa/server.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
if TYPE_CHECKING:
2222
from .client import WhatsApp
2323

24-
2524
_MESSAGE_TYPES: dict[MessageType, type[handlers.Handler]] = {
2625
MessageType.BUTTON: handlers.CallbackButtonHandler,
2726
MessageType.EDIT: handlers.EditedMessageHandler,
@@ -33,22 +32,25 @@
3332
}
3433
_SYSTEM_TYPES: dict[SystemType | str, type[handlers.Handler]] = {
3534
SystemType.USER_CHANGED_NUMBER: handlers.PhoneNumberChangeHandler,
36-
SystemType.USER_CHANGED_USER_ID: handlers.PhoneNumberChangeHandler, # That's the new system message type for phone number changes, according to BSUID documentation
37-
"customer_changed_number": handlers.PhoneNumberChangeHandler, # https://developers.facebook.com/docs/whatsapp/cloud-api/webhooks/components#messages-object
35+
SystemType.USER_CHANGED_USER_ID: handlers.PhoneNumberChangeHandler,
36+
# That's the new system message type for phone number changes, according to BSUID documentation
37+
"customer_changed_number": handlers.PhoneNumberChangeHandler,
38+
# https://developers.facebook.com/docs/whatsapp/cloud-api/webhooks/components#messages-object
3839
SystemType.CUSTOMER_IDENTITY_CHANGED: handlers.IdentityChangeHandler,
3940
}
4041
_INTERACTIVE_TYPES: dict[str, type[handlers.Handler]] = {
4142
"button_reply": handlers.CallbackButtonHandler,
4243
"list_reply": handlers.CallbackSelectionHandler,
43-
"nfm_reply": handlers.FlowCompletionHandler,
4444
"call_permission_reply": handlers.CallPermissionUpdateHandler,
4545
}
46+
_NFM_REPLY_TYPES: dict[str, type[handlers.Handler]] = {
47+
"flow": handlers.FlowCompletionHandler,
48+
}
4649
_CALL_EVENTS: dict[str, type[handlers.Handler]] = {
4750
"connect": handlers.CallConnectHandler,
4851
"terminate": handlers.CallTerminateHandler,
4952
}
5053

51-
5254
_logger = logging.getLogger(__name__)
5355

5456
MAX_PROCESSED_UPDATES = 100_000
@@ -567,12 +569,14 @@ def _handle_messages_field(
567569
if msg_type == MessageType.INTERACTIVE:
568570
try:
569571
interactive_type = value["messages"][0]["interactive"]["type"]
570-
except (
571-
KeyError
572-
): # value with errors, when a user tries to send the interactive msg again
572+
except KeyError: # value has `errors`, when a user tries to send the interactive msg again
573573
return handlers.MessageHandler
574574
if (handler := _INTERACTIVE_TYPES.get(interactive_type)) is not None:
575575
return handler
576+
if interactive_type == "nfm_reply":
577+
return _NFM_REPLY_TYPES.get(
578+
value["messages"][0]["interactive"]["nfm_reply"]["name"]
579+
)
576580
_logger.warning(
577581
"Webhook ('%s'): Unknown interactive message type: %s. Falling back to MessageHandler.",
578582
wa._webhook_endpoint,

pywa/types/user_preferences.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,13 @@ class UserMarketingPreferences(BaseUserUpdate):
3737
value: The marketing preference chosen by the user, either ``stop`` or ``resume``.
3838
detail: A description of the marketing preference change (e.g. `User requested to stop marketing messages`).
3939
category: The category of the user preference, which is always ``marketing_messages``.
40+
signup_id: The signup id the user click on.
4041
"""
4142

4243
value: MarketingPreference
4344
detail: str
4445
category: UserPreferenceCategory
46+
signup_id: str | None
4547

4648
_webhook_field = "user_preferences"
4749

@@ -70,6 +72,7 @@ def from_update(
7072
value=MarketingPreference(prefs["value"]),
7173
detail=prefs["detail"],
7274
category=UserPreferenceCategory(prefs["category"]),
75+
signup_id=prefs.get("signup_id"),
7376
)
7477

7578
def __bool__(self):
@@ -84,13 +87,15 @@ class MarketingPreference(helpers.StrEnum):
8487
Attributes:
8588
STOP: The user has requested to stop receiving marketing messages.
8689
RESUME: The user has requested to resume receiving marketing messages.
90+
SIGNUP: The user signed up via signup link.
8791
"""
8892

8993
_check_value = str.islower
9094
_modify_value = str.lower
9195

9296
STOP = "stop"
9397
RESUME = "resume"
98+
SIGNUP = "signup"
9499

95100
UNKNOWN = "UNKNOWN"
96101

pywa_async/types/user_preferences.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
UserMarketingPreferences as _UserMarketingPreferences,
1414
) # noqa MUST BE IMPORTED FIRST
1515

16-
1716
from .base_update import BaseUserUpdateAsync # noqa
1817

1918

@@ -31,4 +30,5 @@ class UserMarketingPreferences(BaseUserUpdateAsync, _UserMarketingPreferences):
3130
value: The marketing preference chosen by the user, either ``stop`` or ``resume``.
3231
detail: A description of the marketing preference change (e.g. `User requested to stop marketing messages`).
3332
category: The category of the user preference, which is always ``marketing_messages``.
33+
signup_id: The signup id the user click on.
3434
"""

tests/data/updates/user_marketing_preferences.json

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,45 @@
3737
]
3838
}
3939
]
40+
},
41+
"signup": {
42+
"object": "whatsapp_business_account",
43+
"entry": [
44+
{
45+
"id": "102290129340398",
46+
"changes": [
47+
{
48+
"value": {
49+
"messaging_product": "whatsapp",
50+
"metadata": {
51+
"display_phone_number": "15550783881",
52+
"phone_number_id": "106540352242922"
53+
},
54+
"contacts": [
55+
{
56+
"profile": {
57+
"name": "Test Name"
58+
},
59+
"wa_id": "972987654321",
60+
"user_id": "US.13491208655302741918",
61+
"parent_user_id": "US.ENT.11815799212886844830"
62+
}
63+
],
64+
"user_preferences": [
65+
{
66+
"wa_id": "16505551234",
67+
"detail": "User signed up via signup link",
68+
"category": "marketing_messages",
69+
"value": "signup",
70+
"signup_id": "13176843987434774",
71+
"timestamp": 1731705721
72+
}
73+
]
74+
},
75+
"field": "user_preferences"
76+
}
77+
]
78+
}
79+
]
4080
}
4181
}

tests/test_updates.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@
162162
},
163163
"user_marketing_preferences": {
164164
"resume": [lambda u: u.value == MarketingPreference.RESUME],
165+
"signup": [lambda u: u.value == MarketingPreference.SIGNUP],
165166
},
166167
"account_update": {
167168
"account_deleted": [],

0 commit comments

Comments
 (0)