Search in sources :

Example 21 with App

use of org.sagebionetworks.bridge.models.apps.App in project BridgeServer2 by Sage-Bionetworks.

the class Exporter3ServiceTest method initExporter3.

@Test
public void initExporter3() throws Exception {
    // App has no exporter3config.
    app.setExporter3Configuration(null);
    app.setExporter3Enabled(false);
    // Mock SynapseHelper.
    Team createdTeam = new Team();
    createdTeam.setId(String.valueOf(DATA_ACCESS_TEAM_ID));
    when(mockSynapseHelper.createTeamWithRetry(any())).thenReturn(createdTeam);
    Project createdProject = new Project();
    createdProject.setId(PROJECT_ID);
    when(mockSynapseHelper.createEntityWithRetry(any(Project.class))).thenReturn(createdProject);
    EntityView trackingView = new EntityView();
    trackingView.setScopeIds(new ArrayList<>());
    when(mockSynapseHelper.getEntityWithRetry(SYNAPSE_TRACKING_VIEW_ID, EntityView.class)).thenReturn(trackingView);
    TableEntity createdTable = new TableEntity();
    createdTable.setId(PARTICIPANT_VERSION_TABLE_ID);
    when(mockSynapseHelper.createTableWithColumnsAndAcls(anyList(), anySet(), anySet(), anyString(), anyString())).thenReturn(PARTICIPANT_VERSION_TABLE_ID);
    Folder createdFolder = new Folder();
    createdFolder.setId(RAW_FOLDER_ID);
    when(mockSynapseHelper.createEntityWithRetry(any(Folder.class))).thenReturn(createdFolder);
    ExternalS3StorageLocationSetting createdStorageLocation = new ExternalS3StorageLocationSetting();
    createdStorageLocation.setStorageLocationId(STORAGE_LOCATION_ID);
    when(mockSynapseHelper.createStorageLocationForEntity(eq(RAW_FOLDER_ID), any(ExternalS3StorageLocationSetting.class))).thenReturn(createdStorageLocation);
    // Execute and verify output.
    Exporter3Configuration returnedEx3Config = exporter3Service.initExporter3(TestConstants.TEST_APP_ID);
    assertEquals(returnedEx3Config.getDataAccessTeamId().longValue(), DATA_ACCESS_TEAM_ID);
    assertEquals(returnedEx3Config.getParticipantVersionTableId(), PARTICIPANT_VERSION_TABLE_ID);
    assertEquals(returnedEx3Config.getProjectId(), PROJECT_ID);
    assertEquals(returnedEx3Config.getRawDataFolderId(), RAW_FOLDER_ID);
    assertEquals(returnedEx3Config.getStorageLocationId().longValue(), STORAGE_LOCATION_ID);
    // Verify created team.
    ArgumentCaptor<Team> teamToCreateCaptor = ArgumentCaptor.forClass(Team.class);
    verify(mockSynapseHelper).createTeamWithRetry(teamToCreateCaptor.capture());
    Team teamToCreate = teamToCreateCaptor.getValue();
    assertEquals(teamToCreate.getName(), EXPECTED_TEAM_NAME);
    // Verify created project. Note that we call this method again later, which is why we verify it twice now.
    ArgumentCaptor<Entity> entitiesToCreateCaptor = ArgumentCaptor.forClass(Project.class);
    verify(mockSynapseHelper, times(2)).createEntityWithRetry(entitiesToCreateCaptor.capture());
    List<Entity> entitiesToCreateList = entitiesToCreateCaptor.getAllValues();
    Project projectToCreate = (Project) entitiesToCreateList.get(0);
    assertEquals(projectToCreate.getName(), EXPECTED_PROJECT_NAME);
    // Verify project ACLs.
    verify(mockSynapseHelper).createAclWithRetry(PROJECT_ID, ADMIN_PRINCIPAL_ID_SET, READ_ONLY_PRINCIPAL_ID_SET);
    // Verify project added to tracking view. For whatever reason, view scope IDs don't include the "syn" prefix.
    ArgumentCaptor<EntityView> viewToUpdateCaptor = ArgumentCaptor.forClass(EntityView.class);
    verify(mockSynapseHelper).updateEntityWithRetry(viewToUpdateCaptor.capture());
    EntityView viewToUpdate = viewToUpdateCaptor.getValue();
    assertTrue(viewToUpdate.getScopeIds().contains(PROJECT_ID_WITHOUT_PREFIX));
    // Verify created participant version table.
    verify(mockSynapseHelper).createTableWithColumnsAndAcls(Exporter3Service.PARTICIPANT_VERSION_COLUMN_MODELS, READ_ONLY_PRINCIPAL_ID_SET, ADMIN_PRINCIPAL_ID_SET, PROJECT_ID, Exporter3Service.TABLE_NAME_PARTICIPANT_VERSIONS);
    // Verify created folder.
    Folder folderToCreate = (Folder) entitiesToCreateList.get(1);
    assertEquals(folderToCreate.getName(), Exporter3Service.FOLDER_NAME_BRIDGE_RAW_DATA);
    assertEquals(folderToCreate.getParentId(), PROJECT_ID);
    // Verify folder ACLs.
    verify(mockSynapseHelper).createAclWithRetry(RAW_FOLDER_ID, ADMIN_PRINCIPAL_ID_SET, READ_ONLY_PRINCIPAL_ID_SET);
    // Verify we write to S3 for the storage location.
    verify(mockS3Helper).writeLinesToS3(RAW_HEALTH_DATA_BUCKET, TestConstants.TEST_APP_ID + "/owner.txt", ImmutableList.of(EXPORTER_SYNAPSE_USER));
    // Verify created storage location.
    ArgumentCaptor<ExternalS3StorageLocationSetting> storageLocationToCreateCaptor = ArgumentCaptor.forClass(ExternalS3StorageLocationSetting.class);
    verify(mockSynapseHelper).createStorageLocationForEntity(eq(RAW_FOLDER_ID), storageLocationToCreateCaptor.capture());
    ExternalS3StorageLocationSetting storageLocationToCreate = storageLocationToCreateCaptor.getValue();
    assertEquals(storageLocationToCreate.getBaseKey(), TestConstants.TEST_APP_ID);
    assertEquals(storageLocationToCreate.getBucket(), RAW_HEALTH_DATA_BUCKET);
    assertTrue(storageLocationToCreate.getStsEnabled());
    // Verify updated app.
    ArgumentCaptor<App> appToUpdateCaptor = ArgumentCaptor.forClass(App.class);
    verify(mockAppService).updateApp(appToUpdateCaptor.capture(), eq((true)));
    App appToUpdate = appToUpdateCaptor.getValue();
    assertTrue(appToUpdate.isExporter3Enabled());
    Exporter3Configuration ex3ConfigToCreate = appToUpdate.getExporter3Configuration();
    assertEquals(ex3ConfigToCreate, returnedEx3Config);
}
Also used : App(org.sagebionetworks.bridge.models.apps.App) Entity(org.sagebionetworks.repo.model.Entity) TableEntity(org.sagebionetworks.repo.model.table.TableEntity) EntityView(org.sagebionetworks.repo.model.table.EntityView) Folder(org.sagebionetworks.repo.model.Folder) Project(org.sagebionetworks.repo.model.Project) ExternalS3StorageLocationSetting(org.sagebionetworks.repo.model.project.ExternalS3StorageLocationSetting) TableEntity(org.sagebionetworks.repo.model.table.TableEntity) Team(org.sagebionetworks.repo.model.Team) Exporter3Configuration(org.sagebionetworks.bridge.models.apps.Exporter3Configuration) Test(org.testng.annotations.Test)

