blob: fc79656d2edb99ce5fe86b2da495c25445ccea34 [file] [log] [blame]
/*
* 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.dao;
import com.epam.dlab.auth.UserInfo;
import com.epam.dlab.backendapi.domain.ProjectDTO;
import com.epam.dlab.dto.UserInstanceStatus;
import com.epam.dlab.dto.base.edge.EdgeInfo;
import com.google.common.collect.Iterables;
import com.google.inject.Inject;
import com.mongodb.BasicDBObject;
import org.bson.Document;
import org.bson.conversions.Bson;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.mongodb.client.model.Filters.and;
import static com.mongodb.client.model.Filters.elemMatch;
import static com.mongodb.client.model.Filters.eq;
import static com.mongodb.client.model.Filters.in;
import static com.mongodb.client.model.Filters.not;
public class ProjectDAOImpl extends BaseDAO implements ProjectDAO {
private static final String PROJECTS_COLLECTION = "Projects";
private static final String GROUPS = "groups";
private static final String ENDPOINTS = "endpoints";
private static final String STATUS_FIELD = "status";
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";
private static final String ENDPOINT_FIELD = "endpoints.$.";
private static final String ANYUSER = Pattern.quote("$anyuser");
private final UserGroupDao userGroupDao;
@Inject
public ProjectDAOImpl(UserGroupDao userGroupDao) {
this.userGroupDao = userGroupDao;
}
@Override
public List<ProjectDTO> getProjects() {
return find(PROJECTS_COLLECTION, ProjectDTO.class);
}
@Override
public List<ProjectDTO> getProjectsWithEndpointStatusNotIn(UserInstanceStatus... statuses) {
final List<String> statusList =
Arrays.stream(statuses).map(UserInstanceStatus::name).collect(Collectors.toList());
return find(PROJECTS_COLLECTION, not(in(ENDPOINT_STATUS_FIELD, statusList)), ProjectDTO.class);
}
@Override
public List<ProjectDTO> getUserProjects(UserInfo userInfo, boolean active) {
final Set<String> groups = Stream.concat(userGroupDao.getUserGroups(userInfo.getName()).stream(),
userInfo.getRoles().stream())
.collect(Collectors.toSet());
return find(PROJECTS_COLLECTION, userProjectCondition(groups, active), ProjectDTO.class);
}
@Override
public void create(ProjectDTO projectDTO) {
insertOne(PROJECTS_COLLECTION, projectDTO);
}
@Override
public void updateStatus(String projectName, ProjectDTO.Status status) {
updateOne(PROJECTS_COLLECTION, projectCondition(projectName),
new Document(SET, new Document(STATUS_FIELD, status.toString())));
}
@Override
public void updateEdgeStatus(String projectName, String endpoint, UserInstanceStatus status) {
BasicDBObject dbObject = new BasicDBObject();
dbObject.put(ENDPOINT_FIELD + STATUS_FIELD, status.name());
updateOne(PROJECTS_COLLECTION, projectAndEndpointCondition(projectName,
endpoint), new Document(SET, dbObject));
}
@Override
public void updateEdgeInfo(String projectName, String endpointName, EdgeInfo edgeInfo) {
BasicDBObject dbObject = new BasicDBObject();
dbObject.put(ENDPOINT_FIELD + STATUS_FIELD, UserInstanceStatus.RUNNING.name());
dbObject.put(ENDPOINT_FIELD + EDGE_INFO_FIELD, convertToBson(edgeInfo));
updateOne(PROJECTS_COLLECTION, projectAndEndpointCondition(projectName, endpointName), new Document(SET,
dbObject));
}
@Override
public Optional<ProjectDTO> get(String name) {
return findOne(PROJECTS_COLLECTION, projectCondition(name), ProjectDTO.class);
}
@Override
public List<ProjectDTO> getProjectsByEndpoint(String endpointName) {
return find(PROJECTS_COLLECTION, elemMatch(ENDPOINTS, eq("name", endpointName)), ProjectDTO.class);
}
@Override
public boolean update(ProjectDTO projectDTO) {
BasicDBObject updateProject = new BasicDBObject();
updateProject.put(GROUPS, projectDTO.getGroups());
updateProject.put(ENDPOINTS,
projectDTO.getEndpoints().stream().map(this::convertToBson).collect(Collectors.toList()));
updateProject.put(SHARED_IMAGE_FIELD, projectDTO.isSharedImageEnabled());
return updateOne(PROJECTS_COLLECTION, projectCondition(projectDTO.getName()),
new Document(SET, updateProject)).getMatchedCount() > 0L;
}
@Override
public void remove(String name) {
deleteOne(PROJECTS_COLLECTION, projectCondition(name));
}
@Override
public Optional<Integer> getAllowedBudget(String project) {
return get(project).map(ProjectDTO::getBudget);
}
@Override
public void updateBudget(String project, Integer budget) {
updateOne(PROJECTS_COLLECTION, projectCondition(project), new Document(SET, new Document("budget", budget)));
}
@Override
public boolean isAnyProjectAssigned(Set<String> groups) {
final String groupsRegex = !groups.isEmpty() ? String.join("|", groups) + "|" + ANYUSER : ANYUSER;
return !Iterables.isEmpty(find(PROJECTS_COLLECTION, elemMatch(GROUPS, regexCaseInsensitive(groupsRegex))));
}
private Bson projectCondition(String name) {
return eq("name", name);
}
private Bson userProjectCondition(Set<String> groups, boolean active) {
final String groupsRegex = !groups.isEmpty() ? String.join("|", groups) + "|" + ANYUSER : ANYUSER;
if (active) {
return and(elemMatch(GROUPS, regexCaseInsensitive(groupsRegex)),
eq(ENDPOINT_STATUS_FIELD, UserInstanceStatus.RUNNING.name()));
}
return elemMatch(GROUPS, regexCaseInsensitive(groupsRegex));
}
private Bson projectAndEndpointCondition(String projectName, String endpointName) {
return and(eq("name", projectName), eq("endpoints.name", endpointName));
}
private Document regexCaseInsensitive(String values) {
return new Document("$regex",
"^(" + values + ")$").append("$options", "i");
}
}