diff --git a/docs-core/src/main/resources/db/update/dbupdate-015-0.sql b/docs-core/src/main/resources/db/update/dbupdate-015-0.sql index a5c2af7f..cba91ec2 100644 --- a/docs-core/src/main/resources/db/update/dbupdate-015-0.sql +++ b/docs-core/src/main/resources/db/update/dbupdate-015-0.sql @@ -3,4 +3,7 @@ create cached table T_ROUTE ( RTE_ID_C varchar(36) not null, RTE_IDDOCUMENT_C va create cached table T_ROUTE_STEP ( RTP_ID_C varchar(36) not null, RTP_IDROUTE_C varchar(36) not null, RTP_NAME_C varchar(200) not null, RTP_TYPE_C varchar(50) not null, RTP_TRANSITION_C varchar(50), RTP_COMMENT_C varchar(500), RTP_IDTARGET_C varchar(36) not null, RTP_ORDER_N int not null, RTE_CREATEDATE_D datetime not null, RTP_ENDDATE_D datetime, RTP_DELETEDATE_D datetime, primary key (RTP_ID_C) );; alter table T_ROUTE add constraint FK_RTE_IDDOCUMENT_C foreign key (RTE_IDDOCUMENT_C) references T_DOCUMENT (DOC_ID_C) on delete restrict on update restrict; alter table T_ROUTE_STEP add constraint FK_RTP_IDROUTE_C foreign key (RTP_IDROUTE_C) references T_ROUTE (RTE_ID_C) on delete restrict on update restrict; + +insert into T_ROUTE_MODEL (RTM_ID_C, RTM_NAME_C, RTM_STEPS_C, RTM_CREATEDATE_D) values ('default-document-review', 'Document review', '[{"type":"VALIDATE","target":{"name":"administrators","type":"GROUP"},"name":"Check the document''s metadata"},{"type":"VALIDATE","target":{"name":"administrators","type":"GROUP"},"name":"Add relevant files to the document"},{"type":"APPROVE","target":{"name":"administrators","type":"GROUP"},"name":"Approve the document"}]', now()); + update T_CONFIG set CFG_VALUE_C = '15' where CFG_ID_C = 'DB_VERSION'; diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/RouteModelResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/RouteModelResource.java index 1ef943bc..cd5c4f4f 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/RouteModelResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/RouteModelResource.java @@ -1,19 +1,25 @@ package com.sismics.docs.rest.resource; +import com.sismics.docs.core.constant.AclTargetType; +import com.sismics.docs.core.constant.RouteStepType; +import com.sismics.docs.core.dao.jpa.GroupDao; import com.sismics.docs.core.dao.jpa.RouteModelDao; +import com.sismics.docs.core.dao.jpa.UserDao; import com.sismics.docs.core.dao.jpa.criteria.RouteModelCriteria; import com.sismics.docs.core.dao.jpa.dto.RouteModelDto; +import com.sismics.docs.core.model.jpa.Group; import com.sismics.docs.core.model.jpa.RouteModel; +import com.sismics.docs.core.model.jpa.User; import com.sismics.docs.core.util.jpa.SortCriteria; import com.sismics.docs.rest.constant.BaseFunction; +import com.sismics.rest.exception.ClientException; import com.sismics.rest.exception.ForbiddenClientException; import com.sismics.rest.util.ValidationUtil; -import javax.json.Json; -import javax.json.JsonArrayBuilder; -import javax.json.JsonObjectBuilder; +import javax.json.*; import javax.ws.rs.*; import javax.ws.rs.core.Response; +import java.io.StringReader; import java.util.List; /** @@ -91,7 +97,8 @@ public class RouteModelResource extends BaseResource { // Validate input name = ValidationUtil.validateLength(name, "name", 1, 50, false); - // TODO Validate steps data + steps = ValidationUtil.validateLength(steps, "steps", 1, 5000, false); + validateRouteModelSteps(steps); // Create the route model RouteModelDao routeModelDao = new RouteModelDao(); @@ -105,6 +112,66 @@ public class RouteModelResource extends BaseResource { return Response.ok().entity(response.build()).build(); } + /** + * Validate route model steps. + * + * @param steps Route model steps data + */ + private void validateRouteModelSteps(String steps) { + UserDao userDao = new UserDao(); + GroupDao groupDao = new GroupDao(); + + try (JsonReader reader = Json.createReader(new StringReader(steps))) { + JsonArray stepsJson = reader.readArray(); + if (stepsJson.size() == 0) { + throw new ClientException("ValidationError", "At least one step is required"); + } + for (int i = 0; i < stepsJson.size(); i++) { + JsonObject step = stepsJson.getJsonObject(i); + if (step.size() != 3) { + throw new ClientException("ValidationError", "Steps data not valid"); + } + String type = step.getString("type"); + ValidationUtil.validateLength(step.getString("name"), "step.name", 1, 200, false); + try { + RouteStepType.valueOf(type); + } catch (IllegalArgumentException e) { + throw new ClientException("ValidationError", type + "is not a valid route step type"); + } + JsonObject target = step.getJsonObject("target"); + if (target.size() != 2) { + throw new ClientException("ValidationError", "Steps data not valid"); + } + AclTargetType targetType; + String targetTypeStr = target.getString("type"); + String targetName = target.getString("name"); + ValidationUtil.validateRequired(targetName, "step.target.name"); + ValidationUtil.validateRequired(targetTypeStr, "step.target.type"); + try { + targetType = AclTargetType.valueOf(targetTypeStr); + } catch (IllegalArgumentException e) { + throw new ClientException("ValidationError", targetTypeStr + " is not a valid ACL target type"); + } + switch (targetType) { + case USER: + User user = userDao.getActiveByUsername(targetName); + if (user == null) { + throw new ClientException("ValidationError", targetName + " is not a valid user"); + } + break; + case GROUP: + Group group = groupDao.getActiveByName(targetName); + if (group == null) { + throw new ClientException("ValidationError", targetName + " is not a valid group"); + } + break; + } + } + } catch (JsonException e) { + throw new ClientException("ValidationError", "Steps data not valid"); + } + } + /** * Update a route model. * diff --git a/docs-web/src/main/webapp/src/partial/docs/settings.workflow.html b/docs-web/src/main/webapp/src/partial/docs/settings.workflow.html index a02a9238..707a67a6 100644 --- a/docs-web/src/main/webapp/src/partial/docs/settings.workflow.html +++ b/docs-web/src/main/webapp/src/partial/docs/settings.workflow.html @@ -5,7 +5,7 @@
- +
diff --git a/docs-web/src/test/java/com/sismics/docs/rest/TestRouteModelResource.java b/docs-web/src/test/java/com/sismics/docs/rest/TestRouteModelResource.java index ce6fedd1..7d41201d 100644 --- a/docs-web/src/test/java/com/sismics/docs/rest/TestRouteModelResource.java +++ b/docs-web/src/test/java/com/sismics/docs/rest/TestRouteModelResource.java @@ -26,31 +26,31 @@ public class TestRouteModelResource extends BaseJerseyTest { // Get all route models JsonObject json = target().path("/routemodel") - .queryParam("sort_column", "1") - .queryParam("asc", "true") + .queryParam("sort_column", "2") + .queryParam("asc", "false") .request() .cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken) .get(JsonObject.class); JsonArray routeModels = json.getJsonArray("routemodels"); - Assert.assertEquals(0, routeModels.size()); + Assert.assertEquals(1, routeModels.size()); // Create a route model json = target().path("/routemodel").request() .cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken) .put(Entity.form(new Form() .param("name", "Workflow validation 1") - .param("steps", "[]")), JsonObject.class); + .param("steps", "[{\"type\":\"VALIDATE\",\"target\":{\"name\":\"administrators\",\"type\":\"GROUP\"},\"name\":\"Check the document's metadata\"}]")), JsonObject.class); String routeModelId = json.getString("id"); // Get all route models json = target().path("/routemodel") - .queryParam("sort_column", "1") - .queryParam("asc", "true") + .queryParam("sort_column", "2") + .queryParam("asc", "false") .request() .cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken) .get(JsonObject.class); routeModels = json.getJsonArray("routemodels"); - Assert.assertEquals(1, routeModels.size()); + Assert.assertEquals(2, routeModels.size()); Assert.assertEquals(routeModelId, routeModels.getJsonObject(0).getString("id")); Assert.assertEquals("Workflow validation 1", routeModels.getJsonObject(0).getString("name")); @@ -61,14 +61,14 @@ public class TestRouteModelResource extends BaseJerseyTest { .get(JsonObject.class); Assert.assertEquals(routeModelId, json.getString("id")); Assert.assertEquals("Workflow validation 1", json.getString("name")); - Assert.assertEquals("[]", json.getString("steps")); + Assert.assertEquals("[{\"type\":\"VALIDATE\",\"target\":{\"name\":\"administrators\",\"type\":\"GROUP\"},\"name\":\"Check the document's metadata\"}]", json.getString("steps")); // Update the route model - json = target().path("/routemodel/" + routeModelId).request() + target().path("/routemodel/" + routeModelId).request() .cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken) .post(Entity.form(new Form() .param("name", "Workflow validation 2") - .param("steps", "[{}]")), JsonObject.class); + .param("steps", "[{\"type\":\"APPROVE\",\"target\":{\"name\":\"administrators\",\"type\":\"GROUP\"},\"name\":\"Check the document's metadata\"}]")), JsonObject.class); // Get the route model json = target().path("/routemodel/" + routeModelId) @@ -77,7 +77,7 @@ public class TestRouteModelResource extends BaseJerseyTest { .get(JsonObject.class); Assert.assertEquals(routeModelId, json.getString("id")); Assert.assertEquals("Workflow validation 2", json.getString("name")); - Assert.assertEquals("[{}]", json.getString("steps")); + Assert.assertEquals("[{\"type\":\"APPROVE\",\"target\":{\"name\":\"administrators\",\"type\":\"GROUP\"},\"name\":\"Check the document's metadata\"}]", json.getString("steps")); // Delete the route model target().path("/routemodel/" + routeModelId) @@ -87,12 +87,12 @@ public class TestRouteModelResource extends BaseJerseyTest { // Get all route models json = target().path("/routemodel") - .queryParam("sort_column", "1") - .queryParam("asc", "true") + .queryParam("sort_column", "2") + .queryParam("asc", "false") .request() .cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken) .get(JsonObject.class); routeModels = json.getJsonArray("routemodels"); - Assert.assertEquals(0, routeModels.size()); + Assert.assertEquals(1, routeModels.size()); } } \ No newline at end of file
{{ 'settings.workflow.name' | translate }}