1
0
mirror of https://github.com/sismics/docs.git synced 2025-12-18 12:11:40 +00:00

#159: validate route steps

This commit is contained in:
Benjamin Gamard
2018-02-01 18:01:11 +01:00
parent c9adff5a25
commit 2b4ddfa072
14 changed files with 352 additions and 91 deletions

View File

@@ -1,7 +1,6 @@
package com.sismics.docs.core.dao.jpa;
import com.sismics.docs.core.constant.AclTargetType;
import com.sismics.docs.core.constant.AclType;
import com.sismics.docs.core.constant.AuditLogType;
import com.sismics.docs.core.constant.PermType;
import com.sismics.docs.core.dao.jpa.dto.AclDto;
@@ -65,7 +64,7 @@ public class AclDao {
* @return ACL DTO list
*/
@SuppressWarnings("unchecked")
public List<AclDto> getBySourceId(String sourceId, AclType type) {
public List<AclDto> getBySourceId(String sourceId) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
StringBuilder sb = new StringBuilder("select a.ACL_ID_C, a.ACL_PERM_C, a.ACL_TARGETID_C, ");
sb.append(" u.USE_USERNAME_C, s.SHA_ID_C, s.SHA_NAME_C, g.GRP_NAME_C ");
@@ -73,12 +72,11 @@ public class AclDao {
sb.append(" left join T_USER u on u.USE_ID_C = a.ACL_TARGETID_C ");
sb.append(" left join T_SHARE s on s.SHA_ID_C = a.ACL_TARGETID_C ");
sb.append(" left join T_GROUP g on g.GRP_ID_C = a.ACL_TARGETID_C ");
sb.append(" where a.ACL_DELETEDATE_D is null and a.ACL_SOURCEID_C = :sourceId and a.ACL_TYPE_C = :type ");
sb.append(" where a.ACL_DELETEDATE_D is null and a.ACL_SOURCEID_C = :sourceId ");
// Perform the query
Query q = em.createNativeQuery(sb.toString());
q.setParameter("sourceId", sourceId);
q.setParameter("type", type.name());
List<Object[]> l = q.getResultList();
// Assemble results
@@ -142,29 +140,26 @@ public class AclDao {
* @param perm Permission
* @param targetId Target ID
* @param userId User ID
* @param type Type
*/
@SuppressWarnings("unchecked")
public void delete(String sourceId, PermType perm, String targetId, String userId, AclType type) {
public void delete(String sourceId, PermType perm, String targetId, String userId) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
// Create audit log
Query q = em.createQuery("from Acl a where a.sourceId = :sourceId and a.perm = :perm and a.targetId = :targetId and a.type = :type");
Query q = em.createQuery("from Acl a where a.sourceId = :sourceId and a.perm = :perm and a.targetId = :targetId");
q.setParameter("sourceId", sourceId);
q.setParameter("perm", perm);
q.setParameter("targetId", targetId);
q.setParameter("type", type);
List<Acl> aclList = q.getResultList();
for (Acl acl : aclList) {
AuditLogUtil.create(acl, AuditLogType.DELETE, userId);
}
// Soft delete the ACLs
q = em.createQuery("update Acl a set a.deleteDate = :dateNow where a.sourceId = :sourceId and a.perm = :perm and a.targetId = :targetId and a.type = :type");
q = em.createQuery("update Acl a set a.deleteDate = :dateNow where a.sourceId = :sourceId and a.perm = :perm and a.targetId = :targetId");
q.setParameter("sourceId", sourceId);
q.setParameter("perm", perm);
q.setParameter("targetId", targetId);
q.setParameter("type", type);
q.setParameter("dateNow", new Date());
q.executeUpdate();
}

View File

@@ -6,9 +6,7 @@ import com.sismics.docs.core.util.AuditLogUtil;
import com.sismics.util.context.ThreadLocalContext;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.Date;
import java.util.List;
import java.util.UUID;
/**
@@ -38,12 +36,4 @@ public class RouteDao {
return route.getId();
}
@SuppressWarnings("unchecked")
public List<Route> getActiveRoutes(String documentId) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
Query q = em.createQuery("from Route r where r.documentId = :documentId and r.deleteDate is null order by r.createDate desc");
q.setParameter("documentId", documentId);
return q.getResultList();
}
}

View File

@@ -1,10 +1,14 @@
package com.sismics.docs.core.dao.jpa;
import com.sismics.docs.core.constant.RouteStepTransition;
import com.sismics.docs.core.constant.RouteStepType;
import com.sismics.docs.core.dao.jpa.dto.RouteStepDto;
import com.sismics.docs.core.model.jpa.RouteStep;
import com.sismics.util.context.ThreadLocalContext;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;
import java.util.UUID;
@@ -33,11 +37,63 @@ public class RouteStepDao {
return routeStep.getId();
}
/**
* Get the current route step from a document.
*
* @param documentId Document ID
* @return Current route step
*/
@SuppressWarnings("unchecked")
public List<RouteStep> getRouteSteps(String routeId) {
public RouteStepDto getCurrentStep(String documentId) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
Query q = em.createQuery("from RouteStep r where r.routeId = :routeId and r.deleteDate is null order by r.order asc");
q.setParameter("routeId", routeId);
return q.getResultList();
StringBuilder sb = new StringBuilder("select rs.RTP_ID_C, rs.RTP_NAME_C, rs.RTP_TYPE_C, rs.RTP_TRANSITION_C, rs.RTP_COMMENT_C, rs.RTP_IDTARGET_C, rs.RTP_ENDDATE_D");
sb.append(" from T_ROUTE_STEP rs ");
sb.append(" join T_ROUTE r on r.RTE_ID_C = rs.RTP_IDROUTE_C ");
sb.append(" where r.RTE_IDDOCUMENT_C = :documentId and rs.RTP_ENDDATE_D is null ");
sb.append(" order by rs.RTP_ORDER_N asc ");
Query q = em.createNativeQuery(sb.toString());
q.setParameter("documentId", documentId);
List<Object[]> l = q.getResultList();
if (l.isEmpty()) {
return null;
}
Object[] o = l.get(0);
int i = 0;
RouteStepDto routeStepDto = new RouteStepDto();
routeStepDto.setId((String) o[i++]);
routeStepDto.setName((String) o[i++]);
routeStepDto.setType(RouteStepType.valueOf((String) o[i++]));
String transition = (String) o[i++];
routeStepDto.setTransition(transition == null ? null : RouteStepTransition.valueOf(transition));
routeStepDto.setComment((String) o[i++]);
routeStepDto.setTargetId((String) o[i++]);
Timestamp endDateTimestamp = (Timestamp) o[i];
routeStepDto.setEndDateTimestamp(endDateTimestamp == null ? null : endDateTimestamp.getTime());
return routeStepDto;
}
/**
* End a route step.
*
* @param id Route step ID
* @param transition Transition
* @param comment Comment
* @param validatorUserId Validator user ID
*/
public void endRouteStep(String id, RouteStepTransition transition, String comment, String validatorUserId) {
StringBuilder sb = new StringBuilder("update T_ROUTE_STEP r ");
sb.append(" set r.RTP_ENDDATE_D = :endDate, r.RTP_TRANSITION_C = :transition, r.RTP_COMMENT_C = :comment, r.RTP_IDVALIDATORUSER_C = :validatorUserId ");
sb.append(" where r.RTP_ID_C = :id");
EntityManager em = ThreadLocalContext.get().getEntityManager();
Query q = em.createNativeQuery(sb.toString());
q.setParameter("endDate", new Date());
q.setParameter("transition", transition.name());
q.setParameter("comment", comment);
q.setParameter("validatorUserId", validatorUserId);
q.setParameter("id", id);
q.executeUpdate();
}
}

View File

@@ -121,7 +121,7 @@ public class UserDao {
User userDb = (User) q.getSingleResult();
// Update the user
userDb.setStorageQuota(user.getStorageQuota());
userDb.setStorageCurrent(user.getStorageCurrent());
}
/**

View File

@@ -0,0 +1,109 @@
package com.sismics.docs.core.dao.jpa.dto;
import com.sismics.docs.core.constant.RouteStepTransition;
import com.sismics.docs.core.constant.RouteStepType;
/**
* Route step DTO.
*
* @author bgamard
*/
public class RouteStepDto {
/**
* Route step ID.
*/
private String id;
/**
* Name.
*/
private String name;
/**
* Type.
*/
private RouteStepType type;
/**
* Transition.
*/
private RouteStepTransition transition;
/**
* Comment.
*/
private String comment;
/**
* Target ID (user or group).
*/
private String targetId;
/**
* End date.
*/
private Long endDateTimestamp;
public String getId() {
return id;
}
public RouteStepDto setId(String id) {
this.id = id;
return this;
}
public String getName() {
return name;
}
public RouteStepDto setName(String name) {
this.name = name;
return this;
}
public RouteStepType getType() {
return type;
}
public RouteStepDto setType(RouteStepType type) {
this.type = type;
return this;
}
public RouteStepTransition getTransition() {
return transition;
}
public RouteStepDto setTransition(RouteStepTransition transition) {
this.transition = transition;
return this;
}
public String getComment() {
return comment;
}
public RouteStepDto setComment(String comment) {
this.comment = comment;
return this;
}
public String getTargetId() {
return targetId;
}
public RouteStepDto setTargetId(String targetId) {
this.targetId = targetId;
return this;
}
public Long getEndDateTimestamp() {
return endDateTimestamp;
}
public RouteStepDto setEndDateTimestamp(Long endDateTimestamp) {
this.endDateTimestamp = endDateTimestamp;
return this;
}
}

View File

@@ -1,10 +1,5 @@
package com.sismics.docs.core.listener.async;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.eventbus.Subscribe;
import com.sismics.docs.core.dao.jpa.ContributorDao;
import com.sismics.docs.core.dao.jpa.DocumentDao;
@@ -12,6 +7,10 @@ import com.sismics.docs.core.dao.lucene.LuceneDao;
import com.sismics.docs.core.event.DocumentUpdatedAsyncEvent;
import com.sismics.docs.core.model.jpa.Contributor;
import com.sismics.docs.core.util.TransactionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
* Listener on document updated.
@@ -31,7 +30,7 @@ public class DocumentUpdatedAsyncListener {
* @throws Exception
*/
@Subscribe
public void on(final DocumentUpdatedAsyncEvent event) throws Exception {
public void on(final DocumentUpdatedAsyncEvent event) {
if (log.isInfoEnabled()) {
log.info("Document updated event: " + event.toString());
}

View File

@@ -60,6 +60,12 @@ public class RouteStep {
@Column(name = "RTP_IDTARGET_C", nullable = false, length = 36)
private String targetId;
/**
* Validator user ID.
*/
@Column(name = "RTP_IDVALIDATORUSER_C", length = 36)
private String validatorUserId;
/**
* Order.
*/
@@ -156,6 +162,15 @@ public class RouteStep {
return this;
}
public String getValidatorUserId() {
return validatorUserId;
}
public RouteStep setValidatorUserId(String validatorUserId) {
this.validatorUserId = validatorUserId;
return this;
}
public Date getCreateDate() {
return createDate;
}

View File

@@ -3,13 +3,8 @@ package com.sismics.docs.core.util;
import com.sismics.docs.core.constant.AclType;
import com.sismics.docs.core.constant.PermType;
import com.sismics.docs.core.dao.jpa.AclDao;
import com.sismics.docs.core.dao.jpa.RouteDao;
import com.sismics.docs.core.dao.jpa.RouteStepDao;
import com.sismics.docs.core.dao.jpa.dto.RouteStepDto;
import com.sismics.docs.core.model.jpa.Acl;
import com.sismics.docs.core.model.jpa.Route;
import com.sismics.docs.core.model.jpa.RouteStep;
import java.util.List;
/**
* Routing utilities.
@@ -17,31 +12,6 @@ import java.util.List;
* @author bgamard
*/
public class RoutingUtil {
/**
* Get the current route step from a document.
*
* @param documentId Document ID
* @return Active route step
*/
public static RouteStep getCurrentStep(String documentId) {
// TODO Optimize
RouteDao routeDao = new RouteDao();
List<Route> routeList = routeDao.getActiveRoutes(documentId);
if (routeList.isEmpty()) {
return null;
}
Route route = routeList.get(0);
RouteStepDao routeStepDao = new RouteStepDao();
List<RouteStep> routeStepList = routeStepDao.getRouteSteps(route.getId());
for (RouteStep routeStep : routeStepList) {
if (routeStep.getEndDate() == null) {
return routeStep;
}
}
return null;
}
/**
* Update routing ACLs according to the current route step.
@@ -51,7 +21,7 @@ public class RoutingUtil {
* @param previousStep Previous route step
* @param userId User ID
*/
public static void updateAcl(String sourceId, RouteStep currentStep, RouteStep previousStep, String userId) {
public static void updateAcl(String sourceId, RouteStepDto currentStep, RouteStepDto previousStep, String userId) {
AclDao aclDao = new AclDao();
if (previousStep != null) {
@@ -59,12 +29,14 @@ public class RoutingUtil {
aclDao.delete(sourceId, PermType.READ, previousStep.getTargetId(), userId, AclType.ROUTING);
}
// Create a temporary READ ACL
Acl acl = new Acl();
acl.setPerm(PermType.READ);
acl.setType(AclType.ROUTING);
acl.setSourceId(sourceId);
acl.setTargetId(currentStep.getTargetId());
aclDao.create(acl, userId);
if (currentStep != null) {
// Create a temporary READ ACL
Acl acl = new Acl();
acl.setPerm(PermType.READ);
acl.setType(AclType.ROUTING);
acl.setSourceId(sourceId);
acl.setTargetId(currentStep.getTargetId());
aclDao.create(acl, userId);
}
}
}

View File

@@ -71,6 +71,11 @@ public class ThreadLocalContext {
* @return entityManager
*/
public EntityManager getEntityManager() {
if (entityManager != null && entityManager.isOpen()) {
// This disables the L1 cache
entityManager.flush();
entityManager.clear();
}
return entityManager;
}

View File

@@ -1,9 +1,10 @@
create table T_ROUTE_MODEL ( RTM_ID_C varchar(36) not null, RTM_NAME_C varchar(50) not null, RTM_STEPS_C varchar(5000) not null, RTM_CREATEDATE_D datetime not null, RTM_DELETEDATE_D datetime, primary key (RTM_ID_C) );
create cached table T_ROUTE ( RTE_ID_C varchar(36) not null, RTE_IDDOCUMENT_C varchar(36) not null, RTE_NAME_C varchar(50) not null, RTE_CREATEDATE_D datetime not null, RTE_DELETEDATE_D datetime, primary key (RTE_ID_C) );
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, RTP_CREATEDATE_D datetime not null, RTP_ENDDATE_D datetime, RTP_DELETEDATE_D datetime, primary key (RTP_ID_C) );
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_IDVALIDATORUSER_C varchar(36), RTP_ORDER_N int not null, RTP_CREATEDATE_D datetime not null, RTP_ENDDATE_D datetime, RTP_DELETEDATE_D datetime, primary key (RTP_ID_C) );
alter table T_ACL add column ACL_TYPE_C varchar(30) not null default 'USER';
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;
alter table T_ROUTE_STEP add constraint FK_RTP_IDVALIDATORUSER_C foreign key (RTP_IDVALIDATORUSER_C) references T_USER (USE_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());