diff --git a/.gitignore b/.gitignore index f23a362c..6959ef19 100644 --- a/.gitignore +++ b/.gitignore @@ -271,4 +271,5 @@ src/main/resources/ .vscode/settings.json .vscode/ /.vscode/ -.env \ No newline at end of file +.env + diff --git a/changelog.md b/changelog.md index 10ad0edd..0207b743 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,12 @@ # Changelog +## v1.7.0 + +### Jul 07, 2025 + +- Nested Global Field Support added +- Snyk fixes + ## v1.6.1 ### Jun 23, 2025 diff --git a/pom.xml b/pom.xml index b373b2ac..d3e28f20 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ cms jar contentstack-management-java - 1.6.1 + 1.7.0 Contentstack Java Management SDK for Content Management API, Contentstack is a headless CMS with an API-first approach @@ -89,14 +89,14 @@ 3.0.0 5.2.2 3.1.10 - 2.11.0 - 2.11.0 + 2.12.0 + 2.12.0 4.12.0 0.8.7 1.18.38 5.11.4 5.10.1 - 2.13.0 + 2.13.1 3.3 1.5 3.8.0 @@ -213,7 +213,7 @@ org.jetbrains.kotlin kotlin-stdlib - 2.1.20 + 2.1.21 diff --git a/src/main/java/com/contentstack/cms/stack/GlobalField.java b/src/main/java/com/contentstack/cms/stack/GlobalField.java index 47ad9599..681e2e16 100644 --- a/src/main/java/com/contentstack/cms/stack/GlobalField.java +++ b/src/main/java/com/contentstack/cms/stack/GlobalField.java @@ -37,7 +37,7 @@ public class GlobalField implements BaseImplementation { protected HashMap headers; protected HashMap params; protected String globalFiledUid; - + protected String apiVersion; protected GlobalField(Retrofit retrofit,Map headers) { this.headers = new HashMap<>(); this.headers.putAll(headers); @@ -85,7 +85,23 @@ public GlobalField addParam(@NotNull String key, @NotNull Object value) { */ @Override public GlobalField addHeader(@NotNull String key, @NotNull String value) { - this.headers.put(key, value); + if ("api_version".equalsIgnoreCase(key)) { + this.apiVersion = value; + } else { + this.headers.put(key, value); + } + return this; + } + + /** + * @param key The key parameter is a string that represents the name or + * identifier of the header. + * It is used to specify the type of information being sent in the + * header. + * @return instance of the GlobalField object + */ + public GlobalField removeHeader(@NotNull String key) { + this.headers.remove(key); return this; } @@ -110,6 +126,10 @@ public GlobalField addParams(@NotNull HashMap params) { */ @Override public GlobalField addHeaders(@NotNull HashMap headers) { + if (headers.containsKey("api_version")) { + this.apiVersion = headers.get("api_version"); + headers.remove("api_version"); + } this.headers.putAll(headers); return this; } @@ -134,6 +154,21 @@ protected GlobalField clearParams() { this.params.clear(); return this; } + /* + * For Nested Global Fields the api_version is set to 3.2 which needs + * to removed from the headers inorder for other modules to function correctly + */ + + /** + * Returns a copy of the headers with api_version set if needed. + */ + private Map getRequestHeaders() { + Map requestHeaders = new HashMap<>(this.headers); + if (this.apiVersion != null) { + requestHeaders.put("api_version", this.apiVersion); + } + return requestHeaders; + } /** * Get All Global Fields @@ -158,7 +193,7 @@ protected GlobalField clearParams() { * @since 0.1.0 */ public Call find() { - return this.service.fetch(this.headers, this.params); + return this.service.fetch(getRequestHeaders(), this.params); } /** @@ -188,7 +223,7 @@ public Call find() { */ public Call fetch() { validate(); - return this.service.single(this.headers, this.globalFiledUid, this.params); + return this.service.single(getRequestHeaders(), this.globalFiledUid, this.params); } /** @@ -219,7 +254,7 @@ public Call fetch() { * @since 0.1.0 */ public Call create(@NotNull JSONObject requestBody) { - return this.service.create(this.headers, requestBody); + return this.service.create(getRequestHeaders(), requestBody); } /** @@ -249,7 +284,7 @@ public Call create(@NotNull JSONObject requestBody) { */ public Call update(@NotNull JSONObject requestBody) { validate(); - return this.service.update(this.headers, this.globalFiledUid, requestBody); + return this.service.update(getRequestHeaders(), this.globalFiledUid, requestBody); } /** @@ -274,7 +309,7 @@ public Call update(@NotNull JSONObject requestBody) { */ public Call delete() { validate(); - return this.service.delete(this.headers, this.globalFiledUid); + return this.service.delete(getRequestHeaders(), this.globalFiledUid); } /** @@ -301,7 +336,7 @@ public Call delete() { * @since 0.1.0 */ public Call imports(@NotNull JSONObject body) { - return this.service.imports(this.headers, body); + return this.service.imports(getRequestHeaders(), body); } /** @@ -322,6 +357,36 @@ public Call imports(@NotNull JSONObject body) { */ public Call export() { validate(); - return this.service.export(this.headers, this.globalFiledUid); + return this.service.export(getRequestHeaders(), this.globalFiledUid); + } + + /** + * Restore a global field + *

