From 460e71100d8aa86229c9022ebd4bef6c4a26be35 Mon Sep 17 00:00:00 2001 From: Zhan Date: Wed, 12 Feb 2025 15:42:58 +0300 Subject: [PATCH 1/3] SW-3741 --- whatsapp_api_client_python/API.py | 51 +++++++++++-- whatsapp_api_client_python/tools/partner.py | 80 +++++++++++++++++++++ 2 files changed, 124 insertions(+), 7 deletions(-) create mode 100644 whatsapp_api_client_python/tools/partner.py diff --git a/whatsapp_api_client_python/API.py b/whatsapp_api_client_python/API.py index 62a2612..77cc82d 100644 --- a/whatsapp_api_client_python/API.py +++ b/whatsapp_api_client_python/API.py @@ -16,7 +16,8 @@ receiving, sending, serviceMethods, - webhooks + webhooks, + partner ) @@ -78,18 +79,14 @@ def request( url = url.replace("{{idInstance}}", self.idInstance) url = url.replace("{{apiTokenInstance}}", self.apiTokenInstance) - headers = { - 'User-Agent': 'GREEN-API_SDK_PY/1.0' - } - try: if not files: response = self.session.request( - method=method, url=url, json=payload, timeout=self.host_timeout, headers=headers + method=method, url=url, json=payload, timeout=self.host_timeout ) else: response = self.session.request( - method=method, url=url, data=payload, files=files, timeout=self.media_timeout, headers=headers + method=method, url=url, data=payload, files=files, timeout=self.media_timeout ) except Exception as error: error_message = f"Request was failed with error: {error}." @@ -182,3 +179,43 @@ class GreenAPI(GreenApi): class GreenAPIError(Exception): pass + +class GreenApiPartner(GreenApi): + def __init__( + self, + partnerToken: str, + email: str = None, + debug_mode: bool = False, + raise_errors: bool = False, + host: str = "https://api.green-api.com", + media: str = "https://media.green-api.com", + host_timeout: float = 180, + media_timeout: float = 10800 + ): + + super().__init__( + idInstance="", + apiTokenInstance="", + debug_mode=debug_mode, + raise_errors=raise_errors, + host=host, + media=media, + host_timeout=host_timeout, + media_timeout=media_timeout + ) + + self.partnerToken = partnerToken + self.email = email + self.partner = partner.Partner(self) + + def request( + self, + method: str, + url: str, + payload: Optional[dict] = None, + files: Optional[dict] = None + ) -> GreenAPIResponse: + + url = url.replace("{{partnerToken}}", self.partnerToken) + + return super().request(method, url, payload, files) \ No newline at end of file diff --git a/whatsapp_api_client_python/tools/partner.py b/whatsapp_api_client_python/tools/partner.py new file mode 100644 index 0000000..78b9d6a --- /dev/null +++ b/whatsapp_api_client_python/tools/partner.py @@ -0,0 +1,80 @@ +from typing import Dict, List, Optional, TYPE_CHECKING, Union + +from ..response import Response + +if TYPE_CHECKING: + from ..API import GreenApiPartner + +class Partner: + def __init__(self, api: "GreenApiPartner"): + self.api = api + + def getInstances( + self + ) -> Response: + + request_body = self.__handle_parameters(locals()) + + return self.api.request( + "GET", ( + "{{host}}/partner/" + "getInstances/{{partnerToken}}" + ), request_body + ) ### GOOD + + def createInstance( + self, + name: Optional[str] = None, + webhookUrl: Optional[str] = None, + webhookUrlToken: Optional[str] = None, + delaySendMessagesMilliseconds: Optional[int] = None, + markIncomingMessagesReaded: Optional[str] = None, + markIncomingMessagesReadedOnReply: Optional[str] = None, + outgoingWebhook: Optional[str] = None, + outgoingMessageWebhook: Optional[str] = None, + outgoingAPIMessageWebhook: Optional[str] = None, + stateWebhook: Optional[str] = None, + incomingWebhook: Optional[str] = None, + deviceWebhook: Optional[str] = None, + keepOnlineStatus: Optional[str] = None, + pollMessageWebhook: Optional[str] = None, + incomingBlockWebhook: Optional[str] = None, + incomingCallWebhook: Optional[str] = None, + editedMessageWebhook: Optional[str] = None, + deletedMessageWebhook: Optional[str] = None + ) -> Response: + + request_body = self.__handle_parameters(locals()) + + return self.api.request( + "POST", ( + "{{host}}/partner/" + "createInstance/{{partnerToken}}" + ), request_body + ) ### NOT FINISHED!!!! + + def deleteInstanceAccount( + self, + idInstance: int + ) -> Response: + + request_body = self.__handle_parameters(locals()) + + return self.api.request( + "POST", ( + "{{host}}/partner/" + "deleteInstanceAccount/{{partnerToken}}" + ), request_body + ) ###GOOD + + @classmethod + def __handle_parameters(cls, parameters: dict) -> dict: + handled_parameters = parameters.copy() + + handled_parameters.pop("self") + + for key, value in parameters.items(): + if value is None: + handled_parameters.pop(key) + + return handled_parameters \ No newline at end of file From 1aae5a154369adb9e99109f964c0f006ec643aa8 Mon Sep 17 00:00:00 2001 From: Zhan Date: Wed, 12 Feb 2025 15:50:47 +0300 Subject: [PATCH 2/3] SW-3741 --- whatsapp_api_client_python/tools/partner.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/whatsapp_api_client_python/tools/partner.py b/whatsapp_api_client_python/tools/partner.py index 78b9d6a..8e69186 100644 --- a/whatsapp_api_client_python/tools/partner.py +++ b/whatsapp_api_client_python/tools/partner.py @@ -1,4 +1,4 @@ -from typing import Dict, List, Optional, TYPE_CHECKING, Union +from typing import Optional, TYPE_CHECKING from ..response import Response @@ -20,7 +20,7 @@ def getInstances( "{{host}}/partner/" "getInstances/{{partnerToken}}" ), request_body - ) ### GOOD + ) def createInstance( self, @@ -51,7 +51,7 @@ def createInstance( "{{host}}/partner/" "createInstance/{{partnerToken}}" ), request_body - ) ### NOT FINISHED!!!! + ) def deleteInstanceAccount( self, @@ -65,7 +65,7 @@ def deleteInstanceAccount( "{{host}}/partner/" "deleteInstanceAccount/{{partnerToken}}" ), request_body - ) ###GOOD + ) @classmethod def __handle_parameters(cls, parameters: dict) -> dict: From f604ad237e0971aa7f1e053624cdbb57c786668d Mon Sep 17 00:00:00 2001 From: prostraction Date: Sat, 22 Feb 2025 23:23:22 +0500 Subject: [PATCH 3/3] Refactored code, added documentation --- README.md | 4 + docs/README.md | 3 + examples/partherMethods/CreateInstance.py | 34 +++++++++ .../partherMethods/DeleteInstanceAccount.py | 14 ++++ examples/partherMethods/GetInstances.py | 13 ++++ examples/setSettings.py | 34 +++++++++ whatsapp_api_client_python/API.py | 22 ++---- whatsapp_api_client_python/tools/partner.py | 75 +++++++------------ 8 files changed, 138 insertions(+), 61 deletions(-) create mode 100644 examples/partherMethods/CreateInstance.py create mode 100644 examples/partherMethods/DeleteInstanceAccount.py create mode 100644 examples/partherMethods/GetInstances.py create mode 100644 examples/setSettings.py diff --git a/README.md b/README.md index d9704f4..caaf591 100644 --- a/README.md +++ b/README.md @@ -237,6 +237,10 @@ print(response.data) | `serviceMethods.setDisappearingChat` | The method is designed to change the settings of disappearing messages in chats | [SetDisappearingChat](https://green-api.com/en/docs/api/service/SetDisappearingChat/) | | `webhooks.startReceivingNotifications` | The method is designed to start receiving new notifications | | | `webhooks.stopReceivingNotifications` | The method is designed to stop receiving new notifications | | +| `partner.GetInstances` | The method is for getting all the account instances created by the partner. | [GetInstances](https://green-api.com/en/docs/partners/getInstances/) | +| `partner.CreateInstance` | The method is for creating an instance. | [CreateInstance](https://green-api.com/en/docs/partners/createInstance/) | +| `partner.DeleteInstanceAccount` | The method is for deleting an instance. | [DeleteInstanceAccount](https://green-api.com/en/docs/partners/deleteInstanceAccount/) | + ## Service methods documentation diff --git a/docs/README.md b/docs/README.md index d8127a7..a8704ce 100644 --- a/docs/README.md +++ b/docs/README.md @@ -221,6 +221,9 @@ print(response.data) | `serviceMethods.setDisappearingChat` | Метод предназначен для изменения настроек исчезающих сообщений в чатах | [SetDisappearingChat](https://green-api.com/docs/api/service/SetDisappearingChat/) | | `webhooks.startReceivingNotifications` | Метод предназначен для старта получения новых уведомлений | | | `webhooks.stopReceivingNotifications` | Метод предназначен для остановки получения новых уведомлений | | +| `partner.GetInstances` | Метод предназначен для получения всех инстансов аккаунтов созданных партнёром. | [GetInstances](https://green-api.com/docs/partners/getInstances/) | +| `partner.CreateInstance` | Метод предназначен для создания инстанса от имени партнёра. | [CreateInstance](https://green-api.com/docs/partners/createInstance/) | +| `partner.DeleteInstanceAccount` | Метод предназначен для удаления инстанса аккаунта партнёра. | [DeleteInstanceAccount](https://green-api.com/docs/partners/deleteInstanceAccount/) | ## Документация по методам сервиса diff --git a/examples/partherMethods/CreateInstance.py b/examples/partherMethods/CreateInstance.py new file mode 100644 index 0000000..fdbd327 --- /dev/null +++ b/examples/partherMethods/CreateInstance.py @@ -0,0 +1,34 @@ +from whatsapp_api_client_python import API + +greenAPI = API.GreenApiPartner( + "gac.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst" +) + + +def main(): + settings = { + "name": "Created by Python SDK", + "webhookUrl": "https://webhook.url", + "webhookUrlToken": "auth_token", + "delaySendMessagesMilliseconds": 5000, + "markIncomingMessagesReaded": "yes", + "markIncomingMessagesReadedOnReply": "yes", + "outgoingWebhook": "yes", + "outgoingMessageWebhook": "yes", + "outgoingAPIMessageWebhook": "yes", + "stateWebhook": "yes", + "incomingWebhook": "yes", + "deviceWebhook": "yes", + "keepOnlineStatus": "yes", + "pollMessageWebhook": "yes", + "incomingBlockWebhook": "yes", + "incomingCallWebhook": "yes", + "editedMessageWebhook": "yes", + "deletedMessageWebhook": "yes" + } + + response = greenAPI.partner.createInstance(settings) + print(response.data) + +if __name__ == '__main__': + main() diff --git a/examples/partherMethods/DeleteInstanceAccount.py b/examples/partherMethods/DeleteInstanceAccount.py new file mode 100644 index 0000000..a6b48e0 --- /dev/null +++ b/examples/partherMethods/DeleteInstanceAccount.py @@ -0,0 +1,14 @@ +from whatsapp_api_client_python import API + +greenAPI = API.GreenApiPartner( + "gac.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst" +) + + +def main(): + response = greenAPI.partner.deleteInstanceAccount(1103123456) + print(response.data) + + +if __name__ == '__main__': + main() diff --git a/examples/partherMethods/GetInstances.py b/examples/partherMethods/GetInstances.py new file mode 100644 index 0000000..e24dd39 --- /dev/null +++ b/examples/partherMethods/GetInstances.py @@ -0,0 +1,13 @@ +from whatsapp_api_client_python import API + +greenAPI = API.GreenApiPartner( + "gac.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst" +) + + +def main(): + response = greenAPI.partner.getInstances() + print(response.data) + +if __name__ == '__main__': + main() diff --git a/examples/setSettings.py b/examples/setSettings.py new file mode 100644 index 0000000..4652e9e --- /dev/null +++ b/examples/setSettings.py @@ -0,0 +1,34 @@ +from whatsapp_api_client_python import API + +greenAPI = API.GreenAPI( + "1101000001", "d75b3a66374942c5b3c019c698abc2067e151558acbd412345" +) + + +def main(): + settings = { + "webhookUrl": "https://webhook.url", + "webhookUrlToken": "auth_token", + "delaySendMessagesMilliseconds": 5000, + "markIncomingMessagesReaded": "yes", + "markIncomingMessagesReadedOnReply": "yes", + "outgoingWebhook": "yes", + "outgoingMessageWebhook": "yes", + "outgoingAPIMessageWebhook": "yes", + "stateWebhook": "yes", + "incomingWebhook": "yes", + "deviceWebhook": "yes", + "keepOnlineStatus": "yes", + "pollMessageWebhook": "yes", + "incomingBlockWebhook": "yes", + "incomingCallWebhook": "yes", + "editedMessageWebhook": "yes", + "deletedMessageWebhook": "yes" + } + + response = greenAPI.account.setSettings(settings) + print(response.data) + + +if __name__ == '__main__': + main() diff --git a/whatsapp_api_client_python/API.py b/whatsapp_api_client_python/API.py index 77cc82d..fb900f0 100644 --- a/whatsapp_api_client_python/API.py +++ b/whatsapp_api_client_python/API.py @@ -79,14 +79,18 @@ def request( url = url.replace("{{idInstance}}", self.idInstance) url = url.replace("{{apiTokenInstance}}", self.apiTokenInstance) + headers = { + 'User-Agent': 'GREEN-API_SDK_PY/1.0' + } + try: if not files: response = self.session.request( - method=method, url=url, json=payload, timeout=self.host_timeout + method=method, url=url, json=payload, timeout=self.host_timeout, headers=headers ) else: response = self.session.request( - method=method, url=url, data=payload, files=files, timeout=self.media_timeout + method=method, url=url, data=payload, files=files, timeout=self.media_timeout, headers=headers ) except Exception as error: error_message = f"Request was failed with error: {error}." @@ -185,23 +189,13 @@ def __init__( self, partnerToken: str, email: str = None, - debug_mode: bool = False, - raise_errors: bool = False, - host: str = "https://api.green-api.com", - media: str = "https://media.green-api.com", - host_timeout: float = 180, - media_timeout: float = 10800 + host: str = "https://api.green-api.com" ): super().__init__( idInstance="", apiTokenInstance="", - debug_mode=debug_mode, - raise_errors=raise_errors, - host=host, - media=media, - host_timeout=host_timeout, - media_timeout=media_timeout + host=host ) self.partnerToken = partnerToken diff --git a/whatsapp_api_client_python/tools/partner.py b/whatsapp_api_client_python/tools/partner.py index 8e69186..73d3435 100644 --- a/whatsapp_api_client_python/tools/partner.py +++ b/whatsapp_api_client_python/tools/partner.py @@ -1,4 +1,4 @@ -from typing import Optional, TYPE_CHECKING +from typing import Dict, TYPE_CHECKING, Union from ..response import Response @@ -8,57 +8,43 @@ class Partner: def __init__(self, api: "GreenApiPartner"): self.api = api + + def getInstances(self) -> Response: + """ + The method is aimed for getting all the account instances created by the partner. - def getInstances( - self - ) -> Response: - - request_body = self.__handle_parameters(locals()) + https://green-api.com/en/docs/partners/getInstances/ + """ return self.api.request( "GET", ( "{{host}}/partner/" "getInstances/{{partnerToken}}" - ), request_body + ) ) - def createInstance( - self, - name: Optional[str] = None, - webhookUrl: Optional[str] = None, - webhookUrlToken: Optional[str] = None, - delaySendMessagesMilliseconds: Optional[int] = None, - markIncomingMessagesReaded: Optional[str] = None, - markIncomingMessagesReadedOnReply: Optional[str] = None, - outgoingWebhook: Optional[str] = None, - outgoingMessageWebhook: Optional[str] = None, - outgoingAPIMessageWebhook: Optional[str] = None, - stateWebhook: Optional[str] = None, - incomingWebhook: Optional[str] = None, - deviceWebhook: Optional[str] = None, - keepOnlineStatus: Optional[str] = None, - pollMessageWebhook: Optional[str] = None, - incomingBlockWebhook: Optional[str] = None, - incomingCallWebhook: Optional[str] = None, - editedMessageWebhook: Optional[str] = None, - deletedMessageWebhook: Optional[str] = None - ) -> Response: - - request_body = self.__handle_parameters(locals()) + def createInstance(self, requestBody: Dict[str, Union[int, str]]) -> Response: + """ + The method is aimed for creating a messenger account instance on the partner's part. + + https://green-api.com/en/docs/partners/createInstance/ + """ return self.api.request( "POST", ( "{{host}}/partner/" "createInstance/{{partnerToken}}" - ), request_body + ), requestBody ) - def deleteInstanceAccount( - self, - idInstance: int - ) -> Response: + def deleteInstanceAccount(self, idInstance: int) -> Response: + """ + The method is aimed for deleting an instance of the partners's account. + + https://green-api.com/en/docs/partners/deleteInstanceAccount/ + """ - request_body = self.__handle_parameters(locals()) + request_body = self.handle_parameters(locals()) return self.api.request( "POST", ( @@ -67,14 +53,9 @@ def deleteInstanceAccount( ), request_body ) - @classmethod - def __handle_parameters(cls, parameters: dict) -> dict: - handled_parameters = parameters.copy() - - handled_parameters.pop("self") - - for key, value in parameters.items(): - if value is None: - handled_parameters.pop(key) - - return handled_parameters \ No newline at end of file + def handle_parameters(self, parameters: dict) -> dict: + return { + key: value + for key, value in parameters.items() + if value is not None and key != "self" + } \ No newline at end of file