diff --git a/src/main/java/ru/ulstu/conference/controller/ConferenceController.java b/src/main/java/ru/ulstu/conference/controller/ConferenceController.java index a416345..f9a4bac 100644 --- a/src/main/java/ru/ulstu/conference/controller/ConferenceController.java +++ b/src/main/java/ru/ulstu/conference/controller/ConferenceController.java @@ -6,7 +6,6 @@ import org.springframework.ui.ModelMap; import org.springframework.validation.Errors; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -14,7 +13,6 @@ import ru.ulstu.conference.model.ConferenceDto; import ru.ulstu.conference.model.ConferenceFilterDto; import ru.ulstu.conference.model.ConferenceUser; import ru.ulstu.conference.service.ConferenceService; -import ru.ulstu.deadline.model.Deadline; import ru.ulstu.user.model.User; import springfox.documentation.annotations.ApiIgnore; @@ -23,9 +21,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Calendar; import java.util.List; -import java.util.stream.Collectors; -import static org.springframework.util.StringUtils.isEmpty; import static ru.ulstu.core.controller.Navigation.CONFERENCES_PAGE; import static ru.ulstu.core.controller.Navigation.CONFERENCE_PAGE; import static ru.ulstu.core.controller.Navigation.REDIRECT_TO; @@ -57,6 +53,8 @@ public class ConferenceController { @GetMapping("/dashboard") public void getDashboard(ModelMap modelMap) { modelMap.put("conferences", conferenceService.findAllActiveDto()); + + conferenceService.setChartData(modelMap); // example } @GetMapping("/conference") @@ -68,30 +66,27 @@ public class ConferenceController { } } - @PostMapping(value = "/conference", params = "save") - public String save(@Valid ConferenceDto conferenceDto, Errors errors) throws IOException { - filterEmptyDeadlines(conferenceDto); - if (errors.hasErrors()) { - return CONFERENCE_PAGE; - } - conferenceService.save(conferenceDto); - return String.format(REDIRECT_TO, CONFERENCES_PAGE); - - } - - @GetMapping("/delete/{conference-id}") - public String delete(@PathVariable("conference-id") Integer conferenceId) throws IOException { + @PostMapping(value = "/conferences", params = "deleteConference") + public String delete(@RequestParam("deleteConference") Integer conferenceId) throws IOException { conferenceService.delete(conferenceId); return String.format(REDIRECT_TO, CONFERENCES_PAGE); } + @PostMapping(value = "/conference", params = "save") + public String save(@Valid ConferenceDto conferenceDto, Errors errors) throws IOException { + if (!conferenceService.save(conferenceDto, errors)) { + return CONFERENCE_PAGE; + } + return String.format(REDIRECT_TO, CONFERENCES_PAGE); + } + @PostMapping(value = "/conference", params = "addDeadline") - public String addDeadline(@Valid ConferenceDto conferenceDto, Errors errors) { - filterEmptyDeadlines(conferenceDto); + public String addDeadline(@Valid ConferenceDto conferenceDto, Errors errors) throws IOException { + conferenceService.filterEmptyDeadlines(conferenceDto); if (errors.hasErrors()) { return CONFERENCE_PAGE; } - conferenceDto.getDeadlines().add(new Deadline()); + conferenceService.addDeadline(conferenceDto); return CONFERENCE_PAGE; } @@ -105,6 +100,16 @@ public class ConferenceController { return CONFERENCE_PAGE; } + @PostMapping(value = "/conference", params = "addPaper") + public String addPaper(@Valid ConferenceDto conferenceDto, Errors errors) throws IOException { + if (errors.hasErrors()) { + return CONFERENCE_PAGE; + } + conferenceService.addPaper(conferenceDto); + + return CONFERENCE_PAGE; + } + @PostMapping(value = "/conference", params = "removePaper") public String removePaper(@Valid ConferenceDto conferenceDto, Errors errors, @RequestParam(value = "removePaper") Integer paperIndex) throws IOException { @@ -124,6 +129,15 @@ public class ConferenceController { return CONFERENCE_PAGE; } + @PostMapping(value = "/conference", params = "pingConference") + public String ping(@Valid ConferenceDto conferenceDto, Errors errors) throws IOException { + if (errors.hasErrors()) { + return CONFERENCE_PAGE; + } + conferenceService.ping(conferenceDto); + return CONFERENCE_PAGE; + } + @ModelAttribute("allParticipation") public List getAllParticipation() { return conferenceService.getAllParticipations(); @@ -148,9 +162,4 @@ public class ConferenceController { return years; } - private void filterEmptyDeadlines(ConferenceDto conferenceDto) { - conferenceDto.setDeadlines(conferenceDto.getDeadlines().stream() - .filter(dto -> dto.getDate() != null || !isEmpty(dto.getDescription())) - .collect(Collectors.toList())); - } } diff --git a/src/main/java/ru/ulstu/conference/model/Conference.java b/src/main/java/ru/ulstu/conference/model/Conference.java index 9831a0e..31c5ea7 100644 --- a/src/main/java/ru/ulstu/conference/model/Conference.java +++ b/src/main/java/ru/ulstu/conference/model/Conference.java @@ -21,8 +21,10 @@ import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.validation.constraints.NotBlank; import java.util.ArrayList; +import java.util.Comparator; import java.util.Date; import java.util.List; +import java.util.Optional; @Entity @Table(name = "conference") @@ -35,7 +37,7 @@ public class Conference extends BaseEntity { private String url; - private int ping; + private int ping = 0; @Column(name = "begin_date") @Temporal(TemporalType.TIMESTAMP) @@ -53,10 +55,11 @@ public class Conference extends BaseEntity { @OrderBy("date") private List deadlines = new ArrayList<>(); - @ManyToMany(fetch = FetchType.EAGER) + @ManyToMany(cascade = CascadeType.MERGE, fetch = FetchType.EAGER) @JoinTable(name = "paper_conference", joinColumns = {@JoinColumn(name = "conference_id")}, inverseJoinColumns = {@JoinColumn(name = "paper_id")}) + @Fetch(FetchMode.SUBSELECT) private List papers = new ArrayList<>(); @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) @@ -135,4 +138,13 @@ public class Conference extends BaseEntity { public void setUsers(List users) { this.users = users; } + + public Optional getNextDeadline() { + return deadlines + .stream() + .filter(deadline -> deadline.getDate() != null) + .sorted(Comparator.comparing(Deadline::getDate)) + .filter(d -> d.getDate().after(new Date())) + .findFirst(); + } } diff --git a/src/main/java/ru/ulstu/conference/model/ConferenceDto.java b/src/main/java/ru/ulstu/conference/model/ConferenceDto.java index 6264f62..db669fe 100644 --- a/src/main/java/ru/ulstu/conference/model/ConferenceDto.java +++ b/src/main/java/ru/ulstu/conference/model/ConferenceDto.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import org.springframework.format.annotation.DateTimeFormat; import ru.ulstu.core.model.BaseEntity; import ru.ulstu.deadline.model.Deadline; +import ru.ulstu.name.NameContainer; import ru.ulstu.paper.model.Paper; import javax.persistence.Temporal; @@ -17,7 +18,7 @@ import java.util.List; import static ru.ulstu.core.util.StreamApiUtils.convert; -public class ConferenceDto { +public class ConferenceDto extends NameContainer { private final static String BEGIN_DATE = "Начало: "; private final static String END_DATE = "Конец: "; diff --git a/src/main/java/ru/ulstu/conference/model/ConferenceFilterDto.java b/src/main/java/ru/ulstu/conference/model/ConferenceFilterDto.java index 8503b40..0649901 100644 --- a/src/main/java/ru/ulstu/conference/model/ConferenceFilterDto.java +++ b/src/main/java/ru/ulstu/conference/model/ConferenceFilterDto.java @@ -11,14 +11,14 @@ public class ConferenceFilterDto { public ConferenceFilterDto() { } - public ConferenceFilterDto(List conferenceDtos, Integer filterUserId, Integer year) { - this.conferences = conferenceDtos; + public ConferenceFilterDto(List conferences, Integer filterUserId, Integer year) { + this.conferences = conferences; this.filterUserId = filterUserId; this.year = year; } - public ConferenceFilterDto(List conferenceDtos) { - this(conferenceDtos, null, null); + public ConferenceFilterDto(List conferences) { + this(conferences, null, null); } public List getConferences() { diff --git a/src/main/java/ru/ulstu/conference/repository/ConferenceRepository.java b/src/main/java/ru/ulstu/conference/repository/ConferenceRepository.java index cb8a488..2b0a428 100644 --- a/src/main/java/ru/ulstu/conference/repository/ConferenceRepository.java +++ b/src/main/java/ru/ulstu/conference/repository/ConferenceRepository.java @@ -1,19 +1,32 @@ package ru.ulstu.conference.repository; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import ru.ulstu.conference.model.Conference; +import ru.ulstu.name.BaseRepository; import ru.ulstu.user.model.User; import java.util.Date; import java.util.List; -public interface ConferenceRepository extends JpaRepository { +public interface ConferenceRepository extends JpaRepository, BaseRepository { @Query("SELECT c FROM Conference c LEFT JOIN c.users u WHERE (:user IS NULL OR u.user = :user) " + "AND (YEAR(c.beginDate) = :year OR :year IS NULL) ORDER BY begin_date DESC") List findByUserAndYear(@Param("user") User user, @Param("year") Integer year); @Query("SELECT c FROM Conference c WHERE c.beginDate > :date") List findAllActive(@Param("date") Date date); + + @Query("SELECT case when count(c) > 0 then true else false end FROM Conference c JOIN c.papers p WHERE p.id = :paperId") + boolean isPaperAttached(@Param("paperId") Integer paperId); + + @Modifying + @Query("UPDATE Conference c SET c.ping = (c.ping + 1) WHERE c.id = :id") + int updatePingConference(@Param("id") Integer id); + + @Override + @Query("SELECT title FROM Conference c WHERE (c.title = :name) AND (:id IS NULL OR c.id != :id) ") + String findByNameAndNotId(@Param("name") String name, @Param("id") Integer id); } diff --git a/src/main/java/ru/ulstu/conference/service/ConferenceNotificationService.java b/src/main/java/ru/ulstu/conference/service/ConferenceNotificationService.java index ff9f69a..ddb8130 100644 --- a/src/main/java/ru/ulstu/conference/service/ConferenceNotificationService.java +++ b/src/main/java/ru/ulstu/conference/service/ConferenceNotificationService.java @@ -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 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 variables = ImmutableMap.of("conference", conference); + sendForAllParticipants(variables, conference, TEMPLATE_DEADLINE, String.format(TITLE_DEADLINE, conference.getTitle())); + } + + public void sendCreateNotification(Conference conference) { + Map variables = ImmutableMap.of("conference", conference); + sendForAllUsers(variables, TEMPLATE_CREATE, String.format(TITLE_CREATE, conference.getTitle())); + } + + public void updateDeadlineNotification(Conference conference) { + Map 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 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 variables, String template, String title) { + userService.findAll().forEach(user -> mailService.sendEmailFromTemplate(variables, user, template, title)); + } + + private void sendForAllParticipants(Map variables, Conference conference, String template, String title) { + conference.getUsers().forEach(conferenceUser -> mailService.sendEmailFromTemplate(variables, conferenceUser.getUser(), template, title)); + } + + + public void sendPingNotifications(List 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 variables = ImmutableMap.of("conference", conference); + sendForAllParticipants(variables, conference, TEMPLATE_PING, String.format(TITLE_PING, conference.getTitle())); + } } diff --git a/src/main/java/ru/ulstu/conference/service/ConferenceScheduler.java b/src/main/java/ru/ulstu/conference/service/ConferenceScheduler.java new file mode 100644 index 0000000..6f8fe90 --- /dev/null +++ b/src/main/java/ru/ulstu/conference/service/ConferenceScheduler.java @@ -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"); + } +} diff --git a/src/main/java/ru/ulstu/conference/service/ConferenceService.java b/src/main/java/ru/ulstu/conference/service/ConferenceService.java index dfd0f8a..1754987 100644 --- a/src/main/java/ru/ulstu/conference/service/ConferenceService.java +++ b/src/main/java/ru/ulstu/conference/service/ConferenceService.java @@ -4,14 +4,20 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.ui.ModelMap; +import org.springframework.validation.Errors; import ru.ulstu.conference.model.Conference; import ru.ulstu.conference.model.ConferenceDto; import ru.ulstu.conference.model.ConferenceFilterDto; import ru.ulstu.conference.model.ConferenceUser; import ru.ulstu.conference.repository.ConferenceRepository; +import ru.ulstu.deadline.model.Deadline; import ru.ulstu.deadline.service.DeadlineService; +import ru.ulstu.name.BaseService; import ru.ulstu.paper.model.Paper; import ru.ulstu.paper.service.PaperService; +import ru.ulstu.ping.service.PingService; +import ru.ulstu.timeline.service.EventService; import ru.ulstu.user.model.User; import ru.ulstu.user.service.UserService; @@ -20,12 +26,13 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; +import java.util.stream.Collectors; import static org.springframework.util.ObjectUtils.isEmpty; import static ru.ulstu.core.util.StreamApiUtils.convert; @Service -public class ConferenceService { +public class ConferenceService extends BaseService { private final static int MAX_DISPLAY_SIZE = 40; private final ConferenceRepository conferenceRepository; @@ -33,17 +40,27 @@ public class ConferenceService { private final DeadlineService deadlineService; private final PaperService paperService; private final UserService userService; + private final PingService pingService; + private final ConferenceNotificationService conferenceNotificationService; + private final EventService eventService; public ConferenceService(ConferenceRepository conferenceRepository, ConferenceUserService conferenceUserService, DeadlineService deadlineService, PaperService paperService, - UserService userService) { + UserService userService, + PingService pingService, + ConferenceNotificationService conferenceNotificationService, + EventService eventService) { + this.baseRepository = conferenceRepository; this.conferenceRepository = conferenceRepository; this.conferenceUserService = conferenceUserService; this.deadlineService = deadlineService; this.paperService = paperService; this.userService = userService; + this.pingService = pingService; + this.conferenceNotificationService = conferenceNotificationService; + this.eventService = eventService; } public ConferenceDto getExistConferenceById(Integer id) { @@ -71,39 +88,71 @@ public class ConferenceService { } public ConferenceDto findOneDto(Integer id) { - return new ConferenceDto(conferenceRepository.getOne(id)); + return new ConferenceDto(conferenceRepository.findOne(id)); } - public void save(ConferenceDto conferenceDto) throws IOException { + public boolean save(ConferenceDto conferenceDto, Errors errors) throws IOException { + conferenceDto.setName(conferenceDto.getTitle()); + filterEmptyDeadlines(conferenceDto); + checkEmptyFieldsOfDeadline(conferenceDto, errors); + checkUniqueName(conferenceDto, + errors, + conferenceDto.getId(), + "title", + "Конференция с таким именем уже существует"); + if (errors.hasErrors()) { + return false; + } + if (isEmpty(conferenceDto.getId())) { create(conferenceDto); } else { update(conferenceDto); } + + return true; } @Transactional public Integer create(ConferenceDto conferenceDto) throws IOException { Conference newConference = copyFromDto(new Conference(), conferenceDto); newConference = conferenceRepository.save(newConference); + conferenceNotificationService.sendCreateNotification(newConference); + eventService.createFromConference(newConference); return newConference.getId(); } @Transactional public Integer update(ConferenceDto conferenceDto) throws IOException { - Conference conference = conferenceRepository.getOne(conferenceDto.getId()); + Conference conference = conferenceRepository.findOne(conferenceDto.getId()); + List oldDeadlines = conference.getDeadlines().stream() + .map(this::copyDeadline) + .collect(Collectors.toList()); + Date oldBeginDate = conference.getBeginDate(); + Date oldEndDate = conference.getEndDate(); conferenceRepository.save(copyFromDto(conference, conferenceDto)); + eventService.updateConferenceDeadlines(conference); + sendNotificationAfterUpdateDeadlines(conference, oldDeadlines); + if (!conference.getBeginDate().equals(oldBeginDate) || !conference.getEndDate().equals(oldEndDate)) { + conferenceNotificationService.updateConferencesDatesNotification(conference, oldBeginDate, oldEndDate); + } conferenceDto.getRemovedDeadlineIds().forEach(deadlineService::remove); return conference.getId(); } @Transactional public void delete(Integer conferenceId) { - if (conferenceRepository.existsById(conferenceId)) { - conferenceRepository.deleteById(conferenceId); + if (conferenceRepository.exists(conferenceId)) { + eventService.removeConferencesEvent(conferenceRepository.findOne(conferenceId)); + conferenceRepository.delete(conferenceId); } } + public void addDeadline(ConferenceDto conferenceDto) { + conferenceDto.getDeadlines().add(new Deadline()); + } + + public void removeDeadline(ConferenceDto conferenceDto, Integer deadlineIndex) throws IOException { if (conferenceDto.getDeadlines().get(deadlineIndex).getId() != null) { conferenceDto.getRemovedDeadlineIds().add(conferenceDto.getDeadlines().get(deadlineIndex).getId()); @@ -111,9 +160,19 @@ public class ConferenceService { conferenceDto.getDeadlines().remove((int) deadlineIndex); } + public void addPaper(ConferenceDto conferenceDto) { + Paper paper = new Paper(); + paper.setTitle(userService.getCurrentUser().getLastName() + "_" + conferenceDto.getTitle() + "_" + (new Date()).getTime()); + paper.setStatus(Paper.PaperStatus.DRAFT); + + conferenceDto.getPapers().add(paper); + } + public void removePaper(ConferenceDto conferenceDto, Integer paperIndex) throws IOException { Paper removedPaper = conferenceDto.getPapers().remove((int) paperIndex); - conferenceDto.getNotSelectedPapers().add(removedPaper); + if (removedPaper.getId() != null) { + conferenceDto.getNotSelectedPapers().add(removedPaper); + } } public void takePart(ConferenceDto conferenceDto) throws IOException { @@ -141,15 +200,15 @@ public class ConferenceService { conference.setTitle(conferenceDto.getTitle()); conference.setDescription(conferenceDto.getDescription()); conference.setUrl(conferenceDto.getUrl()); - conference.setPing(0); conference.setBeginDate(conferenceDto.getBeginDate()); conference.setEndDate(conferenceDto.getEndDate()); - conference.setPapers(conferenceDto.getPapers()); + conference.getPapers().clear(); + conferenceDto.getPapers().forEach(paper -> conference.getPapers().add(paper.getId() != null ? paperService.findPaperById(paper.getId()) : paperService.create(paper))); conference.setDeadlines(deadlineService.saveOrCreate(conferenceDto.getDeadlines())); conference.setUsers(conferenceUserService.saveOrCreate(conferenceDto.getUsers())); if (conferenceDto.getPaperIds() != null && !conferenceDto.getPaperIds().isEmpty()) { conferenceDto.getPaperIds().forEach(paperId -> - conference.getPapers().add(paperService.findEntityById(paperId))); + conference.getPapers().add(paperService.findPaperById(paperId))); } return conference; } @@ -173,4 +232,74 @@ public class ConferenceService { public List findAllActive() { return conferenceRepository.findAllActive(new Date()); } + + public boolean isAttachedToConference(Integer paperId) { + return conferenceRepository.isPaperAttached(paperId); + } + + @Transactional + public void ping(ConferenceDto conferenceDto) throws IOException { + pingService.addPing(findOne(conferenceDto.getId())); + conferenceRepository.updatePingConference(conferenceDto.getId()); + } + + public Conference findOne(Integer conferenceId) { + return conferenceRepository.findOne(conferenceId); + } + + public void setChartData(ModelMap modelMap) { + //first, add the regional sales + Integer northeastSales = 17089; + Integer westSales = 10603; + Integer midwestSales = 5223; + Integer southSales = 10111; + + modelMap.addAttribute("northeastSales", northeastSales); + modelMap.addAttribute("southSales", southSales); + modelMap.addAttribute("midwestSales", midwestSales); + modelMap.addAttribute("westSales", westSales); + + //now add sales by lure type + List inshoreSales = Arrays.asList(4074, 3455, 4112); + List nearshoreSales = Arrays.asList(3222, 3011, 3788); + List offshoreSales = Arrays.asList(7811, 7098, 6455); + + modelMap.addAttribute("inshoreSales", inshoreSales); + modelMap.addAttribute("nearshoreSales", nearshoreSales); + modelMap.addAttribute("offshoreSales", offshoreSales); + } + + public void sendNotificationAfterUpdateDeadlines(Conference conference, List oldDeadlines) { + if (oldDeadlines.size() != conference.getDeadlines().size()) { + conferenceNotificationService.updateDeadlineNotification(conference); + return; + } + + if (conference.getDeadlines() + .stream() + .filter(deadline -> !oldDeadlines.contains(deadline)) + .count() > 0) { + conferenceNotificationService.updateDeadlineNotification(conference); + } + } + + public Deadline copyDeadline(Deadline oldDeadline) { + Deadline newDeadline = new Deadline(oldDeadline.getDate(), oldDeadline.getDescription()); + newDeadline.setId(oldDeadline.getId()); + return newDeadline; + } + + public void checkEmptyFieldsOfDeadline(ConferenceDto conferenceDto, Errors errors) { + for (Deadline deadline : conferenceDto.getDeadlines()) { + if (deadline.getDate() == null || deadline.getDescription().isEmpty()) { + errors.rejectValue("deadlines", "errorCode", "Все поля дедлайна должны быть заполнены"); + } + } + } + + public void filterEmptyDeadlines(ConferenceDto conferenceDto) { + conferenceDto.setDeadlines(conferenceDto.getDeadlines().stream() + .filter(dto -> dto.getDate() != null || !org.springframework.util.StringUtils.isEmpty(dto.getDescription())) + .collect(Collectors.toList())); + } } diff --git a/src/main/java/ru/ulstu/core/controller/AdviceController.java b/src/main/java/ru/ulstu/core/controller/AdviceController.java index 8238797..27ba6c9 100644 --- a/src/main/java/ru/ulstu/core/controller/AdviceController.java +++ b/src/main/java/ru/ulstu/core/controller/AdviceController.java @@ -39,6 +39,11 @@ public class AdviceController { return userService.getCurrentUser().getUserAbbreviate(); } + @ModelAttribute("flashMessage") + public String getFlashMessage() { + return null; + } + private Response handleException(ErrorConstants error) { log.warn(error.toString()); return new Response<>(error); diff --git a/src/main/java/ru/ulstu/deadline/model/Deadline.java b/src/main/java/ru/ulstu/deadline/model/Deadline.java index 404e5c8..148697c 100644 --- a/src/main/java/ru/ulstu/deadline/model/Deadline.java +++ b/src/main/java/ru/ulstu/deadline/model/Deadline.java @@ -9,6 +9,7 @@ import javax.persistence.Entity; import javax.persistence.Temporal; import javax.persistence.TemporalType; import java.util.Date; +import java.util.Objects; @Entity public class Deadline extends BaseEntity { @@ -51,4 +52,26 @@ public class Deadline extends BaseEntity { public void setDate(Date date) { this.date = date; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + Deadline deadline = (Deadline) o; + return getId().equals(deadline.getId()) && + description.equals(deadline.description) && + date.equals(deadline.date); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), description, date); + } } diff --git a/src/main/java/ru/ulstu/grant/controller/GrantController.java b/src/main/java/ru/ulstu/grant/controller/GrantController.java index a0bb916..ad5e992 100644 --- a/src/main/java/ru/ulstu/grant/controller/GrantController.java +++ b/src/main/java/ru/ulstu/grant/controller/GrantController.java @@ -13,6 +13,7 @@ import ru.ulstu.deadline.model.Deadline; import ru.ulstu.grant.model.Grant; import ru.ulstu.grant.model.GrantDto; import ru.ulstu.grant.service.GrantService; +import ru.ulstu.paper.model.PaperDto; import ru.ulstu.user.model.User; import springfox.documentation.annotations.ApiIgnore; @@ -50,7 +51,9 @@ public class GrantController { @GetMapping("/grant") public void getGrant(ModelMap modelMap, @RequestParam(value = "id") Integer id) { if (id != null && id > 0) { - modelMap.put("grantDto", grantService.findOneDto(id)); + GrantDto grantDto = grantService.findOneDto(id); + attachPaper(grantDto); + modelMap.put("grantDto", grantDto); } else { modelMap.put("grantDto", new GrantDto()); } @@ -78,6 +81,12 @@ public class GrantController { return GRANT_PAGE; } + @PostMapping(value = "/grant", params = "attachPaper") + public String attachPaper(GrantDto grantDto) { + grantService.attachPaper(grantDto); + return GRANT_PAGE; + } + @PostMapping(value = "/grant", params = "addDeadline") public String addDeadline(@Valid GrantDto grantDto, Errors errors) { filterEmptyDeadlines(grantDto); @@ -88,6 +97,13 @@ public class GrantController { return GRANT_PAGE; } + @PostMapping(value = "/grant", params = "removeDeadline") + public String removeDeadline(GrantDto grantDto, + @RequestParam(value = "removeDeadline") Integer deadlineId) { + grantService.removeDeadline(grantDto, deadlineId); + return GRANT_PAGE; + } + @PostMapping(value = "/grant", params = "createProject") public String createProject(@Valid GrantDto grantDto, Errors errors) throws IOException { if (errors.hasErrors()) { @@ -113,6 +129,11 @@ public class GrantController { return grantService.getGrantAuthors(grantDto); } + @ModelAttribute("allPapers") + public List getAllPapers() { + return grantService.getAllUncompletedPapers(); + } + private void filterEmptyDeadlines(GrantDto grantDto) { grantDto.setDeadlines(grantDto.getDeadlines().stream() .filter(dto -> dto.getDate() != null || !isEmpty(dto.getDescription())) diff --git a/src/main/java/ru/ulstu/grant/model/Grant.java b/src/main/java/ru/ulstu/grant/model/Grant.java index 30d9fb3..e0cd9be 100644 --- a/src/main/java/ru/ulstu/grant/model/Grant.java +++ b/src/main/java/ru/ulstu/grant/model/Grant.java @@ -1,10 +1,15 @@ package ru.ulstu.grant.model; +import org.hibernate.annotations.Fetch; +import org.hibernate.annotations.FetchMode; +import org.hibernate.validator.constraints.NotBlank; import ru.ulstu.core.model.BaseEntity; import ru.ulstu.core.model.UserContainer; import ru.ulstu.deadline.model.Deadline; import ru.ulstu.file.model.FileData; +import ru.ulstu.paper.model.Paper; import ru.ulstu.project.model.Project; +import ru.ulstu.timeline.model.Event; import ru.ulstu.user.model.User; import javax.persistence.CascadeType; @@ -13,12 +18,12 @@ import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.FetchType; import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.OrderBy; import javax.persistence.Table; -import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import java.util.ArrayList; import java.util.Comparator; @@ -62,14 +67,12 @@ public class Grant extends BaseEntity implements UserContainer { @OrderBy("date") private List deadlines = new ArrayList<>(); - //Описание гранта - @NotNull private String comment; - //Заявка на грант - @ManyToOne - @JoinColumn(name = "file_id") - private FileData application; + @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) + @JoinColumn(name = "grant_id", unique = true) + @Fetch(FetchMode.SUBSELECT) + private List files = new ArrayList<>(); @ManyToOne(cascade = CascadeType.ALL) @JoinColumn(name = "project_id") @@ -83,6 +86,17 @@ public class Grant extends BaseEntity implements UserContainer { @JoinColumn(name = "leader_id") private User leader; + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable(name = "grants_papers", + joinColumns = {@JoinColumn(name = "grant_id")}, + inverseJoinColumns = {@JoinColumn(name = "paper_id")}) + @Fetch(FetchMode.SUBSELECT) + private List papers = new ArrayList<>(); + + @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @JoinColumn(name = "grant_id") + private List events = new ArrayList<>(); + public GrantStatus getStatus() { return status; } @@ -107,12 +121,12 @@ public class Grant extends BaseEntity implements UserContainer { this.comment = comment; } - public FileData getApplication() { - return application; + public List getFiles() { + return files; } - public void setApplication(FileData application) { - this.application = application; + public void setFiles(List files) { + this.files = files; } public String getTitle() { @@ -152,6 +166,22 @@ public class Grant extends BaseEntity implements UserContainer { this.leader = leader; } + public List getPapers() { + return papers; + } + + public void setPapers(List papers) { + this.papers = papers; + } + + public List getEvents() { + return events; + } + + public void setEvents(List events) { + this.events = events; + } + public Optional getNextDeadline() { return deadlines .stream() diff --git a/src/main/java/ru/ulstu/grant/model/GrantDto.java b/src/main/java/ru/ulstu/grant/model/GrantDto.java index d836dfb..c2d47f2 100644 --- a/src/main/java/ru/ulstu/grant/model/GrantDto.java +++ b/src/main/java/ru/ulstu/grant/model/GrantDto.java @@ -4,6 +4,8 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import org.apache.commons.lang3.StringUtils; import ru.ulstu.deadline.model.Deadline; +import ru.ulstu.file.model.FileDataDto; +import ru.ulstu.paper.model.PaperDto; import ru.ulstu.project.model.ProjectDto; import ru.ulstu.user.model.UserDto; @@ -24,7 +26,7 @@ public class GrantDto { private Grant.GrantStatus status; private List deadlines = new ArrayList<>(); private String comment; - private String applicationFileName; + private List files = new ArrayList<>(); private ProjectDto project; private Set authorIds; private Set authors; @@ -32,6 +34,11 @@ public class GrantDto { private boolean wasLeader; private boolean hasAge; private boolean hasDegree; + private boolean hasBAKPapers; + private boolean hasScopusPapers; + private List paperIds = new ArrayList<>(); + private List papers = new ArrayList<>(); + private List removedDeadlineIds = new ArrayList<>(); public GrantDto() { deadlines.add(new Deadline()); @@ -43,25 +50,31 @@ public class GrantDto { @JsonProperty("status") Grant.GrantStatus status, @JsonProperty("deadlines") List deadlines, @JsonProperty("comment") String comment, + @JsonProperty("files") List files, @JsonProperty("project") ProjectDto project, @JsonProperty("authorIds") Set authorIds, @JsonProperty("authors") Set authors, - @JsonProperty("leader") Integer leaderId, + @JsonProperty("leaderId") Integer leaderId, @JsonProperty("wasLeader") boolean wasLeader, @JsonProperty("hasAge") boolean hasAge, - @JsonProperty("hasDegree") boolean hasDegree) { + @JsonProperty("hasDegree") boolean hasDegree, + @JsonProperty("paperIds") List paperIds, + @JsonProperty("papers") List papers) { this.id = id; this.title = title; this.status = status; this.deadlines = deadlines; this.comment = comment; - this.applicationFileName = null; + this.files = files; this.project = project; + this.authorIds = authorIds; this.authors = authors; this.leaderId = leaderId; this.wasLeader = wasLeader; this.hasAge = hasAge; this.hasDegree = hasDegree; + this.paperIds = paperIds; + this.papers = papers; } public GrantDto(Grant grant) { @@ -70,14 +83,16 @@ public class GrantDto { this.status = grant.getStatus(); this.deadlines = grant.getDeadlines(); this.comment = grant.getComment(); + this.files = convert(grant.getFiles(), FileDataDto::new); this.project = grant.getProject() == null ? null : new ProjectDto(grant.getProject()); - this.applicationFileName = grant.getApplication() == null ? null : grant.getApplication().getName(); this.authorIds = convert(grant.getAuthors(), user -> user.getId()); this.authors = convert(grant.getAuthors(), UserDto::new); this.leaderId = grant.getLeader().getId(); this.wasLeader = false; this.hasAge = false; this.hasDegree = false; + this.paperIds = convert(grant.getPapers(), paper -> paper.getId()); + this.papers = convert(grant.getPapers(), PaperDto::new); } public Integer getId() { @@ -120,6 +135,14 @@ public class GrantDto { this.comment = comment; } + public List getFiles() { + return files; + } + + public void setFiles(List files) { + this.files = files; + } + public ProjectDto getProject() { return project; } @@ -128,14 +151,6 @@ public class GrantDto { this.project = project; } - public String getApplicationFileName() { - return applicationFileName; - } - - public void setApplicationFileName(String applicationFileName) { - this.applicationFileName = applicationFileName; - } - public Set getAuthorIds() { return authorIds; } @@ -190,4 +205,44 @@ public class GrantDto { public void setHasDegree(boolean hasDegree) { this.hasDegree = hasDegree; } + + public List getPaperIds() { + return paperIds; + } + + public void setPaperIds(List paperIds) { + this.paperIds = paperIds; + } + + public List getPapers() { + return papers; + } + + public void setPapers(List papers) { + this.papers = papers; + } + + public List getRemovedDeadlineIds() { + return removedDeadlineIds; + } + + public void setRemovedDeadlineIds(List removedDeadlineIds) { + this.removedDeadlineIds = removedDeadlineIds; + } + + public boolean isHasBAKPapers() { + return hasBAKPapers; + } + + public void setHasBAKPapers(boolean hasBAKPapers) { + this.hasBAKPapers = hasBAKPapers; + } + + public boolean isHasScopusPapers() { + return hasScopusPapers; + } + + public void setHasScopusPapers(boolean hasScopusPapers) { + this.hasScopusPapers = hasScopusPapers; + } } diff --git a/src/main/java/ru/ulstu/grant/service/GrantNotificationService.java b/src/main/java/ru/ulstu/grant/service/GrantNotificationService.java new file mode 100644 index 0000000..40c045b --- /dev/null +++ b/src/main/java/ru/ulstu/grant/service/GrantNotificationService.java @@ -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 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 variables = ImmutableMap.of("grant", grant); + sendForAllAuthors(variables, grant, TEMPLATE_DEADLINE, String.format(TITLE_DEADLINE, grant.getTitle())); + } + + public void sendCreateNotification(Grant grant) { + Map variables = ImmutableMap.of("grant", grant); + sendForAllAuthors(variables, grant, TEMPLATE_CREATE, String.format(TITLE_CREATE, grant.getTitle())); + } + + public void sendAuthorsChangeNotification(Grant grant, Set oldAuthors) { + Map 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 variables = ImmutableMap.of("grant", grant, "oldLeader", oldLeader); + sendForAllAuthors(variables, grant, TEMPLATE_LEADER_CHANGED, String.format(TITLE_LEADER_CHANGED, grant.getTitle())); + } + private void sendForAllAuthors(Map variables, Grant grant, String template, String title) { + Set allAuthors = grant.getAuthors(); + allAuthors.forEach(author -> mailService.sendEmailFromTemplate(variables, author, template, title)); + mailService.sendEmailFromTemplate(variables, grant.getLeader(), template, title); + } +} diff --git a/src/main/java/ru/ulstu/grant/service/GrantScheduler.java b/src/main/java/ru/ulstu/grant/service/GrantScheduler.java new file mode 100644 index 0000000..1c38c4a --- /dev/null +++ b/src/main/java/ru/ulstu/grant/service/GrantScheduler.java @@ -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"); + } +} diff --git a/src/main/java/ru/ulstu/grant/service/GrantService.java b/src/main/java/ru/ulstu/grant/service/GrantService.java index a6e255f..45f9b2f 100644 --- a/src/main/java/ru/ulstu/grant/service/GrantService.java +++ b/src/main/java/ru/ulstu/grant/service/GrantService.java @@ -5,46 +5,63 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import ru.ulstu.deadline.model.Deadline; import ru.ulstu.deadline.service.DeadlineService; +import ru.ulstu.file.model.FileDataDto; import ru.ulstu.file.service.FileService; import ru.ulstu.grant.model.Grant; import ru.ulstu.grant.model.GrantDto; import ru.ulstu.grant.repository.GrantRepository; +import ru.ulstu.paper.model.Paper; +import ru.ulstu.paper.model.PaperDto; +import ru.ulstu.paper.service.PaperService; import ru.ulstu.project.model.Project; import ru.ulstu.project.model.ProjectDto; import ru.ulstu.project.service.ProjectService; +import ru.ulstu.timeline.service.EventService; import ru.ulstu.user.model.User; import ru.ulstu.user.service.UserService; import java.io.IOException; import java.util.Arrays; +import java.util.Collections; import java.util.Date; +import java.util.HashSet; import java.util.List; -import java.util.stream.Collectors; +import java.util.Set; +import static java.util.stream.Collectors.toList; import static org.springframework.util.ObjectUtils.isEmpty; import static ru.ulstu.core.util.StreamApiUtils.convert; import static ru.ulstu.grant.model.Grant.GrantStatus.APPLICATION; @Service public class GrantService { - private final static int MAX_DISPLAY_SIZE = 40; + private final static int MAX_DISPLAY_SIZE = 50; private final GrantRepository grantRepository; private final ProjectService projectService; private final DeadlineService deadlineService; private final FileService fileService; private final UserService userService; + private final PaperService paperService; + private final EventService eventService; + private final GrantNotificationService grantNotificationService; public GrantService(GrantRepository grantRepository, FileService fileService, DeadlineService deadlineService, ProjectService projectService, - UserService userService) { + UserService userService, + PaperService paperService, + EventService eventService, + GrantNotificationService grantNotificationService) { this.grantRepository = grantRepository; this.fileService = fileService; this.deadlineService = deadlineService; this.projectService = projectService; this.userService = userService; + this.paperService = paperService; + this.eventService = eventService; + this.grantNotificationService = grantNotificationService; } public List findAll() { @@ -58,13 +75,15 @@ public class GrantService { } public GrantDto findOneDto(Integer id) { - return new GrantDto(grantRepository.getOne(id)); + return new GrantDto(grantRepository.findOne(id)); } @Transactional public Integer create(GrantDto grantDto) throws IOException { Grant newGrant = copyFromDto(new Grant(), grantDto); newGrant = grantRepository.save(newGrant); + eventService.createFromGrant(newGrant); + grantNotificationService.sendCreateNotification(newGrant); return newGrant.getId(); } @@ -76,9 +95,9 @@ public class GrantService { grant.setProject(projectService.findById(grantDto.getProject().getId())); } grant.setDeadlines(deadlineService.saveOrCreate(grantDto.getDeadlines())); - if (grantDto.getApplicationFileName() != null) { - grant.setApplication(fileService.createFileFromTmp(grantDto.getApplicationFileName())); - } + grant.setFiles(fileService.saveOrCreate(grantDto.getFiles().stream() + .filter(f -> !f.isDeleted()) + .collect(toList()))); grant.getAuthors().clear(); if (grantDto.getAuthorIds() != null && !grantDto.getAuthorIds().isEmpty()) { grantDto.getAuthorIds().forEach(authorIds -> grant.getAuthors().add(userService.findById(authorIds))); @@ -86,6 +105,10 @@ public class GrantService { if (grantDto.getLeaderId() != null) { grant.setLeader(userService.findById(grantDto.getLeaderId())); } + grant.getPapers().clear(); + if (grantDto.getPaperIds() != null && !grantDto.getPaperIds().isEmpty()) { + grantDto.getPaperIds().forEach(paperIds -> grant.getPapers().add(paperService.findPaperById(paperIds))); + } return grant; } @@ -96,21 +119,37 @@ public class GrantService { @Transactional public Integer update(GrantDto grantDto) throws IOException { - Grant grant = grantRepository.getOne(grantDto.getId()); - Grant.GrantStatus oldStatus = grant.getStatus(); - if (grantDto.getApplicationFileName() != null && grant.getApplication() != null) { - fileService.deleteFile(grant.getApplication()); + Grant grant = grantRepository.findOne(grantDto.getId()); + Set oldAuthors = new HashSet<>(grant.getAuthors()); + User oldLeader = grant.getLeader(); + for (FileDataDto file : grantDto.getFiles().stream() + .filter(f -> f.isDeleted() && f.getId() != null) + .collect(toList())) { + fileService.delete(file.getId()); } + grantDto.getRemovedDeadlineIds().forEach(deadlineService::remove); 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); return grant.getId(); } @Transactional public void delete(Integer grantId) throws IOException { - Grant grant = grantRepository.getOne(grantId); - if (grant.getApplication() != null) { - fileService.deleteFile(grant.getApplication()); - } + Grant grant = grantRepository.findOne(grantId); grantRepository.delete(grant); } @@ -119,7 +158,7 @@ public class GrantService { } @Transactional - public Grant create(String title, Project projectId, Date deadlineDate, User user) { + public Grant create(String title, Project projectId, Date deadlineDate, User user, Paper paper) { Grant grant = new Grant(); grant.setTitle(title); grant.setComment("Комментарий к гранту 1"); @@ -128,7 +167,12 @@ public class GrantService { grant.getDeadlines().add(new Deadline(deadlineDate, "первый дедлайн")); grant.getAuthors().add(user); grant.setLeader(user); + grant.getPapers().add(paper); grant = grantRepository.save(grant); + + eventService.createFromGrant(grant); + grantNotificationService.sendCreateNotification(grant); + return grant; } @@ -143,18 +187,78 @@ public class GrantService { public List getGrantAuthors(GrantDto grantDto) { List filteredUsers = userService.filterByAgeAndDegree(grantDto.isHasAge(), grantDto.isHasDegree()); if (grantDto.isWasLeader()) { - filteredUsers = filteredUsers - .stream() - .filter(getCompletedGrantLeaders()::contains) - .collect(Collectors.toList()); + filteredUsers = checkContains(filteredUsers, getCompletedGrantLeaders()); + } + if (grantDto.isHasBAKPapers()) { + filteredUsers = checkContains(filteredUsers, getBAKAuthors()); + } + if (grantDto.isHasScopusPapers()) { + filteredUsers = checkContains(filteredUsers, getScopusAuthors()); } return filteredUsers; } + private List checkContains(List filteredUsers, List checkUsers) { + return filteredUsers.stream() + .filter(checkUsers::contains) + .collect(toList()); + } + private List getCompletedGrantLeaders() { return grantRepository.findByStatus(Grant.GrantStatus.COMPLETED) .stream() .map(Grant::getLeader) - .collect(Collectors.toList()); + .collect(toList()); + } + + public List getGrantPapers(List paperIds) { + return paperService.findAllSelect(paperIds); + } + + public List getAllUncompletedPapers() { + List papers = paperService.findAllNotCompleted(); + papers.stream() + .forEach(paper -> + paper.setTitle(StringUtils.abbreviate(paper.getTitle(), MAX_DISPLAY_SIZE))); + return papers; + } + + public void attachPaper(GrantDto grantDto) { + if (!grantDto.getPaperIds().isEmpty()) { + grantDto.getPapers().clear(); + grantDto.setPapers(getGrantPapers(grantDto.getPaperIds())); + } else { + grantDto.getPapers().clear(); + } + } + + public void removeDeadline(GrantDto grantDto, Integer deadlineId) { + if (grantDto.getDeadlines().get(deadlineId).getId() != null) { + grantDto.getRemovedDeadlineIds().add(grantDto.getDeadlines().get(deadlineId).getId()); + } + grantDto.getDeadlines().remove((int) deadlineId); + } + + private List getCompletedPapersAuthors(Paper.PaperType type) { + List papers = paperService.findAllCompletedByType(type); + return papers.stream() + .filter(paper -> paper.getAuthors() != null) + .flatMap(paper -> paper.getAuthors().stream()) + .collect(toList()); + } + + private List getBAKAuthors() { + return getCompletedPapersAuthors(Paper.PaperType.VAK) + .stream() + .distinct() + .collect(toList()); + } + + private List getScopusAuthors() { + List authors = getCompletedPapersAuthors(Paper.PaperType.SCOPUS); + return authors + .stream() + .filter(author -> Collections.frequency(authors, author) > 3) + .collect(toList()); } } diff --git a/src/main/java/ru/ulstu/name/BaseRepository.java b/src/main/java/ru/ulstu/name/BaseRepository.java new file mode 100644 index 0000000..b691ea2 --- /dev/null +++ b/src/main/java/ru/ulstu/name/BaseRepository.java @@ -0,0 +1,7 @@ +package ru.ulstu.name; + +import org.springframework.data.repository.query.Param; + +public interface BaseRepository { + String findByNameAndNotId(@Param("name") String name, @Param("id") Integer id); +} diff --git a/src/main/java/ru/ulstu/name/BaseService.java b/src/main/java/ru/ulstu/name/BaseService.java new file mode 100644 index 0000000..6619385 --- /dev/null +++ b/src/main/java/ru/ulstu/name/BaseService.java @@ -0,0 +1,16 @@ +package ru.ulstu.name; + +import org.springframework.stereotype.Service; +import org.springframework.validation.Errors; + +@Service +public abstract class BaseService { + + public BaseRepository baseRepository; + + public void checkUniqueName(NameContainer nameContainer, Errors errors, Integer id, String checkField, String errorMessage) { + if (nameContainer.getName().equals(baseRepository.findByNameAndNotId(nameContainer.getName(), id))) { + errors.rejectValue(checkField, "errorCode", errorMessage); + } + } +} diff --git a/src/main/java/ru/ulstu/name/NameContainer.java b/src/main/java/ru/ulstu/name/NameContainer.java new file mode 100644 index 0000000..4339fb2 --- /dev/null +++ b/src/main/java/ru/ulstu/name/NameContainer.java @@ -0,0 +1,14 @@ +package ru.ulstu.name; + +public abstract class NameContainer { + + private String name = ""; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/src/main/java/ru/ulstu/paper/controller/PaperController.java b/src/main/java/ru/ulstu/paper/controller/PaperController.java index e11e4d9..41d5586 100644 --- a/src/main/java/ru/ulstu/paper/controller/PaperController.java +++ b/src/main/java/ru/ulstu/paper/controller/PaperController.java @@ -8,14 +8,14 @@ import org.springframework.ui.ModelMap; import org.springframework.validation.Errors; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; +import ru.ulstu.conference.service.ConferenceService; import ru.ulstu.deadline.model.Deadline; import ru.ulstu.paper.model.Paper; import ru.ulstu.paper.model.PaperDto; -import ru.ulstu.paper.model.PaperFilterDto; +import ru.ulstu.paper.model.PaperListDto; import ru.ulstu.paper.service.LatexService; import ru.ulstu.paper.service.PaperService; import ru.ulstu.user.model.User; @@ -38,23 +38,34 @@ import static org.springframework.util.StringUtils.isEmpty; @ApiIgnore public class PaperController { private final PaperService paperService; + private final ConferenceService conferenceService; private final LatexService latexService; - public PaperController(PaperService paperService, LatexService latexService) { + public PaperController(PaperService paperService, + ConferenceService conferenceService, + LatexService latexService) { this.paperService = paperService; + this.conferenceService = conferenceService; this.latexService = latexService; } @GetMapping("/papers") public void getPapers(ModelMap modelMap) { - modelMap.put("filteredPapers", new PaperFilterDto(paperService.findAllDto(), null, null)); + modelMap.put("filteredPapers", new PaperListDto(paperService.findAllDto(), null, null)); } @PostMapping("/papers") - public void filterPapers(@Valid PaperFilterDto paperFilterDto, ModelMap modelMap) { - modelMap.put("filteredPapers", new PaperFilterDto(paperService.filter(paperFilterDto), - paperFilterDto.getFilterAuthorId(), - paperFilterDto.getYear())); + public void listPapers(@Valid PaperListDto paperListDto, ModelMap modelMap) { + if (paperListDto.getPaperDeleteId() != null) { + if (conferenceService.isAttachedToConference(paperListDto.getPaperDeleteId())) { + modelMap.put("flashMessage", "Статью нельзя удалить, она прикреплена к конференции"); + } else { + paperService.delete(paperListDto.getPaperDeleteId()); + } + } + modelMap.put("filteredPapers", new PaperListDto(paperService.filter(paperListDto), + paperListDto.getFilterAuthorId(), + paperListDto.getYear())); } @GetMapping("/dashboard") @@ -94,12 +105,6 @@ public class PaperController { return "/papers/paper"; } - @GetMapping("/delete/{paper-id}") - public String delete(@PathVariable("paper-id") Integer paperId) throws IOException { - paperService.delete(paperId); - return "redirect:/papers/papers"; - } - @ModelAttribute("allStatuses") public List getPaperStatuses() { return paperService.getPaperStatuses(); diff --git a/src/main/java/ru/ulstu/paper/controller/PaperRestController.java b/src/main/java/ru/ulstu/paper/controller/PaperRestController.java index 2bd8384..6da009f 100644 --- a/src/main/java/ru/ulstu/paper/controller/PaperRestController.java +++ b/src/main/java/ru/ulstu/paper/controller/PaperRestController.java @@ -11,7 +11,8 @@ import org.springframework.web.bind.annotation.RestController; import ru.ulstu.configuration.Constants; import ru.ulstu.core.model.response.Response; import ru.ulstu.paper.model.PaperDto; -import ru.ulstu.paper.model.PaperFilterDto; +import ru.ulstu.paper.model.PaperListDto; +import ru.ulstu.paper.model.ReferenceDto; import ru.ulstu.paper.service.PaperService; import javax.validation.Valid; @@ -58,12 +59,17 @@ public class PaperRestController { } @PostMapping("/filter") - public Response> filter(@RequestBody @Valid PaperFilterDto paperFilterDto) throws IOException { - return new Response<>(paperService.filter(paperFilterDto)); + public Response> filter(@RequestBody @Valid PaperListDto paperListDto) throws IOException { + return new Response<>(paperService.filter(paperListDto)); } @GetMapping("formatted-list") public Response> getFormattedPaperList() { return new Response<>(paperService.getFormattedPaperList()); } + + @PostMapping("/getFormattedReference") + public Response getFormattedReference(@RequestBody @Valid ReferenceDto referenceDto) { + return new Response<>(paperService.getFormattedReference(referenceDto)); + } } diff --git a/src/main/java/ru/ulstu/paper/error/PaperConferenceRelationExistException.java b/src/main/java/ru/ulstu/paper/error/PaperConferenceRelationExistException.java new file mode 100644 index 0000000..ddb3b5e --- /dev/null +++ b/src/main/java/ru/ulstu/paper/error/PaperConferenceRelationExistException.java @@ -0,0 +1,7 @@ +package ru.ulstu.paper.error; + +public class PaperConferenceRelationExistException extends RuntimeException { + public PaperConferenceRelationExistException(String message) { + super(message); + } +} diff --git a/src/main/java/ru/ulstu/paper/model/Paper.java b/src/main/java/ru/ulstu/paper/model/Paper.java index 4f77826..4536ce5 100644 --- a/src/main/java/ru/ulstu/paper/model/Paper.java +++ b/src/main/java/ru/ulstu/paper/model/Paper.java @@ -2,10 +2,13 @@ package ru.ulstu.paper.model; import org.hibernate.annotations.Fetch; import org.hibernate.annotations.FetchMode; +import org.hibernate.validator.constraints.NotBlank; +import ru.ulstu.conference.model.Conference; import ru.ulstu.core.model.BaseEntity; import ru.ulstu.core.model.UserContainer; import ru.ulstu.deadline.model.Deadline; import ru.ulstu.file.model.FileData; +import ru.ulstu.grant.model.Grant; import ru.ulstu.timeline.model.Event; import ru.ulstu.user.model.User; @@ -21,7 +24,6 @@ import javax.persistence.OneToMany; import javax.persistence.OrderBy; import javax.persistence.Temporal; import javax.persistence.TemporalType; -import javax.validation.constraints.NotBlank; import java.util.ArrayList; import java.util.Comparator; import java.util.Date; @@ -114,6 +116,12 @@ public class Paper extends BaseEntity implements UserContainer { @Column(name = "latex_text") private String latexText; + @ManyToMany(mappedBy = "papers") + private List conferences; + + @ManyToMany(mappedBy = "papers") + private List grants; + public PaperStatus getStatus() { return status; } @@ -218,6 +226,22 @@ public class Paper extends BaseEntity implements UserContainer { this.latexText = latexText; } + public List getConferences() { + return conferences; + } + + public void setConferences(List conferences) { + this.conferences = conferences; + } + + public List getGrants() { + return grants; + } + + public void setGrants(List grants) { + this.grants = grants; + } + @Override public Set getUsers() { return getAuthors(); diff --git a/src/main/java/ru/ulstu/paper/model/PaperFilterDto.java b/src/main/java/ru/ulstu/paper/model/PaperListDto.java similarity index 67% rename from src/main/java/ru/ulstu/paper/model/PaperFilterDto.java rename to src/main/java/ru/ulstu/paper/model/PaperListDto.java index f7aef29..871047a 100644 --- a/src/main/java/ru/ulstu/paper/model/PaperFilterDto.java +++ b/src/main/java/ru/ulstu/paper/model/PaperListDto.java @@ -2,15 +2,16 @@ package ru.ulstu.paper.model; import java.util.List; -public class PaperFilterDto { +public class PaperListDto { private List papers; private Integer filterAuthorId; + private Integer paperDeleteId; private Integer year; - public PaperFilterDto() { + public PaperListDto() { } - public PaperFilterDto(List paperDtos, Integer filterAuthorId, Integer year) { + public PaperListDto(List paperDtos, Integer filterAuthorId, Integer year) { this.papers = paperDtos; this.filterAuthorId = filterAuthorId; this.year = year; @@ -39,4 +40,12 @@ public class PaperFilterDto { public void setYear(Integer year) { this.year = year; } + + public Integer getPaperDeleteId() { + return paperDeleteId; + } + + public void setPaperDeleteId(Integer paperDeleteId) { + this.paperDeleteId = paperDeleteId; + } } diff --git a/src/main/java/ru/ulstu/paper/model/ReferenceDto.java b/src/main/java/ru/ulstu/paper/model/ReferenceDto.java new file mode 100644 index 0000000..8d71ae5 --- /dev/null +++ b/src/main/java/ru/ulstu/paper/model/ReferenceDto.java @@ -0,0 +1,129 @@ +package ru.ulstu.paper.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class ReferenceDto { + public enum ReferenceType { + ARTICLE("Статья"), + BOOK("Книга"); + + private String typeName; + + ReferenceType(String name) { + this.typeName = name; + } + + public String getTypeName() { + return typeName; + } + } + + public enum FormatStandard { + GOST("ГОСТ"), + SPRINGER("Springer"); + + private String standardName; + + FormatStandard(String name) { + this.standardName = name; + } + + public String getStandardName() { + return standardName; + } + } + + private String authors; + private String publicationTitle; + private Integer publicationYear; + private String publisher; + private String pages; + private String journalOrCollectionTitle; + private ReferenceType referenceType; + private FormatStandard formatStandard; + + @JsonCreator + public ReferenceDto( + @JsonProperty("authors") String authors, + @JsonProperty("publicationTitle") String publicationTitle, + @JsonProperty("publicationYear") Integer publicationYear, + @JsonProperty("publisher") String publisher, + @JsonProperty("pages") String pages, + @JsonProperty("journalOrCollectionTitle") String journalOrCollectionTitle, + @JsonProperty("referenceType") ReferenceType referenceType, + @JsonProperty("formatStandard") FormatStandard formatStandard) { + this.authors = authors; + this.publicationTitle = publicationTitle; + this.publicationYear = publicationYear; + this.publisher = publisher; + this.pages = pages; + this.journalOrCollectionTitle = journalOrCollectionTitle; + this.referenceType = referenceType; + this.formatStandard = formatStandard; + } + + public String getAuthors() { + return authors; + } + + public void setAuthors(String authors) { + this.authors = authors; + } + + public String getPublicationTitle() { + return publicationTitle; + } + + public void setPublicationTitle(String publicationTitle) { + this.publicationTitle = publicationTitle; + } + + public Integer getPublicationYear() { + return publicationYear; + } + + public void setPublicationYear(Integer publicationYear) { + this.publicationYear = publicationYear; + } + + public String getPublisher() { + return publisher; + } + + public void setPublisher(String publisher) { + this.publisher = publisher; + } + + public String getPages() { + return pages; + } + + public void setPages(String pages) { + this.pages = pages; + } + + public String getJournalOrCollectionTitle() { + return journalOrCollectionTitle; + } + + public void setJournalOrCollectionTitle(String journalOrCollectionTitle) { + this.journalOrCollectionTitle = journalOrCollectionTitle; + } + + public ReferenceType getReferenceType() { + return referenceType; + } + + public void setReferenceType(ReferenceType referenceType) { + this.referenceType = referenceType; + } + + public FormatStandard getFormatStandard() { + return formatStandard; + } + + public void setFormatStandard(FormatStandard formatStandard) { + this.formatStandard = formatStandard; + } +} diff --git a/src/main/java/ru/ulstu/paper/repository/PaperRepository.java b/src/main/java/ru/ulstu/paper/repository/PaperRepository.java index 343e9e2..42d3703 100644 --- a/src/main/java/ru/ulstu/paper/repository/PaperRepository.java +++ b/src/main/java/ru/ulstu/paper/repository/PaperRepository.java @@ -14,4 +14,14 @@ public interface PaperRepository extends JpaRepository { List filter(@Param("author") User author, @Param("year") Integer year); List findByIdNotIn(List paperIds); + + List findAllByIdIn(List paperIds); + + List findByTypeAndStatus(Paper.PaperType type, Paper.PaperStatus status); + + List findByStatusNot(Paper.PaperStatus status); + + List findByConferencesIsNullAndStatusNot(Paper.PaperStatus status); + + List findByIdNotInAndConferencesIsNullAndStatusNot(List paperIds, Paper.PaperStatus status); } diff --git a/src/main/java/ru/ulstu/paper/service/PaperService.java b/src/main/java/ru/ulstu/paper/service/PaperService.java index 33344a5..db810f5 100644 --- a/src/main/java/ru/ulstu/paper/service/PaperService.java +++ b/src/main/java/ru/ulstu/paper/service/PaperService.java @@ -9,13 +9,15 @@ import ru.ulstu.file.model.FileDataDto; import ru.ulstu.file.service.FileService; import ru.ulstu.paper.model.Paper; import ru.ulstu.paper.model.PaperDto; -import ru.ulstu.paper.model.PaperFilterDto; +import ru.ulstu.paper.model.PaperListDto; +import ru.ulstu.paper.model.ReferenceDto; import ru.ulstu.paper.repository.PaperRepository; import ru.ulstu.timeline.service.EventService; import ru.ulstu.user.model.User; import ru.ulstu.user.service.UserService; import java.io.IOException; +import java.text.MessageFormat; import java.util.Arrays; import java.util.Date; import java.util.HashSet; @@ -32,6 +34,9 @@ import static ru.ulstu.paper.model.Paper.PaperStatus.DRAFT; import static ru.ulstu.paper.model.Paper.PaperStatus.FAILED; import static ru.ulstu.paper.model.Paper.PaperStatus.ON_PREPARATION; import static ru.ulstu.paper.model.Paper.PaperType.OTHER; +import static ru.ulstu.paper.model.ReferenceDto.FormatStandard.GOST; +import static ru.ulstu.paper.model.ReferenceDto.ReferenceType.ARTICLE; +import static ru.ulstu.paper.model.ReferenceDto.ReferenceType.BOOK; @Service public class PaperService { @@ -81,7 +86,7 @@ public class PaperService { } public PaperDto findOneDto(Integer id) { - return new PaperDto(paperRepository.getOne(id)); + return new PaperDto(paperRepository.findOne(id)); } @Transactional @@ -93,6 +98,14 @@ public class PaperService { return newPaper.getId(); } + @Transactional + public Paper create(Paper paper) { + Paper newPaper = paperRepository.save(paper); + paperNotificationService.sendCreateNotification(newPaper); + eventService.createFromPaper(newPaper); + return newPaper; + } + private Paper copyFromDto(Paper paper, PaperDto paperDto) throws IOException { paper.setComment(paperDto.getComment()); paper.setUrl(paperDto.getUrl()); @@ -116,7 +129,7 @@ public class PaperService { @Transactional public Integer update(PaperDto paperDto) throws IOException { - Paper paper = paperRepository.getOne(paperDto.getId()); + Paper paper = paperRepository.findOne(paperDto.getId()); Paper.PaperStatus oldStatus = paper.getStatus(); Set oldAuthors = new HashSet<>(paper.getAuthors()); @@ -142,8 +155,8 @@ public class PaperService { } @Transactional - public void delete(Integer paperId) throws IOException { - Paper paper = paperRepository.getOne(paperId); + public void delete(Integer paperId) { + Paper paper = paperRepository.findOne(paperId); paperRepository.delete(paper); } @@ -173,7 +186,7 @@ public class PaperService { return paper; } - public List filter(PaperFilterDto filterDto) { + public List filter(PaperListDto filterDto) { return convert(sortPapers(paperRepository.filter( filterDto.getFilterAuthorId() == null ? null : userService.findById(filterDto.getFilterAuthorId()), filterDto.getYear())), PaperDto::new); @@ -220,20 +233,27 @@ public class PaperService { } public PaperDto findById(Integer paperId) { - return new PaperDto(paperRepository.getOne(paperId)); + return new PaperDto(paperRepository.findOne(paperId)); } - public Paper findEntityById(Integer paperId) { - return paperRepository.getOne(paperId); + public Paper findPaperById(Integer paperId) { + return paperRepository.findOne(paperId); } public List findAllNotSelect(List paperIds) { if (!paperIds.isEmpty()) { - return sortPapers(paperRepository.findByIdNotIn(paperIds)); + return sortPapers(paperRepository.findByIdNotInAndConferencesIsNullAndStatusNot(paperIds, COMPLETED)); } else { - return sortPapers(paperRepository.findAll()); + return sortPapers(paperRepository.findByConferencesIsNullAndStatusNot(COMPLETED)); } + } + public List findAllNotCompleted() { + return convert(paperRepository.findByStatusNot(COMPLETED), PaperDto::new); + } + + public List findAllSelect(List paperIds) { + return convert(paperRepository.findAllByIdIn(paperIds), PaperDto::new); } public List getPaperAuthors() { @@ -260,4 +280,34 @@ public class PaperService { .map(User::getUserAbbreviate) .collect(Collectors.joining(", ")); } + + public String getFormattedReference(ReferenceDto referenceDto) { + return referenceDto.getFormatStandard() == GOST + ? getGostReference(referenceDto) + : getSpringerReference(referenceDto); + } + + public String getGostReference(ReferenceDto referenceDto) { + return MessageFormat.format(referenceDto.getReferenceType() == BOOK ? "{0} {1} - {2}{3}. - {4}с." : "{0} {1}{5} {2}{3}. С. {4}.", + referenceDto.getAuthors(), + referenceDto.getPublicationTitle(), + StringUtils.isEmpty(referenceDto.getPublisher()) ? "" : referenceDto.getPublisher() + ", ", + referenceDto.getPublicationYear().toString(), + referenceDto.getPages(), + StringUtils.isEmpty(referenceDto.getJournalOrCollectionTitle()) ? "." : " // " + referenceDto.getJournalOrCollectionTitle() + "."); + } + + public String getSpringerReference(ReferenceDto referenceDto) { + return MessageFormat.format("{0} ({1}) {2}.{3} {4}pp {5}", + referenceDto.getAuthors(), + referenceDto.getPublicationYear().toString(), + referenceDto.getPublicationTitle(), + referenceDto.getReferenceType() == ARTICLE ? " " + referenceDto.getJournalOrCollectionTitle() + "," : "", + StringUtils.isEmpty(referenceDto.getPublisher()) ? "" : referenceDto.getPublisher() + ", ", + referenceDto.getPages()); + } + + public List findAllCompletedByType(Paper.PaperType type) { + return paperRepository.findByTypeAndStatus(type, Paper.PaperStatus.COMPLETED); + } } diff --git a/src/main/java/ru/ulstu/ping/model/Ping.java b/src/main/java/ru/ulstu/ping/model/Ping.java new file mode 100644 index 0000000..c7e4c5e --- /dev/null +++ b/src/main/java/ru/ulstu/ping/model/Ping.java @@ -0,0 +1,73 @@ +package ru.ulstu.ping.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.springframework.format.annotation.DateTimeFormat; +import ru.ulstu.conference.model.Conference; +import ru.ulstu.core.model.BaseEntity; +import ru.ulstu.user.model.User; + +import javax.persistence.Entity; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import java.util.Date; + +@Entity +@Table(name = "ping") +public class Ping extends BaseEntity { + @Temporal(value = TemporalType.TIMESTAMP) + @DateTimeFormat(pattern = "yyyy-MM-dd") + private Date date; + + @ManyToOne(optional = false) + @JoinColumn(name = "users_id") + private User user; + + @ManyToOne(optional = false) + @JoinColumn(name = "conference_id") + private Conference conference; + + public Ping() { + } + + public Ping(Date date, User user) { + this.date = date; + this.user = user; + } + + public Ping(@JsonProperty("id") Integer id, + @JsonProperty("date") Date date, + @JsonProperty("user") User user, + @JsonProperty("conference") Conference conference) { + setId(id); + this.date = date; + this.user = user; + this.conference = conference; + } + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public Conference getConference() { + return conference; + } + + public void setConference(Conference conference) { + this.conference = conference; + } +} diff --git a/src/main/java/ru/ulstu/ping/repository/PingRepository.java b/src/main/java/ru/ulstu/ping/repository/PingRepository.java new file mode 100644 index 0000000..de79dd7 --- /dev/null +++ b/src/main/java/ru/ulstu/ping/repository/PingRepository.java @@ -0,0 +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 { + + @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); +} diff --git a/src/main/java/ru/ulstu/ping/service/PingService.java b/src/main/java/ru/ulstu/ping/service/PingService.java new file mode 100644 index 0000000..f7156f0 --- /dev/null +++ b/src/main/java/ru/ulstu/ping/service/PingService.java @@ -0,0 +1,36 @@ +package ru.ulstu.ping.service; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.ulstu.conference.model.Conference; +import ru.ulstu.ping.model.Ping; +import ru.ulstu.ping.repository.PingRepository; +import ru.ulstu.user.service.UserService; + +import java.io.IOException; +import java.util.Calendar; +import java.util.Date; + +@Service +public class PingService { + private final PingRepository pingRepository; + private final UserService userService; + + public PingService(PingRepository pingRepository, + UserService userService) { + this.pingRepository = pingRepository; + this.userService = userService; + } + + @Transactional + public void addPing(Conference conference) throws IOException { + Ping newPing = new Ping(new Date(), userService.getCurrentUser()); + newPing.setConference(conference); + pingRepository.save(newPing); + } + + public Integer countPingYesterday(Conference conference, Calendar calendar) { + return Math.toIntExact(pingRepository.countByConferenceAndDate(conference, calendar.get(Calendar.DAY_OF_MONTH), + calendar.get(Calendar.MONTH) + 1, calendar.get(Calendar.YEAR))); + } +} diff --git a/src/main/java/ru/ulstu/project/controller/ProjectController.java b/src/main/java/ru/ulstu/project/controller/ProjectController.java index affdaec..ae09658 100644 --- a/src/main/java/ru/ulstu/project/controller/ProjectController.java +++ b/src/main/java/ru/ulstu/project/controller/ProjectController.java @@ -5,6 +5,7 @@ import org.springframework.ui.ModelMap; import org.springframework.validation.Errors; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -78,6 +79,12 @@ public class ProjectController { return "/projects/project"; } + @GetMapping("/delete/{project-id}") + public String delete(@PathVariable("project-id") Integer projectId) throws IOException { + projectService.delete(projectId); + return String.format("redirect:%s", "/projects/projects"); + } + private void filterEmptyDeadlines(ProjectDto projectDto) { projectDto.setDeadlines(projectDto.getDeadlines().stream() .filter(dto -> dto.getDate() != null || !isEmpty(dto.getDescription())) diff --git a/src/main/java/ru/ulstu/project/service/ProjectService.java b/src/main/java/ru/ulstu/project/service/ProjectService.java index 115f5ae..89a36d8 100644 --- a/src/main/java/ru/ulstu/project/service/ProjectService.java +++ b/src/main/java/ru/ulstu/project/service/ProjectService.java @@ -62,6 +62,25 @@ public class ProjectService { return newProject; } + @Transactional + public Project update(ProjectDto projectDto) throws IOException { + Project project = projectRepository.findOne(projectDto.getId()); + if (projectDto.getApplicationFileName() != null && project.getApplication() != null) { + fileService.deleteFile(project.getApplication()); + } + projectRepository.save(copyFromDto(project, projectDto)); + return project; + } + + @Transactional + public void delete(Integer projectId) throws IOException { + Project project = projectRepository.findOne(projectId); + if (project.getApplication() != null) { + fileService.deleteFile(project.getApplication()); + } + projectRepository.delete(project); + } + private Project copyFromDto(Project project, ProjectDto projectDto) throws IOException { project.setDescription(projectDto.getDescription()); project.setStatus(projectDto.getStatus() == null ? APPLICATION : projectDto.getStatus()); @@ -85,10 +104,6 @@ public class ProjectService { } } - private Project update(ProjectDto projectDto) { - throw new RuntimeException("not implemented yet"); - } - public Project findById(Integer id) { return projectRepository.getOne(id); } diff --git a/src/main/java/ru/ulstu/students/controller/TaskController.java b/src/main/java/ru/ulstu/students/controller/TaskController.java index 50cb052..5d0f4e8 100644 --- a/src/main/java/ru/ulstu/students/controller/TaskController.java +++ b/src/main/java/ru/ulstu/students/controller/TaskController.java @@ -5,13 +5,16 @@ import org.springframework.ui.ModelMap; import org.springframework.validation.Errors; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import ru.ulstu.deadline.model.Deadline; import ru.ulstu.students.model.Task; import ru.ulstu.students.model.TaskDto; +import ru.ulstu.students.model.TaskFilterDto; import ru.ulstu.students.service.TaskService; +import ru.ulstu.tags.model.Tag; import springfox.documentation.annotations.ApiIgnore; import javax.validation.Valid; @@ -35,16 +38,16 @@ public class TaskController { this.taskService = taskService; } - @GetMapping("/tasks") - public void getTasks(ModelMap modelMap) { - modelMap.put("tasks", taskService.findAllDto()); - } - @GetMapping("/dashboard") public void getDashboard(ModelMap modelMap) { modelMap.put("tasks", taskService.findAllDto()); } + @GetMapping("/tasks") + public void getTask(ModelMap modelMap) { + modelMap.put("filteredTasks", new TaskFilterDto(taskService.findAllDto(), null, null, null)); + } + @GetMapping("/task") public void getTask(ModelMap modelMap, @RequestParam(value = "id") Integer id) { if (id != null && id > 0) { @@ -54,6 +57,14 @@ public class TaskController { } } + @PostMapping("/tasks") + public void filterTasks(@Valid TaskFilterDto taskFilterDto, ModelMap modelMap) { + modelMap.put("filteredTasks", new TaskFilterDto(taskService.filter(taskFilterDto), + taskFilterDto.getStatus(), + taskFilterDto.getTag(), + taskFilterDto.getOrder())); + } + @PostMapping(value = "/task", params = "save") public String save(@Valid TaskDto taskDto, Errors errors) throws IOException { filterEmptyDeadlines(taskDto); @@ -77,11 +88,23 @@ public class TaskController { return TASK_PAGE; } + @GetMapping("/delete/{task-id}") + public String delete(@PathVariable("task-id") Integer taskId) throws IOException { + taskService.delete(taskId); + return String.format(REDIRECT_TO, TASKS_PAGE); + } + + @ModelAttribute("allStatuses") public List getTaskStatuses() { return taskService.getTaskStatuses(); } + @ModelAttribute("allTags") + public List getTags() { + return taskService.getTags(); + } + private void filterEmptyDeadlines(TaskDto taskDto) { taskDto.setDeadlines(taskDto.getDeadlines().stream() .filter(dto -> dto.getDate() != null || !isEmpty(dto.getDescription())) diff --git a/src/main/java/ru/ulstu/students/model/Task.java b/src/main/java/ru/ulstu/students/model/Task.java index 5646ef3..733447b 100644 --- a/src/main/java/ru/ulstu/students/model/Task.java +++ b/src/main/java/ru/ulstu/students/model/Task.java @@ -50,7 +50,7 @@ public class Task extends BaseEntity { private String description; @Enumerated(value = EnumType.STRING) - private ru.ulstu.students.model.Task.TaskStatus status = TaskStatus.IN_WORK; + private TaskStatus status = TaskStatus.IN_WORK; @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) @JoinColumn(name = "task_id", unique = true) @@ -67,6 +67,7 @@ public class Task extends BaseEntity { private Date updateDate = new Date(); @ManyToMany(fetch = FetchType.EAGER) + @Fetch(FetchMode.SUBSELECT) @JoinTable(name = "task_tags", joinColumns = {@JoinColumn(name = "task_id")}, inverseJoinColumns = {@JoinColumn(name = "tag_id")}) @@ -127,4 +128,5 @@ public class Task extends BaseEntity { public void setTags(List tags) { this.tags = tags; } + } diff --git a/src/main/java/ru/ulstu/students/model/TaskDto.java b/src/main/java/ru/ulstu/students/model/TaskDto.java index 5071dab..36e235d 100644 --- a/src/main/java/ru/ulstu/students/model/TaskDto.java +++ b/src/main/java/ru/ulstu/students/model/TaskDto.java @@ -26,7 +26,7 @@ public class TaskDto { private Date createDate; private Date updateDate; private Set tagIds; - private List tags; + private List tags = new ArrayList<>(); public TaskDto() { deadlines.add(new Deadline()); diff --git a/src/main/java/ru/ulstu/students/model/TaskFilterDto.java b/src/main/java/ru/ulstu/students/model/TaskFilterDto.java new file mode 100644 index 0000000..21bd5ac --- /dev/null +++ b/src/main/java/ru/ulstu/students/model/TaskFilterDto.java @@ -0,0 +1,54 @@ +package ru.ulstu.students.model; + +import java.util.List; + +public class TaskFilterDto { + + private List tasks; + private Task.TaskStatus status; + private Integer tagId; + private String order; + + public TaskFilterDto(List tasks, Task.TaskStatus status, Integer tagId, String order) { + this.tasks = tasks; + this.status = status; + this.tagId = tagId; + this.order = order; + } + + public TaskFilterDto() { + + } + + public List getTasks() { + return tasks; + } + + public void setTasks(List tasks) { + this.tasks = tasks; + } + + public Task.TaskStatus getStatus() { + return status; + } + + public void setStatus(Task.TaskStatus status) { + this.status = status; + } + + public Integer getTag() { + return tagId; + } + + public void setTag(Integer tagId) { + this.tagId = tagId; + } + + public String getOrder() { + return order; + } + + public void setOrder(String order) { + this.order = order; + } +} diff --git a/src/main/java/ru/ulstu/students/repository/TaskRepository.java b/src/main/java/ru/ulstu/students/repository/TaskRepository.java index 6f48d1f..ee49ab8 100644 --- a/src/main/java/ru/ulstu/students/repository/TaskRepository.java +++ b/src/main/java/ru/ulstu/students/repository/TaskRepository.java @@ -1,7 +1,18 @@ package ru.ulstu.students.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.students.model.Task; +import ru.ulstu.tags.model.Tag; + +import java.util.List; public interface TaskRepository extends JpaRepository { + + @Query("SELECT t FROM Task t WHERE (t.status = :status OR :status IS NULL) AND (:tag IS NULL OR :tag MEMBER OF t.tags) ORDER BY create_date DESC") + List filterNew(@Param("status") Task.TaskStatus status, @Param("tag") Tag tag); + + @Query("SELECT t FROM Task t WHERE (t.status = :status OR :status IS NULL) AND (:tag IS NULL OR :tag MEMBER OF t.tags) ORDER BY create_date ASC") + List filterOld(@Param("status") Task.TaskStatus status, @Param("tag") Tag tag); } diff --git a/src/main/java/ru/ulstu/students/service/TaskService.java b/src/main/java/ru/ulstu/students/service/TaskService.java index dac6ef5..8f335ac 100644 --- a/src/main/java/ru/ulstu/students/service/TaskService.java +++ b/src/main/java/ru/ulstu/students/service/TaskService.java @@ -1,13 +1,17 @@ package ru.ulstu.students.service; import org.apache.commons.lang3.StringUtils; +import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import ru.ulstu.deadline.service.DeadlineService; import ru.ulstu.students.model.Task; import ru.ulstu.students.model.TaskDto; +import ru.ulstu.students.model.TaskFilterDto; import ru.ulstu.students.repository.TaskRepository; +import ru.ulstu.tags.model.Tag; import ru.ulstu.tags.service.TagService; +import ru.ulstu.timeline.service.EventService; import java.io.IOException; import java.util.Arrays; @@ -26,16 +30,18 @@ public class TaskService { private final TaskRepository taskRepository; private final DeadlineService deadlineService; private final TagService tagService; + private final EventService eventService; - public TaskService(TaskRepository grantRepository, - DeadlineService deadlineService, TagService tagService) { - this.taskRepository = grantRepository; + public TaskService(TaskRepository taskRepository, + DeadlineService deadlineService, TagService tagService, EventService eventService) { + this.taskRepository = taskRepository; this.deadlineService = deadlineService; this.tagService = tagService; + this.eventService = eventService; } public List findAll() { - return taskRepository.findAll(); + return taskRepository.findAll(new Sort(Sort.Direction.DESC, "createDate")); } public List findAllDto() { @@ -45,13 +51,26 @@ public class TaskService { } public TaskDto findOneDto(Integer id) { - return new TaskDto(taskRepository.getOne(id)); + return new TaskDto(taskRepository.findOne(id)); + } + + public List filter(TaskFilterDto filterDto) { + if (filterDto.getOrder().compareTo("new") == 0) { + return convert(taskRepository.filterNew( + filterDto.getStatus(), + filterDto.getTag() == null ? null : tagService.findById(filterDto.getTag())), TaskDto::new); + } else { + return convert(taskRepository.filterOld( + filterDto.getStatus(), + filterDto.getTag() == null ? null : tagService.findById(filterDto.getTag())), TaskDto::new); + } } @Transactional public Integer create(TaskDto taskDto) throws IOException { Task newTask = copyFromDto(new Task(), taskDto); newTask = taskRepository.save(newTask); + eventService.createFromTask(newTask); return newTask.getId(); } @@ -69,15 +88,18 @@ public class TaskService { @Transactional public Integer update(TaskDto taskDto) throws IOException { - Task task = taskRepository.getOne(taskDto.getId()); + Task task = taskRepository.findOne(taskDto.getId()); taskRepository.save(copyFromDto(task, taskDto)); + eventService.updateTaskDeadlines(task); return task.getId(); } @Transactional public void delete(Integer taskId) throws IOException { - Task task = taskRepository.getOne(taskId); - taskRepository.delete(task); + if (taskRepository.exists(taskId)) { + taskRepository.delete(taskId); + } + } public void save(TaskDto taskDto) throws IOException { @@ -92,4 +114,8 @@ public class TaskService { return Arrays.asList(Task.TaskStatus.values()); } + public List getTags() { + return tagService.getTags(); + } + } diff --git a/src/main/java/ru/ulstu/tags/service/TagService.java b/src/main/java/ru/ulstu/tags/service/TagService.java index ad5d227..24822b0 100644 --- a/src/main/java/ru/ulstu/tags/service/TagService.java +++ b/src/main/java/ru/ulstu/tags/service/TagService.java @@ -50,4 +50,12 @@ public class TagService { return newTag; } + public List getTags() { + return tagRepository.findAll(); + } + + public Tag findById(Integer tagId) { + return tagRepository.findOne(tagId); + } + } diff --git a/src/main/java/ru/ulstu/timeline/model/Event.java b/src/main/java/ru/ulstu/timeline/model/Event.java index f8fd179..e56c91c 100644 --- a/src/main/java/ru/ulstu/timeline/model/Event.java +++ b/src/main/java/ru/ulstu/timeline/model/Event.java @@ -1,7 +1,11 @@ package ru.ulstu.timeline.model; +import org.hibernate.validator.constraints.NotBlank; +import ru.ulstu.conference.model.Conference; import ru.ulstu.core.model.BaseEntity; +import ru.ulstu.grant.model.Grant; import ru.ulstu.paper.model.Paper; +import ru.ulstu.students.model.Task; import ru.ulstu.user.model.User; import javax.persistence.CascadeType; @@ -16,8 +20,8 @@ import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.Temporal; import javax.persistence.TemporalType; -import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; +import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -62,7 +66,7 @@ public class Event extends BaseEntity { private String description; @ManyToMany(fetch = FetchType.EAGER) - private List recipients; + private List recipients = new ArrayList(); @ManyToOne @JoinColumn(name = "child_id") @@ -76,6 +80,18 @@ public class Event extends BaseEntity { @JoinColumn(name = "paper_id") private Paper paper; + @ManyToOne + @JoinColumn(name = "conference_id") + private Conference conference; + + @ManyToOne + @JoinColumn(name = "grant_id") + private Grant grant; + + @ManyToOne + @JoinColumn(name = "task_id") + private Task task; + public String getTitle() { return title; } @@ -163,4 +179,28 @@ public class Event extends BaseEntity { public void setPaper(Paper paper) { this.paper = paper; } + + public Conference getConference() { + return conference; + } + + public void setConference(Conference conference) { + this.conference = conference; + } + + public Grant getGrant() { + return grant; + } + + public void setGrant(Grant grant) { + this.grant = grant; + } + + public Task getTask() { + return task; + } + + public void setTask(Task task) { + this.task = task; + } } diff --git a/src/main/java/ru/ulstu/timeline/model/EventDto.java b/src/main/java/ru/ulstu/timeline/model/EventDto.java index 17e4623..ccf0f0a 100644 --- a/src/main/java/ru/ulstu/timeline/model/EventDto.java +++ b/src/main/java/ru/ulstu/timeline/model/EventDto.java @@ -2,8 +2,11 @@ package ru.ulstu.timeline.model; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -import javax.validation.constraints.NotBlank; +import org.hibernate.validator.constraints.NotBlank; +import ru.ulstu.conference.model.ConferenceDto; +import ru.ulstu.grant.model.GrantDto; import ru.ulstu.paper.model.PaperDto; +import ru.ulstu.students.model.TaskDto; import ru.ulstu.user.model.UserDto; import javax.validation.constraints.NotNull; @@ -25,6 +28,9 @@ public class EventDto { private final String description; private final List recipients; private PaperDto paperDto; + private ConferenceDto conferenceDto; + private GrantDto grantDto; + private TaskDto taskDto; @JsonCreator public EventDto(@JsonProperty("id") Integer id, @@ -36,7 +42,10 @@ public class EventDto { @JsonProperty("updateDate") Date updateDate, @JsonProperty("description") String description, @JsonProperty("paperDto") PaperDto paperDto, - @JsonProperty("recipients") List recipients) { + @JsonProperty("recipients") List recipients, + @JsonProperty("conferenceDto") ConferenceDto conferenceDto, + @JsonProperty("grantDto") GrantDto grantDto, + @JsonProperty("taskDto") TaskDto taskDto) { this.id = id; this.title = title; this.period = period; @@ -47,6 +56,9 @@ public class EventDto { this.description = description; this.recipients = recipients; this.paperDto = paperDto; + this.conferenceDto = conferenceDto; + this.grantDto = grantDto; + this.taskDto = taskDto; } public EventDto(Event event) { @@ -58,8 +70,19 @@ public class EventDto { this.createDate = event.getCreateDate(); this.updateDate = event.getUpdateDate(); this.description = event.getDescription(); - this.paperDto = new PaperDto(event.getPaper()); this.recipients = convert(event.getRecipients(), UserDto::new); + if (paperDto != null) { + this.paperDto = new PaperDto(event.getPaper()); + } + if (conferenceDto != null) { + this.conferenceDto = new ConferenceDto(event.getConference()); + } + if (grantDto != null) { + this.grantDto = new GrantDto(event.getGrant()); + } + if (taskDto != null) { + this.taskDto = new TaskDto(event.getTask()); + } } public Integer getId() { @@ -105,4 +128,28 @@ public class EventDto { public void setPaperDto(PaperDto paperDto) { this.paperDto = paperDto; } + + public ConferenceDto getConferenceDto() { + return conferenceDto; + } + + public void setConferenceDto(ConferenceDto conferenceDto) { + this.conferenceDto = conferenceDto; + } + + public GrantDto getGrantDto() { + return grantDto; + } + + public void setGrantDto(GrantDto grantDto) { + this.grantDto = grantDto; + } + + public TaskDto getTaskDto() { + return taskDto; + } + + public void setTaskDto(TaskDto taskDto) { + this.taskDto = taskDto; + } } diff --git a/src/main/java/ru/ulstu/timeline/repository/EventRepository.java b/src/main/java/ru/ulstu/timeline/repository/EventRepository.java index eb5c08b..7ebd3c9 100644 --- a/src/main/java/ru/ulstu/timeline/repository/EventRepository.java +++ b/src/main/java/ru/ulstu/timeline/repository/EventRepository.java @@ -2,7 +2,10 @@ package ru.ulstu.timeline.repository; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; +import ru.ulstu.conference.model.Conference; +import ru.ulstu.grant.model.Grant; import ru.ulstu.paper.model.Paper; +import ru.ulstu.students.model.Task; import ru.ulstu.timeline.model.Event; import java.util.List; @@ -15,4 +18,10 @@ public interface EventRepository extends JpaRepository { List findAllFuture(); List findAllByPaper(Paper paper); + + List findAllByConference(Conference conference); + + List findAllByGrant(Grant grant); + + List findAllByTask(Task task); } diff --git a/src/main/java/ru/ulstu/timeline/service/EventService.java b/src/main/java/ru/ulstu/timeline/service/EventService.java index a1f54f5..aa0bd2f 100644 --- a/src/main/java/ru/ulstu/timeline/service/EventService.java +++ b/src/main/java/ru/ulstu/timeline/service/EventService.java @@ -4,8 +4,11 @@ import org.apache.commons.lang3.time.DateUtils; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import ru.ulstu.conference.model.Conference; import ru.ulstu.deadline.model.Deadline; +import ru.ulstu.grant.model.Grant; import ru.ulstu.paper.model.Paper; +import ru.ulstu.students.model.Task; import ru.ulstu.timeline.model.Event; import ru.ulstu.timeline.model.EventDto; import ru.ulstu.timeline.model.Timeline; @@ -140,4 +143,99 @@ public class EventService { public List findAllFutureDto() { return convert(findAllFuture(), EventDto::new); } + + public void createFromConference(Conference newConference) { + List timelines = timelineService.findAll(); + Timeline timeline = timelines.isEmpty() ? new Timeline() : timelines.get(0); + + for (Deadline deadline : newConference.getDeadlines() + .stream() + .filter(d -> d.getDate().after(new Date()) || DateUtils.isSameDay(d.getDate(), new Date())) + .collect(Collectors.toList())) { + Event newEvent = new Event(); + newEvent.setTitle("Дедлайн конференции"); + newEvent.setStatus(Event.EventStatus.NEW); + newEvent.setExecuteDate(deadline.getDate()); + newEvent.setCreateDate(new Date()); + newEvent.setUpdateDate(new Date()); + newEvent.setDescription("Дедлайн '" + deadline.getDescription() + "' конференции '" + newConference.getTitle() + "'"); + newConference.getUsers().forEach(conferenceUser -> newEvent.getRecipients().add(conferenceUser.getUser())); + newEvent.setConference(newConference); + save(newEvent); + + timeline.getEvents().add(newEvent); + timelineService.save(timeline); + } + } + + public void updateConferenceDeadlines(Conference conference) { + eventRepository.delete(eventRepository.findAllByConference(conference)); + createFromConference(conference); + } + + public void createFromGrant(Grant newGrant) { + List timelines = timelineService.findAll(); + Timeline timeline = timelines.isEmpty() ? new Timeline() : timelines.get(0); + + for (Deadline deadline : newGrant.getDeadlines() + .stream() + .filter(d -> d.getDate().after(new Date()) || DateUtils.isSameDay(d.getDate(), new Date())) + .collect(Collectors.toList())) { + Event newEvent = new Event(); + newEvent.setTitle("Дедлайн гранта"); + newEvent.setStatus(Event.EventStatus.NEW); + newEvent.setExecuteDate(deadline.getDate()); + newEvent.setCreateDate(new Date()); + newEvent.setUpdateDate(new Date()); + newEvent.setDescription("Дедлайн '" + deadline.getDescription() + "' гранта '" + newGrant.getTitle() + "'"); + if (newGrant.getAuthors() != null) { + newEvent.setRecipients(new ArrayList(newGrant.getAuthors())); + } + newEvent.getRecipients().add(newGrant.getLeader()); + newEvent.setGrant(newGrant); + eventRepository.save(newEvent); + + timeline.getEvents().add(newEvent); + timelineService.save(timeline); + } + } + + public void updateGrantDeadlines(Grant grant) { + eventRepository.delete(eventRepository.findAllByGrant(grant)); + createFromGrant(grant); + } + + public void removeConferencesEvent(Conference conference) { + List eventList = eventRepository.findAllByConference(conference); + eventList.forEach(event -> eventRepository.delete(event.getId())); + } + + public void createFromTask(Task newTask) { + List timelines = timelineService.findAll(); + Timeline timeline = timelines.isEmpty() ? new Timeline() : timelines.get(0); + + for (Deadline deadline : newTask.getDeadlines() + .stream() + .filter(d -> d.getDate().after(new Date()) || DateUtils.isSameDay(d.getDate(), new Date())) + .collect(Collectors.toList())) { + Event newEvent = new Event(); + newEvent.setTitle("Дедлайн задачи"); + newEvent.setStatus(Event.EventStatus.NEW); + newEvent.setExecuteDate(deadline.getDate()); + newEvent.setCreateDate(new Date()); + newEvent.setUpdateDate(new Date()); + newEvent.setDescription("Дедлайн '" + deadline.getDescription() + "' задачи '" + newTask.getTitle() + "'"); + newEvent.getRecipients().add(userService.getCurrentUser()); + newEvent.setTask(newTask); + eventRepository.save(newEvent); + + timeline.getEvents().add(newEvent); + timelineService.save(timeline); + } + } + + public void updateTaskDeadlines(Task task) { + eventRepository.delete(eventRepository.findAllByTask(task)); + createFromTask(task); + } } diff --git a/src/main/resources/db/changelog-20190419_000000-schema.xml b/src/main/resources/db/changelog-20190419_000000-schema.xml new file mode 100644 index 0000000..b56f322 --- /dev/null +++ b/src/main/resources/db/changelog-20190419_000000-schema.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/src/main/resources/db/changelog-20190424_000000-schema.xml b/src/main/resources/db/changelog-20190424_000000-schema.xml new file mode 100644 index 0000000..d61b38a --- /dev/null +++ b/src/main/resources/db/changelog-20190424_000000-schema.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/db/changelog-20190426_000000-schema.xml b/src/main/resources/db/changelog-20190426_000000-schema.xml new file mode 100644 index 0000000..5304032 --- /dev/null +++ b/src/main/resources/db/changelog-20190426_000000-schema.xml @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/src/main/resources/db/changelog-20190428_000000-schema.xml b/src/main/resources/db/changelog-20190428_000000-schema.xml new file mode 100644 index 0000000..b44691d --- /dev/null +++ b/src/main/resources/db/changelog-20190428_000000-schema.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/db/changelog-20190430_000000-schema.xml b/src/main/resources/db/changelog-20190430_000000-schema.xml new file mode 100644 index 0000000..58a3bc5 --- /dev/null +++ b/src/main/resources/db/changelog-20190430_000000-schema.xml @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/src/main/resources/db/changelog-20190505_000000-schema.xml b/src/main/resources/db/changelog-20190505_000000-schema.xml new file mode 100644 index 0000000..ac8707a --- /dev/null +++ b/src/main/resources/db/changelog-20190505_000000-schema.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/src/main/resources/db/changelog-20190507_000000-schema.xml b/src/main/resources/db/changelog-20190507_000000-schema.xml new file mode 100644 index 0000000..0cdb99b --- /dev/null +++ b/src/main/resources/db/changelog-20190507_000000-schema.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/src/main/resources/db/changelog-20190507_000001-schema.xml b/src/main/resources/db/changelog-20190507_000001-schema.xml new file mode 100644 index 0000000..c320eba --- /dev/null +++ b/src/main/resources/db/changelog-20190507_000001-schema.xml @@ -0,0 +1,14 @@ + + + + + update grants + set leader_id = + (select u.id + from users u + where u.last_name = 'Романов' AND u.first_name = 'Антон'); + + + diff --git a/src/main/resources/db/changelog-20190511_000000-schema.xml b/src/main/resources/db/changelog-20190511_000000-schema.xml new file mode 100644 index 0000000..62e914f --- /dev/null +++ b/src/main/resources/db/changelog-20190511_000000-schema.xml @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/src/main/resources/db/changelog-master.xml b/src/main/resources/db/changelog-master.xml index dfe3cfc..98e3c17 100644 --- a/src/main/resources/db/changelog-master.xml +++ b/src/main/resources/db/changelog-master.xml @@ -30,7 +30,15 @@ + - + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mail_templates/conferenceCreateNotification.html b/src/main/resources/mail_templates/conferenceCreateNotification.html new file mode 100644 index 0000000..055e85d --- /dev/null +++ b/src/main/resources/mail_templates/conferenceCreateNotification.html @@ -0,0 +1,30 @@ + + + + Уведомление о создании конференции + + + + +

+ Уважаемый(ая) Ivan Ivanov +

+

+ Была создана новая конференция: " + Title". +
+ Спешите принять участие! +

+

+ Даты проведения: + + - + . +

+

+ Regards, +
+ NG-tracker. +

+ + \ No newline at end of file diff --git a/src/main/resources/mail_templates/conferenceDeadlineNotification.html b/src/main/resources/mail_templates/conferenceDeadlineNotification.html new file mode 100644 index 0000000..77c89b1 --- /dev/null +++ b/src/main/resources/mail_templates/conferenceDeadlineNotification.html @@ -0,0 +1,29 @@ + + + + Уведомление о дедлайне конференции + + + + +

+ Уважаемый(ая) Ivan Ivanov +

+

+ Приближается дедлайн конференции " + Title". +

+

+ Срок исполнения: . +

+ +

+ Примечание: . +

+

+ Regards, +
+ NG-tracker. +

+ + diff --git a/src/main/resources/mail_templates/conferencePingNotification.html b/src/main/resources/mail_templates/conferencePingNotification.html new file mode 100644 index 0000000..a80a3f2 --- /dev/null +++ b/src/main/resources/mail_templates/conferencePingNotification.html @@ -0,0 +1,25 @@ + + + + Обратите внимание на конференциию + + + + +

+ Уважаемый(ая) Ivan Ivanov +

+

+ Конференция " + Title" была пропингована + раз. +
+ Обратите внимание. +

+

+ Regards, +
+ NG-tracker. +

+ + \ No newline at end of file diff --git a/src/main/resources/mail_templates/conferenceUpdateDatesNotification.html b/src/main/resources/mail_templates/conferenceUpdateDatesNotification.html new file mode 100644 index 0000000..479336f --- /dev/null +++ b/src/main/resources/mail_templates/conferenceUpdateDatesNotification.html @@ -0,0 +1,31 @@ + + + + Уведомление об изменении дат проведения конференции + + + + +

+ Уважаемый(ая) Ivan Ivanov +

+

+ Даты проведения конференции " + Title" изменились с
+ "oldBeginDate" + - + "oldEndDate" +
+ + на
+ "" + - + "". +

+

+ Regards, +
+ NG-tracker. +

+ + \ No newline at end of file diff --git a/src/main/resources/mail_templates/conferenceUpdateDeadlinesNotification.html b/src/main/resources/mail_templates/conferenceUpdateDeadlinesNotification.html new file mode 100644 index 0000000..f010fb8 --- /dev/null +++ b/src/main/resources/mail_templates/conferenceUpdateDeadlinesNotification.html @@ -0,0 +1,24 @@ + + + + Уведомление об изменении дедлайнов конференции + + + + +

+ Уважаемый(ая) Ivan Ivanov +

+

+ Дедлайны конференции " + Title" притерпели изменения. +
+ Ознакомтесь с изменениями. +

+

+ Regards, +
+ NG-tracker. +

+ + \ No newline at end of file diff --git a/src/main/resources/mail_templates/grantAuthorsChangeNotification.html b/src/main/resources/mail_templates/grantAuthorsChangeNotification.html new file mode 100644 index 0000000..2bae4fe --- /dev/null +++ b/src/main/resources/mail_templates/grantAuthorsChangeNotification.html @@ -0,0 +1,24 @@ + + + + Уведомление об изменении состава рабочей группы + + + + +

+ Уважаемый(ая) Ivan Ivanov +

+

+ Состав рабочей группы гранта "Title" сменился с + " oldAuthors" + на " newAuthors". +

+

+ Regards, +
+ NG-tracker. +

+ + diff --git a/src/main/resources/mail_templates/grantCreateNotification.html b/src/main/resources/mail_templates/grantCreateNotification.html new file mode 100644 index 0000000..69736cd --- /dev/null +++ b/src/main/resources/mail_templates/grantCreateNotification.html @@ -0,0 +1,28 @@ + + + + Уведомление о создании гранта + + + + +

+ Уважаемый(ая) Ivan Ivanov +

+

+ Был добавлен новый грант: " + Title". +
+

+

+ Руководитель гранта: + + Leader. +

+

+ Regards, +
+ NG-tracker. +

+ + \ No newline at end of file diff --git a/src/main/resources/mail_templates/grantDeadlineNotification.html b/src/main/resources/mail_templates/grantDeadlineNotification.html new file mode 100644 index 0000000..190ef67 --- /dev/null +++ b/src/main/resources/mail_templates/grantDeadlineNotification.html @@ -0,0 +1,28 @@ + + + + Уведомление о дедлайне гранта + + + + +

+ Уважаемый(ая) Ivan Ivanov +

+

+ Приближается дедлайн гранта "Title". +

+

+ Срок исполнения: Date. +

+

+ Примечание: Description. +

+

+ Regards, +
+ NG-tracker. +

+ + diff --git a/src/main/resources/mail_templates/grantLeaderChangeNotification.html b/src/main/resources/mail_templates/grantLeaderChangeNotification.html new file mode 100644 index 0000000..c6a37e0 --- /dev/null +++ b/src/main/resources/mail_templates/grantLeaderChangeNotification.html @@ -0,0 +1,24 @@ + + + + Уведомление об изменении руководителя гранта + + + + +

+ Уважаемый(ая) Ivan Ivanov +

+

+ Руководитель гранта "Title" сменился с + "oldLeader" + на "newLeader". +

+

+ Regards, +
+ NG-tracker. +

+ + diff --git a/src/main/resources/mail_templates/paperCreateNotification.html b/src/main/resources/mail_templates/paperCreateNotification.html index 2758143..82362bd 100644 --- a/src/main/resources/mail_templates/paperCreateNotification.html +++ b/src/main/resources/mail_templates/paperCreateNotification.html @@ -12,9 +12,11 @@

Вам нужно поработать над статьей "Title".

-

- Срок исполнения: . -

+
+

+ Срок исполнения: . +

+

Regards,
diff --git a/src/main/resources/public/css/conference.css b/src/main/resources/public/css/conference.css index 8cebd1d..dc83057 100644 --- a/src/main/resources/public/css/conference.css +++ b/src/main/resources/public/css/conference.css @@ -2,11 +2,15 @@ body { min-width: 400px; } -.conference-row .col:hover { - background-color: #f3f3f3; +.conference-row .d-flex:hover { + background-color: #f1f1f1; border-radius: .25rem; } +.conference-row .d-flex:hover .icon-delete { + visibility: visible; +} + .filter-option-inner-inner { color: white; } @@ -15,8 +19,28 @@ body { margin-bottom: 10px; } -.conference-row .col .text-decoration { +.conference-row .d-flex .text-decoration { text-decoration: none; + margin: 0; +} + +.conference-row .d-flex .text-decoration:nth-child(1) { + margin-left: 5px; +} + +.conference-row .d-flex .icon-delete { + width: 29px; + height: 29px; + margin: auto; + border: none; + visibility: hidden; + background-color: transparent; +} + + + +.conference-row .d-flex { + margin: 0 15px; } @@ -52,7 +76,6 @@ body { height: 40px; max-height: 40px; } - .member select { appearance: none; -moz-appearance: none; @@ -62,13 +85,17 @@ body { padding: 0.5rem 1.75em 0.5rem 0.5em; display: inline-block; background: transparent url("https://cdn3.iconfinder.com/data/icons/faticons/32/arrow-down-01-16.png") no-repeat right 7px center; - + cursor: pointer; } .member select:nth-child(4) { border-right: 1px solid #ced4da; } +.member select:hover { + background-color: #f1f1f1; +} + .member-name { padding: .75rem 1.25rem; @@ -78,6 +105,16 @@ body { border-right: 1px solid #ced4da; } +#ping-button[disabled=disabled] { + background-color: #ced4da; + border-color: #c2c5c7; +} + +#ping-button[disabled=disabled]:hover { + background-color: #737475 !important; + border-color: #5d5e5f !important; +} + #take-part[disabled=disabled] { background-color: #ced4da; border-color: #c2c5c7; @@ -103,13 +140,34 @@ body { .paper-name { flex: 1; + overflow: hidden; +} + +.paper-name:hover { + background-color: #f1f1f1; } .paper-name span { - margin: 6px 15px; + margin: 7px 10px; display: inline-block; } +.paper-name span:nth-child(1) { + margin: 3px 0px 3px 10px; + float: left; +} + +.paper-name span:nth-child(2) { + max-width: 326px; + white-space: nowrap; +} + +.dropdown-menu { + max-width: 445px; +} + + + .icon { width: 38px; height: 38px; @@ -118,14 +176,14 @@ body { } .icon-delete { - background-color: #f44; + background-color: #ff7272; background-image: url(/img/conference/delete.png); background-repeat: round; color: transparent !important; } .icon-delete:hover { - background-color: #ff2929; + background-color: #ff0000 !important; transition: background-color .15s ease-in-out; } @@ -154,7 +212,23 @@ body { float: right; } -@media (max-width: 1199px) and (min-width: 768px) { +.note-1 { + background-color: #bfffce; +} + +.note-2 { + background-color: #eaffb4; +} + +.note-3 { + background-color: #fff69f; +} + +.note-4 { + background-color: #ff9973; +} + +@media (max-width: 1199px) and (min-width: 768px){ .paper-control { display: block!important; } diff --git a/src/main/resources/public/css/grant.css b/src/main/resources/public/css/grant.css index 1073cdf..8b5ca8e 100644 --- a/src/main/resources/public/css/grant.css +++ b/src/main/resources/public/css/grant.css @@ -9,4 +9,35 @@ .div-deadline-description { padding-left: 5px; padding-right: 5px; +} + +.div-view-paper { + margin-top: 6px; +} + +.div-selected-papers { + border: 0px; + padding-left: 12px; +} + +.icon-paper { + height: 22px; + width: 22px; + margin: 3px; +} + +.btn-delete-deadline { + color: black; +} + +.div-file-name{ + padding-top: 6px; +} + +.div-loader { + margin-bottom: 5px; +} + +.div-row-file { + margin-bottom: 2px; } \ No newline at end of file diff --git a/src/main/resources/public/css/tasks.css b/src/main/resources/public/css/tasks.css index 14718de..da46bd3 100644 --- a/src/main/resources/public/css/tasks.css +++ b/src/main/resources/public/css/tasks.css @@ -13,6 +13,21 @@ cursor: text; } +.filter .bootstrap-select{ + margin-bottom: 10px; +} + +.filter-option-inner-inner{ + font-size: 12px; + text-transform: uppercase; + font-weight: normal; + line-height: 25px; +} + +.sorting .bootstrap-select{ + margin-bottom: 10px; +} + .input-tag-name { border: none; box-shadow: none; @@ -24,6 +39,42 @@ max-width: inherit; } +.task-row{ + + position: relative; +} + +.task-row .col:hover{ + + background-color: #f8f9fa; + +} + +.task-row .col > a{ + display: block; + text-decoration: none; +} + +.task-row .col:hover .remove-task{ + + visibility: visible; + +} + +.remove-task{ + visibility: hidden; + position: absolute; + right: -20px; + top: 50%; + transform: translate(-50%, -50%); + padding: 0 20px; +} + +.remove-task:hover{ + + background-color: #ebebeb; +} + .tag { display: inline-block; padding: .2em .6em .3em; diff --git a/src/main/resources/public/js/conference.js b/src/main/resources/public/js/conference.js index 8335f54..8273557 100644 --- a/src/main/resources/public/js/conference.js +++ b/src/main/resources/public/js/conference.js @@ -1,7 +1,6 @@ $(document).ready(function () { - - $('a[data-confirm]').click(function (ev) { - var href = $(this).attr('href'); + $('input[data-confirm]').click(function(ev) { + var value = $(this).attr('value'); if (!$('#dataConfirmModal').length) { $('#modalDelete').append('

\n' + ' \n' + ' \n' + ' \n' + ' '); } $('#dataConfirmModal').find('#myModalLabel').text($(this).attr('data-confirm')); - $('#dataConfirmOK').attr('href', href); - $('#dataConfirmModal').modal({show: true}); + $('#deleteConference').attr('value', value); + $('#dataConfirmModal').modal({show:true}); return false; }); + }); diff --git a/src/main/resources/public/js/papers.js b/src/main/resources/public/js/papers.js index 78d3120..7a937ba 100644 --- a/src/main/resources/public/js/papers.js +++ b/src/main/resources/public/js/papers.js @@ -13,7 +13,8 @@ $(document).ready(function () { }); $('a[data-confirm]').click(function(ev) { - var href = $(this).attr('href'); + var id = $(this).parent().parent().find('.id-class').val(); + if (!$('#dataConfirmModal').length) { $('#modalDelete').append(''); } $('#dataConfirmModal').find('#myModalLabel').text($(this).attr('data-confirm')); - $('#dataConfirmOK').attr('href', href); + $('#dataConfirmOK').click(function () { + $("#paperDeleteId").val(id); + $('form').submit(); + }); $('#dataConfirmModal').modal({show:true}); return false; }); diff --git a/src/main/resources/public/js/projects.js b/src/main/resources/public/js/projects.js new file mode 100644 index 0000000..5867c50 --- /dev/null +++ b/src/main/resources/public/js/projects.js @@ -0,0 +1,42 @@ +/*\n' + + ' \n' + + ' '); + } + $('#dataConfirmModal').find('#myModalLabel').text($(this).attr('data-confirm')); + $('#dataConfirmOK').attr('href', href); + $('#dataConfirmModal').modal({show:true}); + return false; + }); +}); +/*]]>*/ \ No newline at end of file diff --git a/src/main/resources/public/js/tasks.js b/src/main/resources/public/js/tasks.js index 6ee3537..b184d1a 100644 --- a/src/main/resources/public/js/tasks.js +++ b/src/main/resources/public/js/tasks.js @@ -70,17 +70,17 @@ $(document).ready(function () { }); $("span[data-role=remove]").click(removeTag); - $(".task-row").mouseenter(function (event) { - var taskRow = $(event.target).closest(".task-row"); - $(taskRow).css("background-color", "#f8f9fa"); - $(taskRow).find(".remove-task").removeClass("d-none"); - - }); - $(".task-row").mouseleave(function (event) { - var taskRow = $(event.target).closest(".task-row"); - $(taskRow).css("background-color", "white"); - $(taskRow).closest(".task-row").find(".remove-task").addClass("d-none"); - }); +// $(".task-row").mouseenter(function (event) { +// var taskRow = $(event.target).closest(".task-row"); +// $(taskRow).css("background-color", "#f8f9fa"); +// $(taskRow).find(".remove-task").removeClass("d-none"); +// +// }); +// $(".task-row").mouseleave(function (event) { +// var taskRow = $(event.target).closest(".task-row"); +// $(taskRow).css("background-color", "white"); +// $(taskRow).closest(".task-row").find(".remove-task").addClass("d-none"); +// }); $('a[data-confirm]').click(function(ev) { var href = $(this).attr('href'); @@ -90,7 +90,7 @@ $(document).ready(function () { '