Skip to content

Commit

Permalink
Merge pull request #7 from samply/feature/notifications
Browse files Browse the repository at this point in the history
Feature/notifications
  • Loading branch information
djuarezgf authored Jan 30, 2024
2 parents f64b6ea + 68a7c77 commit 9458fa9
Show file tree
Hide file tree
Showing 14 changed files with 188 additions and 118 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Frontend DTO converters
- Fetch all user visible notifications
- Accepted state requirement for setting user as developer or pilot
- Notification User Action
- Replace Bridgehead Operation through Notification
- Set notification as read
3 changes: 3 additions & 0 deletions src/main/java/de/samply/app/ProjectManagerConst.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public class ProjectManagerConst {
public final static String REJECT_PROJECT_RESULTS_ACTION = "REJECT_PROJECT_RESULTS";
public final static String REQUEST_CHANGES_IN_PROJECT_ACTION = "REQUEST_CHANGES_IN_PROJECT";
public final static String FETCH_NOTIFICATIONS_ACTION = "FETCH_NOTIFICATIONS";
public final static String SET_NOTIFICATION_AS_READ_ACTION = "SET_NOTIFICATION_AS_READ";


// REST Services
Expand Down Expand Up @@ -122,9 +123,11 @@ public class ProjectManagerConst {
public final static String FETCH_PUBLICATIONS = "/publications";
public final static String FETCH_OTHER_DOCUMENTS = "/other-documents";
public final static String FETCH_NOTIFICATIONS = "/notifications";
public final static String SET_NOTIFICATION_AS_READ = "/read-notification";

// REST Parameters
public final static String PROJECT_CODE = "project-code";
public final static String NOTIFICATION_ID = "notification-id";
public final static String BRIDGEHEAD = "bridgehead";
public final static String BRIDGEHEADS = "bridgeheads";
public final static String SITE = "site";
Expand Down
13 changes: 12 additions & 1 deletion src/main/java/de/samply/app/ProjectManagerController.java
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ public ResponseEntity<String> createQueryAndDesignProject(
String projectCode = this.projectEventService.draft(bridgeheads, queryCode, projectType);
return convertToResponseEntity(() -> this.frontendService.fetchUrl(
ProjectManagerConst.PROJECT_VIEW_SITE,
Map.of(ProjectManagerConst.QUERY_CODE, projectCode)
Map.of(ProjectManagerConst.PROJECT_CODE, projectCode)
));
}

Expand Down Expand Up @@ -813,6 +813,17 @@ public ResponseEntity<String> fetchNotifications(
return convertToResponseEntity(() -> this.notificationService.fetchUserVisibleNotifications(Optional.ofNullable(projectCode), Optional.ofNullable(bridgehead)));
}

@RoleConstraints(organisationRoles = {OrganisationRole.RESEARCHER, OrganisationRole.BRIDGEHEAD_ADMIN, OrganisationRole.PROJECT_MANAGER_ADMIN})
@FrontendSiteModule(site = ProjectManagerConst.PROJECT_VIEW_SITE, module = ProjectManagerConst.NOTIFICATIONS_MODULE)
@FrontendSiteModule(site = ProjectManagerConst.PROJECT_DASHBOARD_SITE, module = ProjectManagerConst.NOTIFICATIONS_MODULE)
@FrontendAction(action = ProjectManagerConst.SET_NOTIFICATION_AS_READ_ACTION)
@PostMapping(value = ProjectManagerConst.SET_NOTIFICATION_AS_READ)
public ResponseEntity<String> setNotificationAsRead(
@RequestParam(name = ProjectManagerConst.NOTIFICATION_ID) Long notificationId
) {
return convertToResponseEntity(() -> this.notificationService.setNotificationAsRead(notificationId));
}


private ResponseEntity convertToResponseEntity(RunnableWithException runnable) {
try {
Expand Down
48 changes: 0 additions & 48 deletions src/main/java/de/samply/db/model/BridgeheadOperation.java

This file was deleted.

10 changes: 8 additions & 2 deletions src/main/java/de/samply/db/model/Notification.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.http.HttpStatus;

import java.time.Instant;

Expand Down Expand Up @@ -33,14 +34,19 @@ public class Notification {
@Column(name = "bridgehead")
private String bridgehead;

@Column(name = "operation_type", nullable = false)
@Column(name = "operation_type")
@Enumerated(EnumType.STRING)
private OperationType operationType;

@Column(name = "details", nullable = false)
@Column(name = "details")
private String details;

@Column(name = "error")
private String error;

@Column(name = "http_status")
@Enumerated(EnumType.STRING)
private HttpStatus httpStatus;


}
35 changes: 35 additions & 0 deletions src/main/java/de/samply/db/model/NotificationUserAction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package de.samply.db.model;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.Instant;

@Entity
@Table(name = "notification_user_action", schema = "samply")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class NotificationUserAction {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Long id;

@Column(name = "email", nullable = false)
private String email;

@Column(name = "read", nullable = false)
private boolean read = false;

@ManyToOne
@JoinColumn(name = "notification_id", nullable = false)
private Notification notification;

@Column(name = "modified_at", nullable = false)
private Instant modifiedAt = Instant.now();

}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package de.samply.db.repository;

import de.samply.db.model.Notification;
import de.samply.db.model.NotificationUserAction;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.Optional;

@Repository
public interface NotificationUserActionRepository extends JpaRepository<NotificationUserAction, Long> {

Optional<NotificationUserAction> findByNotification(Notification notification);

}
37 changes: 13 additions & 24 deletions src/main/java/de/samply/exporter/ExporterService.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import de.samply.app.ProjectManagerConst;
import de.samply.bridgehead.BridgeheadOperationType;
import de.samply.db.model.BridgeheadOperation;
import de.samply.db.model.Project;
import de.samply.db.model.Query;
import de.samply.db.repository.BridgeheadOperationRepository;
import de.samply.db.repository.ProjectRepository;
import de.samply.exporter.focus.FocusQuery;
import de.samply.exporter.focus.FocusService;
import de.samply.exporter.focus.FocusServiceException;
import de.samply.notification.NotificationService;
import de.samply.notification.OperationType;
import de.samply.project.ProjectType;
import de.samply.security.SessionUser;
import de.samply.utils.Base64Utils;
Expand All @@ -35,10 +34,8 @@
import reactor.netty.http.client.HttpClient;

import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
Expand All @@ -59,7 +56,7 @@ public class ExporterService {
private final int webClientBufferSizeInBytes;
private final SessionUser sessionUser;
private final ProjectRepository projectRepository;
private final BridgeheadOperationRepository bridgeheadOperationRepository;
private final NotificationService notificationService;
private final Set<String> exportTemplates;
private final Set<String> datashieldTemplates;
private final String focusProjectManagerId;
Expand All @@ -84,7 +81,7 @@ public ExporterService(
FocusService focusService,
ProjectRepository projectRepository,
SessionUser sessionUser,
BridgeheadOperationRepository bridgeheadOperationRepository) {
NotificationService notificationService) {
this.focusService = focusService;
this.webClientMaxNumberOfRetries = webClientMaxNumberOfRetries;
this.webClientTimeInSecondsAfterRetryWithFailure = webClientTimeInSecondsAfterRetryWithFailure;
Expand All @@ -96,7 +93,7 @@ public ExporterService(
this.webClientBufferSizeInBytes = webClientBufferSizeInBytes;
this.sessionUser = sessionUser;
this.projectRepository = projectRepository;
this.bridgeheadOperationRepository = bridgeheadOperationRepository;
this.notificationService = notificationService;
this.exportTemplates = exportTemplates;
this.datashieldTemplates = datashieldTemplates;
this.focusProjectManagerId = focusProjectManagerId;
Expand Down Expand Up @@ -154,14 +151,14 @@ private void postRequest(String bridgehead, String projectCode, FocusQuery focus
}
// We don't use the normal retry functionality of webclient, because focus requires to change the focus query ID after every retry
if (numberOfRetries >= webClientMaxNumberOfRetries) {
createBridgeheadOperation((HttpStatus) ex.getStatusCode(), error, bridgehead, projectCode, email, toBeExecuted);
createBridgeheadNotification((HttpStatus) ex.getStatusCode(), error, bridgehead, projectCode, email, toBeExecuted);
} else {
waitUntilNextRetry();
focusQuery.setId(focusService.generateId()); // Generate new Focus Query ID
postRequest(bridgehead, projectCode, focusQuery, toBeExecuted, numberOfRetries + 1);
}
})
.subscribe(result -> createBridgeheadOperation(HttpStatus.OK, null, bridgehead, projectCode, email, toBeExecuted));
.subscribe(result -> createBridgeheadNotification(HttpStatus.OK, null, bridgehead, projectCode, email, toBeExecuted));
}

private void waitUntilNextRetry() {
Expand All @@ -176,22 +173,15 @@ private String fetchAuthorization() {
return ProjectManagerConst.API_KEY + ' ' + focusProjectManagerId + ' ' + focusApiKey;
}

private void createBridgeheadOperation(
private void createBridgeheadNotification(
HttpStatus status, String error, String bridgehead, String projectCode, String email, boolean toBeExecuted) {
BridgeheadOperation bridgeheadOperation = new BridgeheadOperation();
bridgeheadOperation.setBridgehead(bridgehead);
bridgeheadOperation.setProject(projectRepository.findByCode(projectCode).get());
bridgeheadOperation.setTimestamp(Instant.now());
bridgeheadOperation.setType(fetchBridgeheadOperationType(toBeExecuted));
bridgeheadOperation.setHttpStatus(status);
bridgeheadOperation.setError(error);
bridgeheadOperation.setUserEmail(email);
bridgeheadOperationRepository.save(bridgeheadOperation);
notificationService.createNotification(
projectCode, bridgehead, email,
fetchBridgeheadOperationType(toBeExecuted), null, error, status);
}

private BridgeheadOperationType fetchBridgeheadOperationType(boolean toBeExecuted) {
return (toBeExecuted) ? BridgeheadOperationType.SEND_QUERY_TO_BRIDGEHEAD_AND_EXECUTE :
BridgeheadOperationType.SEND_QUERY_TO_BRIDGEHEAD;
private OperationType fetchBridgeheadOperationType(boolean toBeExecuted) {
return (toBeExecuted) ? OperationType.SEND_QUERY_TO_BRIDGEHEAD_AND_EXECUTE : OperationType.SEND_QUERY_TO_BRIDGEHEAD;
}

private String convertToBase64String(Object jsonObject) {
Expand Down Expand Up @@ -276,7 +266,6 @@ public Set<String> getExporterTemplates(@NotNull ProjectType projectType) {
return switch (projectType) {
case EXPORT -> exportTemplates;
case DATASHIELD -> datashieldTemplates;
default -> new HashSet<>();
};
}

Expand Down
10 changes: 6 additions & 4 deletions src/main/java/de/samply/frontend/dto/DtoFactory.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package de.samply.frontend.dto;

import de.samply.project.state.ProjectBridgeheadState;
import de.samply.db.model.NotificationUserAction;
import jakarta.validation.constraints.NotNull;

import java.time.Instant;
import java.util.function.Supplier;

public class DtoFactory {

Expand All @@ -29,15 +29,17 @@ public static Project convert(@NotNull de.samply.db.model.Project project) {
);
}

public static Notification convert(@NotNull de.samply.db.model.Notification notification) {
public static Notification convert(@NotNull de.samply.db.model.Notification notification, Supplier<NotificationUserAction> userActionSupplier) {
return new Notification(
notification.getEmail(),
notification.getTimestamp(),
notification.getProject().getCode(),
notification.getBridgehead(),
notification.getOperationType(),
notification.getDetails(),
notification.getError()
notification.getError(),
notification.getHttpStatus(),
userActionSupplier.get().isRead()
);
}

Expand Down
5 changes: 4 additions & 1 deletion src/main/java/de/samply/frontend/dto/Notification.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package de.samply.frontend.dto;

import de.samply.notification.OperationType;
import org.springframework.http.HttpStatus;

import java.time.Instant;

Expand All @@ -11,6 +12,8 @@ public record Notification(
String bridgehead,
OperationType operationType,
String details,
String error
String error,
HttpStatus httpStatus,
Boolean read
) {
}
Loading

0 comments on commit 9458fa9

Please sign in to comment.