Skip to content

Commit

Permalink
fixes: (#121)
Browse files Browse the repository at this point in the history
- event windows
  • Loading branch information
ndc-dxc authored Jul 4, 2024
1 parent 80949fc commit 34310f8
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public void alert(AlertableEvent alertableEvent) {
.build());
}

private String getUser() {
public static String getUser() {
return Optional.of(SecurityContextHolder.getContext())
.map(SecurityContext::getAuthentication)
.map(Principal::getName)
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/it/gov/innovazione/ndc/alerter/data/EventMapper.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package it.gov.innovazione.ndc.alerter.data;

import it.gov.innovazione.ndc.alerter.AlerterService;
import it.gov.innovazione.ndc.alerter.dto.EventDto;
import it.gov.innovazione.ndc.alerter.entities.Event;
import org.apache.commons.lang3.StringUtils;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -20,8 +22,16 @@ public void setContextUtils(ContextUtils contextUtils) {
@Mapping(target = "context", expression = "java(contextUtils.toContext(entity.getContext()))")
public abstract EventDto toDto(Event entity);

public static String defaultIfNull(String createdBy) {
if (StringUtils.isEmpty(createdBy)) {
return AlerterService.getUser();
}
return createdBy;
}

@Override
@Mapping(target = "context", expression = "java(contextUtils.fromContext(dto.getContext()))")
@Mapping(target = "createdAt", ignore = true)
@Mapping(target = "createdBy", expression = "java(EventMapper.defaultIfNull(dto.getCreatedBy()))")
public abstract Event toEntity(EventDto dto);
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ public class ProfileService extends EntityService<Profile, ProfileDto> {
@Getter(AccessLevel.PROTECTED)
private final Sort defaultSorting = Sort.by("name").ascending();

public void setLastAlertedAt(String id) {
public void setLastAlertedAt(String id, Instant instant) {
Profile profile = repository.findById(id)
.orElseThrow(() -> new IllegalStateException("Profile not found: " + id));
profile.setLastAlertedAt(Instant.now());
profile.setLastAlertedAt(instant);
repository.save(profile);
}

Expand Down
84 changes: 52 additions & 32 deletions src/main/java/it/gov/innovazione/ndc/service/AlerterMailSender.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

Expand All @@ -34,33 +33,52 @@ public class AlerterMailSender {
private final UserService userService;
private final ConfigService configService;

@Value("${alerter.aggregation-time-multiplier:50}")
private final long aggregationTimeMultiplier;

private static boolean isNotTooRecent(ProfileDto profileDto, EventDto eventDto, Instant now) {
return eventDto.getCreatedAt().plusSeconds(profileDto.getAggregationTime()).isBefore(now);
private static boolean isAlertable(Instant lastAlertedAt, Integer aggregationTime, Instant now) {
return lastAlertedAt.plusSeconds(aggregationTime).isBefore(now);
}

@Scheduled(fixedDelayString = "${alerter.mail-sender.fixed-delay:6000}")
void getEventsAndAlert() {

log.info("Executing AlerterMailSenderJob");

Collection<ProfileDto> profiles = profileService.findAll();
for (ProfileDto profileDto : profiles) {


log.info("Checking for alertable events for profile: {}", profileDto.getName());

Instant now = Instant.now();
Instant lastAlertedAt = profileDto.getLastAlertedAt();

eventService.getEventsNewerThan(lastAlertedAt).stream()
.filter(eventDto -> isNotTooRecent(profileDto, eventDto, now))
.filter(eventDto -> isNotTooOld(eventDto, profileDto, now))
.filter(eventDto -> isSeverityGteThanMin(eventDto, profileDto))
.filter(eventDto -> isApplicableToProfile(eventDto, profileDto))
.collect(Collectors.groupingBy(EventDto::getCategory))
.forEach((key, value) -> sendMessages(key, value, profileDto));
}
}
if (isAlertable(lastAlertedAt, profileDto.getAggregationTime(), now)) {

List<EventDto> eventsNewerThan = eventService.getEventsNewerThan(lastAlertedAt).stream()
.filter(eventDto -> isApplicableToProfile(eventDto, profileDto))
.collect(Collectors.toList());

List<EventDto> filteredEvents = eventsNewerThan.stream()
.filter(eventDto -> eventDto.getCreatedAt().isBefore(now))
.filter(eventDto -> isSeverityGteThanMin(eventDto, profileDto))
.filter(eventDto -> isApplicableToProfile(eventDto, profileDto))
.collect(Collectors.toList());

log.info("Found {} event applicable to profile {}, of which {} match the conditions for alert",
eventsNewerThan.size(),
profileDto.getName(),
filteredEvents);

filteredEvents.stream()
.collect(Collectors.groupingBy(EventDto::getCategory))
.forEach((key, value) -> sendMessages(key, value, profileDto));

private boolean isNotTooOld(EventDto eventDto, ProfileDto profileDto, Instant now) {
return eventDto.getCreatedAt().plusSeconds(aggregationTimeMultiplier * profileDto.getAggregationTime()).isAfter(now);
log.info("Updating profile {} using lastAlertedAt {}", profileDto.getName(), now);
profileService.setLastAlertedAt(profileDto.getId(), now);
return;
}

log.info("No alertable events found");
}
}

private boolean isAlerterEnabled() {
Expand All @@ -78,7 +96,7 @@ private void sendMessages(EventCategory category, List<EventDto> eventDtos, Prof
}

if (!isAlerterEnabled()) {
log.warn("Alerter is disabled, no mails will be sent, following events will be stored in the database."
log.warn("Alerter is disabled, no mails will be sent, following events will be just stored in the database."
+ "Events: {}",
eventDtos.stream()
.map(EventDto::toString)
Expand All @@ -88,42 +106,44 @@ private void sendMessages(EventCategory category, List<EventDto> eventDtos, Prof

log.info("Sending email for detected {} events, to users with profile {} for category: {}",
eventDtos.size(), profileDto.getName(), category);

List<UserDto> recipients = userService.findAll().stream()
.filter(user -> StringUtils.equals(user.getProfile(), profileDto.getName()))
.collect(Collectors.toList());

if (!recipients.isEmpty()) {
for (UserDto recipient : recipients) {
emailService.sendEmail(recipient.getEmail(),
"[SCHEMAGOV] [" + category + "] Alerter: Report degli eventi",
getMessageBody(eventDtos, recipient, profileDto));
getMessageBody(eventDtos, recipient));
}
} else {
log.warn("No recipients found for profile {}, "
+ "for this profile no mails will be sent. "
+ "It might still be possible these events will be notified to other profiles. "
+ "Events: {}",
profileDto.getName(),
eventDtos.stream()
.map(EventDto::toString)
.collect(Collectors.joining(", ")));
return;
}
profileService.setLastAlertedAt(profileDto.getId());

log.warn("No recipients found for profile {}, "
+ "for this profile no mails will be sent. "
+ "It might still be possible these events will be notified to other profiles. "
+ "Events: {}",
profileDto.getName(),
eventDtos.stream()
.map(EventDto::toString)
.collect(Collectors.joining(", ")));
}

private String getMessageBody(List<EventDto> eventDtos, UserDto recipient, ProfileDto profileDto) {
private String getMessageBody(List<EventDto> eventDtos, UserDto recipient) {
StringBuilder message = new StringBuilder("Ciao " + recipient.getName() + " " + recipient.getSurname() + ",\n\n"
+ "Di seguito i dettagli degli eventi riscontrati:\n");
int i = 1;
for (EventDto eventDto : eventDtos) {
message.append(getDetailsForEvent(i, eventDto, recipient, profileDto));
message.append(getDetailsForEvent(i, eventDto));
i++;
}
message.append("Origine: Generata automaticamente dall'harvester.\n\n");
message.append("Cordiali saluti,\n\nIl team di supporto di Schemagov");
return message.toString();
}

private String getDetailsForEvent(int i, EventDto eventDto, UserDto recipient, ProfileDto profileDto) {
private String getDetailsForEvent(int i, EventDto eventDto) {
return i + ". Titolo: " + eventDto.getName() + "\n"
+ "Descrizione: " + eventDto.getDescription() + "\n"
+ "Severity: " + eventDto.getSeverity() + "\n"
Expand Down

0 comments on commit 34310f8

Please sign in to comment.