From 174f6f8309a1b4fc999fd79c360d28c8c0996c9f Mon Sep 17 00:00:00 2001 From: sunil-lakshman <104969541+sunil-lakshman@users.noreply.github.com> Date: Thu, 5 Jun 2025 11:48:46 +0530 Subject: [PATCH 1/7] Added nested global fields support --- CHANGELOG.md | 6 +++ contentstack_management/__init__.py | 2 +- .../global_fields/global_fields.py | 54 ++++++++++++++++--- contentstack_management/stack/stack.py | 6 +-- .../global_fields/test_global_fields_api.py | 34 +++++++----- .../test_global_fields_unittest.py | 38 +++++++++++++ 6 files changed, 113 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6f7ffe..dd99cca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Content Management SDK For Python --- +## v1.5.0 + +#### Date: 09 June 2025 + +- Added Nested Global fields support. +--- ## v1.4.0 #### Date: 26 May 2025 diff --git a/contentstack_management/__init__.py b/contentstack_management/__init__.py index 849cd80..bcfeb42 100644 --- a/contentstack_management/__init__.py +++ b/contentstack_management/__init__.py @@ -72,7 +72,7 @@ __author__ = 'dev-ex' __status__ = 'debug' __region__ = 'na' -__version__ = '1.4.0' +__version__ = '1.5.0' __host__ = 'api.contentstack.io' __protocol__ = 'https://' __api_version__ = 'v3' diff --git a/contentstack_management/global_fields/global_fields.py b/contentstack_management/global_fields/global_fields.py index d681b49..0e040ed 100644 --- a/contentstack_management/global_fields/global_fields.py +++ b/contentstack_management/global_fields/global_fields.py @@ -18,10 +18,13 @@ class GlobalFields(Parameter): methods each correspond to the CRUD operations that can be performed on the API """ - def __init__(self, client, global_field_uid=None): + def __init__(self, client, global_field_uid=None, options=None): self.client = client self.global_field_uid = global_field_uid + self.options = options super().__init__(self.client) + if self.options and'api_version' in self.options: + Parameter.add_header(self, 'api_version', str(self.options['api_version'])) def find(self): """ @@ -34,7 +37,12 @@ def find(self): >>> result = client.stack("api_key").global_fields('global_field_uid').find().json() ------------------------------- """ - return self.client.get(_path, headers=self.client.headers, params = self.params) + response = self.client.get(_path, headers=self.client.headers, params = self.params) + # Remove the api_version header after request + if self.options and 'api_version' in self.options: + self.client.headers.pop('api_version', None) + + return response def fetch(self): """ @@ -50,7 +58,12 @@ def fetch(self): ------------------------------- """ url = f"{_path}/{self.global_field_uid}" - return self.client.get(url, headers=self.client.headers, params = self.params) + response = self.client.get(url, headers=self.client.headers, params = self.params) + # Remove the api_version header after request + if self.options and 'api_version' in self.options: + self.client.headers.pop('api_version', None) + + return response def create(self, data): """ @@ -74,7 +87,12 @@ def create(self, data): ------------------------------- """ data = json.dumps(data) - return self.client.post(_path, headers=self.client.headers, data=data, params = self.params) + response = self.client.post(_path, headers=self.client.headers, data=data, params = self.params) + # Remove the api_version header after request + if self.options and 'api_version' in self.options: + self.client.headers.pop('api_version', None) + + return response def update(self, data): """ @@ -99,7 +117,12 @@ def update(self, data): """ url = f"{_path}/{self.global_field_uid}" data = json.dumps(data) - return self.client.put(url, headers=self.client.headers, params=self.params, data=data) + response = self.client.put(url, headers=self.client.headers, params=self.params, data=data) + # Remove the api_version header after request + if self.options and 'api_version' in self.options: + self.client.headers.pop('api_version', None) + + return response def delete(self): """ @@ -114,7 +137,12 @@ def delete(self): ------------------------------- """ url = f"{_path}/{self.global_field_uid}" - return self.client.delete(url, headers=self.client.headers, params=self.params) + response = self.client.delete(url, headers=self.client.headers, params=self.params) + # Remove the api_version header after request + if self.options and 'api_version' in self.options: + self.client.headers.pop('api_version', None) + + return response def imports(self, file_path): """ @@ -131,7 +159,12 @@ def imports(self, file_path): """ self.client.headers['Content-Type'] = "multipart/form-data" files = {'global_field': open(f"{file_path}", 'rb')} - return self.client.post('global_fields/import', headers=self.client.headers, params=self.params, files=files) + response = self.client.post('global_fields/import', headers=self.client.headers, params=self.params, files=files) + # Remove the api_version header after request + if self.options and 'api_version' in self.options: + self.client.headers.pop('api_version', None) + + return response def export(self): """ @@ -148,4 +181,9 @@ def export(self): if self.global_field_uid is None or '': raise Exception('global_field_uid is required') url = f"{_path}/{self.global_field_uid}/export" - return self.client.get(url, headers=self.client.headers, params=self.params) + response = self.client.get(url, headers=self.client.headers, params=self.params) + # Remove the api_version header after request + if self.options and 'api_version' in self.options: + self.client.headers.pop('api_version', None) + + return response diff --git a/contentstack_management/stack/stack.py b/contentstack_management/stack/stack.py index 9d40699..8fe4ee5 100644 --- a/contentstack_management/stack/stack.py +++ b/contentstack_management/stack/stack.py @@ -293,10 +293,8 @@ def unshare(self, data): data = json.dumps(data) return self.client.post('stacks/unshare', headers=self.client.headers, params=self.params, data=data) - def global_fields(self, global_field_uid=None): - if 'api_key' not in self.client.headers: - raise Exception('api_key is required') - return GlobalFields(self.client, global_field_uid) + def global_fields(self, global_field_uid=None, options=None): + return GlobalFields(self.client, global_field_uid, options) def branch(self, branch_uid=None): return Branch(self.client, branch_uid) diff --git a/tests/api/global_fields/test_global_fields_api.py b/tests/api/global_fields/test_global_fields_api.py index e230971..8fe168e 100644 --- a/tests/api/global_fields/test_global_fields_api.py +++ b/tests/api/global_fields/test_global_fields_api.py @@ -8,7 +8,7 @@ password = credentials["password"] host = credentials["host"] api_key = credentials["api_key"] -global_field_uid = credentials["global_field_uid"] +global_field_uid = 'global_field_uid' # Replace with actual UID or fetch from response if available class GlobalFieldsApiTests(unittest.TestCase): @@ -23,13 +23,27 @@ def read_file(self, file_name): infile.close() return data - + def test_create_global_fields(self): + read_mock_global_fileds_data = self.read_file("create_global_fields.json") + read_mock_global_fileds_data = json.loads(read_mock_global_fileds_data) + response = self.client.stack(api_key).global_fields().create(read_mock_global_fileds_data) + global_field_uid = response.data.get('uid', 'global_field_uid') + self.assertIsNotNone(global_field_uid, "Global field UID should not be None") + self.assertEqual(response.status_code, 201) + + def test_create_nested_global_fields(self): + read_mock_global_fileds_data = self.read_file("create_global_fields.json") + read_mock_global_fileds_data = json.loads(read_mock_global_fileds_data) + response = self.client.stack(api_key).global_fields(options={'api_version': 3.2}).create(read_mock_global_fileds_data) + global_field_uid1 = response.data.get('uid', 'global_field_uid') + self.assertIsNotNone(global_field_uid1, "Global field UID should not be None") + self.assertEqual(response.status_code, 201) + def test_fetch_global_fields(self): response = self.client.stack(api_key).global_fields(global_field_uid).fetch() - if response.status_code == 200: - self.assertEqual(response.status_code, 200) - else: - self.assertEqual(response.status_code, 422) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.data.get('uid'), global_field_uid, "Fetched global field UID should match the provided UID") + def test_find_all_global_fields(self): response = self.client.stack(api_key).global_fields().find() @@ -38,14 +52,6 @@ def test_find_all_global_fields(self): else: self.assertEqual(response.status_code, 400) - def test_create_global_fields(self): - read_mock_global_fileds_data = self.read_file("create_global_fields.json") - read_mock_global_fileds_data = json.loads(read_mock_global_fileds_data) - response = self.client.stack(api_key).global_fields().create(read_mock_global_fileds_data) - if response.status_code == 200: - self.assertEqual(response.status_code, 200) - else: - self.assertEqual(response.status_code, 422) def test_update_global_fields(self): read_mock_global_fileds_data = self.read_file("create_global_fields.json") diff --git a/tests/unit/global_fields/test_global_fields_unittest.py b/tests/unit/global_fields/test_global_fields_unittest.py index 62499a0..e233619 100644 --- a/tests/unit/global_fields/test_global_fields_unittest.py +++ b/tests/unit/global_fields/test_global_fields_unittest.py @@ -73,6 +73,44 @@ def test_export_global_fields(self): self.assertEqual(response.request.method, "GET") self.assertEqual(response.request.headers["Content-Type"], "application/json") self.assertEqual(response.request.body, None) + + def test_create_nested_global_fields(self): + read_mock_global_fileds_data = self.read_file("create_global_fields.json") + read_mock_global_fileds_data = json.loads(read_mock_global_fileds_data) + response = self.client.stack(api_key).global_fields(options={"api_version": 3.2}).create(read_mock_global_fileds_data) + self.assertEqual(response.request.url, f"{self.client.endpoint}global_fields") + self.assertEqual(response.request.method, "POST") + self.assertEqual(response.request.headers["Content-Type"], "application/json") + self.assertEqual(response.request.headers["api_version"], "3.2") + + def test_update_nested_global_fields(self): + read_mock_global_fileds_data = self.read_file("create_global_fields.json") + read_mock_global_fileds_data = json.loads(read_mock_global_fileds_data) + response = self.client.stack(api_key).global_fields(global_field_uid, options={"api_version": 3.2}).update(read_mock_global_fileds_data) + self.assertEqual(response.request.url, f"{self.client.endpoint}global_fields/{global_field_uid}") + self.assertEqual(response.request.method, "PUT") + self.assertEqual(response.request.headers["api_version"], "3.2") + + def test_delete_nested_global_fields(self): + response= self.client.stack(api_key).global_fields(global_field_uid, options={"api_version": 3.2}).delete() + self.assertEqual(response.request.url, f"{self.client.endpoint}global_fields/{global_field_uid}") + self.assertEqual(response.request.method, "DELETE") + self.assertEqual(response.request.headers["api_version"], "3.2") + + def test_get_nested_global_field(self): + response = self.client.stack(api_key).global_fields(global_field_uid, options={"api_version": 3.2}).fetch() + self.assertEqual(response.request.url, f"{self.client.endpoint}global_fields/{global_field_uid}") + self.assertEqual(response.request.method, "GET") + self.assertEqual(response.request.headers["Content-Type"], "application/json") + self.assertEqual(response.request.headers["api_version"], "3.2") + self.assertEqual(response.request.body, None) + + def test_get_all_nested_global_fields(self): + response = self.client.stack(api_key).global_fields(options={"api_version": 3.2}).find() + self.assertEqual(response.request.url, f"{self.client.endpoint}global_fields") + self.assertEqual(response.request.method, "GET") + self.assertEqual(response.request.headers["Content-Type"], "application/json") + self.assertEqual(response.request.headers["api_version"], "3.2") From 410c13b84c686314af455ca57272d0b8150c267d Mon Sep 17 00:00:00 2001 From: sunil-lakshman <104969541+sunil-lakshman@users.noreply.github.com> Date: Thu, 5 Jun 2025 11:51:29 +0530 Subject: [PATCH 2/7] ignore the dummy secret values --- .talismanrc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.talismanrc b/.talismanrc index 8dc2dcc..8904a30 100644 --- a/.talismanrc +++ b/.talismanrc @@ -354,4 +354,10 @@ fileignoreconfig: checksum: c7323b95249759bc67c33d3a89d3d2e8b3ed3d146b944682d451ebebe22567c0 - filename: .github/workflows/secrets-scan.yml checksum: d79ec3f3288964f7d117b9ad319a54c0ebc152e35f69be8fde95522034fdfb2a -version: "" \ No newline at end of file +version: "" +fileignoreconfig: +- filename: tests/api/global_fields/test_global_fields_api.py + checksum: 1cd57383fcad33cfaddc03aec9a7ee3e85b27de35e4545462fca33e74768e812 +- filename: tests/unit/global_fields/test_global_fields_unittest.py + checksum: 9bb05624cf1dadb770b3cf17fbfe915cf3133d622110da30a7dfebdeab0a315c +version: "1.0" \ No newline at end of file From 09e006f7d7e965c5601d3f51f44c1fb6234e563f Mon Sep 17 00:00:00 2001 From: sunil-lakshman <104969541+sunil-lakshman@users.noreply.github.com> Date: Thu, 5 Jun 2025 12:05:14 +0530 Subject: [PATCH 3/7] Fixed copilot PR comments --- contentstack_management/global_fields/global_fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contentstack_management/global_fields/global_fields.py b/contentstack_management/global_fields/global_fields.py index 0e040ed..760532b 100644 --- a/contentstack_management/global_fields/global_fields.py +++ b/contentstack_management/global_fields/global_fields.py @@ -23,7 +23,7 @@ def __init__(self, client, global_field_uid=None, options=None): self.global_field_uid = global_field_uid self.options = options super().__init__(self.client) - if self.options and'api_version' in self.options: + if self.options and 'api_version' in self.options: Parameter.add_header(self, 'api_version', str(self.options['api_version'])) def find(self): From a98ea787c6f254a347d6925fd83f533725f4bb04 Mon Sep 17 00:00:00 2001 From: sunil-lakshman <104969541+sunil-lakshman@users.noreply.github.com> Date: Thu, 5 Jun 2025 12:57:46 +0530 Subject: [PATCH 4/7] Fixed copilot PR comments --- .../test_global_fields_unittest.py | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/unit/global_fields/test_global_fields_unittest.py b/tests/unit/global_fields/test_global_fields_unittest.py index e233619..86c043a 100644 --- a/tests/unit/global_fields/test_global_fields_unittest.py +++ b/tests/unit/global_fields/test_global_fields_unittest.py @@ -39,17 +39,17 @@ def test_get_all_global_fields(self): self.assertEqual(response.request.body, None) def test_create_global_fields(self): - read_mock_global_fileds_data = self.read_file("create_global_fields.json") - read_mock_global_fileds_data = json.loads(read_mock_global_fileds_data) - response = self.client.stack(api_key).global_fields().create(read_mock_global_fileds_data) + read_mock_global_fields_data = self.read_file("create_global_fields.json") + read_mock_global_fields_data = json.loads(read_mock_global_fields_data) + response = self.client.stack(api_key).global_fields().create(read_mock_global_fields_data) self.assertEqual(response.request.url, f"{self.client.endpoint}global_fields") self.assertEqual(response.request.method, "POST") self.assertEqual(response.request.headers["Content-Type"], "application/json") def test_update_global_fields(self): - read_mock_global_fileds_data = self.read_file("create_global_fields.json") - read_mock_global_fileds_data = json.loads(read_mock_global_fileds_data) - response = self.client.stack(api_key).global_fields(global_field_uid).update(read_mock_global_fileds_data) + read_mock_global_fields_data = self.read_file("create_global_fields.json") + read_mock_global_fields_data = json.loads(read_mock_global_fields_data) + response = self.client.stack(api_key).global_fields(global_field_uid).update(read_mock_global_fields_data) self.assertEqual(response.request.url, f"{self.client.endpoint}global_fields/{global_field_uid}") self.assertEqual(response.request.method, "PUT") self.assertEqual(response.request.headers["Content-Type"], "application/json") @@ -75,18 +75,18 @@ def test_export_global_fields(self): self.assertEqual(response.request.body, None) def test_create_nested_global_fields(self): - read_mock_global_fileds_data = self.read_file("create_global_fields.json") - read_mock_global_fileds_data = json.loads(read_mock_global_fileds_data) - response = self.client.stack(api_key).global_fields(options={"api_version": 3.2}).create(read_mock_global_fileds_data) + read_mock_global_fields_data = self.read_file("create_global_fields.json") + read_mock_global_fields_data = json.loads(read_mock_global_fields_data) + response = self.client.stack(api_key).global_fields(options={"api_version": 3.2}).create(read_mock_global_fields_data) self.assertEqual(response.request.url, f"{self.client.endpoint}global_fields") self.assertEqual(response.request.method, "POST") self.assertEqual(response.request.headers["Content-Type"], "application/json") self.assertEqual(response.request.headers["api_version"], "3.2") def test_update_nested_global_fields(self): - read_mock_global_fileds_data = self.read_file("create_global_fields.json") - read_mock_global_fileds_data = json.loads(read_mock_global_fileds_data) - response = self.client.stack(api_key).global_fields(global_field_uid, options={"api_version": 3.2}).update(read_mock_global_fileds_data) + read_mock_global_fields_data = self.read_file("create_global_fields.json") + read_mock_global_fields_data = json.loads(read_mock_global_fields_data) + response = self.client.stack(api_key).global_fields(global_field_uid, options={"api_version": 3.2}).update(read_mock_global_fields_data) self.assertEqual(response.request.url, f"{self.client.endpoint}global_fields/{global_field_uid}") self.assertEqual(response.request.method, "PUT") self.assertEqual(response.request.headers["api_version"], "3.2") From 8a7420cfe6bfcd7d116d22a79c9eab15b4f91f72 Mon Sep 17 00:00:00 2001 From: sunil-lakshman <104969541+sunil-lakshman@users.noreply.github.com> Date: Thu, 5 Jun 2025 12:59:13 +0530 Subject: [PATCH 5/7] Fixed PR comments --- .talismanrc | 2 -- 1 file changed, 2 deletions(-) diff --git a/.talismanrc b/.talismanrc index 8904a30..6527e8d 100644 --- a/.talismanrc +++ b/.talismanrc @@ -354,8 +354,6 @@ fileignoreconfig: checksum: c7323b95249759bc67c33d3a89d3d2e8b3ed3d146b944682d451ebebe22567c0 - filename: .github/workflows/secrets-scan.yml checksum: d79ec3f3288964f7d117b9ad319a54c0ebc152e35f69be8fde95522034fdfb2a -version: "" -fileignoreconfig: - filename: tests/api/global_fields/test_global_fields_api.py checksum: 1cd57383fcad33cfaddc03aec9a7ee3e85b27de35e4545462fca33e74768e812 - filename: tests/unit/global_fields/test_global_fields_unittest.py From 90fd509b541e3bb2f36fb48bd459e4ba84e49100 Mon Sep 17 00:00:00 2001 From: sunil-lakshman <104969541+sunil-lakshman@users.noreply.github.com> Date: Thu, 5 Jun 2025 13:31:19 +0530 Subject: [PATCH 6/7] Fixed PR comments --- .../global_fields/test_global_fields_api.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/api/global_fields/test_global_fields_api.py b/tests/api/global_fields/test_global_fields_api.py index 8fe168e..a80985b 100644 --- a/tests/api/global_fields/test_global_fields_api.py +++ b/tests/api/global_fields/test_global_fields_api.py @@ -24,17 +24,17 @@ def read_file(self, file_name): return data def test_create_global_fields(self): - read_mock_global_fileds_data = self.read_file("create_global_fields.json") - read_mock_global_fileds_data = json.loads(read_mock_global_fileds_data) - response = self.client.stack(api_key).global_fields().create(read_mock_global_fileds_data) + read_mock_global_fields_data = self.read_file("create_global_fields.json") + read_mock_global_fields_data = json.loads(read_mock_global_fields_data) + response = self.client.stack(api_key).global_fields().create(read_mock_global_fields_data) global_field_uid = response.data.get('uid', 'global_field_uid') self.assertIsNotNone(global_field_uid, "Global field UID should not be None") self.assertEqual(response.status_code, 201) def test_create_nested_global_fields(self): - read_mock_global_fileds_data = self.read_file("create_global_fields.json") - read_mock_global_fileds_data = json.loads(read_mock_global_fileds_data) - response = self.client.stack(api_key).global_fields(options={'api_version': 3.2}).create(read_mock_global_fileds_data) + read_mock_global_fields_data = self.read_file("create_global_fields.json") + read_mock_global_fields_data = json.loads(read_mock_global_fields_data) + response = self.client.stack(api_key).global_fields(options={'api_version': 3.2}).create(read_mock_global_fields_data) global_field_uid1 = response.data.get('uid', 'global_field_uid') self.assertIsNotNone(global_field_uid1, "Global field UID should not be None") self.assertEqual(response.status_code, 201) @@ -54,9 +54,9 @@ def test_find_all_global_fields(self): def test_update_global_fields(self): - read_mock_global_fileds_data = self.read_file("create_global_fields.json") - read_mock_global_fileds_data = json.loads(read_mock_global_fileds_data) - response = self.client.stack(api_key).global_fields(global_field_uid).update(read_mock_global_fileds_data) + read_mock_global_fields_data = self.read_file("create_global_fields.json") + read_mock_global_fields_data = json.loads(read_mock_global_fields_data) + response = self.client.stack(api_key).global_fields(global_field_uid).update(read_mock_global_fields_data) if response.status_code == 200: self.assertEqual(response.status_code, 200) else: From 6ceff158bf4b618ee8a49ad7d3ffa24e582ed30d Mon Sep 17 00:00:00 2001 From: sunil-lakshman <104969541+sunil-lakshman@users.noreply.github.com> Date: Thu, 5 Jun 2025 13:32:58 +0530 Subject: [PATCH 7/7] Updated talismanrc --- .talismanrc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.talismanrc b/.talismanrc index 6527e8d..8ebc737 100644 --- a/.talismanrc +++ b/.talismanrc @@ -358,4 +358,6 @@ fileignoreconfig: checksum: 1cd57383fcad33cfaddc03aec9a7ee3e85b27de35e4545462fca33e74768e812 - filename: tests/unit/global_fields/test_global_fields_unittest.py checksum: 9bb05624cf1dadb770b3cf17fbfe915cf3133d622110da30a7dfebdeab0a315c +- filename: tests/api/global_fields/test_global_fields_api.py + checksum: ef69455a51168ea34d62a68caea0984504d3feeafb78010947fa99d7c54d9e9c version: "1.0" \ No newline at end of file