From 89c4a3234d7f8040da58043be56814fb598efa9e Mon Sep 17 00:00:00 2001 From: David Lev Date: Sun, 28 Apr 2024 16:06:37 +0300 Subject: [PATCH] [filters] adding `send_to_me` filters shortcut and `replays_to` filters --- README.md | 4 +- .../errors/sending_messages_errors.rst | 6 +++ .../source/content/filters/common_filters.rst | 1 + .../content/filters/message_filters.rst | 1 + pywa/filters.py | 31 +++++++++++-- tests/test_filters.py | 46 +++++++++++++++++++ 6 files changed, 84 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index fe5f1cd..be2b553 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ ________________________ # [PyWa](https://github.com/david-lev/pywa) • Python wrapper for the WhatsApp Cloud API -![PyPI Downloads](https://img.shields.io/pypi/dm/pywa) -[![PyPI Version](https://badge.fury.io/py/pywa.svg)](https://badge.fury.io/py/pywa) +[![PyPi Downloads](https://img.shields.io/pypi/dm/pywa)](https://pypi.org/project/pywa/) +[![PyPI Version](https://badge.fury.io/py/pywa.svg)](https://pypi.org/project/pywa/) ![Tests](https://img.shields.io/github/actions/workflow/status/david-lev/pywa/python-app.yml?label=Tests) [![Docs](https://readthedocs.org/projects/pywa/badge/?version=latest&)](https://pywa.readthedocs.io) [![License](https://img.shields.io/github/license/david-lev/pywa)](https://github.com/david-lev/pywa/blob/master/LICENSE) diff --git a/docs/source/content/errors/sending_messages_errors.rst b/docs/source/content/errors/sending_messages_errors.rst index 4c857e2..4c82975 100644 --- a/docs/source/content/errors/sending_messages_errors.rst +++ b/docs/source/content/errors/sending_messages_errors.rst @@ -23,6 +23,8 @@ Sending Messages Errors :show-inheritance: .. autoclass:: TemplateParamCountMismatch() :show-inheritance: +.. autoclass:: TemplateParamFormatMismatch() + :show-inheritance: .. autoclass:: TemplateNotExists() :show-inheritance: .. autoclass:: TemplateTextTooLong() @@ -39,3 +41,7 @@ Sending Messages Errors :show-inheritance: .. autoclass:: BusinessPaymentIssue() :show-inheritance: +.. autoclass:: IncorrectCertificate() + :show-inheritance: +.. autoclass:: AccountInMaintenanceMode() + :show-inheritance: diff --git a/docs/source/content/filters/common_filters.rst b/docs/source/content/filters/common_filters.rst index 83bae32..eaa9e0e 100644 --- a/docs/source/content/filters/common_filters.rst +++ b/docs/source/content/filters/common_filters.rst @@ -7,5 +7,6 @@ Common filters .. autofunction:: any_ .. autofunction:: not_ .. autofunction:: sent_to +.. autoattribute:: pywa.filters.send_to_me .. autofunction:: from_users .. autofunction:: from_countries diff --git a/docs/source/content/filters/message_filters.rst b/docs/source/content/filters/message_filters.rst index 7200692..8e84cb9 100644 --- a/docs/source/content/filters/message_filters.rst +++ b/docs/source/content/filters/message_filters.rst @@ -6,6 +6,7 @@ Message Filters .. autoattribute:: pywa.filters.forwarded .. autoattribute:: pywa.filters.forwarded_many_times .. autoattribute:: pywa.filters.reply +.. autofunction:: pywa.filters.replays_to .. autoattribute:: pywa.filters.has_referred_product ---------------- diff --git a/pywa/filters.py b/pywa/filters.py index 22977ff..cb5eb8f 100644 --- a/pywa/filters.py +++ b/pywa/filters.py @@ -9,8 +9,10 @@ "forwarded", "forwarded_many_times", "reply", + "replays_to", "has_referred_product", "sent_to", + "send_to_me", "from_users", "from_countries", "text", @@ -74,6 +76,19 @@ >>> filters.reply """ + +def replays_to(*msg_ids: str) -> _MessageFilterT: + """ + Filter for messages that reply to any of the given message ids. + + >>> replays_to("wamid.HBKHUIyNTM4NjAfiefhwojfMTNFQ0Q2MERGRjVDMUHUIGGA=") + """ + return ( + lambda _, m: m.reply_to_message is not None + and m.reply_to_message.message_id in msg_ids + ) + + has_referred_product: _MessageFilterT = lambda _, m: ( m.reply_to_message is not None and m.reply_to_message.referred_product is not None ) @@ -132,6 +147,16 @@ def sent_to(*, display_phone_number: str = None, phone_number_id: str = None): ) +send_to_me: _MessageFilterT = lambda wa, m: sent_to(phone_number_id=wa.phone_id)(wa, m) +""" +Filter for updates that are sent to the client phone number. + +- Use this filter when you choose not filter updates (e.g. ``WhatsApp(..., filter_updates=False)``) so you can still filter for messages that are sent to the client phone number. + +>>> send_to_me +""" + + def from_users( *numbers: str, ) -> _MessageFilterT | _CallbackFilterT | _MessageStatusFilterT: @@ -214,7 +239,7 @@ def mimetypes(cls, *mimetypes: str) -> _MessageFilterT: """ Filter for media messages that match any of the given mime types. - - `\`Supported Media Types\` on developers.facebook.com `_. + - `Supported Media Types on developers.facebook.com `_. >>> media.mimetypes("application/pdf", "image/png") >>> video.mimetypes("video/mp4") @@ -344,7 +369,7 @@ def regex(*patterns: str | re.Pattern, flags: int = 0) -> _MessageFilterT: """ Filter for text messages that match any of the given regexes. - >>> text.regex(r"Hello\s+World", r"Bye\s+World", flags=re.IGNORECASE) + >>> text.regex(r"^hello", r"bye$") Args: *patterns: The regex/regexes to filter for. @@ -833,7 +858,7 @@ def data_regex(*patterns: str | re.Pattern, flags: int = 0) -> _CallbackFilterT: """ Filter for callbacks their data matches the given regex/regexes. - >>> callback.data_regex(r"^\d+$") # only digits + >>> callback.data_regex(r"^id:", r"true$") Args: *patterns: The regex/regexes to match. diff --git a/tests/test_filters.py b/tests/test_filters.py index 8ce3049..ac468b4 100644 --- a/tests/test_filters.py +++ b/tests/test_filters.py @@ -10,6 +10,8 @@ CallbackButton, MessageStatus, TemplateStatus, + ReplyToMessage, + ReferredProduct, ) from pywa.types.base_update import BaseUpdate from tests.common import UPDATES, API_VERSIONS, WA_NO_FILTERS @@ -159,6 +161,20 @@ def same(x: _T) -> _T: ], "unsupported": [(same, fil.unsupported)], "reply": [(same, fil.reply)], + "replays_to": [(lambda m: modify_replies_to(m, "123"), fil.replays_to("123"))], + "sent_to": [ + (lambda m: modify_send_to(m, "123"), fil.sent_to(phone_number_id="123")) + ], + "send_to_me": [ + (lambda m: modify_send_to(m, WA_NO_FILTERS.phone_id), fil.send_to_me) + ], + "from_users": [(lambda m: modify_send_from(m, "123"), fil.from_users("123"))], + "from_countries": [ + (lambda m: modify_send_from(m, "97212345678"), fil.from_countries("972")) + ], + "has_referred_product": [ + (lambda m: modify_referred_product(m, "IPHONE"), fil.has_referred_product) + ], "forwarded": [(same, fil.forwarded)], "forwarded_many_times": [(same, fil.forwarded)], "interactive_message_with_err": [], @@ -355,3 +371,33 @@ def modify_callback_data(clb: CallbackButton | CallbackSelection, data: str): def modify_status_err(status: MessageStatus, err: WhatsAppError): return dataclasses.replace(status, error=err) + + +def modify_send_from(msg: Message, wa_id: str): + return dataclasses.replace( + msg, from_user=dataclasses.replace(msg.from_user, wa_id=wa_id) + ) + + +def modify_send_to(msg: Message, wa_id: str): + return dataclasses.replace( + msg, metadata=dataclasses.replace(msg.metadata, phone_number_id=wa_id) + ) + + +def modify_replies_to(msg: Message, message_id: str): + return dataclasses.replace( + msg, + reply_to_message=dataclasses.replace( + msg.reply_to_message, message_id=message_id + ), + ) + + +def modify_referred_product(msg: Message, product: str): + reply_to_msg = ReplyToMessage( + message_id=msg.id, + from_user_id=msg.from_user.wa_id, + referred_product=ReferredProduct(catalog_id="123", sku=product), + ) + return dataclasses.replace(msg, reply_to_message=reply_to_msg)