Search in sources :

Example 21 with User

use of org.pmiops.workbench.db.model.User in project workbench by all-of-us.

the class ProfileController method initializeUserIfNeeded.

private User initializeUserIfNeeded() {
    UserAuthentication userAuthentication = userAuthenticationProvider.get();
    User user = userAuthentication.getUser();
    if (userAuthentication.getUserType() == UserType.SERVICE_ACCOUNT) {
        // Service accounts don't need further initialization.
        return user;
    }
    // On first sign-in, create a FC user, billing project, and set the first sign in time.
    if (user.getFirstSignInTime() == null) {
        // instead use the freeTierBillingProjectStatus.
        if (user.getFreeTierBillingProjectName() == null) {
            String billingProjectName = createFirecloudUserAndBillingProject(user);
            user.setFreeTierBillingProjectName(billingProjectName);
            user.setFreeTierBillingProjectStatus(BillingProjectStatus.PENDING);
        }
        user.setFirstSignInTime(new Timestamp(clock.instant().toEpochMilli()));
        try {
            return userDao.save(user);
        } catch (ObjectOptimisticLockingFailureException e) {
            log.log(Level.WARNING, "version conflict for user update", e);
            throw new ConflictException("Failed due to concurrent modification");
        }
    }
    // Free tier billing project setup is complete; nothing to do.
    if (BillingProjectStatus.READY.equals(user.getFreeTierBillingProjectStatus())) {
        return user;
    }
    // On subsequent sign-ins to the first, attempt to complete the setup of the FC billing project
    // and mark the Workbench's project setup as completed. FC project creation is asynchronous, so
    // first confirm whether Firecloud claims the project setup is complete.
    BillingProjectStatus status = null;
    try {
        status = fireCloudService.getBillingProjectMemberships().stream().filter(m -> user.getFreeTierBillingProjectName().equals(m.getProjectName())).map(m -> fcToWorkbenchBillingMap.get(m.getCreationStatus())).findFirst().orElse(BillingProjectStatus.NONE);
    } catch (ApiException e) {
        log.log(Level.WARNING, "failed to retrieve billing projects, continuing", e);
        return user;
    }
    switch(status) {
        case NONE:
        case PENDING:
            log.log(Level.INFO, "free tier project is still initializing, continuing");
            return user;
        case ERROR:
            log.log(Level.SEVERE, String.format("free tier project %s failed to be created", user.getFreeTierBillingProjectName()));
            user.setFreeTierBillingProjectStatus(status);
            return userDao.save(user);
        case READY:
            break;
        default:
            log.log(Level.SEVERE, String.format("unrecognized status '%s'", status));
            return user;
    }
    // notebooks.
    try {
        fireCloudService.grantGoogleRoleToUser(user.getFreeTierBillingProjectName(), FireCloudService.BIGQUERY_JOB_USER_GOOGLE_ROLE, user.getEmail());
    } catch (ApiException e) {
        log.log(Level.WARNING, "granting BigQuery role on created free tier billing project failed", e);
        // Allow the user to continue, as most workbench functionality will still be usable.
        return user;
    }
    log.log(Level.INFO, "free tier project initialized and BigQuery role granted");
    user.setFreeTierBillingProjectStatus(BillingProjectStatus.READY);
    return userDao.save(user);
}
Also used : Message(javax.mail.Message) ObjectOptimisticLockingFailureException(org.springframework.orm.ObjectOptimisticLockingFailureException) IdVerificationListResponse(org.pmiops.workbench.model.IdVerificationListResponse) Provider(javax.inject.Provider) MailChimpService(org.pmiops.workbench.mailchimp.MailChimpService) FireCloudService(org.pmiops.workbench.firecloud.FireCloudService) MessagingException(javax.mail.MessagingException) Autowired(org.springframework.beans.factory.annotation.Autowired) EmailException(org.pmiops.workbench.exceptions.EmailException) DirectoryService(org.pmiops.workbench.google.DirectoryService) Authority(org.pmiops.workbench.model.Authority) CreateAccountRequest(org.pmiops.workbench.model.CreateAccountRequest) Map(java.util.Map) CloudStorageService(org.pmiops.workbench.google.CloudStorageService) User(org.pmiops.workbench.db.model.User) Profile(org.pmiops.workbench.model.Profile) UserService(org.pmiops.workbench.db.dao.UserService) UserDao(org.pmiops.workbench.db.dao.UserDao) Transport(javax.mail.Transport) ImmutableMap(com.google.common.collect.ImmutableMap) Timestamp(java.sql.Timestamp) AuthorityRequired(org.pmiops.workbench.annotations.AuthorityRequired) InvitationVerificationRequest(org.pmiops.workbench.model.InvitationVerificationRequest) ConflictException(org.pmiops.workbench.exceptions.ConflictException) Logger(java.util.logging.Logger) Collectors(java.util.stream.Collectors) RestController(org.springframework.web.bind.annotation.RestController) List(java.util.List) Address(com.blockscore.models.Address) BillingProjectStatus(org.pmiops.workbench.model.BillingProjectStatus) WorkbenchEnvironment(org.pmiops.workbench.config.WorkbenchEnvironment) UnsupportedEncodingException(java.io.UnsupportedEncodingException) UserType(org.pmiops.workbench.auth.UserAuthentication.UserType) BillingProjectMembership(org.pmiops.workbench.model.BillingProjectMembership) UsernameTakenResponse(org.pmiops.workbench.model.UsernameTakenResponse) ApiException(org.pmiops.workbench.firecloud.ApiException) Function(java.util.function.Function) ArrayList(java.util.ArrayList) Level(java.util.logging.Level) InternetAddress(javax.mail.internet.InternetAddress) ProfileService(org.pmiops.workbench.auth.ProfileService) BadRequestException(org.pmiops.workbench.exceptions.BadRequestException) ExceptionUtils(org.pmiops.workbench.exceptions.ExceptionUtils) Properties(java.util.Properties) IdVerificationRequest(org.pmiops.workbench.model.IdVerificationRequest) IdVerificationReviewRequest(org.pmiops.workbench.model.IdVerificationReviewRequest) BlockscoreIdVerificationStatus(org.pmiops.workbench.model.BlockscoreIdVerificationStatus) IOException(java.io.IOException) MimeMessage(javax.mail.internet.MimeMessage) BlockscoreService(org.pmiops.workbench.blockscore.BlockscoreService) UserAuthentication(org.pmiops.workbench.auth.UserAuthentication) HttpStatus(org.springframework.http.HttpStatus) ServerErrorException(org.pmiops.workbench.exceptions.ServerErrorException) WorkbenchConfig(org.pmiops.workbench.config.WorkbenchConfig) Clock(java.time.Clock) Session(javax.mail.Session) EmailVerificationStatus(org.pmiops.workbench.model.EmailVerificationStatus) Person(com.blockscore.models.Person) ResponseEntity(org.springframework.http.ResponseEntity) CreationStatusEnum(org.pmiops.workbench.firecloud.model.BillingProjectMembership.CreationStatusEnum) BillingProjectStatus(org.pmiops.workbench.model.BillingProjectStatus) User(org.pmiops.workbench.db.model.User) ConflictException(org.pmiops.workbench.exceptions.ConflictException) UserAuthentication(org.pmiops.workbench.auth.UserAuthentication) Timestamp(java.sql.Timestamp) ObjectOptimisticLockingFailureException(org.springframework.orm.ObjectOptimisticLockingFailureException) ApiException(org.pmiops.workbench.firecloud.ApiException)