Example 22 with App

use of org.sagebionetworks.bridge.models.apps.App in project BridgeServer2 by Sage-Bionetworks.

the class UploadService method uploadComplete.

public void uploadComplete(String appId, UploadCompletionClient completedBy, Upload upload, boolean redrive) {
    String uploadId = upload.getUploadId();
    // We don't want to kick off upload validation on an upload that already has upload validation.
    if (!upload.canBeValidated() && !redrive) {
        logger.info(String.format("uploadComplete called for upload %s, which is already complete", uploadId));
        return;
    }
    final String objectId = upload.getObjectId();
    ObjectMetadata obj;
    try {
        Stopwatch stopwatch = Stopwatch.createStarted();
        obj = s3Client.getObjectMetadata(uploadBucket, objectId);
        logger.info("Finished getting S3 metadata for bucket " + uploadBucket + " key " + objectId + " in " + stopwatch.elapsed(TimeUnit.MILLISECONDS) + " ms");
    } catch (AmazonS3Exception ex) {
        if (ex.getStatusCode() == 404) {
            throw new NotFoundException(ex);
        } else {
            // Only S3 404s are mapped to 404s. Everything else is an internal server error.
            throw new BridgeServiceException(ex);
        }
    }
    String sse = obj.getSSEAlgorithm();
    if (!AES_256_SERVER_SIDE_ENCRYPTION.equals(sse)) {
        logger.error("Missing S3 server-side encryption (SSE) for presigned upload " + uploadId + ".");
    }
    try {
        uploadDao.uploadComplete(completedBy, upload);
    } catch (ConcurrentModificationException ex) {
        // The old workflow is the app calls uploadComplete. The new workflow has an S3 trigger to call
        // uploadComplete. During the transition, it's very likely that this will be called twice, sometimes
        // concurrently. As such, we should log and squelch the ConcurrentModificationException.
        logger.info("Concurrent modification of upload " + uploadId + " while marking upload complete");
        // and duplicate records.
        return;
    }
    // kick off upload validation
    App app = appService.getApp(appId);
    if (BridgeUtils.isExporter3Configured(app)) {
        exporter3Service.completeUpload(app, upload);
    }
    // For backwards compatibility, always call Legacy Exporter 2.0. In the future, we may introduce a setting to
    // disable this for new apps.
    uploadValidationService.validateUpload(appId, upload);
}
Also used : App(org.sagebionetworks.bridge.models.apps.App) ConcurrentModificationException(org.sagebionetworks.bridge.exceptions.ConcurrentModificationException) Stopwatch(com.google.common.base.Stopwatch) BridgeServiceException(org.sagebionetworks.bridge.exceptions.BridgeServiceException) NotFoundException(org.sagebionetworks.bridge.exceptions.NotFoundException) AmazonS3Exception(com.amazonaws.services.s3.model.AmazonS3Exception) ObjectMetadata(com.amazonaws.services.s3.model.ObjectMetadata)

