From 808db4e7b8413a0ab1b280908210f556bc949fe9 Mon Sep 17 00:00:00 2001 From: reeshika-h Date: Mon, 8 Dec 2025 12:14:47 +0530 Subject: [PATCH 1/2] Refactor error handling to use constants for required field messages across multiple modules, enhancing maintainability and consistency in exception messages. --- contentstack_management/_constant.py | 5 +- contentstack_management/_messages.py | 131 ++++++++++++++++++ contentstack_management/aliases/aliases.py | 3 +- contentstack_management/assets/assets.py | 21 +-- contentstack_management/auditlogs/auditlog.py | 3 +- contentstack_management/branches/branches.py | 5 +- .../bulk_operations/bulk_operation.py | 3 +- .../content_types/content_type.py | 5 +- contentstack_management/contentstack.py | 3 +- .../delivery_token/delivery_token.py | 3 +- contentstack_management/entries/entry.py | 37 ++--- .../entry_variants/entry_variants.py | 7 +- .../environments/environment.py | 3 +- .../extensions/extension.py | 3 +- .../global_fields/global_fields.py | 3 +- contentstack_management/labels/label.py | 3 +- contentstack_management/locale/locale.py | 3 +- .../management_token/management_token.py | 3 +- contentstack_management/metadata/metadata.py | 3 +- .../oauth/oauth_handler.py | 52 ++++--- .../oauth/oauth_interceptor.py | 14 +- .../organizations/organization.py | 13 +- .../publish_queue/publish_queue.py | 3 +- .../release_items/release_item.py | 3 +- contentstack_management/releases/release.py | 3 +- contentstack_management/roles/roles.py | 3 +- contentstack_management/stack/stack.py | 21 +-- .../taxonomies/taxonomy.py | 3 +- contentstack_management/terms/terms.py | 7 +- .../user_session/user_session.py | 5 +- .../variant_group/variant_group.py | 3 +- contentstack_management/variants/variants.py | 7 +- contentstack_management/webhooks/webhook.py | 17 +-- .../workflows/workflows.py | 27 ++-- 34 files changed, 300 insertions(+), 128 deletions(-) create mode 100644 contentstack_management/_messages.py diff --git a/contentstack_management/_constant.py b/contentstack_management/_constant.py index e1ed803..8fff8ef 100644 --- a/contentstack_management/_constant.py +++ b/contentstack_management/_constant.py @@ -1,5 +1,6 @@ import platform -import sys +import sys +from ._messages import REQUEST_HEADERS_INVALID def _default_user_agent(): @@ -55,4 +56,4 @@ def _request_headers(): if __name__ == '__main__': - print(_request_headers().__str__()) + print(REQUEST_HEADERS_INVALID) diff --git a/contentstack_management/_messages.py b/contentstack_management/_messages.py new file mode 100644 index 0000000..0e33e83 --- /dev/null +++ b/contentstack_management/_messages.py @@ -0,0 +1,131 @@ +""" +Centralized error and UI messages for Contentstack Management SDK. + +This module contains all user-facing messages used throughout the SDK +to ensure consistency and easy maintenance. +""" + +# General messages +REQUEST_HEADERS_INVALID = "Request headers are invalid. Provide valid headers and try again." + +# Alias messages +ALIAS_UID_REQUIRED = "Alias UID is required. Provide a valid Alias UID and try again." + +# Asset messages +ASSET_UID_REQUIRED = "Asset UID is required. Provide a valid Asset UID and try again." +ASSET_TYPE_REQUIRED = "Asset Type is required. Provide a valid Asset Type and try again." +ASSET_VERSION_NUMBER_REQUIRED = "Version Number is required. Provide a valid Version Number and try again." + +# Audit log messages +LOG_ITEM_UID_REQUIRED = "Log Item UID is required. Provide a valid Log Item UID and try again." + +# Branch messages +BRANCH_UID_REQUIRED = "Branch UID is required. Provide a valid Branch UID and try again." + +# Bulk operation messages +JOB_UID_REQUIRED = "Job UID is required. Provide a valid Job UID and try again." + +# Content type messages +CONTENT_TYPE_UID_REQUIRED = "Content Type UID is required. Provide a valid Content Type UID and try again." + +# Delivery token messages +DELIVERY_TOKEN_UID_REQUIRED = "Delivery Token UID is required. Provide a valid Delivery Token UID and try again." + +# Entry messages +ENTRY_UID_REQUIRED = "Entry UID is required. Provide a valid Entry UID and try again." +ENTRY_VERSION_NUMBER_REQUIRED = "Version Number is required. Provide a valid Version Number and try again." +ENTRY_BODY_REQUIRED = "Body is required. Provide a valid Body value and try again." +ENTRY_FILE_PATH_REQUIRED = "File Path is required. Provide a valid File Path and try again." + +# Entry variant messages +ENTRY_VARIANT_CONTENT_TYPE_UID_REQUIRED = "Content Type UID is required. Provide a valid Content Type UID and try again." +ENTRY_VARIANT_ENTRY_UID_REQUIRED = "Entry UID is required. Provide a valid Entry UID and try again." +ENTRY_VARIANT_UID_REQUIRED = "Variant UID is required. Provide a valid Variant UID and try again." + +# Environment messages +ENVIRONMENT_UID_REQUIRED = "Environment UID is required. Provide a valid Environment UID and try again." + +# Extension messages +EXTENSION_UID_REQUIRED = "Extension UID is required. Provide a valid Extension UID and try again." + +# Global field messages +GLOBAL_FIELD_UID_REQUIRED = "Global Field UID is required. Provide a valid Global Field UID and try again." + +# Label messages +LABEL_UID_REQUIRED = "Label UID is required. Provide a valid Label UID and try again." + +# Locale messages +LOCALE_CODE_REQUIRED = "Locale Code is required. Provide a valid Locale Code and try again." + +# Management token messages +MANAGEMENT_TOKEN_UID_REQUIRED = "Management Token UID is required. Provide a valid Management Token UID and try again." + +# Metadata messages +METADATA_UID_REQUIRED = "Metadata UID is required. Provide a valid Metadata UID and try again." + +# OAuth messages +OAUTH_ACCESS_TOKEN_EXPIRED = "Access token expired. Refreshing the token." +OAUTH_ACCESS_TOKEN_NOT_AVAILABLE = "Access token is not available. Authenticate to continue." +OAUTH_TOKENS_NOT_AVAILABLE = "OAuth tokens are not available. Please authenticate first." +OAUTH_REFRESH_TOKEN_NOT_AVAILABLE = "Refresh token is not available. Please authenticate to get a new token." +OAUTH_NOT_CONFIGURED = "OAuth is not configured. Set up OAuth to continue." +OAUTH_AUTHORIZATION_CODE_NOT_FOUND = "Authorization code was not found in the redirect URL. Provide a valid code and try again." +OAUTH_TOKEN_EXCHANGE_FAILED = "Token exchange failed. Please try authenticating again." +OAUTH_TOKEN_REFRESH_FAILED = "Token refresh failed due to {error}. Review the error and try again." +OAUTH_BASE_URL_NOT_SET = "OAuth Base URL is not set. Provide a valid OAuth Base URL and try again." +OAUTH_AUTHORIZING = "Authorizing using app ID {app_id} and client ID {client_id}." +OAUTH_AUTHORIZATION_URL_GENERATED = "OAuth handler generated the final authorization URL at {final_url}." +OAUTH_AUTHORIZATION_URL_GENERATION_FAILED = "Authorization URL generation failed due to {error}. Review the error and try again." +OAUTH_AUTHORIZATION_CODE_EMPTY = "Authorization code is required. Provide a valid code and try again." +OAUTH_TOKEN_EXCHANGE_ERROR = "Token exchange failed due to {error}. Review the error and try again." +OAUTH_TOKEN_REFRESH_ERROR = "Token refresh failed due to {error}. Review the error and try again." +OAUTH_TOKEN_REFRESH_FAILED_AFTER_401 = "Token refresh failed after a 401 response due to {error}. Review the error and try again." +OAUTH_VISIT_URL_TO_AUTHORIZE = "Visit {auth_url} to authorize." + +# Organization messages +ORGANIZATION_UID_REQUIRED = "Organization UID is required. Provide a valid Organization UID and try again." + +# Publish queue messages +PUBLISH_QUEUE_UID_REQUIRED = "Publish Queue UID is required. Provide a valid Publish Queue UID and try again." + +# Release messages +RELEASE_UID_REQUIRED = "Release UID is required. Provide a valid Release UID and try again." + +# Role messages +ROLE_UID_REQUIRED = "Role UID is required. Provide a valid Release UID and try again." + +# Stack messages +API_KEY_REQUIRED = "API Key is required. Provide a valid API Key and try again." +USER_ID_REQUIRED = "User ID is required. Provide a valid User ID and try again." +OWNERSHIP_TOKEN_REQUIRED = "Ownership Token is required. Provide a valid Ownership Token and try again." + +# Taxonomy messages +TAXONOMY_UID_REQUIRED = "Taxonomy UID is required. Provide a valid Taxonomy UID and try again." + +# Terms messages +TERMS_UID_REQUIRED = "Terms UID is required. Provide a valid Terms UID and try again." +TERM_STRING_REQUIRED = "Term String is required. Provide a valid Term String and try again." + +# User session messages +EMAIL_ID_REQUIRED = "Email ID is required. Provide a valid Email ID and try again." +PASSWORD_REQUIRED = "Password is required. Provide a valid Password and try again." + +# Variant group messages +VARIANT_GROUP_UID_REQUIRED = "Variant Group UID is required. Provide a valid Variant Group UID and try again." + +# Variant messages +VARIANT_UIDS_NON_EMPTY_LIST_REQUIRED = "Variant UIDs must be a non-empty list. Provide at least one Variant UID and try again." +VARIANT_UID_REQUIRED = "Variant UID is required. Provide a valid Variant UID and try again." + +# Webhook messages +WEBHOOK_UID_REQUIRED = "Webhook UID is required. Provide a valid Webhook UID and try again." +WEBHOOK_FILE_PATH_REQUIRED = "File Path is required. Provide a valid File Path and try again." +WEBHOOK_EXECUTION_UID_REQUIRED = "Execution UID is required. Provide a valid Execution UID and try again." + +# Workflow messages +WORKFLOW_UID_REQUIRED = "Workflow UID is required. Provide a valid Workflow UID and try again." +WORKFLOW_CONTENT_TYPE_UID_REQUIRED = "Content Type UID is required. Provide a valid Content Type UID and try again." +WORKFLOW_ENTRY_UID_REQUIRED = "Entry UID is required. Provide a valid Entry UID and try again." +WORKFLOW_RULE_UID_REQUIRED = "Rule UID is required. Provide a valid Rule UID and try again." + + diff --git a/contentstack_management/aliases/aliases.py b/contentstack_management/aliases/aliases.py index 444ce49..6ea1c6e 100644 --- a/contentstack_management/aliases/aliases.py +++ b/contentstack_management/aliases/aliases.py @@ -3,6 +3,7 @@ import json from ..common import Parameter +from .._messages import ALIAS_UID_REQUIRED _path = 'stacks/branch_aliases' @@ -47,7 +48,7 @@ def fetch(self): -------------------------------- """ if self.alias_uid is None or '': - raise Exception('alias_uid is required') + raise Exception(ALIAS_UID_REQUIRED) url = f"{_path}/{self.alias_uid}" return self.client.get(url, headers=self.client.headers, params=self.params) diff --git a/contentstack_management/assets/assets.py b/contentstack_management/assets/assets.py index 3f33149..69ad31d 100644 --- a/contentstack_management/assets/assets.py +++ b/contentstack_management/assets/assets.py @@ -8,6 +8,7 @@ from ..common import Parameter import mimetypes import os +from .._messages import ASSET_UID_REQUIRED, ASSET_TYPE_REQUIRED, ASSET_VERSION_NUMBER_REQUIRED class Assets(Parameter): """ @@ -62,7 +63,7 @@ def fetch(self): """ if self.asset_uid is None or '': - raise Exception('asset_uid is required') + raise Exception(ASSET_UID_REQUIRED) url = f"assets/{self.asset_uid}" return self.client.get(url, headers = self.client.headers, params = self.params) @@ -284,7 +285,7 @@ def version(self): """ if self.asset_uid is None or '': - raise Exception('asset_uid is required') + raise Exception(ASSET_UID_REQUIRED) url = f"assets/{self.asset_uid}/versions" return self.client.get(url, headers = self.client.headers, params = self.params) @@ -305,9 +306,9 @@ def version_delete(self, version_number): """ if self.asset_uid is None or '': - raise Exception('asset_uid is required') + raise Exception(ASSET_UID_REQUIRED) if version_number is None: - raise Exception('Version Number is required') + raise Exception(ASSET_VERSION_NUMBER_REQUIRED) url = f"assets/{self.asset_uid}/versions/{version_number}/name" return self.client.delete(url, headers = self.client.headers, params = self.params) @@ -326,7 +327,7 @@ def references(self): """ if self.asset_uid is None or '': - raise Exception('asset_uid is required') + raise Exception(ASSET_UID_REQUIRED) url = f"assets/{self.asset_uid}/references" return self.client.get(url, headers = self.client.headers, params = self.params) @@ -346,7 +347,7 @@ def specific_asset_type(self, asset_type): """ if asset_type is None or '': - raise Exception('asset_type is required') + raise Exception(ASSET_TYPE_REQUIRED) url = f"assets/{asset_type}" return self.client.get(url, headers = self.client.headers, params = self.params) @@ -376,7 +377,7 @@ def update_asset_revision(self, data): data = json.dumps(data) if self.asset_uid is None or '': - raise Exception('asset_uid is required') + raise Exception(ASSET_UID_REQUIRED) url = f"assets/{self.asset_uid}" return self.client.put(url, headers = self.client.headers, params = self.params, data = data) @@ -404,7 +405,7 @@ def update(self, data): data = json.dumps(data) if self.asset_uid is None or '': - raise Exception('asset_uid is required') + raise Exception(ASSET_UID_REQUIRED) url = f"assets/{self.asset_uid}" Parameter.add_header(self, "Content-Type", "multipart/form-data") return self.client.put(url, headers = self.client.headers, params = self.params, data = data) @@ -439,7 +440,7 @@ def publish(self, data): data = json.dumps(data) if self.asset_uid is None or '': - raise Exception('asset_uid is required') + raise Exception(ASSET_UID_REQUIRED) url = f"assets/{self.asset_uid}/publish" return self.client.post(url, headers = self.client.headers, data = data) @@ -474,7 +475,7 @@ def unpublish(self, data): data = json.dumps(data) if self.asset_uid is None or '': - raise Exception('asset_uid is required') + raise Exception(ASSET_UID_REQUIRED) url = f"assets/{self.asset_uid}/unpublish" return self.client.post(url, headers = self.client.headers, data = data) diff --git a/contentstack_management/auditlogs/auditlog.py b/contentstack_management/auditlogs/auditlog.py index 3a7bf3e..8b8861c 100644 --- a/contentstack_management/auditlogs/auditlog.py +++ b/contentstack_management/auditlogs/auditlog.py @@ -5,6 +5,7 @@ from ..common import Parameter from .._errors import ArgumentException +from .._messages import LOG_ITEM_UID_REQUIRED class Auditlog(Parameter): """ @@ -58,6 +59,6 @@ def fetch(self): def validate_uid(self): if self.log_item_uid is None or '': - raise ArgumentException('Log item Uid is required') + raise ArgumentException(LOG_ITEM_UID_REQUIRED) \ No newline at end of file diff --git a/contentstack_management/branches/branches.py b/contentstack_management/branches/branches.py index 635a7e3..8da5d3c 100644 --- a/contentstack_management/branches/branches.py +++ b/contentstack_management/branches/branches.py @@ -6,6 +6,7 @@ import json from contentstack_management.common import Parameter +from contentstack_management._messages import BRANCH_UID_REQUIRED _path = 'stacks/branches' @@ -55,7 +56,7 @@ def fetch(self): -------------------------------- """ if self.branch_uid is None or '': - raise Exception('branch_uid is required field') + raise Exception(BRANCH_UID_REQUIRED) url = f"{_path}/{self.branch_uid}" return self.client.get(url, headers=self.client.headers, params=self.params) @@ -101,6 +102,6 @@ def delete(self): -------------------------------- """ if self.branch_uid is None or '': - raise Exception('branch_uid is required field') + raise Exception(BRANCH_UID_REQUIRED) url = f"{_path}/{self.branch_uid}" return self.client.delete(url, headers=self.client.headers, params=self.params) diff --git a/contentstack_management/bulk_operations/bulk_operation.py b/contentstack_management/bulk_operations/bulk_operation.py index 72cce6c..4be9a10 100644 --- a/contentstack_management/bulk_operations/bulk_operation.py +++ b/contentstack_management/bulk_operations/bulk_operation.py @@ -7,6 +7,7 @@ from ..common import Parameter from urllib.parse import quote from .._errors import ArgumentException +from .._messages import JOB_UID_REQUIRED class BulkOperation(Parameter): """ @@ -313,7 +314,7 @@ def job_status(self, job_uid: str, headers: dict = None): ------------------------------- """ if job_uid is None: - raise ArgumentException("job_uid", "job_uid cannot be None") + raise ArgumentException(JOB_UID_REQUIRED) if headers is not None: self.client.headers.update(headers) url = f"{self.path}/jobs/{quote(job_uid)}" diff --git a/contentstack_management/content_types/content_type.py b/contentstack_management/content_types/content_type.py index d03ccf1..b3be4cd 100644 --- a/contentstack_management/content_types/content_type.py +++ b/contentstack_management/content_types/content_type.py @@ -6,6 +6,7 @@ from contentstack_management.common import Parameter from ..entries import entry +from .._messages import CONTENT_TYPE_UID_REQUIRED _path = 'content_types' @@ -163,7 +164,7 @@ def update(self, data): """ data = json.dumps(data) if self.content_type_uid is None or '': - raise Exception('content_type_uid is required') + raise Exception(CONTENT_TYPE_UID_REQUIRED) url = f"{_path}/{self.content_type_uid}" return self.client.put(url, headers=self.client.headers, params=self.params, data=data) @@ -347,5 +348,5 @@ def imports(self, file_path): def entry(self, entry_uid: str =None): if self.content_type_uid is None: - raise Exception('Content type uid is required') + raise Exception(CONTENT_TYPE_UID_REQUIRED) return entry.Entry(self.client, self.content_type_uid, entry_uid) \ No newline at end of file diff --git a/contentstack_management/contentstack.py b/contentstack_management/contentstack.py index c9e9cb8..09192cf 100644 --- a/contentstack_management/contentstack.py +++ b/contentstack_management/contentstack.py @@ -168,7 +168,8 @@ def oauth(self, app_id: str, client_id: str, redirect_uri: str, ... redirect_uri='http://localhost:3000/callback' ... ) >>> auth_url = oauth_handler.authorize() - >>> print(f"Visit this URL to authorize: {auth_url}") + >>> from contentstack_management._messages import OAUTH_VISIT_URL_TO_AUTHORIZE + >>> print(OAUTH_VISIT_URL_TO_AUTHORIZE.format(auth_url=auth_url)) """ return OAuthHandler( app_id=app_id, diff --git a/contentstack_management/delivery_token/delivery_token.py b/contentstack_management/delivery_token/delivery_token.py index c22a786..3e1e4bf 100644 --- a/contentstack_management/delivery_token/delivery_token.py +++ b/contentstack_management/delivery_token/delivery_token.py @@ -6,6 +6,7 @@ import json from ..common import Parameter from .._errors import ArgumentException +from .._messages import DELIVERY_TOKEN_UID_REQUIRED class DeliveryToken(Parameter): """ @@ -191,4 +192,4 @@ def delete(self): def validate_uid(self): if self.delivery_token_uid is None or '': - raise ArgumentException("Delivery Token Uid is required") \ No newline at end of file + raise ArgumentException(DELIVERY_TOKEN_UID_REQUIRED) \ No newline at end of file diff --git a/contentstack_management/entries/entry.py b/contentstack_management/entries/entry.py index b56377f..3422eca 100644 --- a/contentstack_management/entries/entry.py +++ b/contentstack_management/entries/entry.py @@ -6,6 +6,7 @@ import json from ..common import Parameter from ..entry_variants.entry_variants import EntryVariants +from .._messages import ENTRY_UID_REQUIRED, ENTRY_VERSION_NUMBER_REQUIRED, ENTRY_BODY_REQUIRED, ENTRY_FILE_PATH_REQUIRED class Entry(Parameter): """ @@ -59,7 +60,7 @@ def fetch(self): ------------------------------- """ if self.entry_uid is None: - raise Exception('Entry uid is required') + raise Exception(ENTRY_UID_REQUIRED) url = f"content_types/{self.content_type_uid}/entries/{self.entry_uid}" return self.client.get(url, headers = self.client.headers, params = self.params) @@ -126,7 +127,7 @@ def update(self, data, locale='en-us'): ------------------------------- """ if self.entry_uid is None: - raise Exception('Entry uid is required') + raise Exception(ENTRY_UID_REQUIRED) url = url = f"content_types/{self.content_type_uid}/entries/{self.entry_uid}" self.params['locale'] = locale data = json.dumps(data) @@ -161,11 +162,11 @@ def version_naming(self, version_number, data): ------------------------------- """ if self.entry_uid is None: - raise Exception('Entry uid is required') + raise Exception(ENTRY_UID_REQUIRED) if version_number is None: - raise Exception('Version Number is required') + raise Exception(ENTRY_VERSION_NUMBER_REQUIRED) if data is None: - raise Exception('Body is required') + raise Exception(ENTRY_BODY_REQUIRED) url = f"content_types/{self.content_type_uid}/entries/{self.entry_uid}/versions/{version_number}/name" data = json.dumps(data) return self.client.post(url, headers = self.client.headers, data=data, params = self.params) @@ -185,7 +186,7 @@ def references(self): ------------------------------- """ if self.entry_uid is None: - raise Exception('Entry uid is required') + raise Exception(ENTRY_UID_REQUIRED) url = f"content_types/{self.content_type_uid}/entries/{self.entry_uid}/references" return self.client.get(url, headers = self.client.headers, params = self.params) @@ -204,7 +205,7 @@ def languages(self): ------------------------------- """ if self.entry_uid is None: - raise Exception('Entry uid is required') + raise Exception(ENTRY_UID_REQUIRED) url = f"content_types/{self.content_type_uid}/entries/{self.entry_uid}/locales" return self.client.get(url, headers = self.client.headers, params = self.params) @@ -247,9 +248,9 @@ def localize(self, data, locale='en-us'): ------------------------------- """ if self.entry_uid is None: - raise Exception('Entry uid is required') + raise Exception(ENTRY_UID_REQUIRED) if data is None: - raise Exception('Body is required') + raise Exception(ENTRY_BODY_REQUIRED) url = f"content_types/{self.content_type_uid}/entries/{self.entry_uid}" self.params['locale'] = locale data = json.dumps(data) @@ -274,7 +275,7 @@ def unlocalize(self, locale='en-us'): ------------------------------- """ if self.entry_uid is None: - raise Exception('Entry uid is required') + raise Exception(ENTRY_UID_REQUIRED) url = f"content_types/{self.content_type_uid}/entries/{self.entry_uid}/unlocalize" self.params['locale'] = locale return self.client.post(url, headers = self.client.headers, params = self.params) @@ -296,7 +297,7 @@ def delete(self): ------------------------------- """ if self.entry_uid is None: - raise Exception('Entry uid is required') + raise Exception(ENTRY_UID_REQUIRED) url = f"content_types/{self.content_type_uid}/entries/{self.entry_uid}" self.params['force'] = True return self.client.delete(url, headers = self.client.headers, params = self.params) @@ -325,7 +326,7 @@ def imports(self, file_path, locale='en-us'): ------------------------------- """ if file_path is None: - raise Exception('File path is required') + raise Exception(ENTRY_FILE_PATH_REQUIRED) url = f"content_types/{self.content_type_uid}/entries/import" self.client.headers['Content-Type'] = "multipart/form-data" files = {'entry': open(f"{file_path}",'rb')} @@ -347,7 +348,7 @@ def export(self): ------------------------------- """ if self.entry_uid is None: - raise Exception('Entry uid is required') + raise Exception(ENTRY_UID_REQUIRED) url = f"content_types/{self.content_type_uid}/entries/{self.entry_uid}/export" return self.client.get(url, headers = self.client.headers, params = self.params) @@ -379,9 +380,9 @@ def publish(self, data): ------------------------------- """ if self.entry_uid is None: - raise Exception('Entry uid is required') + raise Exception(ENTRY_UID_REQUIRED) if data is None: - raise Exception('Body is required') + raise Exception(ENTRY_BODY_REQUIRED) url = f"content_types/{self.content_type_uid}/entries/{self.entry_uid}/publish" data = json.dumps(data) return self.client.post(url, headers = self.client.headers, data = data, params = self.params) @@ -415,9 +416,9 @@ def unpublish(self, data): ------------------------------- """ if self.entry_uid is None: - raise Exception('Entry uid is required') + raise Exception(ENTRY_UID_REQUIRED) if data is None: - raise Exception('Body is required') + raise Exception(ENTRY_BODY_REQUIRED) url = f"content_types/{self.content_type_uid}/entries/{self.entry_uid}/unpublish" data = json.dumps(data) return self.client.post(url, headers = self.client.headers, data = data, params = self.params) @@ -469,7 +470,7 @@ def includeVariants(self, include_variants: str = 'true', variant_uid: str = Non ------------------------------- """ if self.entry_uid is None: - raise Exception('Entry uid is required') + raise Exception(ENTRY_UID_REQUIRED) if params is not None: self.params.update(params) self.params['include_variants'] = include_variants diff --git a/contentstack_management/entry_variants/entry_variants.py b/contentstack_management/entry_variants/entry_variants.py index b2487a9..5dc6bb7 100644 --- a/contentstack_management/entry_variants/entry_variants.py +++ b/contentstack_management/entry_variants/entry_variants.py @@ -6,6 +6,7 @@ import json from ..common import Parameter from .._errors import ArgumentException +from .._messages import ENTRY_VARIANT_CONTENT_TYPE_UID_REQUIRED, ENTRY_VARIANT_ENTRY_UID_REQUIRED, ENTRY_VARIANT_UID_REQUIRED class EntryVariants(Parameter): """ @@ -251,7 +252,7 @@ def validate_content_type_uid(self): """ if self.content_type_uid is None or self.content_type_uid == '': - raise ArgumentException("content type Uid is required") + raise ArgumentException(ENTRY_VARIANT_CONTENT_TYPE_UID_REQUIRED) def validate_entry_uid(self): """ @@ -260,7 +261,7 @@ def validate_entry_uid(self): """ if self.entry_uid is None or self.entry_uid == '': - raise ArgumentException("entry Uid is required") + raise ArgumentException(ENTRY_VARIANT_ENTRY_UID_REQUIRED) def validate_variant_uid(self): """ @@ -269,4 +270,4 @@ def validate_variant_uid(self): """ if self.variant_uid is None or self.variant_uid == '': - raise ArgumentException("variant Uid is required") + raise ArgumentException(ENTRY_VARIANT_UID_REQUIRED) diff --git a/contentstack_management/environments/environment.py b/contentstack_management/environments/environment.py index 2f073e3..bc7fb46 100644 --- a/contentstack_management/environments/environment.py +++ b/contentstack_management/environments/environment.py @@ -6,6 +6,7 @@ import json from ..common import Parameter from .._errors import ArgumentException +from .._messages import ENVIRONMENT_UID_REQUIRED class Environment(Parameter): """ @@ -135,4 +136,4 @@ def delete(self): def validate_uid(self): if self.environment_name is None or '': - raise ArgumentException("Environments Uid is required") \ No newline at end of file + raise ArgumentException(ENVIRONMENT_UID_REQUIRED) \ No newline at end of file diff --git a/contentstack_management/extensions/extension.py b/contentstack_management/extensions/extension.py index c3f8a52..790c498 100644 --- a/contentstack_management/extensions/extension.py +++ b/contentstack_management/extensions/extension.py @@ -6,6 +6,7 @@ import json from ..common import Parameter from .._errors import ArgumentException +from .._messages import EXTENSION_UID_REQUIRED from requests_toolbelt.multipart.encoder import MultipartEncoder class Extension(Parameter): @@ -172,7 +173,7 @@ def delete(self): def validate_uid(self): if self.extension_uid is None or '': - raise ArgumentException("Extension Uid is required") + raise ArgumentException(EXTENSION_UID_REQUIRED) def encode_multipart_formdata(self, fields): # Create a MultipartEncoder instance with the specified fields diff --git a/contentstack_management/global_fields/global_fields.py b/contentstack_management/global_fields/global_fields.py index 760532b..4534355 100644 --- a/contentstack_management/global_fields/global_fields.py +++ b/contentstack_management/global_fields/global_fields.py @@ -4,6 +4,7 @@ the CRUD operations that can be performed on the API """ import json +from .._messages import GLOBAL_FIELD_UID_REQUIRED from contentstack_management.common import Parameter @@ -179,7 +180,7 @@ def export(self): ------------------------------- """ if self.global_field_uid is None or '': - raise Exception('global_field_uid is required') + raise Exception(GLOBAL_FIELD_UID_REQUIRED) url = f"{_path}/{self.global_field_uid}/export" response = self.client.get(url, headers=self.client.headers, params=self.params) # Remove the api_version header after request diff --git a/contentstack_management/labels/label.py b/contentstack_management/labels/label.py index b935ac0..534f333 100644 --- a/contentstack_management/labels/label.py +++ b/contentstack_management/labels/label.py @@ -6,6 +6,7 @@ import json from ..common import Parameter from .._errors import ArgumentException +from .._messages import LABEL_UID_REQUIRED class Label(Parameter): """ @@ -167,4 +168,4 @@ def validate_uid(self): """ if self.label_uid is None or '': - raise ArgumentException("label Uid is required") \ No newline at end of file + raise ArgumentException(LABEL_UID_REQUIRED) \ No newline at end of file diff --git a/contentstack_management/locale/locale.py b/contentstack_management/locale/locale.py index 9d08671..f37451c 100644 --- a/contentstack_management/locale/locale.py +++ b/contentstack_management/locale/locale.py @@ -6,6 +6,7 @@ import json from ..common import Parameter from .._errors import ArgumentException +from .._messages import LOCALE_CODE_REQUIRED class Locale(Parameter): """ @@ -191,7 +192,7 @@ def update_fallback(self, data: dict): def validate_locale_code(self): if self.locale_code is None or '': - raise ArgumentException('Locale code is required') + raise ArgumentException(LOCALE_CODE_REQUIRED) \ No newline at end of file diff --git a/contentstack_management/management_token/management_token.py b/contentstack_management/management_token/management_token.py index 3589d0e..ce39e62 100644 --- a/contentstack_management/management_token/management_token.py +++ b/contentstack_management/management_token/management_token.py @@ -6,6 +6,7 @@ import json from ..common import Parameter from .._errors import ArgumentException +from .._messages import MANAGEMENT_TOKEN_UID_REQUIRED class ManagementToken(Parameter): """ @@ -203,4 +204,4 @@ def delete(self): def validate_uid(self): if self.management_token_uid is None or '': - raise ArgumentException("Management Token Uid is required") \ No newline at end of file + raise ArgumentException(MANAGEMENT_TOKEN_UID_REQUIRED) \ No newline at end of file diff --git a/contentstack_management/metadata/metadata.py b/contentstack_management/metadata/metadata.py index 1f06916..9d25d5f 100644 --- a/contentstack_management/metadata/metadata.py +++ b/contentstack_management/metadata/metadata.py @@ -6,6 +6,7 @@ import json from ..common import Parameter from .._errors import ArgumentException +from .._messages import METADATA_UID_REQUIRED class Metadata(Parameter): """ @@ -220,4 +221,4 @@ def unpublish(self, data: dict): def validate_uid(self): if self.metadata_uid is None or '': - raise ArgumentException("Metadata Uid is required") \ No newline at end of file + raise ArgumentException(METADATA_UID_REQUIRED) \ No newline at end of file diff --git a/contentstack_management/oauth/oauth_handler.py b/contentstack_management/oauth/oauth_handler.py index 4eaebfa..8b7cef2 100644 --- a/contentstack_management/oauth/oauth_handler.py +++ b/contentstack_management/oauth/oauth_handler.py @@ -16,6 +16,23 @@ from urllib.parse import urlparse, parse_qs import requests +from .._messages import ( + OAUTH_ACCESS_TOKEN_EXPIRED, + OAUTH_ACCESS_TOKEN_NOT_AVAILABLE, + OAUTH_TOKENS_NOT_AVAILABLE, + OAUTH_REFRESH_TOKEN_NOT_AVAILABLE, + OAUTH_NOT_CONFIGURED, + OAUTH_AUTHORIZATION_CODE_NOT_FOUND, + OAUTH_TOKEN_EXCHANGE_FAILED, + OAUTH_TOKEN_REFRESH_FAILED, + OAUTH_BASE_URL_NOT_SET, + OAUTH_AUTHORIZING, + OAUTH_AUTHORIZATION_URL_GENERATED, + OAUTH_AUTHORIZATION_URL_GENERATION_FAILED, + OAUTH_AUTHORIZATION_CODE_EMPTY, + OAUTH_TOKEN_EXCHANGE_ERROR, + OAUTH_TOKEN_REFRESH_ERROR +) class OAuthHandler: @@ -26,16 +43,7 @@ class OAuthHandler: token exchange, refresh, and secure storage. """ - # Error messages - ACCESS_TOKEN_EXPIRED_MSG = "🔄 Access token expired, refreshing..." - NO_ACCESS_TOKEN_MSG = "No access token available. Please authenticate first." - NO_OAUTH_TOKENS_MSG = "No OAuth tokens available" - NO_REFRESH_TOKEN_MSG = "No refresh token available" - OAUTH_NOT_CONFIGURED_MSG = "OAuth is not configured. Please set up OAuth first." - INVALID_AUTHORIZATION_CODE_MSG = "Authorization code not found in redirect URL" - TOKEN_EXCHANGE_FAILED_MSG = "Token exchange failed" - TOKEN_REFRESH_FAILED_MSG = "Token refresh failed" - OAUTH_BASE_URL_NOT_SET_MSG = "OAuthBaseURL is not set" + # Base URLs OAUTH_BASE_URL = 'https://app.contentstack.com' DEVELOPER_HUB_BASE_URL = 'https://developerhub-api.contentstack.com' @@ -159,9 +167,9 @@ def authorize(self) -> str: Authorization URL for user to visit """ try: - print(f"OAuth Handler - authorize() called with app_id: {self.app_id}, client_id: {self.client_id}") # Debug + print(OAUTH_AUTHORIZING.format(app_id=self.app_id, client_id=self.client_id)) # Debug if not self._oauth_base_url: - raise ValueError(self.OAUTH_BASE_URL_NOT_SET_MSG) + raise ValueError(OAUTH_BASE_URL_NOT_SET) oauth_base = self._oauth_base_url.rstrip('/') base_url = f"{oauth_base}/#!/apps/{self.app_id}/authorize" params = { @@ -181,11 +189,11 @@ def authorize(self) -> str: query_string = urllib.parse.urlencode(params) final_url = f"{base_url}?{query_string}" - print(f"OAuth Handler - final authorization URL: {final_url}") # Debug + print(OAUTH_AUTHORIZATION_URL_GENERATED.format(final_url=final_url)) # Debug return final_url except Exception as e: - raise ValueError(f"Error generating authorization URL: {e}") + raise ValueError(OAUTH_AUTHORIZATION_URL_GENERATION_FAILED.format(error=e)) def handle_redirect(self, redirect_url: str) -> Dict: """ @@ -196,7 +204,7 @@ def handle_redirect(self, redirect_url: str) -> Dict: parsed_url = urlparse(redirect_url) query_params = parse_qs(parsed_url.query) if "code" not in query_params: - raise ValueError(self.INVALID_AUTHORIZATION_CODE_MSG) + raise ValueError(OAUTH_AUTHORIZATION_CODE_NOT_FOUND) authorization_code = query_params["code"][0] return self.exchange_code_for_token(authorization_code) @@ -207,7 +215,7 @@ def exchange_code_for_token(self, authorization_code: str) -> Dict: Dictionary containing token information """ if not authorization_code or not authorization_code.strip(): - raise ValueError("Authorization code cannot be empty") + raise ValueError(OAUTH_AUTHORIZATION_CODE_EMPTY) data = { "grant_type": "authorization_code", "code": authorization_code.strip(), @@ -237,7 +245,7 @@ def exchange_code_for_token(self, authorization_code: str) -> Dict: return token_data except requests.RequestException as e: - raise requests.RequestException(f"{self.TOKEN_EXCHANGE_FAILED_MSG}: {str(e)}") + raise requests.RequestException(OAUTH_TOKEN_EXCHANGE_ERROR.format(error=str(e))) def _save_tokens(self, token_data: Dict): """ @@ -268,11 +276,11 @@ def get_valid_access_token(self) -> str: Valid access token """ if self.is_token_expired(): - print(self.ACCESS_TOKEN_EXPIRED_MSG) + print(OAUTH_ACCESS_TOKEN_EXPIRED) self.refresh_access_token() access_token = self.get_access_token() if not access_token: - raise ValueError(self.NO_ACCESS_TOKEN_MSG) + raise ValueError(OAUTH_ACCESS_TOKEN_NOT_AVAILABLE) return access_token def is_token_expired(self) -> bool: @@ -300,10 +308,10 @@ def refresh_access_token(self) -> str: New access token """ if not self.api_client or not hasattr(self.api_client, 'oauth') or not self.api_client.oauth: - raise ValueError(self.NO_OAUTH_TOKENS_MSG) + raise ValueError(OAUTH_TOKENS_NOT_AVAILABLE) refresh_token = self.api_client.oauth.get('refreshToken') if not refresh_token: - raise ValueError(self.NO_REFRESH_TOKEN_MSG) + raise ValueError(OAUTH_REFRESH_TOKEN_NOT_AVAILABLE) data = { "grant_type": "refresh_token", "refresh_token": refresh_token, @@ -327,7 +335,7 @@ def refresh_access_token(self) -> str: return self._access_token except requests.RequestException as e: - raise requests.RequestException(f"{self.TOKEN_REFRESH_FAILED_MSG}: {str(e)}") + raise requests.RequestException(OAUTH_TOKEN_REFRESH_ERROR.format(error=str(e))) def logout(self, revoke_authorization: bool = True) -> bool: """ diff --git a/contentstack_management/oauth/oauth_interceptor.py b/contentstack_management/oauth/oauth_interceptor.py index 8888666..494672a 100644 --- a/contentstack_management/oauth/oauth_interceptor.py +++ b/contentstack_management/oauth/oauth_interceptor.py @@ -8,6 +8,11 @@ import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry +from .._messages import ( + OAUTH_TOKEN_REFRESH_FAILED, + OAUTH_TOKENS_NOT_AVAILABLE, + OAUTH_TOKEN_REFRESH_FAILED_AFTER_401 +) class OAuthInterceptor: """ @@ -16,9 +21,6 @@ class OAuthInterceptor: MAX_RETRIES = 3 REFRESH_TIMEOUT = 30 TOKEN_ENDPOINT_PATH = "/token" - TOKEN_REFRESH_FAILED_MSG = "Token refresh failed" - NO_VALID_TOKENS_MSG = "OAuth: No valid tokens available" - TOKEN_REFRESH_FAILED_AFTER_401_MSG = "OAuth: Token refresh failed after 401" # User agent strings USER_AGENT = "contentstack-python-management-sdk" X_USER_AGENT = "contentstack-python-management-sdk" @@ -111,7 +113,7 @@ def _ensure_valid_token(self) -> bool: self.oauth_handler.refresh_access_token() return True except Exception as e: - print(f"{self.TOKEN_REFRESH_FAILED_MSG}: {e}") + print(OAUTH_TOKEN_REFRESH_FAILED.format(error=e)) return False return True @@ -125,7 +127,7 @@ def execute_request(self, method: str, url: str, **kwargs) -> requests.Response: if self.TOKEN_ENDPOINT_PATH in url: return self._make_request(method, url, **kwargs) if not self._ensure_valid_token(): - raise requests.RequestException(self.NO_VALID_TOKENS_MSG) + raise requests.RequestException(OAUTH_TOKENS_NOT_AVAILABLE) return self._execute_with_retry(method, url, 0, **kwargs) def _execute_with_retry(self, method: str, url: str, retry_count: int, **kwargs) -> requests.Response: @@ -159,7 +161,7 @@ def _execute_with_retry(self, method: str, url: str, retry_count: int, **kwargs) kwargs['headers'] = headers return self._execute_with_retry(method, url, retry_count + 1, **kwargs) except Exception as e: - raise requests.RequestException(f"{self.TOKEN_REFRESH_FAILED_AFTER_401_MSG}: {e}") + raise requests.RequestException(OAUTH_TOKEN_REFRESH_FAILED_AFTER_401.format(error=e)) if status_code == 429 or (status_code >= 500 and status_code != 501): # Calculate delay with exponential backoff diff --git a/contentstack_management/organizations/organization.py b/contentstack_management/organizations/organization.py index 1324704..391815f 100644 --- a/contentstack_management/organizations/organization.py +++ b/contentstack_management/organizations/organization.py @@ -1,5 +1,6 @@ import json from ..common import Parameter +from .._messages import ORGANIZATION_UID_REQUIRED class Organization(Parameter): @@ -46,7 +47,7 @@ def fetch(self): ------------------------------- """ if self.organization_uid is None or '': - raise Exception('organization_uid is required') + raise Exception(ORGANIZATION_UID_REQUIRED) return self.client.get(self._path, headers=self.client.headers, params = self.params) def roles(self): @@ -65,7 +66,7 @@ def roles(self): """ url = f"{self._path}/roles" if self.organization_uid is None or '': - raise Exception('organization_uid is required') + raise Exception(ORGANIZATION_UID_REQUIRED) return self.client.get(url, headers=self.client.headers, params = self.params) def add_users(self, user_data): @@ -99,7 +100,7 @@ def add_users(self, user_data): """ url = f"{self._path}/share" if self.organization_uid is None or '': - raise Exception('organization_uid is required') + raise Exception(ORGANIZATION_UID_REQUIRED) data = json.dumps(user_data) return self.client.post(url, headers=self.client.headers, data=data, params = self.params) @@ -120,7 +121,7 @@ def transfer_ownership(self, data): """ url = f"{self._path}/transfer-ownership" if self.organization_uid is None or '': - raise Exception('organization_uid is required') + raise Exception(ORGANIZATION_UID_REQUIRED) data = json.dumps(data) return self.client.post(url, headers=self.client.headers, data=data, params = self.params) @@ -138,7 +139,7 @@ def stacks(self): """ url = f"{self._path}/stacks" if self.organization_uid is None or '': - raise Exception('organization_uid is required') + raise Exception(ORGANIZATION_UID_REQUIRED) return self.client.get(url, headers=self.client.headers, params = self.params) def logs(self): @@ -155,5 +156,5 @@ def logs(self): """ url = f"{self._path}/logs" if self.organization_uid is None or '': - raise Exception('organization_uid is required') + raise Exception(ORGANIZATION_UID_REQUIRED) return self.client.get(url, headers=self.client.headers, params=self.params) diff --git a/contentstack_management/publish_queue/publish_queue.py b/contentstack_management/publish_queue/publish_queue.py index 2be0d2d..2623d89 100644 --- a/contentstack_management/publish_queue/publish_queue.py +++ b/contentstack_management/publish_queue/publish_queue.py @@ -5,6 +5,7 @@ from ..common import Parameter from .._errors import ArgumentException +from .._messages import PUBLISH_QUEUE_UID_REQUIRED class PublishQueue(Parameter): """ @@ -83,4 +84,4 @@ def cancel(self): def validate_uid(self): if self.publish_queue_uid is None or '': - raise ArgumentException("Publish Queue Uid is required") \ No newline at end of file + raise ArgumentException(PUBLISH_QUEUE_UID_REQUIRED) \ No newline at end of file diff --git a/contentstack_management/release_items/release_item.py b/contentstack_management/release_items/release_item.py index 60bc5a3..97f038a 100644 --- a/contentstack_management/release_items/release_item.py +++ b/contentstack_management/release_items/release_item.py @@ -6,6 +6,7 @@ import json from ..common import Parameter from .._errors import ArgumentException +from .._messages import RELEASE_UID_REQUIRED class ReleaseItems(Parameter): """ @@ -247,7 +248,7 @@ def move(self, data: dict): def validate_release_uid(self): if self.release_uid is None or '': - raise ArgumentException('Releases Uid is required') + raise ArgumentException(RELEASE_UID_REQUIRED) diff --git a/contentstack_management/releases/release.py b/contentstack_management/releases/release.py index e3d3d4f..e7b4afd 100644 --- a/contentstack_management/releases/release.py +++ b/contentstack_management/releases/release.py @@ -7,6 +7,7 @@ from ..common import Parameter from .._errors import ArgumentException from ..release_items.release_item import ReleaseItems +from .._messages import RELEASE_UID_REQUIRED class Releases(Parameter): """ @@ -192,7 +193,7 @@ def clone(self, data: dict): def validate_uid(self): if self.release_uid is None or '': - raise ArgumentException("Releases Uid is required") + raise ArgumentException(RELEASE_UID_REQUIRED) def item(self, headers: dict = None): self.validate_uid() diff --git a/contentstack_management/roles/roles.py b/contentstack_management/roles/roles.py index ef37f2c..d4e445e 100644 --- a/contentstack_management/roles/roles.py +++ b/contentstack_management/roles/roles.py @@ -6,6 +6,7 @@ import json from ..common import Parameter from .._errors import ArgumentException +from .._messages import ROLE_UID_REQUIRED class Roles(Parameter): """ @@ -291,5 +292,5 @@ def delete(self): def validate_uid(self): if self.role_uid is None or '': - raise ArgumentException('Role Uid is required') + raise ArgumentException(ROLE_UID_REQUIRED) \ No newline at end of file diff --git a/contentstack_management/stack/stack.py b/contentstack_management/stack/stack.py index 6ef142f..78bec4c 100644 --- a/contentstack_management/stack/stack.py +++ b/contentstack_management/stack/stack.py @@ -22,6 +22,7 @@ from ..extensions.extension import Extension from ..variant_group.variant_group import VariantGroup from ..variants.variants import Variants +from .._messages import API_KEY_REQUIRED, USER_ID_REQUIRED, OWNERSHIP_TOKEN_REQUIRED class Stack(Parameter): @@ -141,7 +142,7 @@ def update_user_role(self, data): ------------------------------- """ if 'api_key' not in self.client.headers: - raise Exception('api_key is required') + raise Exception(API_KEY_REQUIRED) data = json.dumps(data) return self.client.put('stacks/users/roles', headers=self.client.headers, params=self.params, data=data) @@ -160,7 +161,7 @@ def transfer_ownership(self, data): ------------------------------- """ if 'api_key' not in self.client.headers: - raise Exception('api_key is required') + raise Exception(API_KEY_REQUIRED) data = json.dumps(data) return self.client.post('stacks/transfer_ownership', headers=self.client.headers, data=data, params = self.params) @@ -176,11 +177,11 @@ def accept_ownership(self, user_id, ownership_token): ------------------------------- """ if 'api_key' not in self.client.headers: - raise PermissionError('api_key is required') + raise PermissionError(API_KEY_REQUIRED) if user_id is None or '': - raise PermissionError('user_id is required') + raise PermissionError(USER_ID_REQUIRED) if ownership_token is None or '': - raise PermissionError('ownership_token is required') + raise PermissionError(OWNERSHIP_TOKEN_REQUIRED) url = f"stacks/accept_ownership/{ownership_token}" self.params.update({'api_key': self.client.headers['api_key'], 'uid': user_id}) return self.client.get(url, headers=self.client.headers, params=self.params) @@ -197,7 +198,7 @@ def settings(self): ------------------------------- """ if 'api_key' not in self.client.headers: - raise Exception('api_key is required') + raise Exception(API_KEY_REQUIRED) return self.client.get('stacks/settings', headers=self.client.headers, params=self.params) def create_settings(self, data): @@ -225,7 +226,7 @@ def create_settings(self, data): ------------------------------- """ if 'api_key' not in self.client.headers: - raise Exception('api_key is required') + raise Exception(API_KEY_REQUIRED) data = json.dumps(data) return self.client.post('stacks/settings', headers=self.client.headers, params=self.params, data=data) @@ -244,7 +245,7 @@ def reset_settings(self, data): ------------------------------- """ if 'api_key' not in self.client.headers: - raise Exception('api_key is required') + raise Exception(API_KEY_REQUIRED) data = json.dumps(data) return self.client.post('stacks/settings/reset', headers=self.client.headers, data=data, params = self.params) @@ -270,7 +271,7 @@ def share(self, data): ------------------------------- """ if 'api_key' not in self.client.headers: - raise Exception('api_key is required') + raise Exception(API_KEY_REQUIRED) data = json.dumps(data) return self.client.post('stacks/share', headers=self.client.headers, params=self.params, data=data) @@ -291,7 +292,7 @@ def unshare(self, data): ------------------------------- """ if 'api_key' not in self.client.headers: - raise Exception('api_key is required') + raise Exception(API_KEY_REQUIRED) data = json.dumps(data) return self.client.post('stacks/unshare', headers=self.client.headers, params=self.params, data=data) diff --git a/contentstack_management/taxonomies/taxonomy.py b/contentstack_management/taxonomies/taxonomy.py index a6583bd..1223a28 100644 --- a/contentstack_management/taxonomies/taxonomy.py +++ b/contentstack_management/taxonomies/taxonomy.py @@ -7,6 +7,7 @@ from ..common import Parameter from .._errors import ArgumentException from ..terms.terms import Terms +from .._messages import TAXONOMY_UID_REQUIRED class Taxonomy(Parameter): """ @@ -145,7 +146,7 @@ def delete(self, taxonomy_uid: str = None): def validate_taxonomy_uid(self): if self.taxonomy_uid is None or '': - raise ArgumentException('Taxonomy Uid is required') + raise ArgumentException(TAXONOMY_UID_REQUIRED) def terms(self, terms_uid: str = None): self.validate_taxonomy_uid() diff --git a/contentstack_management/terms/terms.py b/contentstack_management/terms/terms.py index cbac34a..18d5de1 100644 --- a/contentstack_management/terms/terms.py +++ b/contentstack_management/terms/terms.py @@ -6,6 +6,7 @@ import json from ..common import Parameter from .._errors import ArgumentException +from .._messages import TAXONOMY_UID_REQUIRED, TERMS_UID_REQUIRED, TERM_STRING_REQUIRED class Terms(Parameter): """ @@ -283,15 +284,15 @@ def descendants(self, terms_uid: str = None): def validate_taxonomy_uid(self): if self.taxonomy_uid is None or '': - raise ArgumentException('Taxonomy Uid is required') + raise ArgumentException(TAXONOMY_UID_REQUIRED) def validate_terms_uid(self): if self.terms_uid is None or '': - raise ArgumentException('Terms Uid is required') + raise ArgumentException(TERMS_UID_REQUIRED) def validate_term_string(self, term_string): if term_string is None or '': - raise ArgumentException('Term String is required') + raise ArgumentException(TERM_STRING_REQUIRED) \ No newline at end of file diff --git a/contentstack_management/user_session/user_session.py b/contentstack_management/user_session/user_session.py index 91588cd..713d8a3 100644 --- a/contentstack_management/user_session/user_session.py +++ b/contentstack_management/user_session/user_session.py @@ -1,4 +1,5 @@ import json +from .._messages import EMAIL_ID_REQUIRED, PASSWORD_REQUIRED _path = "user-session" @@ -49,11 +50,11 @@ def login(self, email=None, password=None, tfa_token=None): if email is None or email == '': raise PermissionError( - 'Email Id is required') + EMAIL_ID_REQUIRED) if password is None or password == '': raise PermissionError( - 'Password is required') + PASSWORD_REQUIRED) data = { "user": { diff --git a/contentstack_management/variant_group/variant_group.py b/contentstack_management/variant_group/variant_group.py index f57d67b..1138fef 100644 --- a/contentstack_management/variant_group/variant_group.py +++ b/contentstack_management/variant_group/variant_group.py @@ -7,6 +7,7 @@ from ..common import Parameter from .._errors import ArgumentException from ..variants.variants import Variants +from .._messages import VARIANT_GROUP_UID_REQUIRED class VariantGroup(Parameter): """ @@ -218,4 +219,4 @@ def validate_uid(self): """ if self.variant_group_uid is None or self.variant_group_uid == '': - raise ArgumentException("variant group Uid is required") \ No newline at end of file + raise ArgumentException(VARIANT_GROUP_UID_REQUIRED) \ No newline at end of file diff --git a/contentstack_management/variants/variants.py b/contentstack_management/variants/variants.py index b19a8d7..0c57192 100644 --- a/contentstack_management/variants/variants.py +++ b/contentstack_management/variants/variants.py @@ -6,6 +6,7 @@ import json from ..common import Parameter from .._errors import ArgumentException +from .._messages import VARIANT_UIDS_NON_EMPTY_LIST_REQUIRED, VARIANT_GROUP_UID_REQUIRED, VARIANT_UID_REQUIRED class Variants(Parameter): """ @@ -225,7 +226,7 @@ def fetchByUIDs(self, variant_uids: list): ------------------------------- """ if not isinstance(variant_uids, list) or len(variant_uids) == 0: - raise ArgumentException("variant_uids must be a non-empty list") + raise ArgumentException(VARIANT_UIDS_NON_EMPTY_LIST_REQUIRED) if self.variant_group_uid: self.validate_variant_group_uid() @@ -244,7 +245,7 @@ def validate_variant_group_uid(self): """ if self.variant_group_uid is None or self.variant_group_uid == '': - raise ArgumentException("variant group Uid is required") + raise ArgumentException(VARIANT_GROUP_UID_REQUIRED) def validate_variant_uid(self): """ @@ -253,4 +254,4 @@ def validate_variant_uid(self): """ if self.variant_uid is None or self.variant_uid == '': - raise ArgumentException("variant Uid is required") \ No newline at end of file + raise ArgumentException(VARIANT_UID_REQUIRED) \ No newline at end of file diff --git a/contentstack_management/webhooks/webhook.py b/contentstack_management/webhooks/webhook.py index f94182e..6694909 100644 --- a/contentstack_management/webhooks/webhook.py +++ b/contentstack_management/webhooks/webhook.py @@ -5,6 +5,7 @@ import json from ..common import Parameter +from .._messages import WEBHOOK_UID_REQUIRED, WEBHOOK_FILE_PATH_REQUIRED, WEBHOOK_EXECUTION_UID_REQUIRED class Webhook(Parameter): """ @@ -61,7 +62,7 @@ def fetch(self): ------------------------------- """ if self.webhook_uid is None: - raise Exception('Webhook uid is required') + raise Exception(WEBHOOK_UID_REQUIRED) url = f"{self.path}/{self.webhook_uid}" return self.client.get(url, headers = self.client.headers, params = self.params) @@ -164,7 +165,7 @@ def update(self, data): """ if self.webhook_uid is None: - raise Exception('Webhook uid is required') + raise Exception(WEBHOOK_UID_REQUIRED) url = f"{self.path}/{self.webhook_uid}" data = json.dumps(data) return self.client.put(url, headers = self.client.headers, data=data, params = self.params) @@ -188,7 +189,7 @@ def delete(self): if self.webhook_uid is None: - raise Exception('Webhook uid is required') + raise Exception(WEBHOOK_UID_REQUIRED) if self.client.headers['Content-Type'] is not None: self.client.headers.pop('Content-Type') url = f"{self.path}/{self.webhook_uid}" @@ -218,7 +219,7 @@ def imports(self, file_path): """ if file_path is None: - raise Exception('File path is required') + raise Exception(WEBHOOK_FILE_PATH_REQUIRED) url = f"{self.path}/import" self.client.headers['Content-Type'] = "multipart/form-data" files = {'entry': open(f"{file_path}",'rb')} @@ -243,7 +244,7 @@ def export(self): """ if self.webhook_uid is None: - raise Exception('Webhok uid is required') + raise Exception(WEBHOOK_UID_REQUIRED) url = f"{self.path}/{self.webhook_uid}/export" return self.client.get(url, headers = self.client.headers, params = self.params) @@ -264,7 +265,7 @@ def executions(self): """ if self.webhook_uid is None: - raise Exception('Webhook uid is required') + raise Exception(WEBHOOK_UID_REQUIRED) url = f"{self.path}/{self.webhook_uid}/executions" return self.client.get(url, headers = self.client.headers, params = self.params) @@ -287,7 +288,7 @@ def retry(self, execution_uid): """ if execution_uid is None: - raise Exception('Execution uid is required') + raise Exception(WEBHOOK_EXECUTION_UID_REQUIRED) url = f"{self.path}/{execution_uid}/retry" return self.client.post(url, headers = self.client.headers, params = self.params) @@ -312,7 +313,7 @@ def logs(self, execution_uid): ------------------------------- """ if execution_uid is None: - raise Exception('Execution uid is required') + raise Exception(WEBHOOK_EXECUTION_UID_REQUIRED) url = f"{self.path}/{execution_uid}/logs" return self.client.get(url, headers = self.client.headers, params = self.params) diff --git a/contentstack_management/workflows/workflows.py b/contentstack_management/workflows/workflows.py index c9825c7..0e08152 100644 --- a/contentstack_management/workflows/workflows.py +++ b/contentstack_management/workflows/workflows.py @@ -5,6 +5,7 @@ import json from ..common import Parameter +from .._messages import WORKFLOW_UID_REQUIRED, WORKFLOW_CONTENT_TYPE_UID_REQUIRED, WORKFLOW_ENTRY_UID_REQUIRED, WORKFLOW_RULE_UID_REQUIRED class Workflows(Parameter): """ @@ -58,7 +59,7 @@ def fetch(self): ------------------------------- """ if self.workflow_uid is None: - raise Exception('workflow uid is required') + raise Exception(WORKFLOW_UID_REQUIRED) url = f"{self.path}/{self.workflow_uid}" return self.client.get(url, headers = self.client.headers, params = self.params) @@ -240,7 +241,7 @@ def update(self, data): """ if self.workflow_uid is None: - raise Exception('workflow uid is required') + raise Exception(WORKFLOW_UID_REQUIRED) url = f"{self.path}/{self.workflow_uid}" data = json.dumps(data) return self.client.put(url, headers = self.client.headers, data=data, params = self.params) @@ -264,7 +265,7 @@ def delete(self): if self.workflow_uid is None: - raise Exception('workflow uid is required') + raise Exception(WORKFLOW_UID_REQUIRED) url = f"{self.path}/{self.workflow_uid}" return self.client.delete(url, headers = self.client.headers, params = self.params) @@ -287,7 +288,7 @@ def disable(self): """ if self.workflow_uid is None: - raise Exception('workflow uid is required') + raise Exception(WORKFLOW_UID_REQUIRED) url = f"{self.path}/{self.workflow_uid}/disable" return self.client.get(url, headers = self.client.headers, params = self.params) @@ -307,7 +308,7 @@ def enable(self): """ if self.workflow_uid is None: - raise Exception('workflow uid is required') + raise Exception(WORKFLOW_UID_REQUIRED) url = f"{self.path}/{self.workflow_uid}/enable" return self.client.get(url, headers = self.client.headers, params = self.params) @@ -354,9 +355,9 @@ def set_workflow_stage(self, content_type_uid, entry_uid, data): if content_type_uid is None: - raise Exception('Content type uid is required') + raise Exception(WORKFLOW_CONTENT_TYPE_UID_REQUIRED) if entry_uid is None: - raise Exception('Entry uid is required') + raise Exception(WORKFLOW_ENTRY_UID_REQUIRED) url = f"content_types/{content_type_uid}/entries/{entry_uid}/workflow" data = json.dumps(data) return self.client.post(url, headers = self.client.headers, data = data, params = self.params) @@ -454,7 +455,7 @@ def update_publish_rule(self, rule_uid, data): """ if rule_uid is None: - raise Exception('Rule uid is required') + raise Exception(WORKFLOW_RULE_UID_REQUIRED) url = f"{self.path}/publishing_rules/{rule_uid}" data = json.dumps(data) return self.client.put(url, headers = self.client.headers, data = data, params = self.params) @@ -479,7 +480,7 @@ def delete_publish_rule(self, rule_uid): """ if rule_uid is None: - raise Exception('Rule uid is required') + raise Exception(WORKFLOW_RULE_UID_REQUIRED) url = f"{self.path}/publishing_rules/{rule_uid}" return self.client.delete(url, headers = self.client.headers, params = self.params) @@ -502,7 +503,7 @@ def fetch_publish_rule(self, rule_uid): """ if rule_uid is None: - raise Exception('Rule uid is required') + raise Exception(WORKFLOW_RULE_UID_REQUIRED) url = f"{self.path}/publishing_rules/{rule_uid}" return self.client.get(url, headers = self.client.headers, params = self.params) @@ -544,7 +545,7 @@ def fetch_publish_rule_content_type(self, content_type_uid): """ if content_type_uid is None: - raise Exception('Content type uid is required') + raise Exception(WORKFLOW_CONTENT_TYPE_UID_REQUIRED) url = f"{self.path}/content_type/{content_type_uid}" return self.client.get(url, headers = self.client.headers, params = self.params) @@ -571,9 +572,9 @@ def publish_request_approval(self, content_type_uid, entry_uid): """ if content_type_uid is None: - raise Exception('Content type uid is required') + raise Exception(WORKFLOW_CONTENT_TYPE_UID_REQUIRED) if entry_uid is None: - raise Exception('Entry uid is required') + raise Exception(WORKFLOW_ENTRY_UID_REQUIRED) url = f"content_types/{content_type_uid}/entries/{entry_uid}/workflow" return self.client.get(url, headers = self.client.headers, params = self.params) From c1923ddd96ac17d74a07fe776f65ab6b189a96ec Mon Sep 17 00:00:00 2001 From: reeshika-h Date: Mon, 8 Dec 2025 12:22:52 +0530 Subject: [PATCH 2/2] Update exception messages in OAuth and TOTP tests for clarity and consistency --- tests/unit/test_oauth_handler.py | 6 +++--- tests/unit/user_session/test_user_session_totp.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/unit/test_oauth_handler.py b/tests/unit/test_oauth_handler.py index 5b3564f..f348ac9 100644 --- a/tests/unit/test_oauth_handler.py +++ b/tests/unit/test_oauth_handler.py @@ -160,7 +160,7 @@ def test_handle_redirect_no_code(self): with self.assertRaises(ValueError) as context: self.oauth_handler_with_secret.handle_redirect(redirect_url) - self.assertIn("Authorization code not found", str(context.exception)) + self.assertIn("Authorization code was not found in the redirect URL", str(context.exception)) def test_exchange_code_for_token_success(self): """Test successful code exchange for token.""" @@ -242,7 +242,7 @@ def test_refresh_access_token_no_refresh_token(self): with self.assertRaises(ValueError) as context: self.oauth_handler_with_secret.refresh_access_token() - self.assertIn("No refresh token available", str(context.exception)) + self.assertIn("Refresh token is not available", str(context.exception)) def test_refresh_access_token_failure(self): """Test refresh access token failure.""" @@ -305,7 +305,7 @@ def test_get_valid_access_token_no_refresh_token(self): with self.assertRaises(ValueError) as context: self.oauth_handler_with_secret.get_valid_access_token() - self.assertIn("No refresh token available", str(context.exception)) + self.assertIn("Refresh token is not available", str(context.exception)) def test_logout_success(self): """Test successful logout.""" diff --git a/tests/unit/user_session/test_user_session_totp.py b/tests/unit/user_session/test_user_session_totp.py index 9107fee..faa8c88 100644 --- a/tests/unit/user_session/test_user_session_totp.py +++ b/tests/unit/user_session/test_user_session_totp.py @@ -116,7 +116,7 @@ def test_login_parameter_validation(self): # Test with empty email with self.assertRaises(PermissionError) as context: self.user_session.login("", self.test_password, self.test_tfa_token) - self.assertIn("Email Id is required", str(context.exception)) + self.assertIn("Email ID is required", str(context.exception)) # Test with empty password with self.assertRaises(PermissionError) as context: