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

Reply via email to