Example 22 with User

use of org.pmiops.workbench.db.model.User in project workbench by all-of-us.

the class WorkspacesController method cloneWorkspace.

@Override
public ResponseEntity<CloneWorkspaceResponse> cloneWorkspace(String workspaceNamespace, String workspaceId, CloneWorkspaceRequest body) {
    Workspace workspace = body.getWorkspace();
    if (Strings.isNullOrEmpty(workspace.getNamespace())) {
        throw new BadRequestException("missing required field 'workspace.namespace'");
    } else if (Strings.isNullOrEmpty(workspace.getName())) {
        throw new BadRequestException("missing required field 'workspace.name'");
    } else if (workspace.getResearchPurpose() == null) {
        throw new BadRequestException("missing required field 'workspace.researchPurpose'");
    }
    User user = userProvider.get();
    if (workspaceService.getByName(workspace.getNamespace(), workspace.getName()) != null) {
        throw new ConflictException(String.format("Workspace %s/%s already exists", workspace.getNamespace(), workspace.getName()));
    }
    // Retrieving the workspace is done first, which acts as an access check.
    String fromBucket = null;
    try {
        fromBucket = fireCloudService.getWorkspace(workspaceNamespace, workspaceId).getWorkspace().getBucketName();
    } catch (ApiException e) {
        if (e.getCode() == 404) {
            log.log(Level.INFO, "Firecloud workspace not found", e);
            throw new NotFoundException(String.format("workspace %s/%s not found or not accessible", workspaceNamespace, workspaceId));
        }
        log.log(Level.SEVERE, "Firecloud server error", e);
        throw new ServerErrorException();
    }
    org.pmiops.workbench.db.model.Workspace fromWorkspace = workspaceService.getRequiredWithCohorts(workspaceNamespace, workspaceId);
    if (fromWorkspace == null) {
        throw new NotFoundException(String.format("Workspace %s/%s not found", workspaceNamespace, workspaceId));
    }
    FirecloudWorkspaceId fcWorkspaceId = generateFirecloudWorkspaceId(workspace.getNamespace(), workspace.getName());
    fireCloudService.cloneWorkspace(workspaceNamespace, workspaceId, fcWorkspaceId.getWorkspaceNamespace(), fcWorkspaceId.getWorkspaceName());
    org.pmiops.workbench.firecloud.model.Workspace toFcWorkspace = null;
    try {
        toFcWorkspace = fireCloudService.getWorkspace(fcWorkspaceId.getWorkspaceNamespace(), fcWorkspaceId.getWorkspaceName()).getWorkspace();
    } catch (ApiException e) {
        log.log(Level.SEVERE, "Firecloud error retrieving newly cloned workspace", e);
        throw new ServerErrorException();
    }
    // feasibly copy within a single API request.
    for (Blob b : cloudStorageService.getBlobList(fromBucket, NOTEBOOKS_WORKSPACE_DIRECTORY)) {
        if (!NOTEBOOK_PATTERN.matcher(b.getName()).matches()) {
            continue;
        }
        if (b.getSize() != null && b.getSize() / 1e6 > MAX_NOTEBOOK_SIZE_MB) {
            throw new FailedPreconditionException(String.format("workspace %s/%s contains a notebook larger than %dMB: '%s'; cannot clone - please " + "remove this notebook, reduce its size, or contact the workspace owner", workspaceNamespace, workspaceId, MAX_NOTEBOOK_SIZE_MB, b.getName()));
        }
        cloudStorageService.copyBlob(b.getBlobId(), BlobId.of(toFcWorkspace.getBucketName(), b.getName()));
    }
    // The final step in the process is to clone the AoU representation of the
    // workspace. The implication here is that we may generate orphaned
    // Firecloud workspaces / buckets, but a user should not be able to see
    // half-way cloned workspaces via AoU - so it will just appear as a
    // transient failure.
    org.pmiops.workbench.db.model.Workspace toWorkspace = FROM_CLIENT_WORKSPACE.apply(body.getWorkspace());
    org.pmiops.workbench.db.model.Workspace dbWorkspace = new org.pmiops.workbench.db.model.Workspace();
    Timestamp now = new Timestamp(clock.instant().toEpochMilli());
    dbWorkspace.setFirecloudName(fcWorkspaceId.getWorkspaceName());
    dbWorkspace.setWorkspaceNamespace(fcWorkspaceId.getWorkspaceNamespace());
    dbWorkspace.setCreator(user);
    dbWorkspace.setCreationTime(now);
    dbWorkspace.setLastModifiedTime(now);
    dbWorkspace.setVersion(1);
    dbWorkspace.setName(toWorkspace.getName());
    ResearchPurpose researchPurpose = body.getWorkspace().getResearchPurpose();
    setResearchPurposeDetails(dbWorkspace, researchPurpose);
    if (researchPurpose.getReviewRequested()) {
        // Use a consistent timestamp.
        dbWorkspace.setTimeRequested(now);
    }
    dbWorkspace.setReviewRequested(researchPurpose.getReviewRequested());
    // Clone the previous description, by default.
    if (Strings.isNullOrEmpty(toWorkspace.getDescription())) {
        dbWorkspace.setDescription(fromWorkspace.getDescription());
    } else {
        dbWorkspace.setDescription(toWorkspace.getDescription());
    }
    dbWorkspace.setCdrVersion(fromWorkspace.getCdrVersion());
    dbWorkspace.setDataAccessLevel(fromWorkspace.getDataAccessLevel());
    writeWorkspaceConfigFile(toFcWorkspace, dbWorkspace.getCdrVersion());
    org.pmiops.workbench.db.model.WorkspaceUserRole permissions = new org.pmiops.workbench.db.model.WorkspaceUserRole();
    permissions.setRole(WorkspaceAccessLevel.OWNER);
    permissions.setWorkspace(dbWorkspace);
    permissions.setUser(user);
    dbWorkspace.addWorkspaceUserRole(permissions);
    dbWorkspace = workspaceService.saveAndCloneCohorts(fromWorkspace, dbWorkspace);
    CloneWorkspaceResponse resp = new CloneWorkspaceResponse();
    resp.setWorkspace(TO_SINGLE_CLIENT_WORKSPACE_FROM_FC_AND_DB.apply(dbWorkspace, toFcWorkspace));
    return ResponseEntity.ok(resp);
}
Also used : Blob(com.google.cloud.storage.Blob) User(org.pmiops.workbench.db.model.User) ConflictException(org.pmiops.workbench.exceptions.ConflictException) NotFoundException(org.pmiops.workbench.exceptions.NotFoundException) WorkspaceUserRole(org.pmiops.workbench.db.model.WorkspaceUserRole) Timestamp(java.sql.Timestamp) FirecloudWorkspaceId(org.pmiops.workbench.db.model.Workspace.FirecloudWorkspaceId) CloneWorkspaceResponse(org.pmiops.workbench.model.CloneWorkspaceResponse) FailedPreconditionException(org.pmiops.workbench.exceptions.FailedPreconditionException) BadRequestException(org.pmiops.workbench.exceptions.BadRequestException) ServerErrorException(org.pmiops.workbench.exceptions.ServerErrorException) WorkspaceUserRole(org.pmiops.workbench.db.model.WorkspaceUserRole) Workspace(org.pmiops.workbench.model.Workspace) ApiException(org.pmiops.workbench.firecloud.ApiException) ResearchPurpose(org.pmiops.workbench.model.ResearchPurpose)

