Merge branch '119-notification-grants' into 'dev'

Resolve "Реализовать уведомления на почту"

Closes #119

See merge request romanov73/ng-tracker!84
This commit is contained in:
Anton Romanov 2019-05-09 04:18:55 +00:00
commit ff7f535980
9 changed files with 239 additions and 2 deletions

View File

@ -0,0 +1,72 @@
package ru.ulstu.grant.service;
import com.google.common.collect.ImmutableMap;
import org.springframework.stereotype.Service;
import ru.ulstu.core.util.DateUtils;
import ru.ulstu.grant.model.Grant;
import ru.ulstu.user.model.User;
import ru.ulstu.user.service.MailService;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Service
public class GrantNotificationService {
private final static int DAYS_TO_DEADLINE_NOTIFICATION = 7;
private final static String TEMPLATE_DEADLINE = "grantDeadlineNotification";
private final static String TEMPLATE_CREATE = "grantCreateNotification";
private final static String TEMPLATE_AUTHORS_CHANGED = "grantAuthorsChangeNotification";
private final static String TEMPLATE_LEADER_CHANGED = "grantLeaderChangeNotification";
private final static String TITLE_DEADLINE = "Приближается дедлайн гранта: %s";
private final static String TITLE_CREATE = "Создан грант: %s";
private final static String TITLE_AUTHORS_CHANGED = "Изменился состав рабочей группы гранта: %s";
private final static String TITLE_LEADER_CHANGED = "Изменился руководитель гранта: %s";
private final MailService mailService;
public GrantNotificationService(MailService mailService) {
this.mailService = mailService;
}
public void sendDeadlineNotifications(List<Grant> grants, boolean isDeadlineBeforeWeek) {
Date now = DateUtils.addDays(new Date(), DAYS_TO_DEADLINE_NOTIFICATION);
grants.stream()
.filter(grant -> needToSendDeadlineNotification(grant, now, isDeadlineBeforeWeek))
.forEach(grant -> sendMessageDeadline(grant));
}
private boolean needToSendDeadlineNotification(Grant grant, Date compareDate, boolean isDeadlineBeforeWeek) {
return (grant.getNextDeadline().isPresent())
&& (compareDate.before(grant.getNextDeadline().get().getDate()) && isDeadlineBeforeWeek
|| compareDate.after(grant.getNextDeadline().get().getDate()) && !isDeadlineBeforeWeek)
&& grant.getNextDeadline().get().getDate().after(new Date());
}
private void sendMessageDeadline(Grant grant) {
Map<String, Object> variables = ImmutableMap.of("grant", grant);
sendForAllAuthors(variables, grant, TEMPLATE_DEADLINE, String.format(TITLE_DEADLINE, grant.getTitle()));
}
public void sendCreateNotification(Grant grant) {
Map<String, Object> variables = ImmutableMap.of("grant", grant);
sendForAllAuthors(variables, grant, TEMPLATE_CREATE, String.format(TITLE_CREATE, grant.getTitle()));
}
public void sendAuthorsChangeNotification(Grant grant, Set<User> oldAuthors) {
Map<String, Object> variables = ImmutableMap.of("grant", grant, "oldAuthors", oldAuthors);
sendForAllAuthors(variables, grant, TEMPLATE_AUTHORS_CHANGED, String.format(TITLE_AUTHORS_CHANGED, grant.getTitle()));
}
public void sendLeaderChangeNotification(Grant grant, User oldLeader) {
Map<String, Object> variables = ImmutableMap.of("grant", grant, "oldLeader", oldLeader);
sendForAllAuthors(variables, grant, TEMPLATE_LEADER_CHANGED, String.format(TITLE_LEADER_CHANGED, grant.getTitle()));
}
private void sendForAllAuthors(Map<String, Object> variables, Grant grant, String template, String title) {
Set<User> allAuthors = grant.getAuthors();
allAuthors.forEach(author -> mailService.sendEmailFromTemplate(variables, author, template, title));
mailService.sendEmailFromTemplate(variables, grant.getLeader(), template, title);
}
}

View File

