diff --git a/src/main/java/eu/bbmri_eric/negotiator/configuration/state_machine/negotiation/InitializeStateForResourceAction.java b/src/main/java/eu/bbmri_eric/negotiator/configuration/state_machine/negotiation/InitializeStateForResourceAction.java index 097a42283..602b098fe 100644 --- a/src/main/java/eu/bbmri_eric/negotiator/configuration/state_machine/negotiation/InitializeStateForResourceAction.java +++ b/src/main/java/eu/bbmri_eric/negotiator/configuration/state_machine/negotiation/InitializeStateForResourceAction.java @@ -9,7 +9,6 @@ import lombok.extern.apachecommons.CommonsLog; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; -import org.springframework.scheduling.annotation.Async; import org.springframework.statemachine.StateContext; import org.springframework.statemachine.action.Action; import org.springframework.stereotype.Component; @@ -25,7 +24,6 @@ public class InitializeStateForResourceAction implements Action @Override @Transactional - @Async public void execute(StateContext context) { String negotiationId = context.getMessage().getHeaders().get("negotiationId", String.class); Negotiation negotiation = negotiationRepository.findDetailedById(negotiationId).orElseThrow(); diff --git a/src/main/java/eu/bbmri_eric/negotiator/database/model/Negotiation.java b/src/main/java/eu/bbmri_eric/negotiator/database/model/Negotiation.java index 6fd6570f0..ca24985df 100644 --- a/src/main/java/eu/bbmri_eric/negotiator/database/model/Negotiation.java +++ b/src/main/java/eu/bbmri_eric/negotiator/database/model/Negotiation.java @@ -11,7 +11,6 @@ import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; -import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; @@ -76,18 +75,16 @@ public class Negotiation extends AuditEntity { @OneToMany( mappedBy = "negotiation", - cascade = {CascadeType.MERGE}, - fetch = FetchType.LAZY) + cascade = {CascadeType.MERGE}) private Set attachments; @OneToMany( mappedBy = "negotiation", - cascade = {CascadeType.PERSIST, CascadeType.REMOVE}, - fetch = FetchType.LAZY) + cascade = {CascadeType.PERSIST, CascadeType.REMOVE}) @Exclude private Set persons = new HashSet<>(); - @OneToMany(mappedBy = "negotiation", cascade = CascadeType.MERGE, fetch = FetchType.LAZY) + @OneToMany(mappedBy = "negotiation", cascade = CascadeType.MERGE) @Exclude private Set requests; @@ -104,7 +101,7 @@ public class Negotiation extends AuditEntity { @Enumerated(EnumType.STRING) private NegotiationState currentState = NegotiationState.SUBMITTED; - @ElementCollection(fetch = FetchType.EAGER) + @ElementCollection @CollectionTable( name = "resource_state_per_negotiation", joinColumns = {@JoinColumn(name = "negotiation_id", referencedColumnName = "id")}) @@ -115,17 +112,13 @@ public class Negotiation extends AuditEntity { @Builder.Default private Map currentStatePerResource = new HashMap<>(); - @OneToMany( - fetch = FetchType.EAGER, - cascade = {CascadeType.ALL}) + @OneToMany(cascade = {CascadeType.ALL}) @JoinColumn(name = "negotiation_id", referencedColumnName = "id") @Setter(AccessLevel.NONE) @Builder.Default private Set lifecycleHistory = creteInitialHistory(); - @OneToMany( - fetch = FetchType.EAGER, - cascade = {CascadeType.ALL}) + @OneToMany(cascade = {CascadeType.ALL}) @JoinColumn(name = "negotiation_id", referencedColumnName = "id") @Setter(AccessLevel.NONE) @Builder.Default diff --git a/src/main/java/eu/bbmri_eric/negotiator/database/model/views/NotificationViewDTO.java b/src/main/java/eu/bbmri_eric/negotiator/database/model/views/NotificationViewDTO.java new file mode 100644 index 000000000..194fbdb54 --- /dev/null +++ b/src/main/java/eu/bbmri_eric/negotiator/database/model/views/NotificationViewDTO.java @@ -0,0 +1,17 @@ +package eu.bbmri_eric.negotiator.database.model.views; + +import eu.bbmri_eric.negotiator.database.model.NotificationEmailStatus; +import eu.bbmri_eric.negotiator.database.model.Person; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class NotificationViewDTO { + private Long id; + private String message; + private NotificationEmailStatus emailStatus; + private String negotiationId; + private String negotiationTitle; + private Person recipient; +} diff --git a/src/main/java/eu/bbmri_eric/negotiator/database/repository/NegotiationRepository.java b/src/main/java/eu/bbmri_eric/negotiator/database/repository/NegotiationRepository.java index 8ef351a6f..f0af88727 100644 --- a/src/main/java/eu/bbmri_eric/negotiator/database/repository/NegotiationRepository.java +++ b/src/main/java/eu/bbmri_eric/negotiator/database/repository/NegotiationRepository.java @@ -33,16 +33,6 @@ Optional findNegotiationResourceStateById( List findByModifiedDateBeforeAndCurrentState( LocalDateTime thresholdTime, NegotiationState currentState); - @Query( - value = - "SELECT EXISTS (" - + "SELECT n.id " - + "FROM negotiation n " - + "WHERE n.id = :negotiationId AND " - + "n.created_by = :personId)", - nativeQuery = true) - boolean isNegotiationCreator(String negotiationId, Long personId); - @Query( value = "SELECT EXISTS (" diff --git a/src/main/java/eu/bbmri_eric/negotiator/database/repository/NotificationRepository.java b/src/main/java/eu/bbmri_eric/negotiator/database/repository/NotificationRepository.java index 16cb27073..6cbf5c1ce 100644 --- a/src/main/java/eu/bbmri_eric/negotiator/database/repository/NotificationRepository.java +++ b/src/main/java/eu/bbmri_eric/negotiator/database/repository/NotificationRepository.java @@ -2,8 +2,10 @@ import eu.bbmri_eric.negotiator.database.model.Notification; import eu.bbmri_eric.negotiator.database.model.NotificationEmailStatus; +import eu.bbmri_eric.negotiator.database.model.views.NotificationViewDTO; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; public interface NotificationRepository extends JpaRepository { @@ -11,9 +13,14 @@ public interface NotificationRepository extends JpaRepository findByEmailStatus(NotificationEmailStatus status); - List findByEmailStatusAndMessageEndsWith( - NotificationEmailStatus status, String messageSuffix); - - List findByRecipientIdAndEmailStatus( + @Query( + "SELECT new eu.bbmri_eric.negotiator.database.model.views.NotificationViewDTO(" + + "nt.id, nt.message, nt.emailStatus, ng.id, ng.title, p) " + + "FROM Notification nt " + + "JOIN nt.negotiation ng " + + "JOIN nt.recipient p " + + "WHERE p.id = :recipientId AND " + + "nt.emailStatus = :status") + List findViewByRecipientIdAndEmailStatus( Long recipientId, NotificationEmailStatus status); } diff --git a/src/main/java/eu/bbmri_eric/negotiator/database/repository/PersonRepository.java b/src/main/java/eu/bbmri_eric/negotiator/database/repository/PersonRepository.java index 7833e39a4..4a2f7ccbd 100644 --- a/src/main/java/eu/bbmri_eric/negotiator/database/repository/PersonRepository.java +++ b/src/main/java/eu/bbmri_eric/negotiator/database/repository/PersonRepository.java @@ -35,6 +35,16 @@ public interface PersonRepository @EntityGraph(value = "person-detailed") boolean existsByIdAndResourcesIn(Long id, Set resources); + @Query( + value = + "SELECT EXISTS (" + + "SELECT n.id " + + "FROM negotiation n " + + "WHERE n.id = :negotiationId AND " + + "n.created_by = :personId)", + nativeQuery = true) + boolean isNegotiationCreator(Long personId, String negotiationId); + @Query( value = "SELECT EXISTS (SELECT rs.id " diff --git a/src/main/java/eu/bbmri_eric/negotiator/service/NegotiationServiceImpl.java b/src/main/java/eu/bbmri_eric/negotiator/service/NegotiationServiceImpl.java index 26b7d22c3..ae1304653 100644 --- a/src/main/java/eu/bbmri_eric/negotiator/service/NegotiationServiceImpl.java +++ b/src/main/java/eu/bbmri_eric/negotiator/service/NegotiationServiceImpl.java @@ -51,8 +51,8 @@ public class NegotiationServiceImpl implements NegotiationService { @Override public boolean isNegotiationCreator(String negotiationId) { - return negotiationRepository.isNegotiationCreator( - negotiationId, NegotiatorUserDetailsService.getCurrentlyAuthenticatedUserInternalId()); + return personRepository.isNegotiationCreator( + NegotiatorUserDetailsService.getCurrentlyAuthenticatedUserInternalId(), negotiationId); } /** @@ -64,9 +64,6 @@ public boolean isNegotiationCreator(String negotiationId) { */ @Override public boolean isAuthorizedForNegotiation(String negotiationId) { - boolean isrepre = - personService.isRepresentativeOfAnyResourceOfNegotiation( - NegotiatorUserDetailsService.getCurrentlyAuthenticatedUserInternalId(), negotiationId); return isNegotiationCreator(negotiationId) || personService.isRepresentativeOfAnyResourceOfNegotiation( NegotiatorUserDetailsService.getCurrentlyAuthenticatedUserInternalId(), negotiationId); @@ -98,12 +95,7 @@ private List findAttachments(Set attachmentDT @Override public boolean exists(String negotiationId) { - try { - findEntityById(negotiationId, false); - return true; - } catch (EntityNotFoundException ex) { - return false; - } + return negotiationRepository.existsById(negotiationId); } private void addPersonToNegotiation( diff --git a/src/main/java/eu/bbmri_eric/negotiator/service/UserNotificationServiceImpl.java b/src/main/java/eu/bbmri_eric/negotiator/service/UserNotificationServiceImpl.java index e1e40258f..ed7e3bf30 100644 --- a/src/main/java/eu/bbmri_eric/negotiator/service/UserNotificationServiceImpl.java +++ b/src/main/java/eu/bbmri_eric/negotiator/service/UserNotificationServiceImpl.java @@ -10,6 +10,7 @@ import eu.bbmri_eric.negotiator.database.model.Person; import eu.bbmri_eric.negotiator.database.model.Post; import eu.bbmri_eric.negotiator.database.model.Resource; +import eu.bbmri_eric.negotiator.database.model.views.NotificationViewDTO; import eu.bbmri_eric.negotiator.database.repository.NegotiationRepository; import eu.bbmri_eric.negotiator.database.repository.NotificationRepository; import eu.bbmri_eric.negotiator.database.repository.PersonRepository; @@ -128,7 +129,18 @@ public void notifyAdmins(Negotiation negotiation) { NotificationEmailStatus.EMAIL_SENT, "New Negotiation %s was added for review.".formatted(negotiation.getId())); notificationRepository.saveAll(newNotifications); - sendNotificationsToAdmins(newNotifications); + sendNotificationsToAdmins( + newNotifications.stream() + .map( + (notification) -> + new NotificationViewDTO( + notification.getId(), + notification.getMessage(), + notification.getEmailStatus(), + negotiation.getId(), + parseTitleFromNegotiation(negotiation), + notification.getRecipient())) + .collect(Collectors.toList())); } @Override @@ -231,7 +243,7 @@ private static boolean postAuthorIsAlsoRequester(Post post) { private void createNotificationsForRepresentatives(Negotiation negotiation) { Set representatives = getRepresentativesForNegotiation(negotiation); for (Person representative : representatives) { - createNewNotification(negotiation, NotificationEmailStatus.EMAIL_NOT_SENT, representative); + createNewNotification(negotiation, representative); Set overlappingResources = getResourcesInNegotiationRepresentedBy(negotiation, representative); markReachableResources(negotiation, overlappingResources); @@ -261,8 +273,8 @@ private List createNotificationsForAdmins( return newNotifications; } - private void sendNotificationsToAdmins(List notifications) { - for (Notification notification : notifications) { + private void sendNotificationsToAdmins(List notifications) { + for (NotificationViewDTO notification : notifications) { sendEmail(notification.getRecipient(), Collections.singletonList(notification)); } } @@ -290,12 +302,11 @@ private void markReachableResources( } } - private void createNewNotification( - Negotiation negotiation, NotificationEmailStatus emailNotSent, Person representative) { + private void createNewNotification(Negotiation negotiation, Person representative) { notificationRepository.save( buildNewNotification( negotiation, - emailNotSent, + NotificationEmailStatus.EMAIL_NOT_SENT, representative, "New Negotiation %s ".formatted(negotiation.getId()))); } @@ -305,16 +316,16 @@ private Notification buildNewNotification( NotificationEmailStatus emailNotSent, Person representative, String message) { - Notification new_notification = + Notification newNotification = Notification.builder() .negotiation(negotiation) .emailStatus(emailNotSent) .recipient(representative) .message(message) .build(); - new_notification.setModifiedDate(LocalDateTime.now()); - new_notification.setCreationDate(LocalDateTime.now()); - return new_notification; + newNotification.setModifiedDate(LocalDateTime.now()); + newNotification.setCreationDate(LocalDateTime.now()); + return newNotification; } @Override @@ -328,67 +339,74 @@ public void sendEmailsForNewNotifications() { private void sendOutNotificationEmails(@NonNull Set recipients) { for (Person recipient : recipients) { - List notifications = getPendingNotifications(recipient); + List notifications = getPendingNotifications(recipient); sendEmail(recipient, notifications); markNotificationsAsEmailSent(notifications); } } - private void markNotificationsAsEmailSent(@NonNull List notifications) { - for (Notification notification : notifications) { + private void markNotificationsAsEmailSent(@NonNull List notifications) { + for (NotificationViewDTO notificationView : notifications) { + Notification notification = + notificationRepository.findById(notificationView.getId()).orElseThrow(); notification.setEmailStatus(NotificationEmailStatus.EMAIL_SENT); notification.setModifiedDate(LocalDateTime.now()); notificationRepository.save(notification); } } - private void sendEmail(@NonNull Person recipient, @NonNull List notifications) { + private void sendEmail( + @NonNull Person recipient, @NonNull List notifications) { sendEmail(recipient, notifications, "email-notification"); } private void sendEmail( - @NonNull Person recipient, @NonNull List notifications, String email_template) { + @NonNull Person recipient, + @NonNull List notifications, + String emailTemplate) { Context context = new Context(); - List negotiations = + List negotiationsIds = notifications.stream() - .map(notification -> notification.getNegotiation()) + .map(NotificationViewDTO::getNegotiationId) .distinct() .collect(Collectors.toList()); Map roleForNegotiation = populateRoleForNegotiationMap(notifications); Map titleForNegotiation = populateTitleForNegotiationMap(notifications); - Map> notificationsForNegotiation = - notifications.stream().collect(Collectors.groupingBy(Notification::getNegotiation)); + Map> notificationsForNegotiation = + notifications.stream() + .collect(Collectors.groupingBy(NotificationViewDTO::getNegotiationId)); context.setVariable("recipient", recipient); - context.setVariable("negotiations", negotiations); + context.setVariable("negotiations", negotiationsIds); context.setVariable("frontendUrl", frontendUrl); context.setVariable("roleForNegotiation", roleForNegotiation); context.setVariable("titleForNegotiation", titleForNegotiation); context.setVariable("notificationsForNegotiation", notificationsForNegotiation); - String emailContent = templateEngine.process(email_template, context); + String emailContent = templateEngine.process(emailTemplate, context); emailService.sendEmail(recipient, "New Notifications", emailContent); } - private Map populateRoleForNegotiationMap(List notifications) { + private Map populateRoleForNegotiationMap( + List notifications) { Map roleForNegotiation = new HashMap<>(); - for (Notification notification : notifications) { - String negotiationId = notification.getNegotiation().getId(); - String role = extractRoleFromNotificationMessage(notification); + for (NotificationViewDTO notification : notifications) { + String negotiationId = notification.getNegotiationId(); + String role = extractRole(notification); roleForNegotiation.put(negotiationId, role); } return roleForNegotiation; } - private Map populateTitleForNegotiationMap(List notifications) { + private Map populateTitleForNegotiationMap( + List notifications) { Map titleForNegotiation = new HashMap<>(); - for (Notification notification : notifications) { - Negotiation negotiation = notification.getNegotiation(); - String negotiatorId = negotiation.getId(); - String title = parseTitleFromNegotiation(negotiation); + for (NotificationViewDTO notification : notifications) { + String negotiatorId = notification.getNegotiationId(); + String title = notification.getNegotiationTitle(); titleForNegotiation.put(negotiatorId, title); } return titleForNegotiation; @@ -406,30 +424,21 @@ private static String parseTitleFromNegotiation(Negotiation negotiation) { return title; } - private String extractRoleFromNotificationMessage(Notification notification) { + private String extractRole(NotificationViewDTO notification) { String message = notification.getMessage(); if (message.matches("New Negotiation .* was added for review\\.") || message.matches("The negotiation .* is awaiting review\\.")) { return "ROLE_ADMIN"; - } else if (message.matches("Negotiation .* had a change of status of .* to .*")) { - // TODO if status changed to "ACCESS_CONDITIONS_MET" role should be "ROLE_REPRESENTATIVE" - // (once notification also goes to REPRESENTATIVE) + } else if (personRepository.isNegotiationCreator( + notification.getRecipient().getId(), notification.getNegotiationId())) { return "ROLE_RESEARCHER"; - } else if (message.matches("Negotiation .* had a new post by .*")) { - String[] parts = message.split("new post by"); - String negotiationCreator = notification.getNegotiation().getCreatedBy().getName(); - String postCreator = parts[1].trim(); - return (negotiationCreator.equals(postCreator)) ? "ROLE_REPRESENTATIVE" : "ROLE_RESEARCHER"; - } else if (message.matches("New Negotiation .*") - || message.matches("The negotiation .* is stale and had no status change in a while\\.")) { - return "ROLE_REPRESENTATIVE"; } else { - return "ROLE_RESEARCHER"; + return "ROLE_REPRESENTATIVE"; } } - private List getPendingNotifications(@NonNull Person recipient) { - return notificationRepository.findByRecipientIdAndEmailStatus( + private List getPendingNotifications(@NonNull Person recipient) { + return notificationRepository.findViewByRecipientIdAndEmailStatus( recipient.getId(), NotificationEmailStatus.EMAIL_NOT_SENT); } diff --git a/src/main/resources/templates/email-notification.html b/src/main/resources/templates/email-notification.html index 321115b35..7747600ad 100755 --- a/src/main/resources/templates/email-notification.html +++ b/src/main/resources/templates/email-notification.html @@ -64,12 +64,12 @@
  • - - + +
    • - +
  • diff --git a/src/test/java/eu/bbmri_eric/negotiator/integration/repository/NotificationRepositoryTest.java b/src/test/java/eu/bbmri_eric/negotiator/integration/repository/NotificationRepositoryTest.java new file mode 100644 index 000000000..ed1d6e554 --- /dev/null +++ b/src/test/java/eu/bbmri_eric/negotiator/integration/repository/NotificationRepositoryTest.java @@ -0,0 +1,194 @@ +package eu.bbmri_eric.negotiator.integration.repository; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import eu.bbmri_eric.negotiator.configuration.state_machine.negotiation.NegotiationState; +import eu.bbmri_eric.negotiator.database.model.DiscoveryService; +import eu.bbmri_eric.negotiator.database.model.Negotiation; +import eu.bbmri_eric.negotiator.database.model.Notification; +import eu.bbmri_eric.negotiator.database.model.NotificationEmailStatus; +import eu.bbmri_eric.negotiator.database.model.Organization; +import eu.bbmri_eric.negotiator.database.model.Person; +import eu.bbmri_eric.negotiator.database.model.PersonNegotiationRole; +import eu.bbmri_eric.negotiator.database.model.Request; +import eu.bbmri_eric.negotiator.database.model.Resource; +import eu.bbmri_eric.negotiator.database.model.Role; +import eu.bbmri_eric.negotiator.database.model.views.NotificationViewDTO; +import eu.bbmri_eric.negotiator.database.repository.DiscoveryServiceRepository; +import eu.bbmri_eric.negotiator.database.repository.NegotiationRepository; +import eu.bbmri_eric.negotiator.database.repository.NotificationRepository; +import eu.bbmri_eric.negotiator.database.repository.OrganizationRepository; +import eu.bbmri_eric.negotiator.database.repository.PersonRepository; +import eu.bbmri_eric.negotiator.database.repository.RequestRepository; +import eu.bbmri_eric.negotiator.database.repository.ResourceRepository; +import eu.bbmri_eric.negotiator.database.repository.RoleRepository; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.sql.DataSource; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.TestPropertySource; + +@DataJpaTest(showSql = false) +@ActiveProfiles("test") +@TestPropertySource(properties = {"spring.sql.init.mode=never"}) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) +public class NotificationRepositoryTest { + @Autowired DataSource dbSource; + @Autowired PersonRepository personRepository; + @Autowired ResourceRepository resourceRepository; + @Autowired RequestRepository requestRepository; + @Autowired DiscoveryServiceRepository discoveryServiceRepository; + @Autowired OrganizationRepository organizationRepository; + @Autowired NegotiationRepository negotiationRepository; + @Autowired RoleRepository roleRepository; + @Autowired NotificationRepository notificationRepository; + + String payload = + " {\n" + + "\"project\": {\n" + + "\"title\": \"Title\",\n" + + "\"description\": \"Description\"\n" + + "},\n" + + " \"samples\": {\n" + + " \"sample-type\": \"DNA\",\n" + + " \"num-of-subjects\": 10,\n" + + " \"num-of-samples\": 20,\n" + + " \"volume-per-sample\": 5\n" + + " },\n" + + " \"ethics-vote\": {\n" + + " \"ethics-vote\": \"My ethic vote\"\n" + + " }\n" + + "}\n"; + private DiscoveryService discoveryService; + private Person person; + private Resource resource; + private Negotiation negotiation; + + public void addH2Function() { + String statementScript = + "create DOMAIN IF NOT EXISTS JSONB AS JSON; \n" + + "CREATE ALIAS IF NOT EXISTS JSONB_EXTRACT_PATH AS '\n" + + "import com.jayway.jsonpath.JsonPath;\n" + + " @CODE\n" + + " String jsonbExtractPath(String jsonString, String...jsonPaths) {\n" + + " String overallPath = String.join(\".\", jsonPaths);\n" + + " try {\n" + + " Object result = JsonPath.read(jsonString, overallPath);\n" + + " if (result != null) {\n" + + " return result.toString();\n" + + " }\n" + + " } catch (Exception e) {\n" + + " e.printStackTrace();\n" + + " }\n" + + " return null;\n" + + " }';"; + JdbcTemplate jdbcTemplate = new JdbcTemplate(dbSource); + jdbcTemplate.execute(statementScript); + } + + @BeforeEach + void setUp() { + addH2Function(); + Organization organization = + organizationRepository.save( + Organization.builder().name("test").externalId("biobank:1").build()); + this.discoveryService = + discoveryServiceRepository.save(DiscoveryService.builder().url("").name("").build()); + this.person = savePerson("test"); + this.resource = + resourceRepository.save( + Resource.builder() + .organization(organization) + .discoveryService(discoveryService) + .sourceId("collection:1") + .name("test") + .representatives(new HashSet<>(List.of(person))) + .build()); + this.negotiation = saveNegotiation(this.person); + } + + private Negotiation saveNegotiation(Person author) { + Set requests = new HashSet<>(); + Set resources = new HashSet<>(); + resources.add(resource); + Request request = + Request.builder() + .url("http://test") + .resources(resources) + .discoveryService(discoveryService) + .humanReadable("everything") + .build(); + request = requestRepository.save(request); + requests.add(request); + Negotiation negotiation = + Negotiation.builder() + .currentState(NegotiationState.SUBMITTED) + .requests(requests) + .postsEnabled(false) + .payload(payload) + .build(); + negotiation.setCreatedBy(author); + Role role = roleRepository.save(new Role(1L, "test")); + Set roles = new HashSet<>(); + PersonNegotiationRole personRole = new PersonNegotiationRole(author, negotiation, role); + roles.add(personRole); + negotiation.setPersons(roles); + request.setNegotiation(negotiation); + negotiationRepository.save(negotiation); + return negotiation; + } + + private Person savePerson(String subjectId) { + return personRepository.save( + Person.builder() + .subjectId(subjectId) + .name("John") + .email("test@test.com") + .resources(new HashSet<>()) + .build()); + } + + private Notification saveNotification() { + Notification notification = + Notification.builder() + .id(1L) + .negotiation(this.negotiation) + .recipient(this.person) + .emailStatus(NotificationEmailStatus.EMAIL_NOT_SENT) + .build(); + return notificationRepository.save(notification); + } + + @Test + public void testFindByRecipientAndEmailStatus_ok() { + saveNotification(); + List notificationViewDTOs = + notificationRepository.findViewByRecipientIdAndEmailStatus( + this.person.getId(), NotificationEmailStatus.EMAIL_NOT_SENT); + NotificationViewDTO notificationViewDTO = notificationViewDTOs.get(0); + assertEquals(person.getId(), notificationViewDTO.getRecipient().getId()); + assertEquals(NotificationEmailStatus.EMAIL_NOT_SENT, notificationViewDTO.getEmailStatus()); + assertEquals(this.negotiation.getId(), notificationViewDTO.getNegotiationId()); + assertEquals(parseTitleFromNegotiation(negotiation), notificationViewDTO.getNegotiationTitle()); + } + + private static String parseTitleFromNegotiation(Negotiation negotiation) { + String title; + try { + JSONObject payloadJson = new JSONObject(negotiation.getPayload()); + title = payloadJson.getJSONObject("project").getString("title"); + } catch (JSONException e) { + title = "Untitled negotiation"; + } + return title; + } +} diff --git a/src/test/java/eu/bbmri_eric/negotiator/integration/service/NegotiationLifecycleServiceImplTest.java b/src/test/java/eu/bbmri_eric/negotiator/integration/service/NegotiationLifecycleServiceImplTest.java index c6cd72efc..6881d80a5 100644 --- a/src/test/java/eu/bbmri_eric/negotiator/integration/service/NegotiationLifecycleServiceImplTest.java +++ b/src/test/java/eu/bbmri_eric/negotiator/integration/service/NegotiationLifecycleServiceImplTest.java @@ -14,7 +14,10 @@ import eu.bbmri_eric.negotiator.database.model.Negotiation; import eu.bbmri_eric.negotiator.database.model.NegotiationLifecycleRecord; import eu.bbmri_eric.negotiator.database.model.NegotiationResourceLifecycleRecord; +import eu.bbmri_eric.negotiator.database.model.Person; +import eu.bbmri_eric.negotiator.database.model.Request; import eu.bbmri_eric.negotiator.database.repository.NegotiationRepository; +import eu.bbmri_eric.negotiator.database.repository.RequestRepository; import eu.bbmri_eric.negotiator.dto.negotiation.NegotiationCreateDTO; import eu.bbmri_eric.negotiator.dto.negotiation.NegotiationDTO; import eu.bbmri_eric.negotiator.exceptions.EntityNotFoundException; @@ -49,6 +52,7 @@ public class NegotiationLifecycleServiceImplTest { @Autowired NegotiationRepository negotiationRepository; @Autowired NegotiationService negotiationService; @Autowired private WebApplicationContext context; + @Autowired RequestRepository requestRepository; private void checkNegotiationResourceRecordPresenceWithAssignedState( String negotiationId, NegotiationResourceState negotiationResourceState) { @@ -118,6 +122,14 @@ void sendEvent_abandonNegotiation_to_inProcess_Negotiation() throws IOException private NegotiationDTO saveNegotiation() throws IOException { NegotiationCreateDTO negotiationCreateDTO = TestUtils.createNegotiation(Set.of("request-2")); + Request request = requestRepository.findById("request-2").get(); + Negotiation negotiation = + Negotiation.builder() + .requests(Set.of(request)) + .payload(negotiationCreateDTO.getPayload().toString()) + .build(); + negotiation.setCreatedBy(Person.builder().id(101L).name("TheBuilder").build()); + negotiationRepository.save(negotiation); return negotiationService.create(negotiationCreateDTO, 101L); } diff --git a/src/test/java/eu/bbmri_eric/negotiator/unit/service/NegotiationServiceTest.java b/src/test/java/eu/bbmri_eric/negotiator/unit/service/NegotiationServiceTest.java index 87af08b34..ed684606c 100644 --- a/src/test/java/eu/bbmri_eric/negotiator/unit/service/NegotiationServiceTest.java +++ b/src/test/java/eu/bbmri_eric/negotiator/unit/service/NegotiationServiceTest.java @@ -20,12 +20,12 @@ import eu.bbmri_eric.negotiator.database.repository.RoleRepository; import eu.bbmri_eric.negotiator.dto.negotiation.NegotiationCreateDTO; import eu.bbmri_eric.negotiator.dto.negotiation.NegotiationDTO; -import eu.bbmri_eric.negotiator.exceptions.EntityNotFoundException; import eu.bbmri_eric.negotiator.integration.api.v3.TestUtils; import eu.bbmri_eric.negotiator.service.EmailService; import eu.bbmri_eric.negotiator.service.NegotiationLifecycleService; import eu.bbmri_eric.negotiator.service.NegotiationServiceImpl; import eu.bbmri_eric.negotiator.service.ResourceLifecycleService; +import eu.bbmri_eric.negotiator.unit.context.WithMockNegotiatorUser; import java.io.IOException; import java.util.List; import java.util.Optional; @@ -34,6 +34,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.InjectMocks; @@ -42,7 +43,11 @@ import org.modelmapper.ModelMapper; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +@ExtendWith(SpringExtension.class) +@ContextConfiguration public class NegotiationServiceTest { @Mock NegotiationRepository negotiationRepository; @Mock RoleRepository roleRepository; @@ -91,10 +96,40 @@ void after() throws Exception { @Test public void test_Exist_IsFalse_WhenNegotiationIsNotFound() { - when(negotiationRepository.findById(any())).thenThrow(EntityNotFoundException.class); + when(negotiationRepository.existsById(any())).thenReturn(false); assertFalse(negotiationService.exists("unknown")); } + @Test + public void test_Exist_IsTrue_WhenNegotiationIsFound() { + when(negotiationRepository.existsById(any())).thenReturn(true); + assertTrue(negotiationService.exists("123")); + } + + @Test + @WithMockNegotiatorUser( + id = 2L, + authName = "researcher", + authSubject = "researcher@aai.eu", + authEmail = "researcher@aai.eu", + authorities = {"ROLE_RESEARCHER"}) + public void test_isNegotiatorCreator_IsFalse_WhenPersonRepositoryIsNegotiatiorCreator_IsFalse() { + when(personRepository.isNegotiationCreator(any(), any())).thenReturn(false); + assertFalse(negotiationService.isNegotiationCreator("123")); + } + + @Test + @WithMockNegotiatorUser( + id = 2L, + authName = "researcher", + authSubject = "researcher@aai.eu", + authEmail = "researcher@aai.eu", + authorities = {"ROLE_RESEARCHER"}) + public void test_isNegotiatorCreator_IsTrue_WhenPersonRepositoryIsNegotiatiorCreator_IsTrue() { + when(personRepository.isNegotiationCreator(any(), any())).thenReturn(true); + assertTrue(negotiationService.isNegotiationCreator("123")); + } + @Disabled void testCreateNegotiation() throws IOException { when(personRepository.findById(100L)).thenReturn(Optional.of(new Person()));