Example 23 with User

use of org.pmiops.workbench.db.model.User in project workbench by all-of-us.

the class WorkspacesController method getWorkspaces.

@Override
public ResponseEntity<WorkspaceResponseListResponse> getWorkspaces() {
    // TODO: use FireCloud to determine what workspaces to return, instead of just returning
    // workspaces from our database.
    User user = userProvider.get();
    List<WorkspaceResponse> responseList = new ArrayList<WorkspaceResponse>();
    if (user != null) {
        for (WorkspaceUserRole userRole : user.getWorkspaceUserRoles()) {
            // TODO: Use FireCloud to determine access roles, not our DB
            WorkspaceResponse currentWorkspace = new WorkspaceResponse();
            currentWorkspace.setWorkspace(TO_CLIENT_WORKSPACE.apply(userRole.getWorkspace()));
            currentWorkspace.setAccessLevel(userRole.getRole());
            responseList.add(currentWorkspace);
        }
    }
    WorkspaceResponseListResponse response = new WorkspaceResponseListResponse();
    response.setItems(responseList);
    return ResponseEntity.ok(response);
}
Also used : ShareWorkspaceResponse(org.pmiops.workbench.model.ShareWorkspaceResponse) CloneWorkspaceResponse(org.pmiops.workbench.model.CloneWorkspaceResponse) WorkspaceResponse(org.pmiops.workbench.model.WorkspaceResponse) User(org.pmiops.workbench.db.model.User) WorkspaceResponseListResponse(org.pmiops.workbench.model.WorkspaceResponseListResponse) ArrayList(java.util.ArrayList) WorkspaceUserRole(org.pmiops.workbench.db.model.WorkspaceUserRole)