Example 23 with App

use of org.sagebionetworks.bridge.models.apps.App in project BridgeServer2 by Sage-Bionetworks.

the class CRCController method updateParticipant.

@PostMapping("/v1/cuimc/participants/{userId}/laborders")
public StatusMessage updateParticipant(@PathVariable String userId) {
    App app = httpBasicAuthentication();
    AccountId accountId = parseAccountId(app.getIdentifier(), userId);
    Account account = accountService.getAccount(accountId).orElseThrow(() -> new EntityNotFoundException(Account.class));
    if (account == null) {
        throw new EntityNotFoundException(Account.class);
    }
    updateState(account, SELECTED);
    accountService.updateAccount(account);
    return new StatusMessage("Participant updated.");
}
Also used : App(org.sagebionetworks.bridge.models.apps.App) Account(org.sagebionetworks.bridge.models.accounts.Account) BridgeUtils.parseAccountId(org.sagebionetworks.bridge.BridgeUtils.parseAccountId) AccountId(org.sagebionetworks.bridge.models.accounts.AccountId) EntityNotFoundException(org.sagebionetworks.bridge.exceptions.EntityNotFoundException) StatusMessage(org.sagebionetworks.bridge.models.StatusMessage) PostMapping(org.springframework.web.bind.annotation.PostMapping)

Example 24 with App

use of org.sagebionetworks.bridge.models.apps.App in project BridgeServer2 by Sage-Bionetworks.

the class CRCController method postProcedureRequest.

@PutMapping("/v1/cuimc/procedurerequests")
public ResponseEntity<StatusMessage> postProcedureRequest() {
    App app = httpBasicAuthentication();
    IParser parser = FHIR_CONTEXT.newJsonParser();
    JsonNode data = parseJson(JsonNode.class);
    ProcedureRequest procedure = parser.parseResource(ProcedureRequest.class, data.toString());
    String userId = findUserId(procedure.getSubject());
    int status = writeReportAndUpdateState(app, userId, data, PROCEDURE_REPORT, AccountStates.TESTS_COLLECTED, true);
    if (status == 200) {
        return ResponseEntity.ok(new StatusMessage("ProcedureRequest updated."));
    }
    return ResponseEntity.created(URI.create("/v1/cuimc/procedurerequests/" + userId)).body(new StatusMessage("ProcedureRequest created."));
}
Also used : App(org.sagebionetworks.bridge.models.apps.App) ProcedureRequest(org.hl7.fhir.dstu3.model.ProcedureRequest) JsonNode(com.fasterxml.jackson.databind.JsonNode) ContactPoint(org.hl7.fhir.dstu3.model.ContactPoint) IParser(ca.uhn.fhir.parser.IParser) StatusMessage(org.sagebionetworks.bridge.models.StatusMessage) PutMapping(org.springframework.web.bind.annotation.PutMapping)

