mirror of
https://github.com/sismics/docs.git
synced 2024-06-03 00:54:32 +02:00
306 lines
12 KiB
Java
306 lines
12 KiB
Java
package com.sismics.docs.rest.resource;
|
|
|
|
import com.sismics.docs.core.constant.AclTargetType;
|
|
import com.sismics.docs.core.constant.PermType;
|
|
import com.sismics.docs.core.constant.RouteStepTransition;
|
|
import com.sismics.docs.core.constant.RouteStepType;
|
|
import com.sismics.docs.core.dao.jpa.*;
|
|
import com.sismics.docs.core.dao.jpa.criteria.RouteCriteria;
|
|
import com.sismics.docs.core.dao.jpa.criteria.RouteStepCriteria;
|
|
import com.sismics.docs.core.dao.jpa.dto.DocumentDto;
|
|
import com.sismics.docs.core.dao.jpa.dto.RouteDto;
|
|
import com.sismics.docs.core.dao.jpa.dto.RouteStepDto;
|
|
import com.sismics.docs.core.model.jpa.Route;
|
|
import com.sismics.docs.core.model.jpa.RouteModel;
|
|
import com.sismics.docs.core.model.jpa.RouteStep;
|
|
import com.sismics.docs.core.util.RoutingUtil;
|
|
import com.sismics.docs.core.util.SecurityUtil;
|
|
import com.sismics.docs.core.util.jpa.SortCriteria;
|
|
import com.sismics.rest.exception.ClientException;
|
|
import com.sismics.rest.exception.ForbiddenClientException;
|
|
import com.sismics.rest.util.ValidationUtil;
|
|
|
|
import javax.json.*;
|
|
import javax.ws.rs.*;
|
|
import javax.ws.rs.core.Response;
|
|
import java.io.StringReader;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* Route REST resources.
|
|
*
|
|
* @author bgamard
|
|
*/
|
|
@Path("/route")
|
|
public class RouteResource extends BaseResource {
|
|
/**
|
|
* Start a route on a document.
|
|
*
|
|
* @api {post} /route/start Start a route on a document
|
|
* @apiName PostRouteStart
|
|
* @apiRouteModel Route
|
|
* @apiParam {String} routeModelId Route model ID
|
|
* @apiParam {String} documentId Document ID
|
|
* @apiSuccess {String} status Status OK
|
|
* @apiError (client) InvalidRouteModel Invalid route model
|
|
* @apiError (client) RunningRoute A running route already exists on this document
|
|
* @apiError (client) ForbiddenError Access denied
|
|
* @apiError (client) NotFound Route model or document not found
|
|
* @apiPermission user
|
|
* @apiVersion 1.5.0
|
|
*
|
|
* @return Response
|
|
*/
|
|
@POST
|
|
@Path("start")
|
|
public Response start(@FormParam("routeModelId") String routeModelId,
|
|
@FormParam("documentId") String documentId) {
|
|
if (!authenticate()) {
|
|
throw new ForbiddenClientException();
|
|
}
|
|
|
|
// Get the document
|
|
AclDao aclDao = new AclDao();
|
|
if (!aclDao.checkPermission(documentId, PermType.WRITE, getTargetIdList(null))) {
|
|
throw new NotFoundException();
|
|
}
|
|
|
|
// Get the route model
|
|
RouteModelDao routeModelDao = new RouteModelDao();
|
|
RouteModel routeModel = routeModelDao.getActiveById(routeModelId);
|
|
if (routeModel == null) {
|
|
throw new NotFoundException();
|
|
}
|
|
|
|
// Avoid creating 2 running routes on the same document
|
|
RouteStepDao routeStepDao = new RouteStepDao();
|
|
if (routeStepDao.getCurrentStep(documentId) != null) {
|
|
throw new ClientException("RunningRoute", "A running route already exists on this document");
|
|
}
|
|
|
|
// Create the route
|
|
Route route = new Route()
|
|
.setDocumentId(documentId)
|
|
.setName(routeModel.getName());
|
|
RouteDao routeDao = new RouteDao();
|
|
routeDao.create(route, principal.getId());
|
|
|
|
// Create the steps
|
|
try (JsonReader reader = Json.createReader(new StringReader(routeModel.getSteps()))) {
|
|
JsonArray stepsJson = reader.readArray();
|
|
for (int order = 0; order < stepsJson.size(); order++) {
|
|
JsonObject step = stepsJson.getJsonObject(order);
|
|
JsonObject target = step.getJsonObject("target");
|
|
AclTargetType targetType = AclTargetType.valueOf(target.getString("type"));
|
|
String targetName = target.getString("name");
|
|
|
|
RouteStep routeStep = new RouteStep()
|
|
.setRouteId(route.getId())
|
|
.setName(step.getString("name"))
|
|
.setOrder(order)
|
|
.setType(RouteStepType.valueOf(step.getString("type")))
|
|
.setTargetId(SecurityUtil.getTargetIdFromName(targetName, targetType));
|
|
|
|
if (routeStep.getTargetId() == null) {
|
|
throw new ClientException("InvalidRouteModel", "A step has an invalid target");
|
|
}
|
|
|
|
routeStepDao.create(routeStep);
|
|
}
|
|
}
|
|
|
|
// Intialize ACLs on the first step
|
|
RouteStepDto routeStepDto = routeStepDao.getCurrentStep(documentId);
|
|
RoutingUtil.updateAcl(documentId, routeStepDto, null, principal.getId());
|
|
RoutingUtil.sendRouteStepEmail(documentId, routeStepDto);
|
|
|
|
JsonObjectBuilder step = routeStepDto.toJson();
|
|
step.add("transitionable", getTargetIdList(null).contains(routeStepDto.getTargetId()));
|
|
JsonObjectBuilder response = Json.createObjectBuilder()
|
|
.add("route_step", step);
|
|
return Response.ok().entity(response.build()).build();
|
|
}
|
|
|
|
/**
|
|
* Validate the current step of a route.
|
|
*
|
|
* @api {post} /route/validate Validate the current step of a route
|
|
* @apiName PostRouteValidate
|
|
* @apiRouteModel Route
|
|
* @apiParam {String} documentId Document ID
|
|
* @apiParam {String} transition Route step transition
|
|
* @apiParam {String} comment Route step comment
|
|
* @apiSuccess {String} status Status OK
|
|
* @apiError (client) ForbiddenError Access denied
|
|
* @apiError (client) NotFound Document or route not found
|
|
* @apiPermission user
|
|
* @apiVersion 1.5.0
|
|
*
|
|
* @return Response
|
|
*/
|
|
@POST
|
|
@Path("validate")
|
|
public Response validate(@FormParam("documentId") String documentId,
|
|
@FormParam("transition") String transitionStr,
|
|
@FormParam("comment") String comment) {
|
|
if (!authenticate()) {
|
|
throw new ForbiddenClientException();
|
|
}
|
|
|
|
// Get the document
|
|
AclDao aclDao = new AclDao();
|
|
if (!aclDao.checkPermission(documentId, PermType.READ, getTargetIdList(null))) {
|
|
throw new NotFoundException();
|
|
}
|
|
|
|
// Get the current step
|
|
RouteStepDao routeStepDao = new RouteStepDao();
|
|
RouteStepDto routeStepDto = routeStepDao.getCurrentStep(documentId);
|
|
if (routeStepDto == null) {
|
|
throw new NotFoundException();
|
|
}
|
|
|
|
// Check permission to validate this step
|
|
if (!getTargetIdList(null).contains(routeStepDto.getTargetId())) {
|
|
throw new ForbiddenClientException();
|
|
}
|
|
|
|
// Validate data
|
|
ValidationUtil.validateRequired(transitionStr, "transition");
|
|
comment = ValidationUtil.validateLength(comment, "comment", 1, 500, true);
|
|
RouteStepTransition transition = RouteStepTransition.valueOf(transitionStr);
|
|
if (routeStepDto.getType() == RouteStepType.VALIDATE && transition != RouteStepTransition.VALIDATED
|
|
|| routeStepDto.getType() == RouteStepType.APPROVE && transition != RouteStepTransition.APPROVED && transition != RouteStepTransition.REJECTED) {
|
|
throw new ClientException("ValidationError", "Invalid transition for this route step type");
|
|
}
|
|
|
|
// Validate the step and update ACLs
|
|
routeStepDao.endRouteStep(routeStepDto.getId(), transition, comment, principal.getId());
|
|
RouteStepDto newRouteStep = routeStepDao.getCurrentStep(documentId);
|
|
RoutingUtil.updateAcl(documentId, newRouteStep, routeStepDto, principal.getId());
|
|
RoutingUtil.sendRouteStepEmail(documentId, routeStepDto);
|
|
|
|
JsonObjectBuilder response = Json.createObjectBuilder()
|
|
.add("readable", aclDao.checkPermission(documentId, PermType.READ, getTargetIdList(null)));
|
|
if (newRouteStep != null) {
|
|
JsonObjectBuilder step = newRouteStep.toJson();
|
|
step.add("transitionable", getTargetIdList(null).contains(newRouteStep.getTargetId()));
|
|
response.add("route_step", step);
|
|
}
|
|
return Response.ok().entity(response.build()).build();
|
|
}
|
|
|
|
/**
|
|
* Returns the routes on a document.
|
|
*
|
|
* @api {get} /route Get the routes on a document
|
|
* @apiName GetRoutes
|
|
* @apiGroup Route
|
|
* @apiParam {String} id Document ID
|
|
* @apiSuccess {Object[]} routes List of routes
|
|
* @apiSuccess {String} routes.name Name
|
|
* @apiSuccess {Number} routes.create_date Create date (timestamp)
|
|
* @apiSuccess {Object[]} routes.steps Route steps
|
|
* @apiSuccess {String} routes.steps.name Route step name
|
|
* @apiSuccess {String="APPROVE", "VALIDATE"} routes.steps.type Route step type
|
|
* @apiSuccess {String} routes.steps.comment Route step comment
|
|
* @apiSuccess {Number} routes.steps.end_date Route step end date (timestamp)
|
|
* @apiSuccess {String="APPROVED","REJECTED","VALIDATED"} routes.steps.transition Route step transition
|
|
* @apiSuccess {Object} routes.steps.validator_username Validator username
|
|
* @apiSuccess {Object} routes.steps.target Route step target
|
|
* @apiSuccess {String} routes.steps.target.id Route step target ID
|
|
* @apiSuccess {String} routes.steps.target.name Route step target name
|
|
* @apiSuccess {String="USER","GROUP"} routes.steps.target.type Route step target type
|
|
* @apiError (client) NotFound Document not found
|
|
* @apiPermission none
|
|
* @apiVersion 1.5.0
|
|
*
|
|
* @param documentId Document ID
|
|
* @return Response
|
|
*/
|
|
@GET
|
|
public Response get(@QueryParam("documentId") String documentId) {
|
|
if (!authenticate()) {
|
|
throw new ForbiddenClientException();
|
|
}
|
|
|
|
DocumentDao documentDao = new DocumentDao();
|
|
DocumentDto documentDto = documentDao.getDocument(documentId, PermType.READ, getTargetIdList(null));
|
|
if (documentDto == null) {
|
|
throw new NotFoundException();
|
|
}
|
|
|
|
JsonArrayBuilder routes = Json.createArrayBuilder();
|
|
|
|
RouteDao routeDao = new RouteDao();
|
|
RouteStepDao routeStepDao = new RouteStepDao();
|
|
List<RouteDto> routeDtoList = routeDao.findByCriteria(new RouteCriteria()
|
|
.setDocumentId(documentId), new SortCriteria(2, false));
|
|
for (RouteDto routeDto : routeDtoList) {
|
|
List<RouteStepDto> routeStepDtoList = routeStepDao.findByCriteria(new RouteStepCriteria()
|
|
.setRouteId(routeDto.getId()), new SortCriteria(6, true));
|
|
JsonArrayBuilder steps = Json.createArrayBuilder();
|
|
|
|
for (RouteStepDto routeStepDto : routeStepDtoList) {
|
|
steps.add(routeStepDto.toJson());
|
|
}
|
|
|
|
routes.add(Json.createObjectBuilder()
|
|
.add("name", routeDto.getName())
|
|
.add("create_date", routeDto.getCreateTimestamp())
|
|
.add("steps", steps));
|
|
}
|
|
|
|
JsonObjectBuilder json = Json.createObjectBuilder()
|
|
.add("routes", routes);
|
|
return Response.ok().entity(json.build()).build();
|
|
}
|
|
|
|
/**
|
|
* Cancel a route.
|
|
*
|
|
* @api {delete} /route Cancel a route
|
|
* @apiName DeleteRoute
|
|
* @apiRouteModel Route
|
|
* @apiParam {String} documentId Document ID
|
|
* @apiSuccess {String} status Status OK
|
|
* @apiError (client) ForbiddenError Access denied
|
|
* @apiError (client) NotFound Document or route not found
|
|
* @apiPermission user
|
|
* @apiVersion 1.5.0
|
|
*
|
|
* @return Response
|
|
*/
|
|
@DELETE
|
|
public Response delete(@QueryParam("documentId") String documentId) {
|
|
if (!authenticate()) {
|
|
throw new ForbiddenClientException();
|
|
}
|
|
|
|
// Get the document
|
|
AclDao aclDao = new AclDao();
|
|
if (!aclDao.checkPermission(documentId, PermType.WRITE, getTargetIdList(null))) {
|
|
throw new NotFoundException();
|
|
}
|
|
|
|
// Get the current step
|
|
RouteStepDao routeStepDao = new RouteStepDao();
|
|
RouteStepDto routeStepDto = routeStepDao.getCurrentStep(documentId);
|
|
if (routeStepDto == null) {
|
|
throw new NotFoundException();
|
|
}
|
|
|
|
// Remove the temporary ACLs
|
|
RoutingUtil.updateAcl(documentId, null, routeStepDto, principal.getId());
|
|
|
|
// Delete the route and the steps
|
|
RouteDao routeDao = new RouteDao();
|
|
routeDao.deleteRoute(routeStepDto.getRouteId());
|
|
|
|
// Always return OK
|
|
JsonObjectBuilder response = Json.createObjectBuilder()
|
|
.add("status", "ok");
|
|
return Response.ok().entity(response.build()).build();
|
|
}
|
|
}
|