/**
* Copyright (c) 2009 - 2012 Red Hat, Inc.
*
* This software is licensed to you under the GNU General Public License,
* version 2 (GPLv2). There is NO WARRANTY for this software, express or
* implied, including the implied warranties of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
* along with this software; if not, see
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* Red Hat trademarks are not licensed under GPLv2. No permission is
* granted to use or replicate Red Hat trademarks that are incorporated
* in this software or its documentation.
*/
package org.candlepin.resource;
import org.candlepin.auth.Access;
import org.candlepin.auth.Principal;
import org.candlepin.auth.SubResource;
import org.candlepin.auth.Verify;
import org.candlepin.common.auth.SecurityHole;
import org.candlepin.common.exceptions.BadRequestException;
import org.candlepin.common.exceptions.ForbiddenException;
import org.candlepin.common.exceptions.NotFoundException;
import org.candlepin.common.paging.Page;
import org.candlepin.common.paging.PageRequest;
import org.candlepin.common.paging.Paginate;
import org.candlepin.controller.PoolManager;
import org.candlepin.model.Cdn;
import org.candlepin.model.Consumer;
import org.candlepin.model.ConsumerCurator;
import org.candlepin.model.Entitlement;
import org.candlepin.model.Owner;
import org.candlepin.model.OwnerCurator;
import org.candlepin.model.Pool;
import org.candlepin.model.PoolFilterBuilder;
import org.candlepin.resource.util.CalculatedAttributesUtil;
import org.candlepin.resource.util.ResourceDateParser;
import com.google.inject.Inject;
import org.jboss.resteasy.annotations.providers.jaxb.Wrapped;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.xnap.commons.i18n.I18n;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
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.Context;
import javax.ws.rs.core.MediaType;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import io.swagger.annotations.Authorization;
/**
* API gateway for the EntitlementPool
*/
@Path("/pools")
@Api(value = "pools", authorizations = { @Authorization("basic") })
public class PoolResource {
private ConsumerCurator consumerCurator;
private OwnerCurator ownerCurator;
private I18n i18n;
private PoolManager poolManager;
private CalculatedAttributesUtil calculatedAttributesUtil;
@Inject
public PoolResource(ConsumerCurator consumerCurator, OwnerCurator ownerCurator,
I18n i18n, PoolManager poolManager, CalculatedAttributesUtil calculatedAttributesUtil) {
this.consumerCurator = consumerCurator;
this.ownerCurator = ownerCurator;
this.i18n = i18n;
this.poolManager = poolManager;
this.calculatedAttributesUtil = calculatedAttributesUtil;
}
/**
* @deprecated Use the method on /owners
* @return List of pools
*/
@ApiOperation(
notes = "Retrieves a list of Pools @deprecated Use the method on /owners",
value = "")
@ApiResponses({
@ApiResponse(code = 400,
message = "if both consumer(unit) and owner are given, or if a" +
" product id is specified without a consumer(unit) or owner"),
@ApiResponse(code = 404, message = "if a specified consumer(unit) or owner is not found"),
@ApiResponse(code = 403, message = "") })
@GET
@Produces(MediaType.APPLICATION_JSON)
@Wrapped(element = "pools")
@Deprecated
@SecurityHole
@Paginate
public List<Pool> list(@QueryParam("owner") String ownerId,
@QueryParam("consumer") String consumerUuid,
@QueryParam("product") String productId,
@ApiParam("Use with consumerUuid to list all pools available to the consumer. " +
"This will include pools which would otherwise be omitted due to a rules" +
" warning. (i.e. not recommended) Pools that trigger an error however will" +
" still be omitted. (no entitlements available, consumer type mismatch, etc)")
@QueryParam("listall") @DefaultValue("false") boolean listAll,
@ApiParam("Uses ISO 8601 format") @QueryParam("activeon") String activeOn,
@Context Principal principal,
@Context PageRequest pageRequest) {
// Make sure we were given sane query parameters:
if (consumerUuid != null && ownerId != null) {
throw new BadRequestException(i18n.tr("Cannot filter on both owner and unit"));
}
if (consumerUuid == null && ownerId == null && productId != null) {
throw new BadRequestException(i18n.tr("A unit or owner is needed to filter on product"));
}
Date activeOnDate = activeOn != null ?
ResourceDateParser.parseDateString(activeOn) :
new Date();
Consumer c = null;
Owner o = null;
if (consumerUuid != null) {
c = consumerCurator.findByUuid(consumerUuid);
if (c == null) {
throw new NotFoundException(i18n.tr("Unit: {0} not found", consumerUuid));
}
// Now that we have a consumer, check that this principal can access it:
if (!principal.canAccess(c, SubResource.NONE, Access.READ_ONLY)) {
throw new ForbiddenException(i18n.tr("User {0} cannot access unit {1}",
principal.getPrincipalName(), consumerUuid));
}
if (listAll) {
o = c.getOwner();
}
}
if (ownerId != null) {
o = ownerCurator.secureFind(ownerId);
if (o == null) {
throw new NotFoundException(i18n.tr("owner: {0}", ownerId));
}
// Now that we have an owner, check that this principal can access it:
if (!principal.canAccess(o, SubResource.POOLS, Access.READ_ONLY)) {
throw new ForbiddenException(i18n.tr("User {0} cannot access owner {1}",
principal.getPrincipalName(), o.getKey()));
}
}
// If we have no consumer, and no owner specified, kick 'em out unless they
// have full system access (this is the same as requesting all pools in
// the system).
if (consumerUuid == null && ownerId == null && !principal.hasFullAccess()) {
throw new ForbiddenException(i18n.tr("User {0} cannot access all pools.",
principal.getPrincipalName()));
}
Page<List<Pool>> page = poolManager.listAvailableEntitlementPools(c, null, o,
productId, null, activeOnDate, listAll, new PoolFilterBuilder(), pageRequest,
false, false);
List<Pool> poolList = page.getPageData();
calculatedAttributesUtil.setCalculatedAttributes(poolList, activeOnDate);
calculatedAttributesUtil.setQuantityAttributes(poolList, c, activeOnDate);
// Store the page for the LinkHeaderResponseFilter
ResteasyProviderFactory.pushContext(Page.class, page);
return poolList;
}
@ApiOperation(notes = "Retrieves a single Pool", value = "getPool")
@ApiResponses({ @ApiResponse(code = 404, message = "if the pool with the specified id is not found"),
@ApiResponse(code = 404, message = "") })
@GET
@Path("/{pool_id}")
@Produces(MediaType.APPLICATION_JSON)
public Pool getPool(@PathParam("pool_id") @Verify(Pool.class) String id,
@QueryParam("consumer") String consumerUuid,
@ApiParam("Uses ISO 8601 format") @QueryParam("activeon") String activeOn,
@Context Principal principal) {
Pool toReturn = poolManager.find(id);
Consumer c = null;
if (consumerUuid != null) {
c = consumerCurator.findByUuid(consumerUuid);
if (c == null) {
throw new NotFoundException(i18n.tr("consumer: {0} not found",
consumerUuid));
}
if (!principal.canAccess(c, SubResource.NONE, Access.READ_ONLY)) {
throw new ForbiddenException(i18n.tr("User {0} cannot access consumer {1}",
principal.getPrincipalName(), c.getUuid()));
}
}
if (toReturn != null) {
Date activeOnDate = new Date();
if (activeOn != null) {
activeOnDate = ResourceDateParser.parseDateString(activeOn);
}
toReturn.setCalculatedAttributes(
calculatedAttributesUtil.buildCalculatedAttributes(toReturn, activeOnDate)
);
calculatedAttributesUtil.setQuantityAttributes(toReturn, c, activeOnDate);
return toReturn;
}
throw new NotFoundException(i18n.tr(
"Subscription Pool with ID ''{0}'' could not be found.", id));
}
@ApiOperation(notes = "Remove a Pool", value = "deletePool")
@ApiResponses({ @ApiResponse(code = 404, message = "if the pool with the specified id is not found") })
@DELETE
@Path("/{pool_id}")
@Produces(MediaType.APPLICATION_JSON)
public void deletePool(@PathParam("pool_id") String id) {
Pool pool = poolManager.find(id);
if (pool == null) {
throw new NotFoundException(i18n.tr(
"Entitlement Pool with ID ''{0}'' could not be found.", id));
}
poolManager.deletePool(pool);
}
@ApiOperation(notes = "Retrieve a CDN for a Pool", value = "getPoolCdn")
@ApiResponses({ @ApiResponse(code = 400, message = "") })
@GET
@Path("{pool_id}/cdn")
@Produces(MediaType.APPLICATION_JSON)
public Cdn getPoolCdn(
@PathParam("pool_id") @Verify(Pool.class) String id) {
Pool pool = poolManager.find(id);
if (pool == null) {
throw new NotFoundException(i18n.tr(
"Subscription Pool with ID ''{0}'' could not be found.", id));
}
return pool.getCdn();
}
@ApiOperation(notes = "Retrieve a list of Entitlements for a Pool", value = "getPoolEntitlements")
@ApiResponses({ @ApiResponse(code = 400, message = "") })
@GET
@Path("{pool_id}/entitlements")
@Produces(MediaType.APPLICATION_JSON)
public List<Entitlement> getPoolEntitlements(@PathParam("pool_id")
@Verify(value = Pool.class, subResource = SubResource.ENTITLEMENTS) String id,
@Context Principal principal) {
Pool pool = poolManager.find(id);
if (pool == null) {
throw new NotFoundException(i18n.tr(
"Subscription Pool with ID ''{0}'' could not be found.", id));
}
List<Entitlement> entitlements = new ArrayList<Entitlement>();
entitlements.addAll(pool.getEntitlements());
return entitlements;
}
}