Example 25 with App

use of org.sagebionetworks.bridge.models.apps.App in project BridgeServer2 by Sage-Bionetworks.

the class CRCController method httpBasicAuthentication.

/**
 * This is bound to specific “machine” accounts that are enumerated in the controller. Authentication is
 * session-less. The account itself has no administrative roles, so it can only execute these endpoints that
 * specifically allows it, in the app to which it is bound.
 */
App httpBasicAuthentication() {
    String value = request().getHeader(AUTHORIZATION);
    if (value == null || value.length() < 5) {
        throw new NotAuthenticatedException();
    }
    // Remove "Basic ";
    value = value.substring(5).trim();
    // Decode the credentials from base 64
    value = new String(Base64.getDecoder().decode(value), Charset.defaultCharset());
    // Split to username and password
    String[] credentials = value.split(":");
    if (credentials.length != 2) {
        throw new NotAuthenticatedException();
    }
    String appId = ACCOUNTS.get(credentials[0]);
    if (appId == null) {
        throw new NotAuthenticatedException();
    }
    SignIn.Builder signInBuilder = new SignIn.Builder().withAppId(appId).withPassword(credentials[1]);
    if (credentials[0].contains("@sagebase.org")) {
        signInBuilder.withEmail(credentials[0]);
    } else {
        signInBuilder.withExternalId(credentials[0]);
    }
    App app = appService.getApp(appId);
    // Verify the password
    SignIn signIn = signInBuilder.build();
    Account account = accountService.authenticate(app, signIn);
    // This method of verification sidesteps RequestContext initialization
    // through a session. Set up what is needed in the controller.
    Set<String> studies = BridgeUtils.collectStudyIds(account);
    RequestContext.Builder builder = new RequestContext.Builder().withCallerAppId(appId).withCallerRoles(account.getRoles()).withCallerUserId(account.getId()).withOrgSponsoredStudies(studies).withCallerOrgMembership(account.getOrgMembership());
    RequestContext.set(builder.build());
    return app;
}
Also used : App(org.sagebionetworks.bridge.models.apps.App) Account(org.sagebionetworks.bridge.models.accounts.Account) NotAuthenticatedException(org.sagebionetworks.bridge.exceptions.NotAuthenticatedException) SignIn(org.sagebionetworks.bridge.models.accounts.SignIn) RequestContext(org.sagebionetworks.bridge.RequestContext)

Aggregations

App (org.sagebionetworks.bridge.models.apps.App)389 Test (org.testng.annotations.Test)213 UserSession (org.sagebionetworks.bridge.models.accounts.UserSession)103 DynamoApp (org.sagebionetworks.bridge.dynamodb.DynamoApp)81 PostMapping (org.springframework.web.bind.annotation.PostMapping)74 StudyParticipant (org.sagebionetworks.bridge.models.accounts.StudyParticipant)65 Account (org.sagebionetworks.bridge.models.accounts.Account)57 GetMapping (org.springframework.web.bind.annotation.GetMapping)36 StatusMessage (org.sagebionetworks.bridge.models.StatusMessage)29 ResponseStatus (org.springframework.web.bind.annotation.ResponseStatus)28 EntityNotFoundException (org.sagebionetworks.bridge.exceptions.EntityNotFoundException)25 RequestContext (org.sagebionetworks.bridge.RequestContext)23 CriteriaContext (org.sagebionetworks.bridge.models.CriteriaContext)23 SignIn (org.sagebionetworks.bridge.models.accounts.SignIn)22 DateTime (org.joda.time.DateTime)20 BadRequestException (org.sagebionetworks.bridge.exceptions.BadRequestException)19 AccountId (org.sagebionetworks.bridge.models.accounts.AccountId)19 JsonNode (com.fasterxml.jackson.databind.JsonNode)18 StudyActivityEvent (org.sagebionetworks.bridge.models.activities.StudyActivityEvent)17 AppAndUsers (org.sagebionetworks.bridge.models.apps.AppAndUsers)16