Example 24 with User

use of org.pmiops.workbench.db.model.User in project workbench by all-of-us.

the class WorkspacesController method shareWorkspace.

@Override
public ResponseEntity<ShareWorkspaceResponse> shareWorkspace(String workspaceNamespace, String workspaceId, ShareWorkspaceRequest request) {
    if (Strings.isNullOrEmpty(request.getWorkspaceEtag())) {
        throw new BadRequestException("Missing required update field 'workspaceEtag'");
    }
    org.pmiops.workbench.db.model.Workspace dbWorkspace = workspaceService.getRequired(workspaceNamespace, workspaceId);
    int version = Etags.toVersion(request.getWorkspaceEtag());
    if (dbWorkspace.getVersion() != version) {
        throw new ConflictException("Attempted to modify user roles with outdated workspace etag");
    }
    Set<WorkspaceUserRole> dbUserRoles = new HashSet<WorkspaceUserRole>();
    for (UserRole user : request.getItems()) {
        WorkspaceUserRole newUserRole = new WorkspaceUserRole();
        User newUser = userDao.findUserByEmail(user.getEmail());
        if (newUser == null) {
            throw new BadRequestException(String.format("User %s doesn't exist", user.getEmail()));
        }
        newUserRole.setUser(newUser);
        newUserRole.setRole(user.getRole());
        dbUserRoles.add(newUserRole);
    }
    // This automatically enforces owner role.
    dbWorkspace = workspaceService.updateUserRoles(dbWorkspace, dbUserRoles);
    ShareWorkspaceResponse resp = new ShareWorkspaceResponse();
    resp.setWorkspaceEtag(Etags.fromVersion(dbWorkspace.getVersion()));
    return ResponseEntity.ok(resp);
}
Also used : ShareWorkspaceResponse(org.pmiops.workbench.model.ShareWorkspaceResponse) User(org.pmiops.workbench.db.model.User) ConflictException(org.pmiops.workbench.exceptions.ConflictException) WorkspaceUserRole(org.pmiops.workbench.db.model.WorkspaceUserRole) WorkspaceUserRole(org.pmiops.workbench.db.model.WorkspaceUserRole) UserRole(org.pmiops.workbench.model.UserRole) BadRequestException(org.pmiops.workbench.exceptions.BadRequestException) HashSet(java.util.HashSet)

