Skip to content

Commit c66ec97

Browse files
reeshika-hclaude
andcommitted
feat: add taxonomy and term publish, unpublish, localize, and unlocalize support
Closes the parity gap with the JS SDK per DX-9676 by adding CMA taxonomy publish/unpublish and taxonomy/term-level localize/unlocalize methods, each live-verified against a real stack. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent 5f6b898 commit c66ec97

10 files changed

Lines changed: 390 additions & 2 deletions

File tree

src/main/java/com/contentstack/cms/core/ErrorMessages.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ private ErrorMessages() {
3636
public static final String PUBLISH_QUEUE_UID_REQUIRED = "Publish Queue UID is required. Provide a valid Publish Queue UID and try again.";
3737
public static final String RELEASE_UID_REQUIRED = "Release UID is required. Provide a valid Release UID and try again.";
3838
public static final String ROLE_UID_REQUIRED = "Role UID is required. Provide a valid Role UID and try again.";
39+
public static final String TAXONOMY_UID_REQUIRED = "Taxonomy UID is required. Provide a valid Taxonomy UID and try again.";
3940
public static final String VARIANT_GROUP_UID_REQUIRED = "Variant Group UID is required. Provide a valid Variant Group UID and try again.";
4041
public static final String WEBHOOK_UID_REQUIRED = "Webhook UID is required. Provide a valid Webhook UID and try again.";
4142
public static final String WORKFLOW_UID_REQUIRED = "Workflow UID is required. Provide a valid Workflow UID and try again.";

src/main/java/com/contentstack/cms/stack/Taxonomy.java

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package com.contentstack.cms.stack;
22

33
import com.contentstack.cms.BaseImplementation;
4+
import com.contentstack.cms.core.ErrorMessages;
45
import okhttp3.ResponseBody;
56
import org.jetbrains.annotations.NotNull;
67
import org.json.simple.JSONObject;
78
import retrofit2.Call;
89
import retrofit2.Retrofit;
910

1011
import java.util.HashMap;
12+
import java.util.Objects;
1113

1214

1315
/**
@@ -229,6 +231,63 @@ public Call<ResponseBody> delete(@NotNull String taxonomyId) {
229231
return this.taxonomyService.delete(this.headers, taxonomyId);
230232
}
231233

234+
/**
235+
* Publish one or more taxonomies to the given environments/locales.
236+
* Call on a collection-level instance, e.g. {@code stack.taxonomy()}.
237+
*
238+
* @param body the request body, e.g. {@code {"locales": [...], "environments": [...], "items": [{"uid": "..."}]}}
239+
* @return the call <b>Example</b> <pre> {@code
240+
* Response<ResponseBody> response = taxonomy.publish(body).execute();
241+
* } </pre>
242+
*/
243+
public Call<ResponseBody> publish(@NotNull JSONObject body) {
244+
return this.taxonomyService.publish(this.headers, body);
245+
}
246+
247+
/**
248+
* Unpublish one or more taxonomies from the given environments/locales.
249+
* Call on a collection-level instance, e.g. {@code stack.taxonomy()}.
250+
*
251+
* @param body the request body, e.g. {@code {"locales": [...], "environments": [...], "items": [{"uid": "..."}]}}
252+
* @return the call <b>Example</b> <pre> {@code
253+
* Response<ResponseBody> response = taxonomy.unpublish(body).execute();
254+
* } </pre>
255+
*/
256+
public Call<ResponseBody> unpublish(@NotNull JSONObject body) {
257+
return this.taxonomyService.unpublish(this.headers, body);
258+
}
259+
260+
/**
261+
* Localize a taxonomy into the given locale.
262+
* Call on an instance-level taxonomy, e.g. {@code stack.taxonomy("taxonomyId")}.
263+
*
264+
* @param body the request body, e.g. {@code {"taxonomy": {"name": "..."}}}
265+
* @param locale the target locale, e.g. {@code hi-in}
266+
* @return the call <b>Example</b> <pre> {@code
267+
* Response<ResponseBody> response = taxonomy.localize(body, "hi-in").execute();
268+
* } </pre>
269+
*/
270+
public Call<ResponseBody> localize(@NotNull JSONObject body, @NotNull String locale) {
271+
Objects.requireNonNull(this.taxonomyId, ErrorMessages.TAXONOMY_UID_REQUIRED);
272+
this.params.put("locale", locale);
273+
return this.taxonomyService.localize(this.headers, this.taxonomyId, this.params, body);
274+
}
275+
276+
/**
277+
* Unlocalize a taxonomy from the given locale.
278+
* Call on an instance-level taxonomy, e.g. {@code stack.taxonomy("taxonomyId")}.
279+
*
280+
* @param locale the locale to remove, e.g. {@code hi-in}
281+
* @return the call <b>Example</b> <pre> {@code
282+
* Response<ResponseBody> response = taxonomy.unlocalize("hi-in").execute();
283+
* } </pre>
284+
*/
285+
public Call<ResponseBody> unlocalize(@NotNull String locale) {
286+
Objects.requireNonNull(this.taxonomyId, ErrorMessages.TAXONOMY_UID_REQUIRED);
287+
this.params.put("locale", locale);
288+
return this.taxonomyService.unlocalize(this.headers, this.taxonomyId, this.params);
289+
}
290+
232291

233292
/**
234293
* Clear params for internal uses only for testing

src/main/java/com/contentstack/cms/stack/TaxonomyService.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,29 @@ Call<ResponseBody> delete(
3737
@HeaderMap Map<String, Object> headers,
3838
@Path("taxonomy_uid") String uid);
3939

40+
@POST("taxonomies/publish")
41+
Call<ResponseBody> publish(
42+
@HeaderMap Map<String, Object> headers,
43+
@Body JSONObject body);
44+
45+
@POST("taxonomies/unpublish")
46+
Call<ResponseBody> unpublish(
47+
@HeaderMap Map<String, Object> headers,
48+
@Body JSONObject body);
49+
50+
@POST("taxonomies/{taxonomy_uid}")
51+
Call<ResponseBody> localize(
52+
@HeaderMap Map<String, Object> headers,
53+
@Path("taxonomy_uid") String uid,
54+
@QueryMap Map<String, Object> params,
55+
@Body JSONObject body);
56+
57+
@DELETE("taxonomies/{taxonomy_uid}")
58+
Call<ResponseBody> unlocalize(
59+
@HeaderMap Map<String, Object> headers,
60+
@Path("taxonomy_uid") String uid,
61+
@QueryMap Map<String, Object> params);
62+
4063

4164
// --Terms--
4265
@POST("taxonomies/{taxonomy_uid}/terms")
@@ -87,6 +110,21 @@ Call<ResponseBody> reorder(
87110
@QueryMap Map<String, Object> queryParams,
88111
@Body JSONObject body);
89112

113+
@POST("taxonomies/{taxonomy_uid}/terms/{term_id}")
114+
Call<ResponseBody> localizeTerm(
115+
@HeaderMap HashMap<String, Object> headers,
116+
@Path("taxonomy_uid") String taxonomyId,
117+
@Path("term_id") String termId,
118+
@QueryMap Map<String, Object> queryParams,
119+
@Body JSONObject body);
120+
121+
@DELETE("taxonomies/{taxonomy_uid}/terms/{term_id}")
122+
Call<ResponseBody> unlocalizeTerm(
123+
@HeaderMap HashMap<String, Object> headers,
124+
@Path("taxonomy_uid") String taxonomyId,
125+
@Path("term_id") String termId,
126+
@QueryMap Map<String, Object> queryParams);
127+
90128
@GET("taxonomies/$all/terms")
91129
Call<ResponseBody> searchTerm(
92130
@HeaderMap HashMap<String, Object> headers,

src/main/java/com/contentstack/cms/stack/Terms.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,37 @@ public Call<ResponseBody> reorder(@NotNull String termUid, @NotNull JSONObject b
278278
return this.taxonomyService.reorder(this.headers, this.taxonomyId, termUid, this.params, body);
279279
}
280280

281+
/**
282+
* Localize a term into the given locale.
283+
*
284+
* @param termUid the term to localize
285+
* @param body the request body, e.g. {@code {"term": {"uid": "...", "name": "..."}}}
286+
* @param locale the target locale, e.g. {@code hi-in}
287+
* @return instance of Call <p> <b>Example</b> <pre> {@code
288+
* Stack stack = new Contentstack.Builder().build().stack(headers);
289+
* Term term = stack.taxonomy("taxonomyId").terms().localize("termId", body, "hi-in");
290+
* } </pre>
291+
*/
292+
public Call<ResponseBody> localize(@NotNull String termUid, @NotNull JSONObject body, @NotNull String locale) {
293+
this.params.put("locale", locale);
294+
return this.taxonomyService.localizeTerm(this.headers, this.taxonomyId, termUid, this.params, body);
295+
}
296+
297+
/**
298+
* Unlocalize a term from the given locale.
299+
*
300+
* @param termUid the term to unlocalize
301+
* @param locale the locale to remove, e.g. {@code hi-in}
302+
* @return instance of Call <p> <b>Example</b> <pre> {@code
303+
* Stack stack = new Contentstack.Builder().build().stack(headers);
304+
* Term term = stack.taxonomy("taxonomyId").terms().unlocalize("termId", "hi-in");
305+
* } </pre>
306+
*/
307+
public Call<ResponseBody> unlocalize(@NotNull String termUid, @NotNull String locale) {
308+
this.params.put("locale", locale);
309+
return this.taxonomyService.unlocalizeTerm(this.headers, this.taxonomyId, termUid, this.params);
310+
}
311+
281312

282313
/**
283314
* Search call.

src/test/java/com/contentstack/cms/UnitTestSuite.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.contentstack.cms.stack.GlobalFieldUnitTests;
88
import com.contentstack.cms.stack.LocaleUnitTest;
99
import com.contentstack.cms.stack.ReleaseUnitTest;
10+
import com.contentstack.cms.stack.TaxonomyTest;
1011
import org.junit.platform.runner.JUnitPlatform;
1112
import org.junit.platform.suite.api.SelectClasses;
1213
import org.junit.runner.RunWith;
@@ -32,7 +33,8 @@
3233
EnvironmentUnitTest.class,
3334
GlobalFieldUnitTests.class,
3435
LocaleUnitTest.class,
35-
ReleaseUnitTest.class
36+
ReleaseUnitTest.class,
37+
TaxonomyTest.class
3638
})
3739
public class UnitTestSuite {
3840
}

src/test/java/com/contentstack/cms/stack/TaxonomyAPITest.java

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,96 @@ void descendantsTerm(){
215215
Assertions.assertNull(request.body());
216216
Assertions.assertEquals("include_count=true", request.url().encodedQuery()); }
217217

218+
@Test
219+
void publishTaxonomy() {
220+
JSONObject publishBody = Utils.readJson("mocktaxonomy/publish.json");
221+
Request request = taxonomy.publish(publishBody).request();
222+
Assertions.assertEquals("POST", request.method());
223+
Assertions.assertTrue(request.url().isHttps());
224+
Assertions.assertEquals(3, request.url().pathSegments().size());
225+
Assertions.assertEquals("v3", request.url().pathSegments().get(0));
226+
Assertions.assertEquals("taxonomies", request.url().pathSegments().get(1));
227+
Assertions.assertEquals("publish", request.url().pathSegments().get(2));
228+
Assertions.assertNotNull(request.body());
229+
}
230+
231+
@Test
232+
void unpublishTaxonomy() {
233+
JSONObject unpublishBody = Utils.readJson("mocktaxonomy/publish.json");
234+
Request request = taxonomy.unpublish(unpublishBody).request();
235+
Assertions.assertEquals("POST", request.method());
236+
Assertions.assertTrue(request.url().isHttps());
237+
Assertions.assertEquals(3, request.url().pathSegments().size());
238+
Assertions.assertEquals("v3", request.url().pathSegments().get(0));
239+
Assertions.assertEquals("taxonomies", request.url().pathSegments().get(1));
240+
Assertions.assertEquals("unpublish", request.url().pathSegments().get(2));
241+
Assertions.assertNotNull(request.body());
242+
}
243+
244+
@Test
245+
void localizeTaxonomy() {
246+
Taxonomy uidTaxonomy = new Contentstack.Builder().setAuthtoken(TestClient.AUTHTOKEN).build()
247+
.stack(API_KEY, MANAGEMENT_TOKEN).taxonomy(_uid);
248+
JSONObject localizeBody = Utils.readJson("mocktaxonomy/localize.json");
249+
Request request = uidTaxonomy.localize(localizeBody, "hi-in").request();
250+
Assertions.assertEquals("POST", request.method());
251+
Assertions.assertTrue(request.url().isHttps());
252+
Assertions.assertEquals(3, request.url().pathSegments().size());
253+
Assertions.assertEquals("v3", request.url().pathSegments().get(0));
254+
Assertions.assertEquals("taxonomies", request.url().pathSegments().get(1));
255+
Assertions.assertEquals(_uid, request.url().pathSegments().get(2));
256+
Assertions.assertEquals("locale=hi-in", request.url().encodedQuery());
257+
Assertions.assertNotNull(request.body());
258+
}
259+
260+
@Test
261+
void unlocalizeTaxonomy() {
262+
Taxonomy uidTaxonomy = new Contentstack.Builder().setAuthtoken(TestClient.AUTHTOKEN).build()
263+
.stack(API_KEY, MANAGEMENT_TOKEN).taxonomy(_uid);
264+
Request request = uidTaxonomy.unlocalize("hi-in").request();
265+
Assertions.assertEquals("DELETE", request.method());
266+
Assertions.assertTrue(request.url().isHttps());
267+
Assertions.assertEquals(3, request.url().pathSegments().size());
268+
Assertions.assertEquals("v3", request.url().pathSegments().get(0));
269+
Assertions.assertEquals("taxonomies", request.url().pathSegments().get(1));
270+
Assertions.assertEquals(_uid, request.url().pathSegments().get(2));
271+
Assertions.assertEquals("locale=hi-in", request.url().encodedQuery());
272+
Assertions.assertNull(request.body());
273+
}
274+
275+
@Test
276+
void localizeTerm() throws IOException {
277+
terms.clearParams();
278+
JSONObject localizeBody = Utils.readJson("mocktaxonomy/localizeTerm.json");
279+
Request request = terms.localize("india", localizeBody, "hi-in").request();
280+
Assertions.assertEquals("POST", request.method());
281+
Assertions.assertTrue(request.url().isHttps());
282+
Assertions.assertEquals(5, request.url().pathSegments().size());
283+
Assertions.assertEquals("v3", request.url().pathSegments().get(0));
284+
Assertions.assertEquals("taxonomies", request.url().pathSegments().get(1));
285+
Assertions.assertEquals(_uid, request.url().pathSegments().get(2));
286+
Assertions.assertEquals("terms", request.url().pathSegments().get(3));
287+
Assertions.assertEquals("india", request.url().pathSegments().get(4));
288+
Assertions.assertEquals("locale=hi-in", request.url().encodedQuery());
289+
Assertions.assertNotNull(request.body());
290+
}
291+
292+
@Test
293+
void unlocalizeTerm() {
294+
terms.clearParams();
295+
Request request = terms.unlocalize("india", "hi-in").request();
296+
Assertions.assertEquals("DELETE", request.method());
297+
Assertions.assertTrue(request.url().isHttps());
298+
Assertions.assertEquals(5, request.url().pathSegments().size());
299+
Assertions.assertEquals("v3", request.url().pathSegments().get(0));
300+
Assertions.assertEquals("taxonomies", request.url().pathSegments().get(1));
301+
Assertions.assertEquals(_uid, request.url().pathSegments().get(2));
302+
Assertions.assertEquals("terms", request.url().pathSegments().get(3));
303+
Assertions.assertEquals("india", request.url().pathSegments().get(4));
304+
Assertions.assertEquals("locale=hi-in", request.url().encodedQuery());
305+
Assertions.assertNull(request.body());
306+
}
307+
218308
@Test
219309
void moveTerms(){
220310
terms.clearParams();

0 commit comments

Comments
 (0)