mirror of
https://github.com/sismics/docs.git
synced 2025-12-14 18:26:17 +00:00
Closes #159: cancel routes + email at route step validation
This commit is contained in:
@@ -82,4 +82,9 @@ public class Constants {
|
||||
* Email template for password recovery.
|
||||
*/
|
||||
public static final String EMAIL_TEMPLATE_PASSWORD_RECOVERY = "password_recovery";
|
||||
|
||||
/**
|
||||
* Email template for route step validate.
|
||||
*/
|
||||
public static final String EMAIL_TEMPLATE_ROUTE_STEP_VALIDATE = "route_step_validate";
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ public class AclDao {
|
||||
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 and a.type = :type and a.deleteDate is null");
|
||||
q.setParameter("sourceId", sourceId);
|
||||
q.setParameter("perm", perm);
|
||||
q.setParameter("targetId", targetId);
|
||||
@@ -160,7 +160,7 @@ public class AclDao {
|
||||
}
|
||||
|
||||
// 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 and a.type = :type and a.deleteDate is null");
|
||||
q.setParameter("sourceId", sourceId);
|
||||
q.setParameter("perm", perm);
|
||||
q.setParameter("targetId", targetId);
|
||||
|
||||
@@ -86,4 +86,23 @@ public class RouteDao {
|
||||
}
|
||||
return dtoList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a route and the associated steps.
|
||||
*
|
||||
* @param routeId Route ID
|
||||
*/
|
||||
public void deleteRoute(String routeId) {
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
|
||||
em.createNativeQuery("update T_ROUTE_STEP rs set rs.RTP_DELETEDATE_D = :dateNow where rs.RTP_IDROUTE_C = :routeId and rs.RTP_DELETEDATE_D is null")
|
||||
.setParameter("routeId", routeId)
|
||||
.setParameter("dateNow", new Date())
|
||||
.executeUpdate();
|
||||
|
||||
em.createNativeQuery("update T_ROUTE r set r.RTE_DELETEDATE_D = :dateNow where r.RTE_ID_C = :routeId and r.RTE_DELETEDATE_D is null")
|
||||
.setParameter("routeId", routeId)
|
||||
.setParameter("dateNow", new Date())
|
||||
.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ public class RouteStepDao {
|
||||
Map<String, Object> parameterMap = new HashMap<>();
|
||||
List<String> criteriaList = new ArrayList<>();
|
||||
|
||||
StringBuilder sb = new StringBuilder("select rs.RTP_ID_C, rs.RTP_NAME_C c0, rs.RTP_TYPE_C c1, rs.RTP_TRANSITION_C c2, rs.RTP_COMMENT_C c3, rs.RTP_IDTARGET_C c4, u.USE_USERNAME_C as targetUsername, g.GRP_NAME_C, rs.RTP_ENDDATE_D c5, uv.USE_USERNAME_C as validatorUsername, rs.RTP_ORDER_N c6")
|
||||
StringBuilder sb = new StringBuilder("select rs.RTP_ID_C, rs.RTP_NAME_C c0, rs.RTP_TYPE_C c1, rs.RTP_TRANSITION_C c2, rs.RTP_COMMENT_C c3, rs.RTP_IDTARGET_C c4, u.USE_USERNAME_C as targetUsername, g.GRP_NAME_C, rs.RTP_ENDDATE_D c5, uv.USE_USERNAME_C as validatorUsername, rs.RTP_IDROUTE_C, rs.RTP_ORDER_N c6")
|
||||
.append(" from T_ROUTE_STEP rs ")
|
||||
.append(" join T_ROUTE r on r.RTE_ID_C = rs.RTP_IDROUTE_C ")
|
||||
.append(" left join T_USER uv on uv.USE_ID_C = rs.RTP_IDVALIDATORUSER_C ")
|
||||
@@ -88,7 +88,7 @@ public class RouteStepDao {
|
||||
if (criteria.getEndDateIsNull() != null) {
|
||||
criteriaList.add("RTP_ENDDATE_D is " + (criteria.getEndDateIsNull() ? "" : "not") + " null");
|
||||
}
|
||||
criteriaList.add("r.RTE_DELETEDATE_D is null");
|
||||
criteriaList.add("rs.RTP_DELETEDATE_D is null");
|
||||
|
||||
if (!criteriaList.isEmpty()) {
|
||||
sb.append(" where ");
|
||||
@@ -123,7 +123,8 @@ public class RouteStepDao {
|
||||
}
|
||||
Timestamp endDateTimestamp = (Timestamp) o[i++];
|
||||
dto.setEndDateTimestamp(endDateTimestamp == null ? null : endDateTimestamp.getTime());
|
||||
dto.setValidatorUserName((String) o[i]);
|
||||
dto.setValidatorUserName((String) o[i++]);
|
||||
dto.setRouteId((String) o[i]);
|
||||
dtoList.add(dto);
|
||||
}
|
||||
return dtoList;
|
||||
|
||||
@@ -276,7 +276,14 @@ public class UserDao {
|
||||
criteriaList.add("lower(u.USE_USERNAME_C) like lower(:search)");
|
||||
parameterMap.put("search", "%" + criteria.getSearch() + "%");
|
||||
}
|
||||
|
||||
if (criteria.getUserId() != null) {
|
||||
criteriaList.add("u.USE_ID_C = :userId");
|
||||
parameterMap.put("userId", criteria.getUserId());
|
||||
}
|
||||
if (criteria.getUserName() != null) {
|
||||
criteriaList.add("u.USE_USERNAME_C = :userName");
|
||||
parameterMap.put("userName", criteria.getUserName());
|
||||
}
|
||||
if (criteria.getGroupId() != null) {
|
||||
sb.append(" join T_USER_GROUP ug on ug.UGP_IDUSER_C = u.USE_ID_C and ug.UGP_IDGROUP_C = :groupId and ug.UGP_DELETEDATE_D is null ");
|
||||
parameterMap.put("groupId", criteria.getGroupId());
|
||||
|
||||
@@ -16,6 +16,16 @@ public class UserCriteria {
|
||||
*/
|
||||
private String groupId;
|
||||
|
||||
/**
|
||||
* User ID.
|
||||
*/
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* Username.
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
public String getSearch() {
|
||||
return search;
|
||||
}
|
||||
@@ -33,4 +43,22 @@ public class UserCriteria {
|
||||
this.groupId = groupId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public UserCriteria setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public UserCriteria setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,11 @@ public class RouteStepDto {
|
||||
*/
|
||||
private String validatorUserName;
|
||||
|
||||
/**
|
||||
* Route ID.
|
||||
*/
|
||||
private String routeId;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
@@ -152,6 +157,15 @@ public class RouteStepDto {
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getRouteId() {
|
||||
return routeId;
|
||||
}
|
||||
|
||||
public RouteStepDto setRouteId(String routeId) {
|
||||
this.routeId = routeId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform in JSON.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.sismics.docs.core.dao.jpa.dto;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
|
||||
/**
|
||||
* User DTO.
|
||||
*
|
||||
@@ -110,4 +112,13 @@ public class UserDto {
|
||||
public void setTotpKey(String totpKey) {
|
||||
this.totpKey = totpKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MoreObjects.toStringHelper(this)
|
||||
.add("id", id)
|
||||
.add("username", username)
|
||||
.add("email", email)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.sismics.docs.core.event;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.sismics.docs.core.dao.jpa.dto.UserDto;
|
||||
import com.sismics.docs.core.model.jpa.PasswordRecovery;
|
||||
import com.sismics.docs.core.model.jpa.User;
|
||||
|
||||
/**
|
||||
* Event fired on user's password lost event.
|
||||
@@ -13,18 +13,18 @@ public class PasswordLostEvent {
|
||||
/**
|
||||
* User.
|
||||
*/
|
||||
private User user;
|
||||
private UserDto user;
|
||||
|
||||
/**
|
||||
* Password recovery request.
|
||||
*/
|
||||
private PasswordRecovery passwordRecovery;
|
||||
|
||||
public User getUser() {
|
||||
public UserDto getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setUser(User user) {
|
||||
public void setUser(UserDto user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.sismics.docs.core.event;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.sismics.docs.core.dao.jpa.dto.UserDto;
|
||||
import com.sismics.docs.core.model.jpa.Document;
|
||||
|
||||
/**
|
||||
* Event fired on route step validation event.
|
||||
*
|
||||
* @author bgamard
|
||||
*/
|
||||
public class RouteStepValidateEvent {
|
||||
/**
|
||||
* User.
|
||||
*/
|
||||
private UserDto user;
|
||||
|
||||
/**
|
||||
* Document linked to the route.
|
||||
*/
|
||||
private Document document;
|
||||
|
||||
public UserDto getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setUser(UserDto user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public Document getDocument() {
|
||||
return document;
|
||||
}
|
||||
|
||||
public RouteStepValidateEvent setDocument(Document document) {
|
||||
this.document = document;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MoreObjects.toStringHelper(this)
|
||||
.add("user", user)
|
||||
.add("document", document)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@ package com.sismics.docs.core.listener.async;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import com.sismics.docs.core.constant.Constants;
|
||||
import com.sismics.docs.core.dao.jpa.dto.UserDto;
|
||||
import com.sismics.docs.core.event.PasswordLostEvent;
|
||||
import com.sismics.docs.core.model.jpa.PasswordRecovery;
|
||||
import com.sismics.docs.core.model.jpa.User;
|
||||
import com.sismics.docs.core.util.TransactionUtil;
|
||||
import com.sismics.util.EmailUtil;
|
||||
import org.slf4j.Logger;
|
||||
@@ -38,7 +38,7 @@ public class PasswordLostAsyncListener {
|
||||
TransactionUtil.handle(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final User user = passwordLostEvent.getUser();
|
||||
final UserDto user = passwordLostEvent.getUser();
|
||||
final PasswordRecovery passwordRecovery = passwordLostEvent.getPasswordRecovery();
|
||||
|
||||
// Send the password recovery email
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.sismics.docs.core.listener.async;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import com.sismics.docs.core.constant.Constants;
|
||||
import com.sismics.docs.core.dao.jpa.dto.UserDto;
|
||||
import com.sismics.docs.core.event.RouteStepValidateEvent;
|
||||
import com.sismics.docs.core.util.TransactionUtil;
|
||||
import com.sismics.util.EmailUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Listener for route step validate.
|
||||
*
|
||||
* @author bgamard
|
||||
*/
|
||||
public class RouteStepValidateAsyncListener {
|
||||
/**
|
||||
* Logger.
|
||||
*/
|
||||
private static final Logger log = LoggerFactory.getLogger(RouteStepValidateAsyncListener.class);
|
||||
|
||||
/**
|
||||
* Handle events.
|
||||
*
|
||||
* @param routeStepValidateEvent Event
|
||||
*/
|
||||
@Subscribe
|
||||
public void onRouteStepValidate(final RouteStepValidateEvent routeStepValidateEvent) {
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info("Route step validate event: " + routeStepValidateEvent.toString());
|
||||
}
|
||||
|
||||
TransactionUtil.handle(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final UserDto user = routeStepValidateEvent.getUser();
|
||||
|
||||
// Send the password recovery email
|
||||
Map<String, Object> paramRootMap = new HashMap<>();
|
||||
paramRootMap.put("user_name", user.getUsername());
|
||||
paramRootMap.put("document_id", routeStepValidateEvent.getDocument().getId());
|
||||
paramRootMap.put("document_title", routeStepValidateEvent.getDocument().getTitle());
|
||||
|
||||
EmailUtil.sendEmail(Constants.EMAIL_TEMPLATE_ROUTE_STEP_VALIDATE, user, paramRootMap);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -104,6 +104,7 @@ public class AppContext {
|
||||
|
||||
mailEventBus = newAsyncEventBus();
|
||||
mailEventBus.register(new PasswordLostAsyncListener());
|
||||
mailEventBus.register(new RouteStepValidateAsyncListener());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -203,6 +203,7 @@ public class User implements Loggable {
|
||||
return MoreObjects.toStringHelper(this)
|
||||
.add("id", id)
|
||||
.add("username", username)
|
||||
.add("email", email)
|
||||
.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,21 @@
|
||||
package com.sismics.docs.core.util;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.sismics.docs.core.constant.AclTargetType;
|
||||
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.DocumentDao;
|
||||
import com.sismics.docs.core.dao.jpa.UserDao;
|
||||
import com.sismics.docs.core.dao.jpa.criteria.UserCriteria;
|
||||
import com.sismics.docs.core.dao.jpa.dto.RouteStepDto;
|
||||
import com.sismics.docs.core.dao.jpa.dto.UserDto;
|
||||
import com.sismics.docs.core.event.RouteStepValidateEvent;
|
||||
import com.sismics.docs.core.model.context.AppContext;
|
||||
import com.sismics.docs.core.model.jpa.Acl;
|
||||
import com.sismics.docs.core.model.jpa.Document;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Routing utilities.
|
||||
@@ -38,4 +49,28 @@ public class RoutingUtil {
|
||||
aclDao.create(acl, userId);
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendRouteStepEmail(String documentId, RouteStepDto routeStepDto) {
|
||||
DocumentDao documentDao = new DocumentDao();
|
||||
Document document = documentDao.getById(documentId);
|
||||
|
||||
List<UserDto> userDtoList = Lists.newArrayList();
|
||||
UserDao userDao = new UserDao();
|
||||
switch (AclTargetType.valueOf(routeStepDto.getTargetType())) {
|
||||
case USER:
|
||||
userDtoList.addAll(userDao.findByCriteria(new UserCriteria().setUserId(routeStepDto.getTargetId()), null));
|
||||
break;
|
||||
case GROUP:
|
||||
userDtoList.addAll(userDao.findByCriteria(new UserCriteria().setGroupId(routeStepDto.getTargetId()), null));
|
||||
break;
|
||||
}
|
||||
|
||||
// Fire route step validate events
|
||||
for (UserDto userDto : userDtoList) {
|
||||
RouteStepValidateEvent routeStepValidateEvent = new RouteStepValidateEvent();
|
||||
routeStepValidateEvent.setUser(userDto);
|
||||
routeStepValidateEvent.setDocument(document);
|
||||
AppContext.getInstance().getMailEventBus().post(routeStepValidateEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ import com.google.common.base.Strings;
|
||||
import com.sismics.docs.core.constant.ConfigType;
|
||||
import com.sismics.docs.core.constant.Constants;
|
||||
import com.sismics.docs.core.dao.jpa.ConfigDao;
|
||||
import com.sismics.docs.core.dao.jpa.dto.UserDto;
|
||||
import com.sismics.docs.core.model.jpa.Config;
|
||||
import com.sismics.docs.core.model.jpa.User;
|
||||
import com.sismics.docs.core.util.ConfigUtil;
|
||||
import freemarker.template.Configuration;
|
||||
import freemarker.template.DefaultObjectWrapperBuilder;
|
||||
@@ -64,7 +64,7 @@ public class EmailUtil {
|
||||
* @param subject Email subject
|
||||
* @param paramMap Email parameters
|
||||
*/
|
||||
public static void sendEmail(String templateName, User recipientUser, String subject, Map<String, Object> paramMap) {
|
||||
public static void sendEmail(String templateName, UserDto recipientUser, String subject, Map<String, Object> paramMap) {
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info("Sending email from template=" + templateName + " to user " + recipientUser);
|
||||
}
|
||||
@@ -154,7 +154,7 @@ public class EmailUtil {
|
||||
* @param recipientUser Recipient user
|
||||
* @param paramMap Email parameters
|
||||
*/
|
||||
public static void sendEmail(String templateName, User recipientUser, Map<String, Object> paramMap) {
|
||||
public static void sendEmail(String templateName, UserDto recipientUser, Map<String, Object> paramMap) {
|
||||
java.util.Locale userLocale = LocaleUtil.getLocale(System.getenv(Constants.DEFAULT_LANGUAGE_ENV));
|
||||
String subject = MessageUtil.getMessage(userLocale, "email.template." + templateName + ".subject");
|
||||
sendEmail(templateName, recipientUser, subject, paramMap);
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<#import "../layout.ftl" as layout>
|
||||
<@layout.email>
|
||||
<h2>${app_name} - ${messages['email.template.route_step_validate.subject']}</h2>
|
||||
<p>${messages('email.template.route_step_validate.hello', user_name)}</p>
|
||||
<p>${messages['email.template.route_step_validate.instruction1']}</p>
|
||||
<p>${messages['email.template.route_step_validate.instruction2']}</p>
|
||||
<a href="${base_url}/#/document/${document_id}">${document_title}</a>
|
||||
</@layout.email>
|
||||
@@ -3,4 +3,8 @@ email.template.password_recovery.hello=Hello {0}.
|
||||
email.template.password_recovery.instruction1=We have received a request to reset your password.<br/>If you did not request help, then feel free to ignore this email.
|
||||
email.template.password_recovery.instruction2=To reset your password, please visit the link below:
|
||||
email.template.password_recovery.click_here=Click here to reset your password
|
||||
email.template.route_step_validate.subject=A document needs your attention
|
||||
email.template.route_step_validate.hello=Hello {0}.
|
||||
email.template.route_step_validate.instruction1=A workflow step has been assigned to you and needs your attention.
|
||||
email.template.route_step_validate.instruction2=To view the document and validate the workflow, please visit the link below:
|
||||
email.no_html.error=Your email client does not support HTML messages
|
||||
Reference in New Issue
Block a user