/*
* Copyright (c) 2015 EMC Corporation
* All Rights Reserved
*/
package com.emc.sa.api;
import static com.emc.sa.api.mapper.ApprovalMapper.map;
import static com.emc.sa.api.mapper.ApprovalMapper.updateObject;
import static com.emc.storageos.db.client.URIUtil.uri;
import static com.emc.storageos.api.mapper.DbObjectMapper.toNamedRelatedResource;
import java.net.URI;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import com.emc.sa.api.mapper.ApprovalFilter;
import com.emc.sa.api.mapper.ApprovalMapper;
import com.emc.sa.catalog.ApprovalManager;
import com.emc.sa.catalog.OrderManager;
import com.emc.storageos.db.client.model.uimodels.ApprovalRequest;
import com.emc.storageos.db.client.model.uimodels.ApprovalStatus;
import com.emc.storageos.db.client.model.uimodels.Order;
import com.emc.storageos.api.service.authorization.PermissionsHelper;
import com.emc.storageos.api.service.impl.resource.ArgValidator;
import com.emc.storageos.api.service.impl.response.BulkList;
import com.emc.storageos.api.service.impl.response.ResRepFilter;
import com.emc.storageos.api.service.impl.response.RestLinkFactory;
import com.emc.storageos.db.exceptions.DatabaseException;
import com.emc.storageos.model.NamedRelatedResourceRep;
import com.emc.storageos.model.RelatedResourceRep;
import com.emc.storageos.model.ResourceTypeEnum;
import com.emc.storageos.model.RestLinkRep;
import com.emc.storageos.model.search.SearchResultResourceRep;
import com.emc.storageos.model.search.SearchResults;
import com.emc.storageos.security.authentication.StorageOSUser;
import com.emc.storageos.security.authorization.ACL;
import com.emc.storageos.security.authorization.CheckPermission;
import com.emc.storageos.security.authorization.DefaultPermissions;
import com.emc.storageos.security.authorization.Role;
import com.emc.storageos.services.OperationTypeEnum;
import com.emc.storageos.svcs.errorhandling.resources.APIException;
import com.emc.storageos.volumecontroller.impl.monitoring.RecordableEventManager;
import com.emc.vipr.client.catalog.impl.SearchConstants;
import com.emc.vipr.model.catalog.ApprovalBulkRep;
import com.emc.vipr.model.catalog.ApprovalCommonParam;
import com.emc.vipr.model.catalog.ApprovalList;
import com.emc.vipr.model.catalog.ApprovalRestRep;
import com.emc.vipr.model.catalog.ApprovalUpdateParam;
import com.google.common.collect.Lists;
@DefaultPermissions(
readRoles = { Role.TENANT_ADMIN, Role.SYSTEM_MONITOR, Role.SYSTEM_ADMIN },
writeRoles = { Role.TENANT_ADMIN },
readAcls = { ACL.ANY })
@Path("/catalog/approvals")
public class ApprovalService extends CatalogTaggedResourceService {
private static final String EVENT_SERVICE_TYPE = "catalog-approval";
@Autowired
private ApprovalManager approvalManager;
@Autowired
private OrderManager orderManager;
@Autowired
private RecordableEventManager eventManager;
@Override
protected ApprovalRequest queryResource(URI id) {
return getApprovalById(id, false);
}
@Override
protected URI getTenantOwner(URI id) {
ApprovalRequest approval = queryResource(id);
return uri(approval.getTenant());
}
@Override
protected ResourceTypeEnum getResourceType() {
return ResourceTypeEnum.APPROVAL;
}
@Override
public String getServiceType() {
return EVENT_SERVICE_TYPE;
}
/**
* Get object specific permissions filter
*/
@Override
public ResRepFilter<? extends RelatedResourceRep> getPermissionFilter(StorageOSUser user,
PermissionsHelper permissionsHelper)
{
return new ApprovalResRepFilter(user, permissionsHelper);
}
/**
* parameter: 'orderId' The id of the order to search for approvals
* parameter: 'approvalStatus' The status for the approval.
* parameter: 'tenantId' The id of the tenant (if not the current tenant)
*
* @return Return a list of matching approvals or an empty list if no match was found.
*/
@Override
protected SearchResults getOtherSearchResults(Map<String, List<String>> parameters, boolean authorized) {
StorageOSUser user = getUserFromContext();
String tenantId = user.getTenantId();
if (parameters.containsKey(SearchConstants.TENANT_ID_PARAM)) {
tenantId = parameters.get(SearchConstants.TENANT_ID_PARAM).get(0);
}
verifyAuthorizedInTenantOrg(uri(tenantId), user);
if (!parameters.containsKey(SearchConstants.ORDER_ID_PARAM) && !parameters.containsKey(SearchConstants.APPROVAL_STATUS_PARAM)) {
throw APIException.badRequests.invalidParameterSearchMissingParameter(getResourceClass().getName(),
SearchConstants.ORDER_ID_PARAM + " or " + SearchConstants.APPROVAL_STATUS_PARAM);
}
if (parameters.containsKey(SearchConstants.ORDER_ID_PARAM) && parameters.containsKey(SearchConstants.APPROVAL_STATUS_PARAM)) {
throw APIException.badRequests.parameterForSearchCouldNotBeCombinedWithAnyOtherParameter(getResourceClass().getName(),
SearchConstants.ORDER_ID_PARAM, SearchConstants.APPROVAL_STATUS_PARAM);
}
List<ApprovalRequest> approvals = Lists.newArrayList();
if (parameters.containsKey(SearchConstants.ORDER_ID_PARAM)) {
String orderId = parameters.get(SearchConstants.ORDER_ID_PARAM).get(0);
ArgValidator.checkFieldNotEmpty(orderId, SearchConstants.ORDER_ID_PARAM);
approvals = approvalManager.findApprovalsByOrderId(uri(orderId));
}
else if (parameters.containsKey(SearchConstants.APPROVAL_STATUS_PARAM)) {
String approvalStatus = parameters.get(SearchConstants.APPROVAL_STATUS_PARAM).get(0);
ArgValidator.checkFieldNotEmpty(approvalStatus, SearchConstants.APPROVAL_STATUS_PARAM);
approvals = approvalManager.findApprovalsByStatus(uri(tenantId), ApprovalStatus.valueOf(approvalStatus));
}
ResRepFilter<SearchResultResourceRep> resRepFilter =
(ResRepFilter<SearchResultResourceRep>) getPermissionFilter(getUserFromContext(), _permissionsHelper);
List<SearchResultResourceRep> searchResultResourceReps = Lists.newArrayList();
for (ApprovalRequest approval : approvals) {
RestLinkRep selfLink = new RestLinkRep("self", RestLinkFactory.newLink(getResourceType(), approval.getId()));
SearchResultResourceRep searchResultResourceRep = new SearchResultResourceRep();
searchResultResourceRep.setId(approval.getId());
searchResultResourceRep.setLink(selfLink);
if (authorized || resRepFilter.isAccessible(searchResultResourceRep)) {
searchResultResourceReps.add(searchResultResourceRep);
}
}
SearchResults result = new SearchResults();
result.setResource(searchResultResourceReps);
return result;
}
/**
* Get info for approval
*
* @param id the URN of an approval
* @prereq none
* @brief Show approval
* @return Approval details
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}")
public ApprovalRestRep getApproval(@PathParam("id") URI id) {
ApprovalRequest approval = queryResource(id);
return map(approval);
}
/**
* Update approval
*
* @param param Approval update parameters
* @param id the URN the approval
* @prereq none
* @brief Update Approval
* @return No data returned in response body
*/
@PUT
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}")
@CheckPermission(roles = { Role.TENANT_APPROVER })
public ApprovalRestRep updateApproval(@PathParam("id") URI id, ApprovalUpdateParam param) {
ApprovalRequest approval = getApprovalById(id, true);
StorageOSUser user = getUserFromContext();
verifyAuthorizedInTenantOrg(uri(approval.getTenant()), user);
Order order = orderManager.getOrderById(approval.getOrderId());
if (order.getSubmittedByUserId().equals(user.getUserName()) &&
param.getApprovalStatus().equals(ApprovalStatus.APPROVED.toString())) {
throw APIException.badRequests.updateApprovalBySameUser(
user.getUserName());
}
validateParam(param, approval);
updateObject(approval, param);
approvalManager.updateApproval(approval, user);
if (approval.getOrderId() != null) {
if (order != null) {
orderManager.processOrder(order);
}
}
auditOpSuccess(OperationTypeEnum.UPDATE_APPROVAL, approval.auditParameters());
approval = approvalManager.getApprovalById(approval.getId());
return map(approval);
}
/**
* Gets the list of approvals
*
* @param tenantId the URN of a tenant
* @brief List Approvals
* @return a list of approvals
* @throws DatabaseException when a DB error occurs
*/
@GET
@Path("")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public ApprovalList getApprovals(@DefaultValue("") @QueryParam(SearchConstants.TENANT_ID_PARAM) String tenantId)
throws DatabaseException {
StorageOSUser user = getUserFromContext();
if (StringUtils.isBlank(tenantId)) {
tenantId = user.getTenantId();
}
verifyAuthorizedInTenantOrg(uri(tenantId), getUserFromContext());
List<ApprovalRequest> approvals = approvalManager.getApprovals(uri(tenantId));
ApprovalList approvalList = new ApprovalList();
for (ApprovalRequest approval : approvals) {
NamedRelatedResourceRep approvalRestRep = toNamedRelatedResource(ResourceTypeEnum.APPROVAL,
approval.getId(), approval.getLabel());
approvalList.getApprovals().add(approvalRestRep);
}
return approvalList;
}
private ApprovalRequest getApprovalById(URI id, boolean checkInactive) {
ApprovalRequest approval = approvalManager.getApprovalById(id);
ArgValidator.checkEntity(approval, id, isIdEmbeddedInURL(id), checkInactive);
return approval;
}
private void validateParam(ApprovalCommonParam input, ApprovalRequest existingApproval) {
// Are we approving or rejecting?
if (StringUtils.equalsIgnoreCase(input.getApprovalStatus(), ApprovalStatus.PENDING.name()) == false) {
// Is existing approval not in pending state
if (existingApproval.pending() == false) {
throw APIException.badRequests.updatingCompletedApproval();
}
}
}
public static class ApprovalResRepFilter<E extends RelatedResourceRep> extends ResRepFilter<E>
{
public ApprovalResRepFilter(StorageOSUser user, PermissionsHelper permissionsHelper) {
super(user, permissionsHelper);
}
@Override
public boolean isAccessible(E resrep) {
boolean ret = false;
URI id = resrep.getId();
ApprovalRequest obj = _permissionsHelper.getObjectById(id, ApprovalRequest.class);
if (obj == null) {
return false;
}
if (obj.getTenant().toString().equals(_user.getTenantId())) {
return true;
}
ret = isTenantAccessible(uri(obj.getTenant()));
return ret;
}
}
@SuppressWarnings("unchecked")
@Override
public Class<ApprovalRequest> getResourceClass() {
return ApprovalRequest.class;
}
@Override
public ApprovalBulkRep queryBulkResourceReps(List<URI> ids) {
Iterator<ApprovalRequest> _dbIterator =
_dbClient.queryIterativeObjects(getResourceClass(), ids);
return new ApprovalBulkRep(BulkList.wrapping(_dbIterator, ApprovalMapper.getInstance()));
}
@Override
public ApprovalBulkRep queryFilteredBulkResourceReps(List<URI> ids) {
Iterator<ApprovalRequest> _dbIterator =
_dbClient.queryIterativeObjects(getResourceClass(), ids);
BulkList.ResourceFilter filter = new ApprovalFilter(getUserFromContext(), _permissionsHelper);
return new ApprovalBulkRep(BulkList.wrapping(_dbIterator, ApprovalMapper.getInstance(), filter));
}
}