@ -0,0 +1,30 @@
package ru.ulstu.grant.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Service
public class GrantScheduler {
private final static boolean IS_DEADLINE_NOTIFICATION_BEFORE_WEEK = true;
private final Logger log = LoggerFactory.getLogger(GrantScheduler.class);
private final GrantNotificationService grantNotificationService;
private final GrantService grantService;
public GrantScheduler(GrantNotificationService grantNotificationService,
GrantService grantService) {
this.grantNotificationService = grantNotificationService;
this.grantService = grantService;
}
@Scheduled(cron = "0 0 8 * * MON", zone = "Europe/Samara")
public void checkDeadlineBeforeWeek() {
log.debug("GrantScheduler.checkDeadlineBeforeWeek started");
grantNotificationService.sendDeadlineNotifications(grantService.findAll(), IS_DEADLINE_NOTIFICATION_BEFORE_WEEK);
log.debug("GrantScheduler.checkDeadlineBeforeWeek finished");
}
}

View File

@ -23,7 +23,9 @@ import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toList;
import static org.springframework.util.ObjectUtils.isEmpty; import static org.springframework.util.ObjectUtils.isEmpty;
@ -41,6 +43,7 @@ public class GrantService {
private final UserService userService; private final UserService userService;
private final PaperService paperService; private final PaperService paperService;
private final EventService eventService; private final EventService eventService;
private final GrantNotificationService grantNotificationService;
public GrantService(GrantRepository grantRepository, public GrantService(GrantRepository grantRepository,
FileService fileService, FileService fileService,
@ -48,7 +51,8 @@ public class GrantService {
ProjectService projectService, ProjectService projectService,
UserService userService, UserService userService,
PaperService paperService, PaperService paperService,
EventService eventService) { EventService eventService,
GrantNotificationService grantNotificationService) {
this.grantRepository = grantRepository; this.grantRepository = grantRepository;
this.fileService = fileService; this.fileService = fileService;
this.deadlineService = deadlineService; this.deadlineService = deadlineService;
@ -56,6 +60,7 @@ public class GrantService {
this.userService = userService; this.userService = userService;
this.paperService = paperService; this.paperService = paperService;
this.eventService = eventService; this.eventService = eventService;
this.grantNotificationService = grantNotificationService;
} }
public List<Grant> findAll() { public List<Grant> findAll() {
@ -77,6 +82,7 @@ public class GrantService {
Grant newGrant = copyFromDto(new Grant(), grantDto); Grant newGrant = copyFromDto(new Grant(), grantDto);
newGrant = grantRepository.save(newGrant); newGrant = grantRepository.save(newGrant);
eventService.createFromGrant(newGrant); eventService.createFromGrant(newGrant);
grantNotificationService.sendCreateNotification(newGrant);
return newGrant.getId(); return newGrant.getId();
} }
@ -113,6 +119,8 @@ public class GrantService {
@Transactional @Transactional
public Integer update(GrantDto grantDto) throws IOException { public Integer update(GrantDto grantDto) throws IOException {
Grant grant = grantRepository.findOne(grantDto.getId()); Grant grant = grantRepository.findOne(grantDto.getId());
Set<User> oldAuthors = new HashSet<>(grant.getAuthors());
User oldLeader = grant.getLeader();
for (FileDataDto file : grantDto.getFiles().stream() for (FileDataDto file : grantDto.getFiles().stream()
.filter(f -> f.isDeleted() && f.getId() != null) .filter(f -> f.isDeleted() && f.getId() != null)
.collect(toList())) { .collect(toList())) {
@ -120,6 +128,20 @@ public class GrantService {
} }
grantDto.getRemovedDeadlineIds().forEach(deadlineService::remove); grantDto.getRemovedDeadlineIds().forEach(deadlineService::remove);
grantRepository.save(copyFromDto(grant, grantDto)); grantRepository.save(copyFromDto(grant, grantDto));
grant.getAuthors().forEach(author -> {
if (!oldAuthors.contains(author)) {
grantNotificationService.sendAuthorsChangeNotification(grant, oldAuthors);
}
});
oldAuthors.forEach(oldAuthor -> {
if (!grant.getAuthors().contains(oldAuthor)) {
grantNotificationService.sendAuthorsChangeNotification(grant, oldAuthors);
}
});
if (grant.getLeader() != oldLeader) {
grantNotificationService.sendLeaderChangeNotification(grant, oldLeader);
}
eventService.updateGrantDeadlines(grant); eventService.updateGrantDeadlines(grant);
return grant.getId(); return grant.getId();
} }
@ -148,6 +170,7 @@ public class GrantService {
grant = grantRepository.save(grant); grant = grantRepository.save(grant);
eventService.createFromGrant(grant); eventService.createFromGrant(grant);
grantNotificationService.sendCreateNotification(grant);
return grant; return grant;
} }
@ -222,7 +245,6 @@ public class GrantService {
.filter(paper -> paper.getAuthors() != null) .filter(paper -> paper.getAuthors() != null)
.flatMap(paper -> paper.getAuthors().stream()) .flatMap(paper -> paper.getAuthors().stream())
.collect(toList()); .collect(toList());
} }
private List<User> getBAKAuthors() { private List<User> getBAKAuthors() {

View File

@ -0,0 +1,8 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<changeSet author="tanya" id="20190507_000000-1">
<dropColumn columnName="deadline_date" tableName="grants"/>
</changeSet>
</databaseChangeLog>

View File

@ -38,5 +38,6 @@
<include file="db/changelog-20190428_000000-schema.xml"/> <include file="db/changelog-20190428_000000-schema.xml"/>
<include file="db/changelog-20190430_000000-schema.xml"/> <include file="db/changelog-20190430_000000-schema.xml"/>
<include file="db/changelog-20190505_000000-schema.xml"/> <include file="db/changelog-20190505_000000-schema.xml"/>
<include file="db/changelog-20190507_000000-schema.xml"/>
<include file="db/changelog-20190507_000001-schema.xml"/> <include file="db/changelog-20190507_000001-schema.xml"/>
</databaseChangeLog> </databaseChangeLog>

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Уведомление об изменении состава рабочей группы</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="shortcut icon" th:href="@{|${baseUrl}/favicon.ico|}"/>
</head>
<body>
<p>
Уважаемый(ая) <span th:text="${user.firstName + ' ' + user.lastName}">Ivan Ivanov</span>
</p>
<p>
Состав рабочей группы гранта "<a th:href="@{|${baseUrl}/grants/grant?id=${grant.id}|}"><span
th:text="${grant.title}">Title</span></a>" сменился с
" <span th:each="author : ${oldAuthors}" th:text="${author.lastName + ' '}">oldAuthors</span>"
на " <span th:each="author : ${grant.authors}" th:text="${author.lastName + ' '}">newAuthors</span>".
</p>
<p>
Regards,
<br/>
<em>NG-tracker.</em>
</p>
</body>
</html>

View File

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Уведомление о создании гранта</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="shortcut icon" th:href="@{|${baseUrl}/favicon.ico|}"/>
</head>
<body>
<p>
Уважаемый(ая) <span th:text="${user.firstName + ' ' + user.lastName}">Ivan Ivanov</span>
</p>
<p>
Был добавлен новый грант: "<a th:href="@{|${baseUrl}/grants/grant?id=${grant.id}|}">
<span th:text="${grant.title}">Title</span></a>".
<br/>
</p>
<p>
Руководитель гранта:
<span th:text="${grant.leader.firstName}"></span>
<span th:text="${grant.leader.lastName}">Leader</span>.
</p>
<p>
Regards,
<br/>
<em>NG-tracker.</em>
</p>
</body>
</html>

View File

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Уведомление о дедлайне гранта</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="shortcut icon" th:href="@{|${baseUrl}/favicon.ico|}"/>
</head>
<body>
<p>
Уважаемый(ая) <span th:text="${user.firstName + ' ' + user.lastName}">Ivan Ivanov</span>
</p>
<p>
Приближается дедлайн гранта "<a th:href="@{|${baseUrl}/grants/grant?id=${grant.id}|}"><span
th:text="${grant.title}">Title</span></a>".
</p>
<p>
Срок исполнения: <b><span th:text="${#dates.format(grant.nextDeadline.get().date, 'dd.MM.yyyy')}">Date</span></b>.
</p>
<p>
Примечание: <b><span th:text="${grant.nextDeadline.get().description}">Description</span></b>.
</p>
<p>
Regards,
<br/>
<em>NG-tracker.</em>
</p>
</body>
</html>

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Уведомление об изменении руководителя гранта</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="shortcut icon" th:href="@{|${baseUrl}/favicon.ico|}"/>
</head>
<body>
<p>
Уважаемый(ая) <span th:text="${user.firstName + ' ' + user.lastName}">Ivan Ivanov</span>
</p>
<p>
Руководитель гранта "<a th:href="@{|${baseUrl}/grants/grant?id=${grant.id}|}"><span
th:text="${grant.title}">Title</span></a>" сменился с
"<span th:text="${oldLeader.lastName} ">oldLeader</span>"
на "<span th:text="${grant.leader.lastName}">newLeader</span>".
</p>
<p>
Regards,
<br/>
<em>NG-tracker.</em>
</p>
</body>
</html>