diff --git a/utils_v2/goog/base.py b/utils_v2/goog/base.py index 3dadac9..e392163 100644 --- a/utils_v2/goog/base.py +++ b/utils_v2/goog/base.py @@ -165,7 +165,13 @@ class AsyncGoogleBase: # ┛ @staticmethod - async def get_error_message(api_response: GoogleApiResponse): + async def __get_error_message(api_response: GoogleApiResponse) -> str: + + """ + To extract various kinds of error messages from Google's responses. + :param api_response: The formatted response from the API call. + :return: The message string. + """ try: return (await api_response.get_json())["error"]["message"] except: return api_response.response.reason_phrase @@ -210,7 +216,7 @@ class AsyncGoogleBase: # Note down the results: api_response.response = response api_response.httpCode = response.status_code - api_response.message = await self.get_error_message(api_response) + api_response.message = await self.__get_error_message(api_response) # If something goes wrong: except Exception as exception: @@ -259,7 +265,7 @@ class AsyncGoogleBase: # Note down the results: api_response.response = response api_response.httpCode = response.status_code - api_response.message = await self.get_error_message(api_response) + api_response.message = await self.__get_error_message(api_response) # If something goes wrong: except Exception as exception: @@ -308,7 +314,7 @@ class AsyncGoogleBase: # Note down the results: api_response.response = response api_response.httpCode = response.status_code - api_response.message = await self.get_error_message(api_response) + api_response.message = await self.__get_error_message(api_response) # If something goes wrong: except Exception as exception: @@ -351,7 +357,7 @@ class AsyncGoogleBase: # Note down the results: api_response.response = response api_response.httpCode = response.status_code - api_response.message = await self.get_error_message(api_response) + api_response.message = await self.__get_error_message(api_response) # If something goes wrong: except Exception as exception: diff --git a/utils_v2/goog/gmail/gmail_v2.py b/utils_v2/goog/gmail/gmail_v2.py index c2dc76c..64150d0 100644 --- a/utils_v2/goog/gmail/gmail_v2.py +++ b/utils_v2/goog/gmail/gmail_v2.py @@ -124,6 +124,15 @@ class AsyncGMailClient(AsyncGoogleBase): user_id: str = "me", ) -> GoogleApiResponse: + """ + To get the list of labels of this user. + DOCUMENTATION: + 1. https://developers.google.com/gmail/api/reference/rest/v1/users/getProfile + :param tokens: The object that holds the access token to the service. + :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". + :return: A structured response where the list of labels will be in the 'data' variable. + """ + # Ensure that the tokens are valid: await tokens.arefresh( http_client = self._http_client, @@ -162,7 +171,7 @@ class AsyncGMailClient(AsyncGoogleBase): 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/list 2. https://developers.google.com/gmail/api/reference/rest/v1/users.labels#Label :param tokens: The object that holds the access token to the service. - :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself. + :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". :return: A structured response where the list of labels will be in the 'data' variable. """ @@ -183,12 +192,216 @@ class AsyncGMailClient(AsyncGoogleBase): # If the call was successful: if api_response.httpCode in [200]: + api_response.success = True api_json = await api_response.get_json() api_response.data = {label.pop("name"): label for label in api_json.get("labels", [])} # Done here: return api_response + async def get_label( + self, + tokens: GoogleAuthTokens, + label_id: str, + user_id: str = "me" + ) -> GoogleApiResponse: + + """ + To get one label of this user. the label will be identified by its id. + DOCUMENTATION: + 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/get + 2. https://developers.google.com/gmail/api/reference/rest/v1/users.labels#Label + :param tokens: The object that holds the access token to the service. + :param label_id: The id that Google assigned to the label. + :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". + :return: A structured response where the list of labels will be in the 'data' variable. + """ + + # Ensure that the tokens are valid: + await tokens.arefresh( + http_client = self._http_client, + client_id = self._client_id, + client_secret = self._client_secret, + force_refresh = False + ) + + # Make the API call: + if not self._debug_only_errors: self._printer("Getting One Label.", user_id) + api_response = await self.get( + url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/labels/{label_id}", + headers = {"Authorization": f"Bearer {tokens.accessToken}"} + ) + + # If the call was successful: + if api_response.httpCode in [200]: + api_response.success = True + api_response.data = await api_response.get_json() + + # Done here: + return api_response + + async def create_label( + self, + tokens: GoogleAuthTokens, + label_name: str, + label_visibility: Literal["labelShow", "labelShowIfUnread", "labelHide"] = "labelShow", + message_visibility: Literal["show", "hide"] = "show", + label_text_color: str = "#434343", + label_background_color: str = "#000000", + user_id: str = "me" + ) -> GoogleApiResponse: + + """ + Create one label for the user. Doesn't apply it to any mail, just creates it. + DOCUMENTATION: + 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/create + 2. https://developers.google.com/gmail/api/reference/rest/v1/users.labels#Label + :param tokens: The object that holds the access token to the service. + :param label_name: The display name of the label. + :param label_visibility: Whether, or not, you would like to show the label in the web UI. + :param message_visibility: Whether, or not, you would like to show messages with this label in the web UI. + :param label_text_color: The colour of the text of the label. + :param label_background_color: The colour of the background/tag of the label. + :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". + :return: A structured response where the list of labels will be in the 'data' variable. + """ + + # Ensure that the tokens are valid: + await tokens.arefresh( + http_client = self._http_client, + client_id = self._client_id, + client_secret = self._client_secret, + force_refresh = False + ) + + # Make the API call: + if not self._debug_only_errors: self._printer("Getting One Label.", user_id) + api_response = await self.post( + url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/labels", + headers = {"Authorization": f"Bearer {tokens.accessToken}"}, + json = { + "name": label_name, + "messageListVisibility": "show" if message_visibility else "hide", + "labelListVisibility": "labelShow" if label_visibility else "labelHide", + "color": { + "textColor": label_text_color.lower(), + "backgroundColor": label_background_color.lower() + } + } + ) + + # If the call was successful: + if api_response.httpCode in [200]: + api_response.success = True + api_response.data = await api_response.get_json() + + # Done here: + return api_response + + async def update_label( + self, + tokens: GoogleAuthTokens, + label_id: str, + label_name: str = None, + label_visibility: Literal["labelShow", "labelShowIfUnread", "labelHide"] = None, + message_visibility: Literal["show", "hide"] = None, + label_text_color: str = None, + label_background_color: str = None, + user_id: str = "me" + ) -> GoogleApiResponse: + + """ + Updates one label for the user. + DOCUMENTATION: + 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/update + 2. https://developers.google.com/gmail/api/reference/rest/v1/users.labels#Label + NOTE: Both or none of the colours must be updated. For this reason, a simple default will be chosen for the + other if only one is provided. + :param tokens: The object that holds the access token to the service. + :param label_id: The id that Google assigned to the label. + :param label_name: The display name of the label. + :param label_visibility: Whether, or not, you would like to show the label in the web UI. + :param message_visibility: Whether, or not, you would like to show messages with this label in the web UI. + :param label_text_color: The colour of the text of the label. + :param label_background_color: The colour of the background/tag of the label. + :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". + :return: A structured response where the list of labels will be in the 'data' variable. + """ + + # Ensure that the tokens are valid: + await tokens.arefresh( + http_client = self._http_client, + client_id = self._client_id, + client_secret = self._client_secret, + force_refresh = False + ) + + # Format the JSON body: + json_body = {} + if label_name: json_body["name"] = label_name + if label_visibility: json_body["labelListVisibility"] = label_visibility + if message_visibility: json_body["messageListVisibility"] = message_visibility + if label_text_color or label_background_color: + json_body["color"] = { + "textColor": (label_text_color or "#434343").lower(), + "backgroundColor": (label_background_color or "#000000").lower() + } + + # Make the API call: + if not self._debug_only_errors: self._printer("Updating One Label.", user_id) + api_response = await self.put( + url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/labels/{label_id}", + headers = {"Authorization": f"Bearer {tokens.accessToken}"}, + json = json_body + ) + + # If the call was successful: + if api_response.httpCode in [200]: + api_response.success = True + api_response.data = await api_response.get_json() + + # Done here: + return api_response + + async def delete_label( + self, + tokens: GoogleAuthTokens, + label_id: str, + user_id: str = "me" + ) -> GoogleApiResponse: + + """ + To delete one label of this user. the label will be identified by its id. + DOCUMENTATION: + 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/delete + :param tokens: The object that holds the access token to the service. + :param label_id: The id that Google assigned to the label. + :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". + :return: A structured response where the list of labels will be in the 'data' variable. + """ + + # Ensure that the tokens are valid: + await tokens.arefresh( + http_client = self._http_client, + client_id = self._client_id, + client_secret = self._client_secret, + force_refresh = False + ) + + # Make the API call: + if not self._debug_only_errors: self._printer("Getting One Label.", user_id) + api_response = await self.delete( + url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/labels/{label_id}", + headers = {"Authorization": f"Bearer {tokens.accessToken}"} + ) + + # If the call was successful: + if api_response.httpCode in [200, 204]: + api_response.success = True + + # Done here: + return api_response + # ***************************************************************************************************************** # ***** ****