package io.cattle.platform.iaas.api.auth.projects;
import io.cattle.platform.api.auth.Identity;
import io.cattle.platform.api.auth.Policy;
import io.cattle.platform.api.resource.AbstractObjectResourceManager;
import io.cattle.platform.core.constants.AccountConstants;
import io.cattle.platform.core.constants.ProjectConstants;
import io.cattle.platform.core.dao.AccountDao;
import io.cattle.platform.core.dao.GenericResourceDao;
import io.cattle.platform.core.model.Account;
import io.cattle.platform.core.model.ProjectMember;
import io.cattle.platform.engine.process.impl.ProcessCancelException;
import io.cattle.platform.iaas.api.auth.dao.AuthDao;
import io.cattle.platform.json.JsonMapper;
import io.cattle.platform.object.ObjectManager;
import io.cattle.platform.object.meta.Relationship;
import io.cattle.platform.object.process.ObjectProcessManager;
import io.cattle.platform.object.process.StandardProcess;
import io.cattle.platform.process.common.util.ProcessUtils;
import io.cattle.platform.util.type.CollectionUtils;
import io.github.ibuildthecloud.gdapi.context.ApiContext;
import io.github.ibuildthecloud.gdapi.exception.ClientVisibleException;
import io.github.ibuildthecloud.gdapi.factory.SchemaFactory;
import io.github.ibuildthecloud.gdapi.model.ListOptions;
import io.github.ibuildthecloud.gdapi.model.Resource;
import io.github.ibuildthecloud.gdapi.model.Schema;
import io.github.ibuildthecloud.gdapi.model.impl.CollectionImpl;
import io.github.ibuildthecloud.gdapi.request.ApiRequest;
import io.github.ibuildthecloud.gdapi.url.UrlBuilder;
import io.github.ibuildthecloud.gdapi.util.RequestUtils;
import io.github.ibuildthecloud.gdapi.util.ResponseCodes;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.inject.Inject;
import org.apache.commons.lang3.StringUtils;
public class ProjectResourceManager extends AbstractObjectResourceManager {
@Inject
JsonMapper jsonMapper;
@Inject
AuthDao authDao;
@Inject
GenericResourceDao resourceDao;
@Inject
ObjectManager objectManager;
@Inject
ObjectProcessManager objectProcessManager;
@Inject
ProjectMemberResourceManager projectMemberResourceManager;
@Inject
AccountDao accountDao;
@Override
public String[] getTypes() {
return new String[]{"project"};
}
@Override
public Class<?>[] getTypeClasses() {
return new Class<?>[0];
}
@Override
public Object listInternal(SchemaFactory schemaFactory, String type, Map<Object, Object> criteria, ListOptions options) {
ApiRequest request = ApiContext.getContext().getApiRequest();
Policy policy = (Policy) ApiContext.getContext().getPolicy();
String id = RequestUtils.getConditionValue("id", criteria);
String uuid = RequestUtils.getConditionValue("uuid", criteria);
String name = RequestUtils.getConditionValue("name", criteria);
if (!StringUtils.isBlank(id)) {
Account project = giveProjectAccess(getObjectManager().loadResource(Account.class, id), policy);
return Collections.singletonList(project);
}
if (!StringUtils.isBlank(uuid)) {
return giveProjectAccess(authDao.getAccountByUuid(uuid), policy);
}
boolean isAdmin;
Object getAll = request.getRequestParams().get("all");
if (getAll != null) {
String all = ((String[]) getAll)[0];
if (all.equalsIgnoreCase("true") && policy.isOption(Policy.AUTHORIZED_FOR_ALL_ACCOUNTS)) {
isAdmin = true;
} else {
isAdmin = false;
}
} else {
isAdmin = false;
}
List<Account> projects = authDao.getAccessibleProjects(policy.getIdentities(),
isAdmin, policy.getAccountId());
List<Account> projectsFiltered = new ArrayList<>();
for (Account project : projects) {
if (StringUtils.isNotBlank(name) && !name.equalsIgnoreCase(project.getName())) {
continue;
}
projectsFiltered.add(giveProjectAccess(project, policy));
}
return projectsFiltered;
}
private Account giveProjectAccess(Account project, Policy policy) {
if (project == null || !ProjectConstants.TYPE.equalsIgnoreCase(project.getKind())) {
return null;
}
if (!authDao.hasAccessToProject(project.getId(), policy.getAccountId(),
policy.isOption(Policy.AUTHORIZED_FOR_ALL_ACCOUNTS), policy.getIdentities())) {
return null;
}
boolean isOwner = authDao.isProjectOwner(project.getId(), policy.getAccountId(), policy.isOption(Policy.AUTHORIZED_FOR_ALL_ACCOUNTS), policy
.getIdentities());
if (!accountDao.isActiveAccount(project) && !isOwner) {
return null;
}
if (isOwner) {
ApiContext.getContext().addCapability(project, ProjectConstants.OWNER);
} else {
ApiContext.getContext().setCapabilities(project, new ArrayList<String>());
}
policy.grantObjectAccess(project);
return project;
}
@Override
protected Object createInternal(String type, ApiRequest request) {
if (!ProjectConstants.TYPE.equals(type)) {
return null;
}
return createProject(type, request);
}
@SuppressWarnings("unchecked")
private Account createProject(String type, ApiRequest apiRequest) {
Policy policy = (Policy) ApiContext.getContext().getPolicy();
Map<String, Object> project = CollectionUtils.toMap(apiRequest.getRequestObject());
if (authDao.getAccountById(policy.getAccountId()).getKind().equalsIgnoreCase(ProjectConstants.TYPE)) {
throw new ClientVisibleException(ResponseCodes.FORBIDDEN);
}
Object object = super.createInternal(type, apiRequest);
if (object instanceof Account) {
Account newProject = (Account) object;
newProject.setKind(AccountConstants.PROJECT_KIND);
objectManager.persist(newProject);
List<Map<String, String>> members = (ArrayList<Map<String, String>>) project.get("members");
projectMemberResourceManager.setMembers(newProject, members);
policy.grantObjectAccess(newProject);
return objectManager.reload(newProject);
} else {
throw new ClientVisibleException(ResponseCodes.INTERNAL_SERVER_ERROR);
}
}
public Account createProjectForUser(Identity identity) {
Account project = authDao.createProject(identity.getLogin() + ProjectConstants.PROJECT_DEFAULT_NAME, null);
authDao.createProjectMember(project, new Member(identity, ProjectConstants.OWNER));
return project;
}
@Override
protected Object deleteInternal(String type, String id, final Object obj, ApiRequest apiRequest) {
if (!(obj instanceof Account) || !(((Account) obj).getKind().equalsIgnoreCase(ProjectConstants.TYPE))) {
return super.deleteInternal(type, id, obj, apiRequest);
}
Policy policy = (Policy) ApiContext.getContext().getPolicy();
if (authDao.getAccountById(Long.valueOf(id)) == null) {
throw new ClientVisibleException(ResponseCodes.NOT_FOUND);
}
if (!authDao.isProjectOwner(Long.valueOf(id), policy.getAccountId(),
policy.isOption(Policy.AUTHORIZED_FOR_ALL_ACCOUNTS), policy.getIdentities())) {
throw new ClientVisibleException(ResponseCodes.FORBIDDEN);
}
try {
objectProcessManager.executeStandardProcess(StandardProcess.REMOVE, obj, null);
} catch (ProcessCancelException e) {
objectProcessManager.executeStandardProcess(StandardProcess.DEACTIVATE, obj,
ProcessUtils.chainInData(new HashMap<String, Object>(), AccountConstants.ACCOUNT_DEACTIVATE, AccountConstants.ACCOUNT_REMOVE));
}
Account deletedProject = (Account) objectManager.reload(obj);
for (ProjectMember member : authDao.getActiveProjectMembers(deletedProject.getId())) {
try {
objectProcessManager.scheduleStandardProcess(StandardProcess.REMOVE, member, null);
} catch (ProcessCancelException e) {
objectProcessManager.scheduleStandardProcess(StandardProcess.DEACTIVATE, member,
ProcessUtils.chainInData(new HashMap<String, Object>(), "projectmember.deactivate", "projectmember.remove"));
}
}
policy.grantObjectAccess(deletedProject);
return Arrays.asList(deletedProject);
}
@Override
protected Object removeFromStore(String type, String id, Object obj, ApiRequest apiRequest) {
throw new UnsupportedOperationException();
}
@Override
protected Object updateInternal(String type, String id, Object obj, ApiRequest apiRequest) {
Policy policy = (Policy) ApiContext.getContext().getPolicy();
Account project = (Account) obj;
if (authDao.isProjectOwner(project.getId(), policy.getAccountId(),
policy.isOption(Policy.AUTHORIZED_FOR_ALL_ACCOUNTS), policy.getIdentities())) {
return super.updateInternal(type, id, obj, apiRequest);
} else {
throw new ClientVisibleException(ResponseCodes.FORBIDDEN, "Forbidden", "You must be a project owner to update the name or description.", null);
}
}
@Override
protected Relationship getRelationship(String type, String linkName) {
if (linkName.equalsIgnoreCase("projectmembers")) {
Relationship rel = super.getMetaDataManager().getRelationship(type, linkName, "projectid");
if (rel != null) {
return rel;
}
}
return super.getRelationship(type, linkName);
}
@Override
protected Relationship getRelationship(Class<?> clz, String linkName) {
if (linkName.equalsIgnoreCase("projectmembers")) {
Relationship rel = super.getMetaDataManager().getRelationship(clz, linkName, "projectid");
if (rel != null) {
return rel;
}
}
return super.getRelationship(clz, linkName);
}
@Override
protected void addLinks(Object obj, SchemaFactory schemaFactory, Schema schema, Resource resource) {
super.addLinks(obj, schemaFactory, schema, resource);
Map<String, URL> links = new TreeMap<>();
UrlBuilder urlBuilder = ApiContext.getUrlBuilder();
for (Schema childSchema : schemaFactory.listSchemas()) {
if (!childSchema.getCollectionMethods().contains(Schema.Method.GET.toString())) {
continue;
}
URL link = urlBuilder.resourceLink(resource, childSchema.getPluralName());
if (link != null) {
links.put(childSchema.getPluralName(), link);
}
}
resource.getLinks().putAll(links);
}
@Override
protected void addFilters(CollectionImpl collection, ApiRequest request) {
}
@Override
protected void addSort(CollectionImpl collection, ApiRequest request) {
}
}