Example 25 with User

use of org.pmiops.workbench.db.model.User in project workbench by all-of-us.

the class ProfileService method getProfile.

public Profile getProfile(User user) throws ApiException {
    // Fetch the user's authorities, since they aren't loaded during normal request interception.
    User userWithAuthorities = userDao.findUserWithAuthorities(user.getUserId());
    if (userWithAuthorities != null) {
        // If the user is already written to the database, use it and whatever authorities are there.
        user = userWithAuthorities;
    }
    boolean enabledInFireCloud = fireCloudService.isRequesterEnabledInFirecloud();
    Profile profile = new Profile();
    profile.setUserId(user.getUserId());
    profile.setUsername(user.getEmail());
    profile.setFamilyName(user.getFamilyName());
    profile.setGivenName(user.getGivenName());
    profile.setContactEmail(user.getContactEmail());
    profile.setPhoneNumber(user.getPhoneNumber());
    profile.setFreeTierBillingProjectName(user.getFreeTierBillingProjectName());
    profile.setFreeTierBillingProjectStatus(user.getFreeTierBillingProjectStatus());
    profile.setEnabledInFireCloud(enabledInFireCloud);
    if (user.getBlockscoreVerificationIsValid() == null) {
        profile.setBlockscoreIdVerificationStatus(BlockscoreIdVerificationStatus.UNVERIFIED);
    } else if (user.getBlockscoreVerificationIsValid() == false) {
        profile.setBlockscoreIdVerificationStatus(BlockscoreIdVerificationStatus.REJECTED);
    } else {
        profile.setBlockscoreIdVerificationStatus(BlockscoreIdVerificationStatus.VERIFIED);
    }
    if (user.getTermsOfServiceCompletionTime() != null) {
        profile.setTermsOfServiceCompletionTime(user.getTermsOfServiceCompletionTime().getTime());
    }
    if (user.getEthicsTrainingCompletionTime() != null) {
        profile.setEthicsTrainingCompletionTime(user.getEthicsTrainingCompletionTime().getTime());
    }
    if (user.getDemographicSurveyCompletionTime() != null) {
        profile.setDemographicSurveyCompletionTime(user.getDemographicSurveyCompletionTime().getTime());
    }
    if (user.getDataAccessLevel() != null) {
        profile.setDataAccessLevel(user.getDataAccessLevel());
    }
    if (user.getAuthorities() != null) {
        profile.setAuthorities(new ArrayList<>(user.getAuthorities()));
    }
    EmailVerificationStatus userEmailVerificationStatus = user.getEmailVerificationStatus();
    // if verification is pending or unverified, need to query MailChimp and update DB accordingly
    if (!userEmailVerificationStatus.equals(EmailVerificationStatus.SUBSCRIBED)) {
        if (userEmailVerificationStatus.equals(EmailVerificationStatus.UNVERIFIED) && user.getContactEmail() != null) {
            mailChimpService.addUserContactEmail(user.getContactEmail());
            userEmailVerificationStatus = EmailVerificationStatus.PENDING;
        } else if (userEmailVerificationStatus.equals(EmailVerificationStatus.PENDING)) {
            userEmailVerificationStatus = EmailVerificationStatus.fromValue(mailChimpService.getMember(user.getContactEmail()));
        }
        user.setEmailVerificationStatus(userEmailVerificationStatus);
        userDao.save(user);
    }
    profile.setEmailVerificationStatus(user.getEmailVerificationStatus());
    return profile;
}
Also used : User(org.pmiops.workbench.db.model.User) EmailVerificationStatus(org.pmiops.workbench.model.EmailVerificationStatus) Profile(org.pmiops.workbench.model.Profile)

Aggregations

User (org.pmiops.workbench.db.model.User)27 Test (org.junit.Test)8 Workspace (org.pmiops.workbench.model.Workspace)8 ApiException (org.pmiops.workbench.firecloud.ApiException)7 DataJpaTest (org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest)6 ResearchPurpose (org.pmiops.workbench.model.ResearchPurpose)5 Before (org.junit.Before)4 AuthorityRequired (org.pmiops.workbench.annotations.AuthorityRequired)4 WorkspaceUserRole (org.pmiops.workbench.db.model.WorkspaceUserRole)4 BadRequestException (org.pmiops.workbench.exceptions.BadRequestException)4 ConflictException (org.pmiops.workbench.exceptions.ConflictException)4 ShareWorkspaceResponse (org.pmiops.workbench.model.ShareWorkspaceResponse)4 UserRole (org.pmiops.workbench.model.UserRole)4 Timestamp (java.sql.Timestamp)3 ArrayList (java.util.ArrayList)3 CdrVersion (org.pmiops.workbench.db.model.CdrVersion)3 WorkspaceACLUpdate (org.pmiops.workbench.firecloud.model.WorkspaceACLUpdate)3 WorkspaceACLUpdateResponseList (org.pmiops.workbench.firecloud.model.WorkspaceACLUpdateResponseList)3 Profile (org.pmiops.workbench.model.Profile)3 ShareWorkspaceRequest (org.pmiops.workbench.model.ShareWorkspaceRequest)3