+ * The Restore a global field request allows you to restore the schema of + * a deleted global field. + *

+ * When executing the API call, in the URI Parameters section, provide + * the unique ID of your global field. + * + * Note: You need to use either the stack's Management Token or the user + * Authtoken (any one is mandatory), along with the stack API key, to make a + * valid Content Management API request. + * Read more about authentication. + * + * @param requestBody the request body + * @return Call + * @see Restore + * a global + * field + * + * + * @see #addHeader(String, String) to add headers + * @since 0.1.0 + */ + public Call restore(@NotNull JSONObject requestBody) { + validate(); + return this.service.restore(getRequestHeaders(), this.globalFiledUid, requestBody); } } diff --git a/src/main/java/com/contentstack/cms/stack/GlobalFieldService.java b/src/main/java/com/contentstack/cms/stack/GlobalFieldService.java index 4e560f1a..3edc5ce7 100644 --- a/src/main/java/com/contentstack/cms/stack/GlobalFieldService.java +++ b/src/main/java/com/contentstack/cms/stack/GlobalFieldService.java @@ -46,4 +46,10 @@ Call imports( Call export( @HeaderMap Map headers, @Path("global_field_uid") String globalFieldUid); + + @PUT("global_fields/{global_field_uid}/restore") + Call restore( + @HeaderMap Map headers, + @Path("global_field_uid") String globalFieldUid, + @Body JSONObject body); } diff --git a/src/test/java/com/contentstack/cms/stack/APISanityTestSuite.java b/src/test/java/com/contentstack/cms/stack/APISanityTestSuite.java index e3fd6f57..afd01049 100644 --- a/src/test/java/com/contentstack/cms/stack/APISanityTestSuite.java +++ b/src/test/java/com/contentstack/cms/stack/APISanityTestSuite.java @@ -18,7 +18,8 @@ RoleAPITest.class, StackAPITest.class, TokenAPITest.class, - OrgApiTests.class + OrgApiTests.class, + GlobalFieldAPITest.class }) public class APISanityTestSuite { diff --git a/src/test/java/com/contentstack/cms/stack/GlobalFieldAPITest.java b/src/test/java/com/contentstack/cms/stack/GlobalFieldAPITest.java new file mode 100644 index 00000000..3ad30016 --- /dev/null +++ b/src/test/java/com/contentstack/cms/stack/GlobalFieldAPITest.java @@ -0,0 +1,468 @@ +package com.contentstack.cms.stack; + +import java.io.IOException; +import java.util.HashMap; + +import com.contentstack.cms.TestClient; +import com.contentstack.cms.Utils; +import com.contentstack.cms.core.Util; + +import okhttp3.Request; + +import org.json.simple.JSONObject; +import org.junit.jupiter.api.*; + +import com.contentstack.cms.Contentstack; +import com.google.gson.JsonObject; + +import okhttp3.ResponseBody; +import retrofit2.Response; + +@Tag("unit") +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class GlobalFieldAPITest { + + public static GlobalField globalField; + protected static String API_KEY = TestClient.API_KEY; + protected static String MANAGEMENT_TOKEN = TestClient.MANAGEMENT_TOKEN; + protected static String AUTHTOKEN = TestClient.AUTHTOKEN; + protected static String globalFieldUid = "global_field_1"; + protected static String globalFieldUid2 = "nested_global_field"; + protected static Stack stack; + private int _COUNT = 2; + + @BeforeAll + public void setUp() { + stack = TestClient.getStack().addHeader(Util.API_KEY, API_KEY) + .addHeader("api_key", API_KEY); + _COUNT = stack.headers.size(); + } + + @Order(1) + @Test + void testCreateGlobalField() { + JSONObject requestBody = Utils.readJson("globalfield/global_field_create.json"); + globalField = stack.globalField(); + Request request = globalField.create(requestBody).request(); + Assertions.assertEquals(_COUNT, request.headers().names().size()); + Assertions.assertEquals("POST", request.method()); + Assertions.assertTrue(request.url().isHttps()); + Assertions.assertEquals(2, request.url().pathSegments().size()); + Assertions.assertEquals("v3", request.url().pathSegments().get(0)); + Assertions.assertEquals("global_fields", request.url().pathSegments().get(1)); + Assertions.assertNull(request.url().encodedQuery()); + } + + @Order(2) + @Test + void testFetchSingleGlobalField() { + globalField = stack.globalField(globalFieldUid); + Request request = globalField.fetch().request(); + Assertions.assertEquals(_COUNT, request.headers().names().size()); + Assertions.assertEquals("GET", request.method()); + Assertions.assertTrue(request.url().isHttps()); + Assertions.assertEquals(3, request.url().pathSegments().size()); + Assertions.assertEquals("v3", request.url().pathSegments().get(0)); + Assertions.assertEquals("global_fields", request.url().pathSegments().get(1)); + Assertions.assertEquals(globalFieldUid, request.url().pathSegments().get(2)); + Assertions.assertNull(request.url().encodedQuery()); + } + + @Order(3) + @Test + void testFetchSingleNestedGlobalFieldWithParams() { + globalField = stack.globalField(globalFieldUid); + globalField.addParam("include_schema", true); + Request request = globalField.fetch().request(); + Assertions.assertEquals(_COUNT, request.headers().names().size()); + Assertions.assertEquals("GET", request.method()); + Assertions.assertTrue(request.url().isHttps()); + Assertions.assertEquals(3, request.url().pathSegments().size()); + Assertions.assertEquals("v3", request.url().pathSegments().get(0)); + Assertions.assertEquals("global_fields", request.url().pathSegments().get(1)); + Assertions.assertEquals(globalFieldUid, request.url().pathSegments().get(2)); + Assertions.assertNotNull(request.url().encodedQuery()); + Assertions.assertEquals("include_schema=true", request.url().query().toString()); + } + + @Order(4) + @Test + void testUpdateGlobalField() { + globalField = stack.globalField(globalFieldUid); + JSONObject requestBody = Utils.readJson("globalfield/global_field_update.json"); + Request request = globalField.update(requestBody).request(); + Assertions.assertEquals(_COUNT, request.headers().names().size()); + Assertions.assertEquals("PUT", request.method()); + Assertions.assertTrue(request.url().isHttps()); + Assertions.assertEquals(3, request.url().pathSegments().size()); + Assertions.assertEquals("v3", request.url().pathSegments().get(0)); + Assertions.assertEquals("global_fields", request.url().pathSegments().get(1)); + Assertions.assertEquals(globalFieldUid, request.url().pathSegments().get(2)); + Assertions.assertNull(request.url().encodedQuery()); + } + + @Order(5) + @Test + void testFindAllGlobalFields() { + globalField = stack.globalField(); + Request request = globalField.find().request(); + Assertions.assertEquals(_COUNT, request.headers().names().size()); + Assertions.assertEquals("GET", request.method()); + Assertions.assertTrue(request.url().isHttps()); + Assertions.assertEquals(2, request.url().pathSegments().size()); + Assertions.assertEquals("v3", request.url().pathSegments().get(0)); + Assertions.assertEquals("global_fields", request.url().pathSegments().get(1)); + Assertions.assertNull(request.url().encodedQuery()); + } + + @Order(6) + @Test + void testFindWithParamsNGF() { + globalField = stack.globalField(); + globalField.addParam("include_count", true); + globalField.addParam("include_global_field_schema", true); + + Request request = globalField.find().request(); + Assertions.assertEquals(_COUNT, request.headers().names().size()); + Assertions.assertEquals("GET", request.method()); + Assertions.assertTrue(request.url().isHttps()); + Assertions.assertEquals(2, request.url().pathSegments().size()); + Assertions.assertEquals("v3", request.url().pathSegments().get(0)); + Assertions.assertEquals("global_fields", request.url().pathSegments().get(1)); + Assertions.assertNotNull(request.url().encodedQuery()); + } + + @Order(7) + @Test + void testDeleteGlobalField() { + globalField = stack.globalField(globalFieldUid); + Request request = globalField.delete().request(); + Assertions.assertEquals(_COUNT, request.headers().names().size()); + Assertions.assertEquals("DELETE", request.method()); + Assertions.assertTrue(request.url().isHttps()); + Assertions.assertEquals(3, request.url().pathSegments().size()); + Assertions.assertEquals("v3", request.url().pathSegments().get(0)); + Assertions.assertEquals("global_fields", request.url().pathSegments().get(1)); + Assertions.assertEquals(globalFieldUid, request.url().pathSegments().get(2)); + Assertions.assertNotNull(request.url().encodedQuery()); + Assertions.assertEquals("force=true", request.url().encodedQuery()); + } + + @Order(8) + @Test + void testImportGlobalField() { + globalField = stack.globalField(); + JSONObject requestBody = Utils.readJson("globalfield/global_field_import.json"); + Request request = globalField.imports(requestBody).request(); + Assertions.assertEquals(_COUNT, request.headers().names().size()); + Assertions.assertEquals("POST", request.method()); + Assertions.assertTrue(request.url().isHttps()); + Assertions.assertEquals(3, request.url().pathSegments().size()); + Assertions.assertEquals("v3", request.url().pathSegments().get(0)); + Assertions.assertEquals("global_fields", request.url().pathSegments().get(1)); + Assertions.assertEquals("import", request.url().pathSegments().get(2)); + Assertions.assertNull(request.url().encodedQuery()); + } + + @Order(9) + @Test + void testExportGlobalField() { + globalField = stack.globalField(globalFieldUid); + Request request = globalField.export().request(); + Assertions.assertEquals(_COUNT, request.headers().names().size()); + Assertions.assertEquals("GET", request.method()); + Assertions.assertTrue(request.url().isHttps()); + Assertions.assertEquals(4, request.url().pathSegments().size()); + Assertions.assertEquals("v3", request.url().pathSegments().get(0)); + Assertions.assertEquals("global_fields", request.url().pathSegments().get(1)); + Assertions.assertEquals(globalFieldUid, request.url().pathSegments().get(2)); + Assertions.assertEquals("export", request.url().pathSegments().get(3)); + Assertions.assertNull(request.url().encodedQuery()); + } + + @Order(10) + @Test + void testCreateNestedGlobalField() { + JSONObject requestBody = Utils.readJson("globalfield/nested_global_field_create.json"); + globalField = stack.globalField().addHeader("api_version", "3.2"); + Request request = globalField.create(requestBody).request(); + globalField.removeHeader("api_version"); + + Assertions.assertEquals("POST", request.method()); + Assertions.assertTrue(request.url().isHttps()); + Assertions.assertEquals(2, request.url().pathSegments().size()); + Assertions.assertEquals("v3", request.url().pathSegments().get(0)); + Assertions.assertEquals("global_fields", request.url().pathSegments().get(1)); + Assertions.assertNull(request.url().encodedQuery()); + } + + @Order(11) + @Test + void testFetchSingleNestedGlobalField() { + globalField = stack.globalField(globalFieldUid).addHeader("api_version", "3.2"); + Request request = globalField.fetch().request(); + + Assertions.assertEquals("GET", request.method()); + Assertions.assertTrue(request.url().isHttps()); + Assertions.assertEquals(3, request.url().pathSegments().size()); + Assertions.assertEquals("v3", request.url().pathSegments().get(0)); + Assertions.assertEquals("global_fields", request.url().pathSegments().get(1)); + Assertions.assertEquals(globalFieldUid, request.url().pathSegments().get(2)); + Assertions.assertNull(request.url().encodedQuery()); + } + + @Order(12) + @Test + void testFetchSingleGlobalFieldWithParams() { + globalField = stack.globalField(globalFieldUid).addHeader("api_version", "3.2"); + globalField.addParam("include_schema", true); + Request request = globalField.fetch().request(); + + Assertions.assertEquals("GET", request.method()); + Assertions.assertTrue(request.url().isHttps()); + Assertions.assertEquals(3, request.url().pathSegments().size()); + Assertions.assertEquals("v3", request.url().pathSegments().get(0)); + Assertions.assertEquals("global_fields", request.url().pathSegments().get(1)); + Assertions.assertEquals(globalFieldUid, request.url().pathSegments().get(2)); + Assertions.assertNotNull(request.url().encodedQuery()); + Assertions.assertEquals("include_schema=true", request.url().query().toString()); + } + + @Order(13) + @Test + void testUpdateNestedGlobalField() { + globalField = stack.globalField(globalFieldUid).addHeader("api_version", "3.2"); + JSONObject requestBody = Utils.readJson("globalfield/nested_global_field_update.json"); + Request request = globalField.update(requestBody).request(); + + Assertions.assertEquals("PUT", request.method()); + Assertions.assertTrue(request.url().isHttps()); + Assertions.assertEquals(3, request.url().pathSegments().size()); + Assertions.assertEquals("v3", request.url().pathSegments().get(0)); + Assertions.assertEquals("global_fields", request.url().pathSegments().get(1)); + Assertions.assertEquals(globalFieldUid, request.url().pathSegments().get(2)); + Assertions.assertNull(request.url().encodedQuery()); + } + + @Order(14) + @Test + void testFindAllNestedGlobalField() { + globalField = stack.globalField().addHeader("api_version", "3.2"); + Request request = globalField.find().request(); + + Assertions.assertEquals("GET", request.method()); + Assertions.assertTrue(request.url().isHttps()); + Assertions.assertEquals(2, request.url().pathSegments().size()); + Assertions.assertEquals("v3", request.url().pathSegments().get(0)); + Assertions.assertEquals("global_fields", request.url().pathSegments().get(1)); + Assertions.assertNull(request.url().encodedQuery()); + } + + @Order(15) + @Test + void testFindWithParams() { + globalField = stack.globalField().addHeader("api_version", "3.2"); + globalField.addParam("include_count", true); + globalField.addParam("include_global_field_schema", true); + + Request request = globalField.find().request(); + + Assertions.assertEquals("GET", request.method()); + Assertions.assertTrue(request.url().isHttps()); + Assertions.assertEquals(2, request.url().pathSegments().size()); + Assertions.assertEquals("v3", request.url().pathSegments().get(0)); + Assertions.assertEquals("global_fields", request.url().pathSegments().get(1)); + Assertions.assertNotNull(request.url().encodedQuery()); + } + + @Order(16) + @Test + void testDeleteNestedGlobalField() { + globalField = stack.globalField(globalFieldUid).addHeader("api_version", "3.2"); + Request request = globalField.delete().request(); + + Assertions.assertEquals("DELETE", request.method()); + Assertions.assertTrue(request.url().isHttps()); + Assertions.assertEquals(3, request.url().pathSegments().size()); + Assertions.assertEquals("v3", request.url().pathSegments().get(0)); + Assertions.assertEquals("global_fields", request.url().pathSegments().get(1)); + Assertions.assertEquals(globalFieldUid, request.url().pathSegments().get(2)); + Assertions.assertNotNull(request.url().encodedQuery()); + Assertions.assertEquals("force=true", request.url().encodedQuery()); + } + + @Order(17) + @Test + void testImportNestedGlobalField() { + globalField = stack.globalField().addHeader("api_version", "3.2"); + JSONObject requestBody = Utils.readJson("globalfield/nested_global_field_import.json"); + Request request = globalField.imports(requestBody).request(); + + Assertions.assertEquals("POST", request.method()); + Assertions.assertTrue(request.url().isHttps()); + Assertions.assertEquals(3, request.url().pathSegments().size()); + Assertions.assertEquals("v3", request.url().pathSegments().get(0)); + Assertions.assertEquals("global_fields", request.url().pathSegments().get(1)); + Assertions.assertEquals("import", request.url().pathSegments().get(2)); + Assertions.assertNull(request.url().encodedQuery()); + } + + @Order(18) + @Test + void testExportNestedGlobalField() { + globalField = stack.globalField(globalFieldUid).addHeader("api_version", "3.2"); + Request request = globalField.export().request(); + + Assertions.assertEquals("GET", request.method()); + Assertions.assertTrue(request.url().isHttps()); + Assertions.assertEquals(4, request.url().pathSegments().size()); + Assertions.assertEquals("v3", request.url().pathSegments().get(0)); + Assertions.assertEquals("global_fields", request.url().pathSegments().get(1)); + Assertions.assertEquals(globalFieldUid, request.url().pathSegments().get(2)); + Assertions.assertEquals("export", request.url().pathSegments().get(3)); + Assertions.assertNull(request.url().encodedQuery()); + } + + // @Order(19) + // @Test + // void testRestoreNestedGlobalField() { + // globalField = stack.globalField(globalFieldUid).addHeader("api_version", "3.2"); + // JSONObject requestBody = Utils.readJson("mockglobalfield/nested_global_field_restore.json"); + // Request request = globalField.restore(requestBody).request(); + // Assertions.assertEquals("PUT", request.method()); + // Assertions.assertTrue(request.url().isHttps()); + // Assertions.assertEquals(4, request.url().pathSegments().size()); + // Assertions.assertEquals("v3", request.url().pathSegments().get(0)); + // Assertions.assertEquals("global_fields", request.url().pathSegments().get(1)); + // Assertions.assertEquals(globalFieldUid, request.url().pathSegments().get(2)); + // Assertions.assertEquals("restore", request.url().pathSegments().get(3)); + // Assertions.assertNull(request.url().encodedQuery()); + // } + @Test + void testApiVersionHeaderIsSet() { + HashMap headers = new HashMap<>(); + headers.put(Util.API_KEY, API_KEY); + headers.put(Util.AUTHORIZATION, MANAGEMENT_TOKEN); + String apiVersion = "3.2"; + Stack stack = new Contentstack.Builder().setAuthtoken(AUTHTOKEN).build().stack(headers); + GlobalField gfWithApiVersion = new GlobalField(stack.client, stack.headers, "feature"); + gfWithApiVersion.addHeader("api_version", apiVersion); + Request request = gfWithApiVersion.fetch().request(); + Assertions.assertEquals(apiVersion, request.header("api_version")); + } + + // --- Nested Global Field Test Suite --- + @Nested + @TestMethodOrder(MethodOrderer.OrderAnnotation.class) + class NestedGlobalFieldTests { + + GlobalField nestedGlobalField; + String nestedUid = "nested_global_field"; + String apiVersion = "3.2"; + + @BeforeEach + void setupNested() { + HashMap headers = new HashMap<>(); + headers.put(Util.API_KEY, API_KEY); + headers.put(Util.AUTHORIZATION, MANAGEMENT_TOKEN); + Stack stack = new Contentstack.Builder().setAuthtoken(AUTHTOKEN).build().stack(headers); + nestedGlobalField = new GlobalField(stack.client, stack.headers, nestedUid); + nestedGlobalField.addHeader("api_version", apiVersion); + } + + @Test + @Order(1) + void testCreateNestedGlobalField() throws IOException { + JSONObject requestBody = Utils.readJson("globalfield/nested_global_field.json"); + Request request = nestedGlobalField.create(requestBody).request(); + Assertions.assertEquals("https://api.contentstack.io/v3/global_fields", request.url().toString()); + Assertions.assertEquals("/v3/global_fields", request.url().encodedPath()); + Assertions.assertEquals("https", request.url().scheme()); + Assertions.assertEquals("POST", request.method()); + Assertions.assertEquals(apiVersion, request.header("api_version")); + Response response = nestedGlobalField.create(requestBody).execute(); + Assertions.assertEquals(201, response.code()); + } + + @Test + @Order(2) + void testGetNestedGlobalField() throws IOException { + nestedGlobalField.addParam("include_global_fields", true); + nestedGlobalField.addParam("include_validation_keys", true); + Request request = nestedGlobalField.fetch().request(); + Assertions.assertEquals("https://api.contentstack.io/v3/global_fields/" + nestedUid + "?include_global_fields=true&include_validation_keys=true", request.url().toString()); + Assertions.assertEquals("https", request.url().scheme()); + Assertions.assertEquals("GET", request.method()); + Assertions.assertEquals(apiVersion, request.header("api_version")); + Response response = nestedGlobalField.fetch().execute(); + Assertions.assertEquals(200, response.code()); + JsonObject responseBody = Utils.toJson(response).getAsJsonObject(); + JsonObject globalField = responseBody.getAsJsonObject("global_field"); + Assertions.assertEquals("Nested Global Field", globalField.get("title").getAsString()); + Assertions.assertTrue(globalField.has("referred_global_fields")); + Assertions.assertTrue(globalField.has("validation_keys")); + } + + @Test + @Order(3) + void testUpdateNestedGlobalField() throws IOException { + JSONObject requestBody = Utils.readJson("globalfield/nested_global_field_update1.json"); + Request request = nestedGlobalField.update(requestBody).request(); + Assertions.assertEquals("https://api.contentstack.io/v3/global_fields/" + nestedUid, request.url().toString()); + Assertions.assertEquals("/v3/global_fields/" + nestedUid, request.url().encodedPath()); + Assertions.assertEquals("https", request.url().scheme()); + Assertions.assertEquals("PUT", request.method()); + Assertions.assertEquals(apiVersion, request.header("api_version")); + Response response = nestedGlobalField.update(requestBody).execute(); + Assertions.assertEquals(200, response.code()); + JsonObject responseBody = Utils.toJson(response).getAsJsonObject(); + JsonObject globalField = responseBody.getAsJsonObject("global_field"); + Assertions.assertEquals("Nested Global Field", globalField.get("title").getAsString()); + + } + + @Test + @Order(4) + void testDeleteNestedGlobalField() throws IOException { + Request request = nestedGlobalField.delete().request(); + Assertions.assertEquals("https://api.contentstack.io/v3/global_fields/" + nestedUid + "?force=true", request.url().toString()); + Assertions.assertEquals("https", request.url().scheme()); + Assertions.assertEquals("DELETE", request.method()); + Assertions.assertEquals(apiVersion, request.header("api_version")); + Response response = nestedGlobalField.delete().execute(); + Assertions.assertEquals(200, response.code()); + JsonObject responseBody = Utils.toJson(response).getAsJsonObject(); + Assertions.assertEquals("Global Field deleted successfully.", responseBody.get("notice").getAsString()); + } + + @Test + void testApiVersionHeaderIsolation() throws IOException { + // Set api_version via addHeader (should not pollute shared headers) + GlobalField gfWithApiVersion = new GlobalField(stack.client, stack.headers, "feature"); + gfWithApiVersion.addHeader("api_version", apiVersion); + // Before request, shared headers should NOT have api_version + Assertions.assertFalse(stack.headers.containsKey("api_version"), + "api_version should not be present in shared headers before GlobalField request"); + // Make a request (should use a copy of headers internally) + Request rq1 = gfWithApiVersion.find().request(); + + // After request, shared headers should STILL NOT have api_version + Assertions.assertFalse(stack.headers.containsKey("api_version"), + "api_version should not be present in shared headers after GlobalField request"); + // Now, create a ContentType and make a request + ContentType ct = stack.contentType("author"); + Request rq2 = ct.fetch().request(); + JSONObject requestBody = Utils.readJson("mockcontenttype/create.json"); + Request rq3 = ct.create(requestBody).request(); + // Again, shared headers should not have api_version + Assertions.assertFalse(stack.headers.containsKey("api_version"), + "api_version should not be present in shared headers after ContentType request"); + // Also, ContentType's request should not have api_version header + Assertions.assertNull(rq2.header("api_version"), + "api_version should not be present in ContentType request headers"); + Assertions.assertNull(rq3.header("api_version"), + "api_version should not be present in ContentType request headers"); + } + } + +} diff --git a/src/test/resources/globalfield/global_field.json b/src/test/resources/globalfield/global_field.json deleted file mode 100644 index 155089d3..00000000 --- a/src/test/resources/globalfield/global_field.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "global_field": { - "title": "Servlet", - "uid": "servlet", - "schema": [{ - "display_name": "Name", - "uid": "name", - "data_type": "text" - }, { - "data_type": "text", - "display_name": "Rich text editor", - "uid": "description", - "field_metadata": { - "allow_rich_text": true, - "description": "", - "multiline": false, - "rich_text_type": "advanced", - "options": [], - "version": 3 - }, - "multiple": false, - "mandatory": false, - "unique": false - }] - } -} \ No newline at end of file diff --git a/src/test/resources/globalfield/global_field_create.json b/src/test/resources/globalfield/global_field_create.json new file mode 100644 index 00000000..fc9b9c2a --- /dev/null +++ b/src/test/resources/globalfield/global_field_create.json @@ -0,0 +1,25 @@ +{ + "title": "global_field_1", + "uid": "global_field_1", + "description": "", + "schema": [ + { + "data_type": "text", + "display_name": "Single Line Textbox", + "uid": "single_line", + "field_metadata": { "description": "", "default_value": "" }, + "format": "", + "error_messages": { "format": "" }, + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false + } + ], + "created_at": "", + "updated_at": "", + "_version": 1, + "inbuilt_class": false, + "last_activity": {}, + "maintain_revisions": true +} diff --git a/src/test/resources/globalfield/global_field_import.json b/src/test/resources/globalfield/global_field_import.json new file mode 100644 index 00000000..c7f228a0 --- /dev/null +++ b/src/test/resources/globalfield/global_field_import.json @@ -0,0 +1,25 @@ +{ + "title": "global_field_2", + "uid": "global_field_2", + "description": "", + "schema": [ + { + "data_type": "text", + "display_name": "Single Line Textbox", + "uid": "single_line", + "field_metadata": { "description": "", "default_value": "" }, + "format": "", + "error_messages": { "format": "" }, + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false + } + ], + "created_at": "", + "updated_at": "", + "_version": 1, + "inbuilt_class": false, + "last_activity": {}, + "maintain_revisions": true +} diff --git a/src/test/resources/globalfield/global_field_update.json b/src/test/resources/globalfield/global_field_update.json new file mode 100644 index 00000000..330b881e --- /dev/null +++ b/src/test/resources/globalfield/global_field_update.json @@ -0,0 +1,25 @@ +{ + "title": "global_field_1", + "uid": "global_field_1", + "description": "", + "schema": [ + { + "data_type": "text", + "display_name": "Single Line Textbox line", + "uid": "single_line", + "field_metadata": { "description": "", "default_value": "" }, + "format": "", + "error_messages": { "format": "" }, + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false + } + ], + "created_at": "", + "updated_at": "", + "_version": 1, + "inbuilt_class": false, + "last_activity": {}, + "maintain_revisions": true +} diff --git a/src/test/resources/globalfield/nested_global_field.json b/src/test/resources/globalfield/nested_global_field.json new file mode 100644 index 00000000..b05957fc --- /dev/null +++ b/src/test/resources/globalfield/nested_global_field.json @@ -0,0 +1,44 @@ +{ + "global_field": { + "title": "Nested Global Field", + "uid": "nested_global_field", + "description": "", + "schema": [ + { + "data_type": "text", + "display_name": "Single Line Textbox", + "uid": "single_line", + "field_metadata": { + "description": "", + "default_value": "", + "version": 3 + }, + "format": "", + "error_messages": { + "format": "" + }, + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false, + "indexed": false, + "inbuilt_model": false + }, + { + "data_type": "global_field", + "display_name": "SEO", + "reference_to": "seo", + "field_metadata": { + "description": "" + }, + "uid": "seo", + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false, + "indexed": false, + "inbuilt_model": false + } + ] + } +} \ No newline at end of file diff --git a/src/test/resources/globalfield/nested_global_field_create.json b/src/test/resources/globalfield/nested_global_field_create.json new file mode 100644 index 00000000..cd088895 --- /dev/null +++ b/src/test/resources/globalfield/nested_global_field_create.json @@ -0,0 +1,44 @@ +{ + "global_field": { + "title": "Nested Global Field", + "uid": "nested_global_field", + "description": "", + "schema": [ + { + "data_type": "text", + "display_name": "Single Line Textbox", + "uid": "single_line", + "field_metadata": { + "description": "", + "default_value": "", + "version": 3 + }, + "format": "", + "error_messages": { + "format": "" + }, + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false, + "indexed": false, + "inbuilt_model": false + }, + { + "data_type": "global_field", + "display_name": "Global", + "reference_to": "global_field_1", + "field_metadata": { + "description": "" + }, + "uid": "global_field", + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false, + "indexed": false, + "inbuilt_model": false + } + ] + } +} diff --git a/src/test/resources/globalfield/nested_global_field_import.json b/src/test/resources/globalfield/nested_global_field_import.json new file mode 100644 index 00000000..2402e93f --- /dev/null +++ b/src/test/resources/globalfield/nested_global_field_import.json @@ -0,0 +1,40 @@ +{ + "title": "Nested Global Field3", + "uid": "nested_global_field3", + "description": "", + "schema": [ + { + "data_type": "text", + "display_name": "Single Line Textbox", + "uid": "single_line", + "field_metadata": { + "description": "", + "default_value": "", + "version": 3 + }, + "format": "", + "error_messages": { "format": "" }, + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false + }, + { + "data_type": "global_field", + "display_name": "Global", + "reference_to": "global_field_1", + "field_metadata": { "description": "" }, + "uid": "global_field", + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false + } + ], + "created_at": "2025-05-21T07:41:43.448Z", + "updated_at": "2025-05-21T07:41:43.448Z", + "_version": 1, + "inbuilt_class": false, + "last_activity": {}, + "maintain_revisions": true +} diff --git a/src/test/resources/globalfield/nested_global_field_restore.json b/src/test/resources/globalfield/nested_global_field_restore.json new file mode 100644 index 00000000..9d19feb6 --- /dev/null +++ b/src/test/resources/globalfield/nested_global_field_restore.json @@ -0,0 +1,44 @@ +{ + "global_field": { + "title": "Nested Global Field", + "uid": "nested_global_field", + "description": "", + "schema": [ + { + "data_type": "text", + "display_name": "Single Line Textbox line", + "uid": "single_line", + "field_metadata": { + "description": "", + "default_value": "", + "version": 3 + }, + "format": "", + "error_messages": { + "format": "" + }, + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false, + "indexed": false, + "inbuilt_model": false + }, + { + "data_type": "global_field", + "display_name": "Global", + "reference_to": "global_field_1", + "field_metadata": { + "description": "" + }, + "uid": "global_field", + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false, + "indexed": false, + "inbuilt_model": false + } + ] + } +} diff --git a/src/test/resources/globalfield/nested_global_field_update.json b/src/test/resources/globalfield/nested_global_field_update.json new file mode 100644 index 00000000..9d19feb6 --- /dev/null +++ b/src/test/resources/globalfield/nested_global_field_update.json @@ -0,0 +1,44 @@ +{ + "global_field": { + "title": "Nested Global Field", + "uid": "nested_global_field", + "description": "", + "schema": [ + { + "data_type": "text", + "display_name": "Single Line Textbox line", + "uid": "single_line", + "field_metadata": { + "description": "", + "default_value": "", + "version": 3 + }, + "format": "", + "error_messages": { + "format": "" + }, + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false, + "indexed": false, + "inbuilt_model": false + }, + { + "data_type": "global_field", + "display_name": "Global", + "reference_to": "global_field_1", + "field_metadata": { + "description": "" + }, + "uid": "global_field", + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false, + "indexed": false, + "inbuilt_model": false + } + ] + } +} diff --git a/src/test/resources/globalfield/nested_global_field_update1.json b/src/test/resources/globalfield/nested_global_field_update1.json new file mode 100644 index 00000000..22631ab3 --- /dev/null +++ b/src/test/resources/globalfield/nested_global_field_update1.json @@ -0,0 +1,59 @@ +{ + "global_field": { + "title": "Nested Global Field", + "uid": "nested_global_field", + "description": "", + "schema": [ + { + "data_type": "text", + "display_name": "Single Line Textbox", + "uid": "single_line", + "field_metadata": { + "description": "", + "default_value": "", + "version": 3 + }, + "format": "", + "error_messages": { + "format": "" + }, + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false, + "indexed": false, + "inbuilt_model": false + }, + { + "data_type": "global_field", + "display_name": "SEO", + "reference_to": "seo", + "field_metadata": { + "description": "" + }, + "uid": "seo", + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false, + "indexed": false, + "inbuilt_model": false + }, + { + "data_type": "global_field", + "display_name": "feature", + "reference_to": "feature", + "field_metadata": { + "description": "" + }, + "uid": "feature", + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false, + "indexed": false, + "inbuilt_model": false + } + ] + } +} \ No newline at end of file