This is an automated email from the ASF dual-hosted git repository. ofuks pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/incubator-dlab.git
The following commit(s) were added to refs/heads/develop by this push: new 6546373 [DLAB-1901] Added support for quota per month 6546373 is described below commit 6546373dfa3effbb4b507f27e54d745edd8cc340 Author: Oleh Fuks <olegfuk...@gmail.com> AuthorDate: Fri Jul 3 15:55:19 2020 +0300 [DLAB-1901] Added support for quota per month --- .../epam/dlab/backendapi/dao/BaseBillingDAO.java | 28 +++++++++++++++- .../com/epam/dlab/backendapi/dao/BillingDAO.java | 3 ++ .../com/epam/dlab/backendapi/dao/ProjectDAO.java | 2 +- .../epam/dlab/backendapi/dao/ProjectDAOImpl.java | 15 +++++++-- .../com/epam/dlab/backendapi/domain/BudgetDTO.java | 34 +++++++++++++++++++ .../epam/dlab/backendapi/domain/ProjectDTO.java | 2 +- .../backendapi/domain/UpdateProjectBudgetDTO.java | 3 ++ .../dlab/backendapi/resources/ProjectResource.java | 13 ++++---- .../service/impl/ProjectServiceImpl.java | 38 +++++++++++++++------- 9 files changed, 115 insertions(+), 23 deletions(-) diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BaseBillingDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BaseBillingDAO.java index 28a6c64..0e21bba 100644 --- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BaseBillingDAO.java +++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BaseBillingDAO.java @@ -20,8 +20,10 @@ package com.epam.dlab.backendapi.dao; import com.epam.dlab.backendapi.domain.BillingReportLine; +import com.epam.dlab.backendapi.domain.BudgetDTO; import com.epam.dlab.backendapi.resources.dto.BillingFilter; import com.epam.dlab.dto.billing.BillingResourceType; +import com.epam.dlab.exceptions.ResourceNotFoundException; import com.google.inject.Inject; import com.mongodb.client.model.Aggregates; import com.mongodb.client.model.Filters; @@ -32,6 +34,7 @@ import org.bson.Document; import org.bson.conversions.Bson; import java.math.BigDecimal; +import java.time.LocalDate; import java.time.ZoneId; import java.util.ArrayList; import java.util.Arrays; @@ -53,6 +56,8 @@ import static com.mongodb.client.model.Filters.gte; import static com.mongodb.client.model.Filters.in; import static com.mongodb.client.model.Filters.lte; import static com.mongodb.client.model.Filters.regex; +import static java.time.temporal.TemporalAdjusters.firstDayOfMonth; +import static java.time.temporal.TemporalAdjusters.lastDayOfMonth; import static java.util.Collections.singletonList; @Slf4j @@ -103,6 +108,18 @@ public class BaseBillingDAO extends BaseDAO implements BillingDAO { } @Override + public Double getProjectCost(String project, LocalDate date) { + final List<Bson> pipeline = Arrays.asList(match( + and( + eq(PROJECT, project), + gte(USAGE_DATE, date.with(firstDayOfMonth()).toString()), + lte(USAGE_DATE, date.with(lastDayOfMonth()).toString())) + ), + group(null, sum(TOTAL_FIELD_NAME, COST_FIELD))); + return aggregateBillingData(pipeline); + } + + @Override public int getBillingQuoteUsed() { return toPercentage(() -> settings.getMaxBudget(), getTotalCost()); } @@ -127,7 +144,12 @@ public class BaseBillingDAO extends BaseDAO implements BillingDAO { @Override public boolean isProjectQuoteReached(String project) { - final Double projectCost = getProjectCost(project); + final boolean monthlyBudget = Optional.ofNullable(projectDAO.get(project) + .orElseThrow(projectNotFound()) + .getBudget()) + .map(BudgetDTO::isMonthlyBudget) + .orElse(Boolean.FALSE); + final Double projectCost = monthlyBudget ? getProjectCost(project, LocalDate.now()) : getProjectCost(project); return projectDAO.getAllowedBudget(project) .filter(allowedBudget -> projectCost.intValue() != 0 && allowedBudget <= projectCost) .isPresent(); @@ -240,4 +262,8 @@ public class BaseBillingDAO extends BaseDAO implements BillingDAO { .currency(id.getString(CURRENCY)) .build(); } + + private Supplier<ResourceNotFoundException> projectNotFound() { + return () -> new ResourceNotFoundException("Project with passed name not found"); + } } diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BillingDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BillingDAO.java index 67630cd..da1c9a7 100644 --- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BillingDAO.java +++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BillingDAO.java @@ -21,6 +21,7 @@ package com.epam.dlab.backendapi.dao; import com.epam.dlab.backendapi.domain.BillingReportLine; import com.epam.dlab.backendapi.resources.dto.BillingFilter; +import java.time.LocalDate; import java.util.List; public interface BillingDAO { @@ -30,6 +31,8 @@ public interface BillingDAO { Double getProjectCost(String project); + Double getProjectCost(String project, LocalDate date); + int getBillingQuoteUsed(); int getBillingUserQuoteUsed(String user); diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ProjectDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ProjectDAO.java index bce53c3..9b7f0a0 100644 --- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ProjectDAO.java +++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ProjectDAO.java @@ -34,7 +34,7 @@ public interface ProjectDAO { Optional<Integer> getAllowedBudget(String project); - void updateBudget(String project, Integer budget); + void updateBudget(String project, Integer budget, boolean monthlyBudget); boolean isAnyProjectAssigned(Set<String> groups); } diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ProjectDAOImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ProjectDAOImpl.java index ac3cfa3..98f0841 100644 --- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ProjectDAOImpl.java +++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ProjectDAOImpl.java @@ -1,6 +1,7 @@ package com.epam.dlab.backendapi.dao; import com.epam.dlab.auth.UserInfo; +import com.epam.dlab.backendapi.domain.BudgetDTO; import com.epam.dlab.backendapi.domain.ProjectDTO; import com.epam.dlab.dto.UserInstanceStatus; import com.epam.dlab.dto.base.edge.EdgeInfo; @@ -30,6 +31,9 @@ public class ProjectDAOImpl extends BaseDAO implements ProjectDAO { private static final String GROUPS = "groups"; private static final String ENDPOINTS = "endpoints"; private static final String STATUS_FIELD = "status"; + private static final String BUDGET_FIELD = "budget"; + private static final String VALUE_FIELD = "value"; + private static final String IS_MONTHLY_BUDGET_FIELD = "isMonthlyBudget"; private static final String SHARED_IMAGE_FIELD = "sharedImageEnabled"; private static final String ENDPOINT_STATUS_FIELD = "endpoints." + STATUS_FIELD; private static final String EDGE_INFO_FIELD = "edgeInfo"; @@ -121,12 +125,17 @@ public class ProjectDAOImpl extends BaseDAO implements ProjectDAO { @Override public Optional<Integer> getAllowedBudget(String project) { - return get(project).map(ProjectDTO::getBudget); + return get(project) + .flatMap(p -> Optional.ofNullable(p.getBudget()) + .map(BudgetDTO::getValue)); } @Override - public void updateBudget(String project, Integer budget) { - updateOne(PROJECTS_COLLECTION, projectCondition(project), new Document(SET, new Document("budget", budget))); + public void updateBudget(String project, Integer budget, boolean isMonthlyBudget) { + BasicDBObject updateBudget = new BasicDBObject(); + updateBudget.put(VALUE_FIELD, budget); + updateBudget.put(IS_MONTHLY_BUDGET_FIELD, isMonthlyBudget); + updateOne(PROJECTS_COLLECTION, projectCondition(project), new Document(SET, new Document(BUDGET_FIELD, updateBudget))); } @Override diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/BudgetDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/BudgetDTO.java new file mode 100644 index 0000000..69a540f --- /dev/null +++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/BudgetDTO.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package com.epam.dlab.backendapi.domain; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Builder; +import lombok.Data; + +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +@Builder +public class BudgetDTO { + private Integer value; + @JsonProperty("is_monthly_budget") + private boolean isMonthlyBudget; +} diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/ProjectDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/ProjectDTO.java index 9cd0a35..32e67ec 100644 --- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/ProjectDTO.java +++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/ProjectDTO.java @@ -25,7 +25,7 @@ public class ProjectDTO { private final String key; @NotNull private final String tag; - private final Integer budget; + private final BudgetDTO budget; private final List<ProjectEndpointDTO> endpoints; private final boolean sharedImageEnabled; diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/UpdateProjectBudgetDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/UpdateProjectBudgetDTO.java index 61ec137..8e6831f 100644 --- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/UpdateProjectBudgetDTO.java +++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/UpdateProjectBudgetDTO.java @@ -1,6 +1,7 @@ package com.epam.dlab.backendapi.domain; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import javax.validation.constraints.NotNull; @@ -12,4 +13,6 @@ public class UpdateProjectBudgetDTO { private final String project; @NotNull private final Integer budget; + @JsonProperty("is_monthly_budget") + private final boolean isMonthlyBudget; } diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ProjectResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ProjectResource.java index 1e61405..f4a18c6 100644 --- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ProjectResource.java +++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ProjectResource.java @@ -73,10 +73,12 @@ public class ProjectResource { @RolesAllowed("/api/project/create") public Response createProject(@Parameter(hidden = true) @Auth UserInfo userInfo, @Valid CreateProjectDTO projectDTO) { - ProjectDTO project = new ProjectDTO(projectDTO.getName(), projectDTO.getGroups(), - projectDTO.getKey(), projectDTO.getTag(), null, - projectDTO.getEndpoints().stream().map(e -> new ProjectEndpointDTO(e, UserInstanceStatus.CREATING, - null)).collect(Collectors.toList()), projectDTO.isSharedImageEnabled()); + List<ProjectEndpointDTO> projectEndpointDTOS = projectDTO.getEndpoints() + .stream() + .map(e -> new ProjectEndpointDTO(e, UserInstanceStatus.CREATING, null)) + .collect(Collectors.toList()); + ProjectDTO project = new ProjectDTO(projectDTO.getName(), projectDTO.getGroups(), projectDTO.getKey(), projectDTO.getTag(), + null, projectEndpointDTOS, projectDTO.isSharedImageEnabled()); projectService.create(userInfo, project, projectDTO.getName()); final URI uri = uriInfo.getRequestUriBuilder().path(projectDTO.getName()).build(); return Response @@ -221,8 +223,7 @@ public class ProjectResource { @RolesAllowed("/api/project") public Response updateBudget( @Parameter(hidden = true) @Auth UserInfo userInfo, - @Parameter(description = "Project name") - List<UpdateProjectBudgetDTO> dtos) { + @Parameter(description = "Update project budgets list") List<UpdateProjectBudgetDTO> dtos) { projectService.updateBudget(userInfo, dtos); return Response.ok().build(); } diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ProjectServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ProjectServiceImpl.java index 2253685..f750960 100644 --- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ProjectServiceImpl.java +++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ProjectServiceImpl.java @@ -12,6 +12,7 @@ import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration; import com.epam.dlab.backendapi.dao.ExploratoryDAO; import com.epam.dlab.backendapi.dao.ProjectDAO; import com.epam.dlab.backendapi.dao.UserGroupDao; +import com.epam.dlab.backendapi.domain.BudgetDTO; import com.epam.dlab.backendapi.domain.EndpointDTO; import com.epam.dlab.backendapi.domain.ProjectDTO; import com.epam.dlab.backendapi.domain.ProjectEndpointDTO; @@ -36,6 +37,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -219,19 +221,19 @@ public class ProjectServiceImpl implements ProjectService { @Override public void updateBudget(UserInfo userInfo, List<UpdateProjectBudgetDTO> dtos) { - final List<ProjectDTO> projects = dtos - .stream() - .filter(dto -> Objects.nonNull(dto.getBudget())) - .map(dto -> ProjectDTO.builder().name(dto.getProject()).budget(dto.getBudget()).build()) - .collect(Collectors.toList()); + final List<ProjectDTO> projects = dtos + .stream() + .filter(dto -> Objects.nonNull(dto.getBudget())) + .map(this::getUpdateProjectDTO) + .collect(Collectors.toList()); - projects.forEach(p -> updateBudget(userInfo, p.getName(), p.getBudget(), getUpdateBudgetAudit(p))); + projects.forEach(p -> updateBudget(userInfo, p.getName(), p.getBudget(), getUpdateBudgetAudit(p))); } - @Audit(action = UPDATE, type = PROJECT) - public void updateBudget(@User UserInfo userInfo, @Project @ResourceName String name, Integer budget, @Info String updateBudgetAudit) { - projectDAO.updateBudget(name, budget); - } + @Audit(action = UPDATE, type = PROJECT) + public void updateBudget(@User UserInfo userInfo, @Project @ResourceName String name, BudgetDTO budget, @Info String updateBudgetAudit) { + projectDAO.updateBudget(name, budget.getValue(), budget.isMonthlyBudget()); + } @Override public boolean isAnyProjectAssigned(UserInfo userInfo) { @@ -321,7 +323,10 @@ public class ProjectServiceImpl implements ProjectService { } private String getUpdateBudgetAudit(ProjectDTO p) { - return String.format(AUDIT_UPDATE_BUDGET, get(p.getName()).getBudget(), p.getBudget()); + Integer value = Optional.ofNullable(get(p.getName()).getBudget()) + .map(BudgetDTO::getValue) + .orElse(null); + return String.format(AUDIT_UPDATE_BUDGET, value, p.getBudget().getValue()); } private List<ProjectEndpointDTO> getProjectEndpointDTOS(List<String> endpoints, @Project String name) { @@ -332,6 +337,17 @@ public class ProjectServiceImpl implements ProjectService { .collect(Collectors.toList()); } + private ProjectDTO getUpdateProjectDTO(UpdateProjectBudgetDTO dto) { + BudgetDTO budgetDTO = BudgetDTO.builder() + .value(dto.getBudget()) + .isMonthlyBudget(dto.isMonthlyBudget()) + .build(); + return ProjectDTO.builder() + .name(dto.getProject()) + .budget(budgetDTO) + .build(); + } + private Supplier<ResourceNotFoundException> projectNotFound() { return () -> new ResourceNotFoundException("Project with passed name not found"); } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@dlab.apache.org For additional commands, e-mail: commits-h...@dlab.apache.org