diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
index 3ff0db47..29ff233c 100644
--- a/.github/workflows/coverage.yml
+++ b/.github/workflows/coverage.yml
@@ -22,7 +22,7 @@ jobs:
run: mvn jacoco:prepare-agent jacoco:report
- name: Upload Code Coverage Report
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: code-coverage-report
path: target/site/jacoco
diff --git a/README.md b/README.md
index 0ef4f52a..7058988a 100644
--- a/README.md
+++ b/README.md
@@ -137,7 +137,7 @@ if(response.isSuccessful()){
### The MIT License (MIT)
-Copyright © 2012-2024 [Contentstack](https://www.contentstack.com/). All Rights Reserved
+Copyright © 2012-2025 [Contentstack](https://www.contentstack.com/). All Rights Reserved
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
diff --git a/changelog.md b/changelog.md
index e9427284..24296ca9 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,11 @@
# Changelog
+## v1.5.2
+
+### Feb 03, 2025
+
+- Feature added related to entry workflow methods
+
## v1.5.1
### Jan 20, 2025
diff --git a/pom.xml b/pom.xml
index 2bee5b15..6c9cbb4f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,7 @@
cms
jar
contentstack-management-java
- 1.5.1
+ 1.5.2
Contentstack Java Management SDK for Content Management API, Contentstack is a headless CMS with an
API-first approach
diff --git a/src/main/java/com/contentstack/cms/stack/Entry.java b/src/main/java/com/contentstack/cms/stack/Entry.java
index d7893869..8fb6d88e 100644
--- a/src/main/java/com/contentstack/cms/stack/Entry.java
+++ b/src/main/java/com/contentstack/cms/stack/Entry.java
@@ -825,4 +825,40 @@ public Call query(@NotNull JSONObject query) {
return this.service.filterTaxonomy(this.headers, this.contentTypeUid, query);
}
+
+ /**
+ * The Set Entry Workflow Stage request allows you to either set a particular workflow stage of an entry or update the workflow stage details of an entry.
+ * To configure the permissions for your application via OAuth,
+ * please include the cm.entry.workflow:write scope.
+ * In the 'Body' section, you need to provide the details of the workflow stage.
+ * Enter a comment for the assigned user, if needed; provide the due date;
+ * set notification settings to ‘true’, so that the specified user will be notified of it;
+ * enter the UID of the workflow stage; and finally, enter the user details, such as UID, name, and email address of the user.
+ * param query the request body of type {@link JSONObject}
+ */
+
+ public Call setWorkflowStage(@NotNull JSONObject workflow) {
+ validateCT();
+ validateEntry();
+ return this.service.setWorkflowStage(this.headers, this.contentTypeUid, this.entryUid, this.params, workflow);
+ }
+
+
+ /**
+ * This multipurpose request allows you to either send a publish request or accept/reject a received publish request.
+ * When executing the API request, in the 'Header' section,
+ * you need to provide the API Key of your stack and the authtoken that you receive after logging into your account.
+ * In the 'Body' section, you need to provide the details of the publish rule,
+ * such as its UID, action (‘publish’, ‘unpublish’, or ’both’),
+ * status (this could be ‘0’ for Approval Requested, ‘1’ for ‘Approval Accepted’, and ‘-1’ for ‘Approval Rejected’),
+ * notification setting, and comment for the approver.
+ * param query the request body of type {@link JSONObject}
+ */
+
+ public Call publishRequest(@NotNull JSONObject publishing_rule) {
+ validateCT();
+ validateEntry();
+ return this.service.publishRequestApproval(this.headers, this.contentTypeUid, this.entryUid, this.params, publishing_rule);
+ }
+
}
diff --git a/src/main/java/com/contentstack/cms/stack/EntryService.java b/src/main/java/com/contentstack/cms/stack/EntryService.java
index fa6ff789..83f54d8a 100644
--- a/src/main/java/com/contentstack/cms/stack/EntryService.java
+++ b/src/main/java/com/contentstack/cms/stack/EntryService.java
@@ -154,4 +154,19 @@ Call filterTaxonomy(
@Path("content_type_uid") String contentTypeUid,
@Query("query") JSONObject queryObject);
+ @POST("content_types/{content_type_uid}/entries/{entry_uid}/workflow")
+ Call setWorkflowStage(
+ @HeaderMap Map headers,
+ @Path("content_type_uid") String contentTypeUid,
+ @Path("entry_uid") String entryUid,
+ @QueryMap Map params,
+ @Body JSONObject body);
+
+ @POST("content_types/{content_type_uid}/entries/{entry_uid}/workflow")
+ Call publishRequestApproval(
+ @HeaderMap Map headers,
+ @Path("content_type_uid") String contentTypeUid,
+ @Path("entry_uid") String entryUid,
+ @QueryMap Map params,
+ @Body JSONObject body);
}
diff --git a/src/main/java/com/contentstack/cms/stack/WorkflowService.java b/src/main/java/com/contentstack/cms/stack/WorkflowService.java
index 68e77a64..f28588fd 100644
--- a/src/main/java/com/contentstack/cms/stack/WorkflowService.java
+++ b/src/main/java/com/contentstack/cms/stack/WorkflowService.java
@@ -45,14 +45,6 @@ Call delete(
@HeaderMap Map headers,
@Path("workflow_uid") String workflowUid);
- @POST("content_types/{content_type_uid}/entries/{entry_uid}/workflow")
- Call updateWorkflowStage(
- @HeaderMap Map headers,
- @Path("content_type_uid") String contentTypeUid,
- @Path("entry_uid") String entryUid,
- @QueryMap Map params,
- @Body JSONObject body);
-
@POST("workflows/publishing_rules")
Call createPublishRules(
@HeaderMap Map headers,
@@ -85,14 +77,6 @@ Call fetchPublishRuleContentType(
@Path("content_type_uid") String contentTypeUid,
@QueryMap Map params);
- @POST("content_types/{content_type_uid}/entries/{entry_uid}/workflow")
- Call publishRequestApproval(
- @HeaderMap Map headers,
- @Path("content_type_uid") String contentTypeUid,
- @Path("entry_uid") String entryUid,
- @QueryMap Map params,
- @Body JSONObject body);
-
@GET("workflows/content_type/{content_type_uid}")
Call fetchTasks(
@HeaderMap Map headers,
diff --git a/src/test/java/com/contentstack/cms/stack/EntryFieldUnitTests.java b/src/test/java/com/contentstack/cms/stack/EntryFieldUnitTests.java
index 1b2f1909..e61c2e1f 100644
--- a/src/test/java/com/contentstack/cms/stack/EntryFieldUnitTests.java
+++ b/src/test/java/com/contentstack/cms/stack/EntryFieldUnitTests.java
@@ -11,6 +11,8 @@
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
import org.junit.jupiter.api.*;
import java.io.IOException;
@@ -818,4 +820,96 @@ void queryFiltersOnTaxonomy() {
}
+ @Test
+ void testSetWorkflowStage() throws ParseException, IOException {
+ String workflowStagePayload = "{\n" +
+ " \"workflow\": {\n" +
+ " \"workflow_stage\": {\n" +
+ " \"uid\": \"uid\",\n" +
+ " \"assigned_by_roles\": [{ \"uid\": \"uid\", \"name\": \"Content Manager\" }],\n" +
+ " \"due_date\": \"Thu Feb 06 2025\",\n" +
+ " \"comment\": \"Review the entry\",\n" +
+ " \"notify\": true,\n" +
+ " \"assigned_to\": [{ \"uid\": \"user_uid\", \"name\": \"name\", \"email\": \"mail.com\" }]\n" +
+ " }\n" +
+ " }\n" +
+ "}";
+ JSONParser parser = new JSONParser();
+ JSONObject body = (JSONObject) parser.parse(workflowStagePayload);
+ Entry entry1 = TestClient.getClient().stack(API_KEY,MANAGEMENT_TOKEN).contentType("author").entry("entry_uid");
+ Request request = entry1.setWorkflowStage(body).request();
+ Assertions.assertNotNull(request);
+ Assertions.assertTrue(request.url().isHttps());
+ Assertions.assertEquals("api.contentstack.io", request.url().host());
+ Assertions.assertEquals(6, request.url().pathSegments().size());
+ Assertions.assertEquals("v3", request.url().pathSegments().get(0));
+ Assertions.assertEquals("content_types", request.url().pathSegments().get(1));
+ Assertions.assertEquals("author", request.url().pathSegments().get(2));
+ Assertions.assertEquals("entries", request.url().pathSegments().get(3));
+ Assertions.assertEquals("entry_uid", request.url().pathSegments().get(4));
+ Assertions.assertEquals("workflow", request.url().pathSegments().get(5));
+ Assertions.assertEquals("https://api.contentstack.io/v3/content_types/author/entries/entry_uid/workflow", request.url().toString());
+ }
+
+ @Test
+ void setWorkflowStage_VerifyQueryParams() throws ParseException {
+ String payload = "{ \"workflow\": { \"workflow_stage\": { \"uid\": \"stage_uid\" } } }";
+ JSONParser parser = new JSONParser();
+ JSONObject body = (JSONObject) parser.parse(payload);
+ Entry entry = TestClient.getClient().stack(API_KEY, MANAGEMENT_TOKEN).contentType("author").entry("entry_uid");
+ entry.addParam("locale", "en-us");
+ Request request = entry.setWorkflowStage(body).request();
+ Assertions.assertNotNull(request.url().encodedQuery());
+ Assertions.assertEquals("locale=en-us", request.url().encodedQuery());
+ Assertions.assertEquals("https://api.contentstack.io/v3/content_types/author/entries/entry_uid/workflow?locale=en-us", request.url().toString());
+ }
+
+ @Test
+ void testPublishRequest_ValidRequest() throws ParseException {
+ Contentstack contentstack = new Contentstack.Builder().setAuthtoken(TestClient.AUTHTOKEN).build();
+ Stack stack = contentstack.stack(TestClient.API_KEY, TestClient.MANAGEMENT_TOKEN);
+ String publishRequestPayload = "{\n" +
+ " \"workflow\": {\n" +
+ " \"publishing_rule\": {\n" +
+ " \"uid\": \"rule_uid\",\n" +
+ " \"action\": \"publish\",\n" +
+ " \"status\": 1,\n" +
+ " \"notify\": true,\n" +
+ " \"comment\": \"Approve this entry.\"\n" +
+ " }\n" +
+ " }\n" +
+ "}";
+ JSONParser parser = new JSONParser();
+ JSONObject body = (JSONObject) parser.parse(publishRequestPayload);
+ Request request = stack.contentType("author").entry("entry_uid").publishRequest(body).request();
+
+ Assertions.assertEquals("POST", request.method());
+ Assertions.assertEquals("https", request.url().scheme());
+ Assertions.assertEquals("api.contentstack.io", request.url().host());
+ Assertions.assertEquals("v3", request.url().pathSegments().get(0));
+ Assertions.assertEquals("content_types", request.url().pathSegments().get(1));
+ Assertions.assertEquals("author", request.url().pathSegments().get(2));
+ Assertions.assertEquals("entries", request.url().pathSegments().get(3));
+ Assertions.assertEquals("entry_uid", request.url().pathSegments().get(4));
+ Assertions.assertEquals("workflow", request.url().pathSegments().get(5));
+ Assertions.assertTrue(request.headers().names().contains("authorization"));
+ Assertions.assertTrue(request.headers().names().contains("api_key"));
+ }
+
+ @Test
+ void testPublishRequest_InvalidRequestBody() throws ParseException, IOException {
+ Contentstack contentstack = new Contentstack.Builder().setAuthtoken(TestClient.AUTHTOKEN).build();
+ Stack stack = contentstack.stack(TestClient.API_KEY, TestClient.MANAGEMENT_TOKEN);
+ String invalidPayload = "{ \"invalid_field\": \"invalid_value\" }";
+ JSONParser parser = new JSONParser();
+ JSONObject body = (JSONObject) parser.parse(invalidPayload);
+ Request request = stack.contentType("author").entry("entry_uid").publishRequest(body).request();
+ Assertions.assertEquals("POST", request.method());
+ Assertions.assertTrue(request.headers().names().contains("authorization"));
+ Assertions.assertTrue(request.headers().names().contains("api_key"));
+ Assertions.assertEquals("https", request.url().scheme());
+ Assertions.assertEquals("api.contentstack.io", request.url().host());
+ Assertions.assertEquals("v3", request.url().pathSegments().get(0));
+ }
+
}
diff --git a/src/test/java/com/contentstack/cms/stack/EntryFieldsAPITest.java b/src/test/java/com/contentstack/cms/stack/EntryFieldsAPITest.java
index ec99a09f..3879ba78 100644
--- a/src/test/java/com/contentstack/cms/stack/EntryFieldsAPITest.java
+++ b/src/test/java/com/contentstack/cms/stack/EntryFieldsAPITest.java
@@ -1,14 +1,21 @@
package com.contentstack.cms.stack;
+import com.contentstack.cms.Contentstack;
import com.contentstack.cms.TestClient;
+
import okhttp3.Request;
import okhttp3.ResponseBody;
+
import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
import org.junit.jupiter.api.*;
+
import retrofit2.Response;
import java.io.IOException;
+import org.json.simple.JSONArray;
+import org.json.simple.parser.ParseException;
@Tag("unit")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class EntryFieldsAPITest {
@@ -365,7 +372,7 @@ void testPublishWithReference() {
request.url().toString());
}
-
+ @Order(18)
@Test
public void testEntryQuery() {
JSONObject query = new JSONObject();
@@ -385,4 +392,163 @@ public void testEntryQuery() {
}
+ @Order(19)
+ @Test
+ void testSetWorkflowStage() throws ParseException, IOException {
+ String workflowStagePayload = "{\n" +
+ " \"workflow\": {\n" +
+ " \"workflow_stage\": {\n" +
+ " \"uid\": \"uid\",\n" +
+ " \"assigned_by_roles\": [{ \"uid\": \"uid\", \"name\": \"Content Manager\" }],\n" +
+ " \"due_date\": \"Thu Feb 06 2025\",\n" +
+ " \"comment\": \"Review the entry\",\n" +
+ " \"notify\": true,\n" +
+ " \"assigned_to\": [{ \"uid\": \"user_uid\", \"name\": \"name\", \"email\": \"mail.com\" }]\n" +
+ " }\n" +
+ " }\n" +
+ "}";
+ JSONParser parser = new JSONParser();
+ JSONObject body = (JSONObject) parser.parse(workflowStagePayload);
+ Entry entry1 = TestClient.getClient().stack(API_KEY,MANAGEMENT_TOKEN).contentType("author").entry("entry_uid");
+ Request request = entry1.setWorkflowStage(body).request();
+ Assertions.assertNotNull(request);
+ Assertions.assertTrue(request.url().isHttps());
+ Assertions.assertEquals("api.contentstack.io", request.url().host());
+ Assertions.assertEquals(6, request.url().pathSegments().size());
+ Assertions.assertEquals("v3", request.url().pathSegments().get(0));
+ Assertions.assertEquals("content_types", request.url().pathSegments().get(1));
+ Assertions.assertEquals("author", request.url().pathSegments().get(2));
+ Assertions.assertEquals("entries", request.url().pathSegments().get(3));
+ Assertions.assertEquals("entry_uid", request.url().pathSegments().get(4));
+ Assertions.assertEquals("workflow", request.url().pathSegments().get(5));
+ Assertions.assertEquals("https://api.contentstack.io/v3/content_types/author/entries/entry_uid/workflow", request.url().toString());
+ }
+
+ @Order(20)
+ @Test
+ void testSetWorkflowStageWithMissingFields() throws ParseException, IOException {
+ String invalidWorkflowStage = "{\n\t\"workflow\": {\n\t\t\"workflow_stage\": {\n\t\t\t\"comment\": \"Review the entry\",\n\t\t\t\"notify\": true\n\t\t}\n\t}\n}";
+ JSONParser parser = new JSONParser();
+ JSONObject body = (JSONObject) parser.parse(invalidWorkflowStage);
+ Entry entry = TestClient.getClient().stack(API_KEY, MANAGEMENT_TOKEN).contentType("author").entry("entry_uid");
+ Request request = entry.setWorkflowStage(body).request();
+ Assertions.assertNotNull(request);
+ Assertions.assertEquals("POST", request.method());
+ Assertions.assertTrue(request.url().toString().contains("workflow"));
+ Assertions.assertFalse(((JSONObject) body.get("workflow")).get("workflow_stage") instanceof JSONObject && ((JSONObject) ((JSONObject) body.get("workflow")).get("workflow_stage")).containsKey("due_date"));
+ Assertions.assertFalse(((JSONObject) body.get("workflow")).get("workflow_stage") instanceof JSONObject && ((JSONObject) ((JSONObject) body.get("workflow")).get("workflow_stage")).containsKey("assigned_to"));
+ }
+
+ @Order(21)
+ @Test
+ void setWorkflowStage_VerifyPayloadContent() throws ParseException {
+ String payload = "{ \"workflow\": { \"workflow_stage\": { \"uid\": \"stage_uid\", \"comment\": \"Approve\", \"notify\": true, \"assigned_to\": [{ \"uid\": \"user1\", \"name\": \"User One\", \"email\": \"user1@example.com\" }] } } }";
+ JSONParser parser = new JSONParser();
+ JSONObject body = (JSONObject) parser.parse(payload);
+ Entry entry = TestClient.getClient().stack(API_KEY, MANAGEMENT_TOKEN).contentType("author").entry("entry_uid");
+ Request request = entry.setWorkflowStage(body).request();
+
+ String requestBodyString = body.toJSONString();
+ JSONObject requestBodyJson = (JSONObject) parser.parse(requestBodyString);
+ JSONObject workflowStage = (JSONObject) ((JSONObject) requestBodyJson.get("workflow")).get("workflow_stage");
+ Assertions.assertEquals("stage_uid", (String) workflowStage.get("uid"));
+ Assertions.assertEquals("Approve", (String) workflowStage.get("comment"));
+ Assertions.assertTrue((Boolean) workflowStage.get("notify"));
+
+ JSONArray assignedTo = (JSONArray) workflowStage.get("assigned_to");
+ Assertions.assertEquals(1, assignedTo.size());
+ JSONObject assignedToUser = (JSONObject) assignedTo.get(0);
+ Assertions.assertEquals("user1", assignedToUser.get("uid"));
+ Assertions.assertEquals("User One", assignedToUser.get("name"));
+ Assertions.assertEquals("user1@example.com", assignedToUser.get("email"));
+ }
+
+ @Order(22)
+ @Test
+ void setWorkflowStage_VerifyQueryParams() throws ParseException {
+ String payload = "{ \"workflow\": { \"workflow_stage\": { \"uid\": \"stage_uid\" } } }";
+ JSONParser parser = new JSONParser();
+ JSONObject body = (JSONObject) parser.parse(payload);
+ Entry entry = TestClient.getClient().stack(API_KEY, MANAGEMENT_TOKEN).contentType("author").entry("entry_uid");
+ entry.addParam("locale", "en-us");
+ Request request = entry.setWorkflowStage(body).request();
+ Assertions.assertNotNull(request.url().encodedQuery());
+ Assertions.assertEquals("locale=en-us", request.url().encodedQuery());
+ Assertions.assertEquals("https://api.contentstack.io/v3/content_types/author/entries/entry_uid/workflow?locale=en-us", request.url().toString());
+ }
+
+ @Order(23)
+ @Test
+ void testPublishRequest_ValidRequest() throws ParseException {
+ Contentstack contentstack = new Contentstack.Builder().setAuthtoken(TestClient.AUTHTOKEN).build();
+ Stack stack = contentstack.stack(TestClient.API_KEY, TestClient.MANAGEMENT_TOKEN);
+ String publishRequestPayload = "{\n" +
+ " \"workflow\": {\n" +
+ " \"publishing_rule\": {\n" +
+ " \"uid\": \"rule_uid\",\n" +
+ " \"action\": \"publish\",\n" +
+ " \"status\": 1,\n" +
+ " \"notify\": true,\n" +
+ " \"comment\": \"Approve this entry.\"\n" +
+ " }\n" +
+ " }\n" +
+ "}";
+ JSONParser parser = new JSONParser();
+ JSONObject body = (JSONObject) parser.parse(publishRequestPayload);
+ Request request = stack.contentType("author").entry("entry_uid").publishRequest(body).request();
+
+ Assertions.assertEquals("POST", request.method());
+ Assertions.assertEquals("https", request.url().scheme());
+ Assertions.assertEquals("api.contentstack.io", request.url().host());
+ Assertions.assertEquals("v3", request.url().pathSegments().get(0));
+ Assertions.assertEquals("content_types", request.url().pathSegments().get(1));
+ Assertions.assertEquals("author", request.url().pathSegments().get(2));
+ Assertions.assertEquals("entries", request.url().pathSegments().get(3));
+ Assertions.assertEquals("entry_uid", request.url().pathSegments().get(4));
+ Assertions.assertEquals("workflow", request.url().pathSegments().get(5));
+ Assertions.assertTrue(request.headers().names().contains("authorization"));
+ Assertions.assertTrue(request.headers().names().contains("api_key"));
+ }
+
+ @Order(24)
+ @Test
+ void testPublishRequest_InvalidRequestBody() throws ParseException, IOException {
+ Contentstack contentstack = new Contentstack.Builder().setAuthtoken(TestClient.AUTHTOKEN).build();
+ Stack stack = contentstack.stack(TestClient.API_KEY, TestClient.MANAGEMENT_TOKEN);
+ String invalidPayload = "{ \"invalid_field\": \"invalid_value\" }";
+ JSONParser parser = new JSONParser();
+ JSONObject body = (JSONObject) parser.parse(invalidPayload);
+ Request request = stack.contentType("author").entry("entry_uid").publishRequest(body).request();
+ Assertions.assertEquals("POST", request.method());
+ Assertions.assertTrue(request.headers().names().contains("authorization"));
+ Assertions.assertTrue(request.headers().names().contains("api_key"));
+ Assertions.assertEquals("https", request.url().scheme());
+ Assertions.assertEquals("api.contentstack.io", request.url().host());
+ Assertions.assertEquals("v3", request.url().pathSegments().get(0));
+ }
+
+ @Order(25)
+ @Test
+ void testPublishRequest_RejectRequest() throws ParseException {
+ Contentstack contentstack = new Contentstack.Builder().setAuthtoken(TestClient.AUTHTOKEN).build();
+ Stack stack = contentstack.stack(TestClient.API_KEY, TestClient.MANAGEMENT_TOKEN);
+ String rejectRequestPayload = "{\n" +
+ " \"workflow\": {\n" +
+ " \"publishing_rule\": {\n" +
+ " \"uid\": \"rule_uid\",\n" +
+ " \"action\": \"unpublish\",\n" +
+ " \"status\": -1,\n" +
+ " \"notify\": false,\n" +
+ " \"comment\": \"Rejected due to incomplete information.\"\n" +
+ " }\n" +
+ " }\n" +
+ "}";
+ JSONParser parser = new JSONParser();
+ JSONObject body = (JSONObject) parser.parse(rejectRequestPayload);
+ Request request = stack.contentType("author").entry("entry_uid").publishRequest(body).request();
+ Assertions.assertEquals("POST", request.method());
+ Assertions.assertTrue(request.url().toString().contains("/workflow"));
+ Assertions.assertTrue(request.headers().names().contains("authorization"));
+ }
+
}