Merge branch 'dev' of https://gitlab.com/romanov73/ng-tracker into dev
commit
82ab40a608
@ -1,7 +1,113 @@
|
||||
package ru.ulstu.conference.service;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.ulstu.conference.model.Conference;
|
||||
import ru.ulstu.core.util.DateUtils;
|
||||
import ru.ulstu.ping.service.PingService;
|
||||
import ru.ulstu.user.service.MailService;
|
||||
import ru.ulstu.user.service.UserService;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class ConferenceNotificationService {
|
||||
|
||||
private final static int YESTERDAY = -1;
|
||||
private final static int DAYS_TO_DEADLINE_NOTIFICATION = 7;
|
||||
private final static String TEMPLATE_PING = "conferencePingNotification";
|
||||
private final static String TEMPLATE_DEADLINE = "conferenceDeadlineNotification";
|
||||
private final static String TEMPLATE_CREATE = "conferenceCreateNotification";
|
||||
private final static String TEMPLATE_UPDATE_DEADLINES = "conferenceUpdateDeadlinesNotification";
|
||||
private final static String TEMPLATE_UPDATE_DATES = "conferenceUpdateDatesNotification";
|
||||
|
||||
private final static String TITLE_PING = "Обратите внимание на конференцию: %s";
|
||||
private final static String TITLE_DEADLINE = "Приближается дедлайн конференции: %s";
|
||||
private final static String TITLE_CREATE = "Создана новая конференция: %s";
|
||||
private final static String TITLE_UPDATE_DEADLINES = "Изменения дедлайнов в конференции: %s";
|
||||
private final static String TITLE_UPDATE_DATES = "Изменение дат проведения конференции: %s";
|
||||
|
||||
private final MailService mailService;
|
||||
private final UserService userService;
|
||||
private final PingService pingService;
|
||||
|
||||
public ConferenceNotificationService(MailService mailService,
|
||||
UserService userService,
|
||||
PingService pingService) {
|
||||
this.mailService = mailService;
|
||||
this.userService = userService;
|
||||
this.pingService = pingService;
|
||||
}
|
||||
|
||||
public void sendDeadlineNotifications(List<Conference> conferences) {
|
||||
Date now = DateUtils.addDays(new Date(), DAYS_TO_DEADLINE_NOTIFICATION);
|
||||
conferences
|
||||
.stream()
|
||||
.filter(conference -> needToSendDeadlineNotification(conference, now))
|
||||
.forEach(this::sendMessageDeadline);
|
||||
}
|
||||
|
||||
private boolean needToSendDeadlineNotification(Conference conference, Date compareDate) {
|
||||
return (conference.getNextDeadline().isPresent())
|
||||
&& conference.getNextDeadline().get().getDate().after(new Date())
|
||||
&& conference.getNextDeadline().get().getDate().before(compareDate);
|
||||
}
|
||||
|
||||
private void sendMessageDeadline(Conference conference) {
|
||||
Map<String, Object> variables = ImmutableMap.of("conference", conference);
|
||||
sendForAllParticipants(variables, conference, TEMPLATE_DEADLINE, String.format(TITLE_DEADLINE, conference.getTitle()));
|
||||
}
|
||||
|
||||
public void sendCreateNotification(Conference conference) {
|
||||
Map<String, Object> variables = ImmutableMap.of("conference", conference);
|
||||
sendForAllUsers(variables, TEMPLATE_CREATE, String.format(TITLE_CREATE, conference.getTitle()));
|
||||
}
|
||||
|
||||
public void updateDeadlineNotification(Conference conference) {
|
||||
Map<String, Object> variables = ImmutableMap.of("conference", conference);
|
||||
sendForAllParticipants(variables, conference, TEMPLATE_UPDATE_DEADLINES, String.format(TITLE_UPDATE_DEADLINES, conference.getTitle()));
|
||||
}
|
||||
|
||||
public void updateConferencesDatesNotification(Conference conference, Date oldBeginDate, Date oldEndDate) {
|
||||
Map<String, Object> variables = ImmutableMap.of("conference", conference, "oldBeginDate", oldBeginDate, "oldEndDate", oldEndDate);
|
||||
sendForAllParticipants(variables, conference, TEMPLATE_UPDATE_DATES, String.format(TITLE_UPDATE_DATES, conference.getTitle()));
|
||||
}
|
||||
|
||||
private void sendForAllUsers(Map<String, Object> variables, String template, String title) {
|
||||
userService.findAll().forEach(user -> mailService.sendEmailFromTemplate(variables, user, template, title));
|
||||
}
|
||||
|
||||
private void sendForAllParticipants(Map<String, Object> variables, Conference conference, String template, String title) {
|
||||
conference.getUsers().forEach(conferenceUser -> mailService.sendEmailFromTemplate(variables, conferenceUser.getUser(), template, title));
|
||||
}
|
||||
|
||||
|
||||
public void sendPingNotifications(List<Conference> conferences) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(new Date());
|
||||
calendar.add(Calendar.DAY_OF_MONTH, YESTERDAY);
|
||||
conferences
|
||||
.stream()
|
||||
.filter(conference -> {
|
||||
Integer pingCount = pingService.countPingYesterday(conference, calendar);
|
||||
return needToSendPingNotification(conference, pingCount);
|
||||
})
|
||||
.forEach(this::sendMessagePing);
|
||||
}
|
||||
|
||||
private boolean needToSendPingNotification(Conference conference, Integer pingCount) {
|
||||
if (pingCount > 0) {
|
||||
conference.setPing((Integer) pingCount);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void sendMessagePing(Conference conference) {
|
||||
Map<String, Object> variables = ImmutableMap.of("conference", conference);
|
||||
sendForAllParticipants(variables, conference, TEMPLATE_PING, String.format(TITLE_PING, conference.getTitle()));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,37 @@
|
||||
package ru.ulstu.conference.service;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class ConferenceScheduler {
|
||||
private final static boolean IS_DEADLINE_NOTIFICATION_BEFORE_WEEK = true;
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(ConferenceScheduler.class);
|
||||
|
||||
private final ConferenceNotificationService conferenceNotificationService;
|
||||
private final ConferenceService conferenceService;
|
||||
|
||||
public ConferenceScheduler(ConferenceNotificationService conferenceNotificationService,
|
||||
ConferenceService conferenceService) {
|
||||
this.conferenceNotificationService = conferenceNotificationService;
|
||||
this.conferenceService = conferenceService;
|
||||
}
|
||||
|
||||
|
||||
@Scheduled(cron = "0 0 8 * * MON", zone = "Europe/Samara")
|
||||
public void checkDeadlineBeforeWeek() {
|
||||
log.debug("ConferenceScheduler.checkDeadlineBeforeWeek started");
|
||||
conferenceNotificationService.sendDeadlineNotifications(conferenceService.findAll());
|
||||
log.debug("ConferenceScheduler.checkDeadlineBeforeWeek finished");
|
||||
}
|
||||
|
||||
@Scheduled(cron = "0 0 8 * * *", zone = "Europe/Samara")
|
||||
public void checkNewPing() {
|
||||
log.debug("ConferenceScheduler.checkPing started");
|
||||
conferenceNotificationService.sendPingNotifications(conferenceService.findAll());
|
||||
log.debug("ConferenceScheduler.checkPing finished");
|
||||
}
|
||||
}
|
@ -1,7 +1,13 @@
|
||||
package ru.ulstu.ping.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import ru.ulstu.conference.model.Conference;
|
||||
import ru.ulstu.ping.model.Ping;
|
||||
|
||||
public interface PingRepository extends JpaRepository<Ping, Integer> {
|
||||
|
||||
@Query("SELECT count(*) FROM Ping p WHERE (DAY(p.date) = :day) AND (MONTH(p.date) = :month) AND (YEAR(p.date) = :year) AND (p.conference = :conference)")
|
||||
long countByConferenceAndDate(@Param("conference") Conference conference, @Param("day") Integer day, @Param("month") Integer month, @Param("year") Integer year);
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
<?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="vova" id="20190426_000000-1">
|
||||
<addColumn tableName="event">
|
||||
<column name="conference_id" type="integer"></column>
|
||||
</addColumn>
|
||||
<addForeignKeyConstraint baseTableName="event" baseColumnNames="conference_id"
|
||||
constraintName="fk_event_conference_id" referencedTableName="conference"
|
||||
referencedColumnNames="id"/>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
@ -0,0 +1,10 @@
|
||||
<?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="anton" id="20190428_000000-1">
|
||||
<update tableName="project">
|
||||
<column name="status" value="APPLICATION"/>
|
||||
</update>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
@ -0,0 +1,11 @@
|
||||
<?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="20190430_000000-1">
|
||||
<dropColumn columnName="file_id" tableName="grants"/>
|
||||
<addColumn tableName="file">
|
||||
<column name="grant_id" type="integer"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
@ -0,0 +1,14 @@
|
||||
<?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="20190505_000000-1">
|
||||
<addColumn tableName="event">
|
||||
<column name="grant_id" type="integer"/>
|
||||
</addColumn>
|
||||
<addForeignKeyConstraint baseTableName="event" baseColumnNames="grant_id"
|
||||
constraintName="fk_event_grant_id" referencedTableName="grants"
|
||||
referencedColumnNames="id"/>
|
||||
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
@ -0,0 +1,25 @@
|
||||
<!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}/conferences/conference?id=${conference.id}|}">
|
||||
<span th:text="${conference.title}">Title</span></a>" была пропингована
|
||||
<b><span th:text="${conference.ping}"></span></b> раз.
|
||||
<br/>
|
||||
Обратите внимание.
|
||||
</p>
|
||||
<p>
|
||||
Regards,
|
||||
<br/>
|
||||
<em>NG-tracker.</em>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,37 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
</head>
|
||||
<body>
|
||||
<div th:fragment="filesList (isLatexAttach)" th:remove="tag">
|
||||
<th:block th:each="file, rowStat : *{files}">
|
||||
<span th:if="${(!isLatexAttach and file.isLatexAttach == null) or file.isLatexAttach == isLatexAttach}"
|
||||
th:remove="tag">
|
||||
<div class="row div-row-file" th:id="|files${rowStat.index}|"
|
||||
th:style="${file.deleted} ? 'display: none;' :''">
|
||||
<input type="hidden" th:field="*{files[__${rowStat.index}__].id}"/>
|
||||
<input type="hidden" th:field="*{files[__${rowStat.index}__].deleted}"/>
|
||||
<input type="hidden" th:field="*{files[__${rowStat.index}__].name}"/>
|
||||
<input type="hidden" th:field="*{files[__${rowStat.index}__].tmpFileName}"/>
|
||||
<div class="col-10 div-file-name">
|
||||
<a th:onclick="${file.id==null} ?
|
||||
'downloadFile('+${file.tmpFileName}+',null,\''+${file.name}+'\')':
|
||||
'downloadFile(null,'+${file.id}+',\''+${file.name}+'\')' "
|
||||
href="javascript:void(0)"
|
||||
th:text="*{files[__${rowStat.index}__].name}">
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<a class="btn btn-danger float-right"
|
||||
th:onclick="|$('#files${rowStat.index}\\.deleted').val('true');
|
||||
$('#files${rowStat.index}').hide(); |">
|
||||
<span aria-hidden="true"><i class="fa fa-times"/></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</th:block>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue