From fbd2e372876fc7a2899697b61235f3ccb0606d69 Mon Sep 17 00:00:00 2001 From: Joel Thibault Date: Thu, 7 Nov 2024 15:12:52 -0500 Subject: [PATCH 1/2] WIP API --- .../pmiops/workbench/db/model/DbWorkspace.java | 15 --------------- .../InitialCreditsExpirationServiceImpl.java | 0 .../initialcredits/InitialCreditsService.java | 8 ++------ .../workspaces/WorkspaceServiceImpl.java | 10 ++++------ ...oudTaskInitialCreditsExpiryControllerTest.java | 7 +------ .../workbench/api/WorkspacesControllerTest.java | 7 ------- .../initialcredits/InitialCreditsServiceTest.java | 9 +++------ .../utils/mappers/WorkspaceMapperTest.java | 8 +++++--- 8 files changed, 15 insertions(+), 49 deletions(-) create mode 100644 api/src/main/java/org/pmiops/workbench/initialcredits/InitialCreditsExpirationServiceImpl.java diff --git a/api/src/main/java/org/pmiops/workbench/db/model/DbWorkspace.java b/api/src/main/java/org/pmiops/workbench/db/model/DbWorkspace.java index 7c04b617736..3db9b55ae47 100644 --- a/api/src/main/java/org/pmiops/workbench/db/model/DbWorkspace.java +++ b/api/src/main/java/org/pmiops/workbench/db/model/DbWorkspace.java @@ -27,7 +27,6 @@ import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.pmiops.workbench.db.model.DbFeaturedWorkspace.DbFeaturedCategory; -import org.pmiops.workbench.model.BillingStatus; import org.pmiops.workbench.model.DisseminateResearchEnum; import org.pmiops.workbench.model.ResearchOutcomeEnum; import org.pmiops.workbench.model.SpecificPopulationEnum; @@ -84,7 +83,6 @@ public class DbWorkspace { private Boolean reviewRequested; private Boolean approved; private Timestamp timeRequested; - private Short billingStatus = DbStorageEnums.billingStatusToStorage(BillingStatus.ACTIVE); private String billingAccountName; private String googleProject; private boolean adminLocked; @@ -638,19 +636,6 @@ public boolean isActive() { return WorkspaceActiveStatus.ACTIVE.equals(getWorkspaceActiveStatusEnum()); } - @Deprecated(since = "September 2024", forRemoval = true) - @Column(name = "billing_status") - public BillingStatus getBillingStatus() { - return (initialCreditsExhausted || initialCreditsExpired - ? BillingStatus.INACTIVE - : BillingStatus.ACTIVE); - } - - public DbWorkspace setBillingStatus(BillingStatus billingStatus) { - this.billingStatus = DbStorageEnums.billingStatusToStorage(billingStatus); - return this; - } - @Column(name = "billing_account_name") public String getBillingAccountName() { return billingAccountName; diff --git a/api/src/main/java/org/pmiops/workbench/initialcredits/InitialCreditsExpirationServiceImpl.java b/api/src/main/java/org/pmiops/workbench/initialcredits/InitialCreditsExpirationServiceImpl.java new file mode 100644 index 00000000000..e69de29bb2d diff --git a/api/src/main/java/org/pmiops/workbench/initialcredits/InitialCreditsService.java b/api/src/main/java/org/pmiops/workbench/initialcredits/InitialCreditsService.java index f353cc32893..9089913b914 100644 --- a/api/src/main/java/org/pmiops/workbench/initialcredits/InitialCreditsService.java +++ b/api/src/main/java/org/pmiops/workbench/initialcredits/InitialCreditsService.java @@ -38,6 +38,7 @@ import org.pmiops.workbench.leonardo.LeonardoApiClient; import org.pmiops.workbench.mail.MailService; import org.pmiops.workbench.model.BillingStatus; +import org.pmiops.workbench.initialcredits.InitialCreditsExpirationService; import org.pmiops.workbench.utils.BillingUtils; import org.pmiops.workbench.utils.CostComparisonUtils; import org.slf4j.Logger; @@ -485,12 +486,7 @@ private void setAllToUnexhausted(final DbUser user) { ws -> BillingUtils.isInitialCredits( ws.getBillingAccountName(), workbenchConfigProvider.get())) - .forEach( - ws -> { - ws.setInitialCreditsExhausted(false); - ws.setBillingStatus(BillingStatus.ACTIVE); - workspaceDao.save(ws); - }); + .forEach(ws -> workspaceDao.save(ws.setInitialCreditsExhausted(false))); } /** diff --git a/api/src/main/java/org/pmiops/workbench/workspaces/WorkspaceServiceImpl.java b/api/src/main/java/org/pmiops/workbench/workspaces/WorkspaceServiceImpl.java index 1d053d35926..cad62a51135 100644 --- a/api/src/main/java/org/pmiops/workbench/workspaces/WorkspaceServiceImpl.java +++ b/api/src/main/java/org/pmiops/workbench/workspaces/WorkspaceServiceImpl.java @@ -509,12 +509,15 @@ public void updateWorkspaceBillingAccount(DbWorkspace workspace, String newBilli initialCreditsService.userHasRemainingFreeTierCredits(creator); workspace.setBillingStatus( hasInitialCreditsRemaining ? BillingStatus.ACTIVE : BillingStatus.INACTIVE); + freeTierBillingService.userHasRemainingFreeTierCredits(creator); workspace.setInitialCreditsExhausted(!hasInitialCreditsRemaining); workspace.setInitialCreditsExpired(initialCreditsService.areUserCreditsExpired(creator)); } else { // At this point, we can assume that a user provided billing account is open since we // throw a BadRequestException if a closed one is provided workspace.setBillingStatus(BillingStatus.ACTIVE); + workspace.setInitialCreditsExpired( + initialCreditsExpirationService.haveCreditsExpired(creator)); } } @@ -616,12 +619,7 @@ public void cloneTanagraFeatureSet( public void updateInitialCreditsExhaustion(DbUser user, boolean exhausted) { workspaceDao.findAllByCreator(user).stream() .filter(ws -> isInitialCredits(ws.getBillingAccountName(), workbenchConfigProvider.get())) - .forEach( - ws -> { - ws.setInitialCreditsExhausted(exhausted); - ws.setBillingStatus(exhausted ? BillingStatus.INACTIVE : BillingStatus.ACTIVE); - workspaceDao.save(ws); - }); + .forEach(ws -> workspaceDao.save(ws.setInitialCreditsExhausted(exhausted))); } @Override diff --git a/api/src/test/java/org/pmiops/workbench/api/CloudTaskInitialCreditsExpiryControllerTest.java b/api/src/test/java/org/pmiops/workbench/api/CloudTaskInitialCreditsExpiryControllerTest.java index f1372058e98..4bffab7d6d7 100644 --- a/api/src/test/java/org/pmiops/workbench/api/CloudTaskInitialCreditsExpiryControllerTest.java +++ b/api/src/test/java/org/pmiops/workbench/api/CloudTaskInitialCreditsExpiryControllerTest.java @@ -48,7 +48,6 @@ import org.pmiops.workbench.institution.InstitutionService; import org.pmiops.workbench.leonardo.LeonardoApiClient; import org.pmiops.workbench.mail.MailService; -import org.pmiops.workbench.model.BillingStatus; import org.pmiops.workbench.model.ExpiredInitialCreditsEventRequest; import org.pmiops.workbench.model.WorkspaceActiveStatus; import org.pmiops.workbench.test.FakeClock; @@ -569,10 +568,7 @@ public void handleInitialCreditsExpiry_singleAlert_forExhaustedAndByoBilling() t // Simulate the user attaching their own billing account to the previously free tier workspace. workspace = workspaceDao.findDbWorkspaceByWorkspaceId(workspace.getWorkspaceId()); - workspaceDao.save( - workspace - .setBillingAccountName(fullBillingAccountName("byo-account")) - .setBillingStatus(BillingStatus.ACTIVE)); + workspaceDao.save(workspace.setBillingAccountName(fullBillingAccountName("byo-account"))); cloudTaskInitialCreditsExpiryController.handleInitialCreditsExpiry( buildExpiredInitialCreditsEventRequest( @@ -594,7 +590,6 @@ public void handleInitialCreditsExpiry_singleAlert_forExhaustedAndByoBilling() t .setWorkspaceNamespace("some other namespace") .setGoogleProject("other project") .setBillingAccountName("some other account") - .setBillingStatus(BillingStatus.ACTIVE) .setInitialCreditsExhausted(false); workspaceDao.save(userAccountWorkspace); diff --git a/api/src/test/java/org/pmiops/workbench/api/WorkspacesControllerTest.java b/api/src/test/java/org/pmiops/workbench/api/WorkspacesControllerTest.java index a836b330496..7ffc0a1d3d7 100644 --- a/api/src/test/java/org/pmiops/workbench/api/WorkspacesControllerTest.java +++ b/api/src/test/java/org/pmiops/workbench/api/WorkspacesControllerTest.java @@ -140,7 +140,6 @@ import org.pmiops.workbench.mail.MailService; import org.pmiops.workbench.model.AnnotationType; import org.pmiops.workbench.model.ArchivalStatus; -import org.pmiops.workbench.model.BillingStatus; import org.pmiops.workbench.model.CloneWorkspaceRequest; import org.pmiops.workbench.model.Cohort; import org.pmiops.workbench.model.CohortAnnotationDefinition; @@ -1173,12 +1172,6 @@ public void testUpdateWorkspace_freeTierBilling_hasCreditsRemaining() { Workspace workspace = createWorkspace(); workspace = workspacesController.createWorkspace(workspace).getBody(); - DbWorkspace dbWorkspace = - workspaceDao.findByWorkspaceNamespaceAndFirecloudNameAndActiveStatus( - workspace.getNamespace(), - workspace.getTerraName(), - DbStorageEnums.workspaceActiveStatusToStorage(WorkspaceActiveStatus.ACTIVE)); - dbWorkspace.setBillingStatus(BillingStatus.INACTIVE); doReturn(true) .when(mockInitialCreditsService) .userHasRemainingFreeTierCredits( diff --git a/api/src/test/java/org/pmiops/workbench/initialcredits/InitialCreditsServiceTest.java b/api/src/test/java/org/pmiops/workbench/initialcredits/InitialCreditsServiceTest.java index d62ef6bc629..ddc23a12f5d 100644 --- a/api/src/test/java/org/pmiops/workbench/initialcredits/InitialCreditsServiceTest.java +++ b/api/src/test/java/org/pmiops/workbench/initialcredits/InitialCreditsServiceTest.java @@ -67,6 +67,7 @@ import org.pmiops.workbench.leonardo.LeonardoApiClient; import org.pmiops.workbench.mail.MailService; import org.pmiops.workbench.model.BillingStatus; +import org.pmiops.workbench.initialcredits.InitialCreditsExpirationService; import org.pmiops.workbench.model.WorkspaceActiveStatus; import org.pmiops.workbench.test.FakeClock; import org.springframework.beans.factory.annotation.Autowired; @@ -627,10 +628,7 @@ public void checkFreeTierBillingUsage_singleAlertForExhaustedAndByoBilling() { // Simulate the user attaching their own billing account to the previously free tier workspace. TestTransaction.start(); workspace = workspaceDao.findDbWorkspaceByWorkspaceId(workspace.getWorkspaceId()); - workspaceDao.save( - workspace - .setBillingAccountName(fullBillingAccountName("byo-account")) - .setBillingStatus(BillingStatus.ACTIVE)); + workspaceDao.save(workspace.setBillingAccountName(fullBillingAccountName("byo-account"))); commitTransaction(); } @@ -770,8 +768,7 @@ public void test_disableOnlyFreeTierWorkspaces() { .setCreator(user) .setWorkspaceNamespace("some other namespace") .setGoogleProject("other project") - .setBillingAccountName("some other account") - .setBillingStatus(BillingStatus.ACTIVE); + .setBillingAccountName("some other account"); workspaceDao.save(userAccountWorkspace); commitTransaction(); diff --git a/api/src/test/java/org/pmiops/workbench/utils/mappers/WorkspaceMapperTest.java b/api/src/test/java/org/pmiops/workbench/utils/mappers/WorkspaceMapperTest.java index dfdf7f2274e..7a31194e39d 100644 --- a/api/src/test/java/org/pmiops/workbench/utils/mappers/WorkspaceMapperTest.java +++ b/api/src/test/java/org/pmiops/workbench/utils/mappers/WorkspaceMapperTest.java @@ -35,7 +35,6 @@ import org.pmiops.workbench.institution.InstitutionService; import org.pmiops.workbench.leonardo.LeonardoApiClient; import org.pmiops.workbench.mail.MailService; -import org.pmiops.workbench.model.BillingStatus; import org.pmiops.workbench.model.FeaturedWorkspaceCategory; import org.pmiops.workbench.model.ResearchOutcomeEnum; import org.pmiops.workbench.model.ResearchPurpose; @@ -171,13 +170,14 @@ public void setUp() { .setReviewRequested(false) .setApproved(true) .setTimeRequested(DB_CREATION_TIMESTAMP) - .setBillingStatus(BillingStatus.ACTIVE) .setBillingAccountName(BILLING_ACCOUNT_NAME) .setSpecificPopulationsEnum(SPECIFIC_POPULATIONS) .setResearchOutcomeEnumSet(RESEARCH_OUTCOMES) .setDisseminateResearchEnumSet(Collections.emptySet()) .setDisseminateResearchOther(DISSEMINATE_FINDINGS_OTHER) - .setGoogleProject(GOOGLE_PROJECT); + .setGoogleProject(GOOGLE_PROJECT) + .setInitialCreditsExpired(false) + .setInitialCreditsExhausted(false); } @Test @@ -194,6 +194,8 @@ public void testConvertsDbToApiWorkspace() { assertThat(ws.getCreator()).isEqualTo(CREATOR_EMAIL); assertThat(ws.getInitialCredits().getExpirationEpochMillis()) .isEqualTo(INITIAL_CREDITS_EXPIRATION_TIMESTAMP.getTime()); + assertThat(ws.getInitialCredits().isExhausted()).isFalse(); + assertThat(ws.getInitialCredits().isExpired()).isFalse(); assertThat(ws.getGoogleBucketName()).isEqualTo(FIRECLOUD_BUCKET_NAME); assertThat(ws.getBillingAccountName()).isEqualTo(BILLING_ACCOUNT_NAME); assertThat(ws.getAccessTierShortName()).isEqualTo(ACCESS_TIER_SHORT_NAME); From 1293a4405471ebe47c9ffcd2dc50352b16a6a049 Mon Sep 17 00:00:00 2001 From: Joel Thibault Date: Tue, 26 Nov 2024 10:56:52 -0500 Subject: [PATCH 2/2] wip --- .../workbench/workspaces/resources/WorkspaceResourceMapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/org/pmiops/workbench/workspaces/resources/WorkspaceResourceMapper.java b/api/src/main/java/org/pmiops/workbench/workspaces/resources/WorkspaceResourceMapper.java index 16b70737ebc..7e5417d612c 100644 --- a/api/src/main/java/org/pmiops/workbench/workspaces/resources/WorkspaceResourceMapper.java +++ b/api/src/main/java/org/pmiops/workbench/workspaces/resources/WorkspaceResourceMapper.java @@ -42,9 +42,9 @@ FirecloudMapper.class, }) public interface WorkspaceResourceMapper { + @Mapping(target = "workspaceBillingStatus", ignore = true) @Mapping(target = "workspaceId", source = "dbWorkspace.workspaceId") @Mapping(target = "workspaceFirecloudName", source = "dbWorkspace.firecloudName") - @Mapping(target = "workspaceBillingStatus", source = "dbWorkspace.billingStatus") @Mapping(target = "cdrVersionId", source = "dbWorkspace.cdrVersion") @Mapping(target = "accessTierShortName", source = "dbWorkspace.cdrVersion.accessTier.shortName") WorkspaceFields fromWorkspace(DbWorkspace dbWorkspace);