Skip to content

Commit

Permalink
[JN-1409] Document library [participant UX] (#1369)
Browse files Browse the repository at this point in the history
  • Loading branch information
MatthewBemis authored Jan 13, 2025
1 parent 54d838b commit 631ec6f
Show file tree
Hide file tree
Showing 42 changed files with 737 additions and 63 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/java-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ jobs:
# Run DSP App Sec Trivy Scanner on PRs
dispatch-trivy:
needs: [ build ]
runs-on: ubuntu-latest
runs-on: ubuntu-22.04

if: github.event_name == 'pull_request'

Expand All @@ -110,7 +110,7 @@ jobs:

dispatch-tag:
needs: [ build ]
runs-on: ubuntu-latest
runs-on: ubuntu-22.04

# Only tag a new release if prior steps were successful and triggering commit is a merge to mainline
if: success() && github.ref == 'refs/heads/development'
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/java-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ env:

jobs:
get-version-tag:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
outputs:
tag: ${{ steps.tag.outputs.tag }}
steps:
Expand All @@ -29,7 +29,7 @@ jobs:
permissions:
contents: 'read'
id-token: 'write'
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
outputs:
tag: ${{ steps.build-publish.outputs.published-image }}
steps:
Expand Down Expand Up @@ -64,7 +64,7 @@ jobs:
permissions:
contents: 'read'
id-token: 'write'
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
outputs:
tag: ${{ steps.build-publish.outputs.published-image }}
steps:
Expand Down Expand Up @@ -119,7 +119,7 @@ jobs:
id-token: 'write'

notify-upon-completion:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
if: always()
needs: [set-version-in-dev, get-version-tag]
steps:
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/juniper-eng-infra-upload-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ env:

jobs:
get-version-tag:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
outputs:
tag: ${{ steps.tag.outputs.tag }}
steps:
Expand All @@ -28,7 +28,7 @@ jobs:
permissions:
contents: 'read'
id-token: 'write'
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
outputs:
tag: ${{ steps.juniper-eng-build-publish.outputs.published-image }}
steps:
Expand All @@ -50,7 +50,7 @@ jobs:
permissions:
contents: 'read'
id-token: 'write'
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
outputs:
tag: ${{ steps.juniper-eng-build-publish.outputs.published-image }}
steps:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/require-ticket.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:

jobs:
require_ticket:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- name: Check for ticket in PR title
id: validate
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/sonar.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on:
jobs:
sonar-java:
name: SonarCloud Java
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -50,7 +50,7 @@ jobs:

sonar-typescript:
name: SonarCloud TypeScript
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
strategy:
matrix:
subproject: ['ui-admin', 'ui-core', 'ui-participant']
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on:

jobs:
tag-job:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
outputs:
tag: ${{ steps.tag.outputs.tag }}
steps:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package bio.terra.pearl.api.participant.controller.file;

import bio.terra.pearl.api.participant.api.ParticipantFileApi;
import bio.terra.pearl.api.participant.service.RequestUtilService;
import bio.terra.pearl.api.participant.service.file.ParticipantFileExtService;
import bio.terra.pearl.core.model.EnvironmentName;
import bio.terra.pearl.core.model.file.ParticipantFile;
import bio.terra.pearl.core.model.participant.ParticipantUser;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.util.List;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.multipart.MultipartFile;

@Controller
public class ParticipantFileController implements ParticipantFileApi {
private final ParticipantFileExtService participantFileExtService;
private final HttpServletRequest request;
private final ObjectMapper objectMapper;
private final RequestUtilService requestUtilService;

public ParticipantFileController(
ParticipantFileExtService participantFileExtService,
HttpServletRequest request,
ObjectMapper objectMapper,
RequestUtilService requestUtilService) {
this.participantFileExtService = participantFileExtService;
this.request = request;
this.objectMapper = objectMapper;
this.requestUtilService = requestUtilService;
}

@Override
public ResponseEntity<Resource> download(
String portalShortcode,
String envName,
String studyShortcode,
String enrolleeShortcode,
String fileName) {
ParticipantUser participantUser = requestUtilService.requireUser(request);

ParticipantFile participantFile =
participantFileExtService.get(
portalShortcode,
EnvironmentName.valueOf(envName),
participantUser,
enrolleeShortcode,
fileName);

InputStream content =
participantFileExtService.downloadFile(
portalShortcode,
EnvironmentName.valueOf(envName),
participantUser,
enrolleeShortcode,
fileName);

MediaType mediaType;
try {
mediaType = MediaType.parseMediaType(participantFile.getFileType());
} catch (Exception e) {
mediaType = MediaType.APPLICATION_OCTET_STREAM;
}

return ResponseEntity.ok().contentType(mediaType).body(new InputStreamResource(content));
}

@Override
public ResponseEntity<Object> upload(
String portalShortcode,
String envName,
String studyShortcode,
String enrolleeShortcode,
MultipartFile participantFile) {
ParticipantUser participantUser = requestUtilService.requireUser(request);

ParticipantFile created =
participantFileExtService.uploadFile(
portalShortcode,
EnvironmentName.valueOf(envName),
participantUser,
enrolleeShortcode,
participantFile);

return ResponseEntity.ok(created);
}

@Override
public ResponseEntity<Object> list(
String portalShortcode, String envName, String studyShortcode, String enrolleeShortcode) {
ParticipantUser participantUser = requestUtilService.requireUser(request);

List<ParticipantFile> participantFiles =
participantFileExtService.list(
portalShortcode, EnvironmentName.valueOf(envName), participantUser, enrolleeShortcode);
return ResponseEntity.ok(participantFiles);
}

@Override
public ResponseEntity<Object> delete(
String portalShortcode,
String envName,
String studyShortcode,
String enrolleeShortcode,
String fileName) {
ParticipantUser participantUser = requestUtilService.requireUser(request);

participantFileExtService.delete(
portalShortcode,
EnvironmentName.valueOf(envName),
participantUser,
enrolleeShortcode,
fileName);

return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package bio.terra.pearl.api.participant.service.file;

import bio.terra.pearl.api.participant.service.AuthUtilService;
import bio.terra.pearl.core.model.EnvironmentName;
import bio.terra.pearl.core.model.file.ParticipantFile;
import bio.terra.pearl.core.model.participant.Enrollee;
import bio.terra.pearl.core.model.participant.ParticipantUser;
import bio.terra.pearl.core.service.exception.NotFoundException;
import bio.terra.pearl.core.service.file.ParticipantFileService;
import bio.terra.pearl.core.service.file.backends.FileStorageBackend;
import bio.terra.pearl.core.service.file.backends.FileStorageBackendProvider;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

@Service
@Slf4j
public class ParticipantFileExtService {

private final ParticipantFileService participantFileService;
private final AuthUtilService authUtilService;
private final FileStorageBackend fileStorageBackend;

public ParticipantFileExtService(
ParticipantFileService participantFileService,
AuthUtilService authUtilService,
FileStorageBackendProvider fileStorageBackendProvider) {
this.participantFileService = participantFileService;
this.authUtilService = authUtilService;
this.fileStorageBackend = fileStorageBackendProvider.get();
}

public ParticipantFile get(
String portalShortcode,
EnvironmentName envName,
ParticipantUser participantUser,
String enrolleeShortcode,
String fileName) {
authUtilService.authParticipantToPortal(participantUser.getId(), portalShortcode, envName);
Enrollee enrollee =
authUtilService.authParticipantUserToEnrollee(participantUser.getId(), enrolleeShortcode);
return participantFileService
.findByEnrolleeIdAndFileName(enrollee.getId(), fileName)
.orElseThrow(() -> new NotFoundException("Could not find file"));
}

public InputStream downloadFile(
String portalShortcode,
EnvironmentName envName,
ParticipantUser participantUser,
String enrolleeShortcode,
String fileName) {
authUtilService.authParticipantToPortal(participantUser.getId(), portalShortcode, envName);
Enrollee enrollee =
authUtilService.authParticipantUserToEnrollee(participantUser.getId(), enrolleeShortcode);
ParticipantFile participantFile =
participantFileService
.findByEnrolleeIdAndFileName(enrollee.getId(), fileName)
.orElseThrow(() -> new NotFoundException("Could not find file"));

return fileStorageBackend.downloadFile(participantFile.getExternalFileId());
}

public ParticipantFile uploadFile(
String portalShortcode,
EnvironmentName envName,
ParticipantUser participantUser,
String enrolleeShortcode,
MultipartFile file) {
authUtilService.authParticipantToPortal(participantUser.getId(), portalShortcode, envName);
Enrollee enrollee =
authUtilService.authParticipantUserToEnrollee(participantUser.getId(), enrolleeShortcode);

try {
return participantFileService.uploadFileAndCreate(
ParticipantFile.builder()
.enrolleeId(enrollee.getId())
.fileName(getFileName(file.getOriginalFilename()))
.fileType(file.getContentType())
.build(),
file.getInputStream());
} catch (IOException e) {
throw new RuntimeException("Error uploading file");
}
}

public List<ParticipantFile> list(
String portalShortcode,
EnvironmentName envName,
ParticipantUser participantUser,
String enrolleeShortcode) {
authUtilService.authParticipantToPortal(participantUser.getId(), portalShortcode, envName);
Enrollee enrollee =
authUtilService.authParticipantUserToEnrollee(participantUser.getId(), enrolleeShortcode);
return participantFileService.findByEnrolleeId(enrollee.getId());
}

// Returns the name of the file without the preceding path
public String getFileName(String fileName) {
if (fileName == null) {
return "";
}
String[] split = fileName.split("\\[/\\\\]");
return split[split.length - 1];
}

public void delete(
String portalShortcode,
EnvironmentName envName,
ParticipantUser participantUser,
String enrolleeShortcode,
String fileName) {
authUtilService.authParticipantToPortal(participantUser.getId(), portalShortcode, envName);
Enrollee enrollee =
authUtilService.authParticipantUserToEnrollee(participantUser.getId(), enrolleeShortcode);
ParticipantFile participantFile =
participantFileService
.findByEnrolleeIdAndFileName(enrollee.getId(), fileName)
.orElseThrow(() -> new NotFoundException("Could not find file"));

participantFileService.delete(participantFile.getId(), Set.of());
fileStorageBackend.deleteFile(participantFile.getExternalFileId());
}
}
Loading

0 comments on commit 631ec6f

Please sign in to comment.