grsf-publisher-ws/src/main/java/org/gcube/data_catalogue/grsf_publish_ws/services/GrsfPublisherStockService.java

321 lines
11 KiB
Java

package org.gcube.data_catalogue.grsf_publish_ws.services;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.validation.Valid;
import javax.validation.ValidationException;
import javax.validation.constraints.NotNull;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
import org.gcube.common.authorization.library.utils.Caller;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.data_catalogue.grsf_publish_ws.json.input.DeleteProductBean;
import org.gcube.data_catalogue.grsf_publish_ws.json.input.StockRecord;
import org.gcube.data_catalogue.grsf_publish_ws.json.output.ResponseCreationBean;
import org.gcube.data_catalogue.grsf_publish_ws.utils.AssociationToGroupThread;
import org.gcube.data_catalogue.grsf_publish_ws.utils.HelperMethods;
import org.gcube.datacatalogue.ckanutillibrary.DataCatalogue;
import org.gcube.datacatalogue.ckanutillibrary.models.ResourceBean;
import org.gcube.datacatalogue.ckanutillibrary.models.RolesCkanGroupOrOrg;
import org.gcube.datacatalogue.ckanutillibrary.utils.UtilMethods;
import org.slf4j.LoggerFactory;
import eu.trentorise.opendata.jackan.model.CkanDataset;
/**
* Stock web service methods
* @author Costantino Perciante at ISTI-CNR
*/
@Path("stock/")
public class GrsfPublisherStockService {
private static final String DEFAULT_STOCK_LICENSE = "CC-BY-SA-4.0";
private static final String THIS_TYPE = "Stock";
// the context
@Context
ServletContext contextServlet;
// Logger
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(GrsfPublisherStockService.class);
@GET
@Path("hello")
@Produces(MediaType.TEXT_PLAIN)
public Response hello(){
return Response.ok("Hello.. Stock service is here").build();
}
@GET
@Path("get-licenses")
@Produces(MediaType.APPLICATION_JSON)
public Response getLicenses(){
// since are equals for stock and fishery, we just retrieve them all
Map<String, String> licenses = new HashMap<String, String>();
Status status;
try{
licenses = HelperMethods.getLicenses();
status = Status.OK;
}catch(Exception e){
logger.error("Failed to retrieve the list of licenses");
status = Status.INTERNAL_SERVER_ERROR;
}
return Response.status(status).entity(licenses).build();
}
@POST
@Path("publish-product")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response publishStock(
@NotNull(message="record cannot be null") @Valid StockRecord record) throws ValidationException{
// retrieve context and username
Caller caller = AuthorizationProvider.instance.get();
String username = caller.getClient().getId();
String context = ScopeProvider.instance.get();
logger.info("Incoming request for creating a stock record = " + record);
logger.info("Request coming from user " + username + " in context " + context);
ResponseCreationBean responseBean = new ResponseCreationBean();
Status status = Status.INTERNAL_SERVER_ERROR;
String id = "";
try{
// determine the organization in which this product should be put
String contextInWhichPublish = HelperMethods.getContextFromStatus(record.getStatus(), contextServlet);
if(contextInWhichPublish == null || !contextInWhichPublish.equals(context)){
// stop, this value must be defined
status = Status.BAD_REQUEST;
responseBean.setId(id);
throw new IllegalArgumentException("Status attribute is not defined or the Token you are using is not correct to perform such request!");
}else{
DataCatalogue catalogue = HelperMethods.getDataCatalogueRunningInstance(context);
if(catalogue == null){
status = Status.INTERNAL_SERVER_ERROR;
responseBean.setId(null);
throw new Exception("There was a problem while serving your request");
}else{
// check the user has editor/admin role into the org
String organization = HelperMethods.retrieveOrgNameFromScope(contextInWhichPublish);
if(!catalogue.getRoleOfUserInOrganization(username, organization, catalogue.getApiKeyFromUsername(username)).equalsIgnoreCase(RolesCkanGroupOrOrg.ADMIN.toString())){
status = Status.FORBIDDEN;
responseBean.setId(null);
throw new Exception("You are not authorized to create a product. Please check you have the Catalogue-Administrator role!");
}
// check the record has a name, at least
String futureTitle = record.getStockName();
if(!HelperMethods.isValid(futureTitle)){
status = Status.BAD_REQUEST;
responseBean.setId(null);
throw new Exception("The name requested for the product is not correct! It should contain only alphanumeric characters, and symbols like '.' or '_', '-'");
}else{
logger.debug("Checking if such name [" + futureTitle + "]doesn't exist yet...");
String futureName = UtilMethods.fromProductTitleToName(futureTitle);
logger.info("Transformed name is " + futureName);
boolean alreadyExist = catalogue.existProductWithNameOrId(futureName);
if(alreadyExist){
logger.debug("A product with name " + futureName + " already exists");
responseBean.setId(null);
status = Status.CONFLICT;
throw new Exception("Sorry but a product with such name already exists!");
}else{
// evaluate the tags of the product
List<String> tags = new ArrayList<String>();
HelperMethods.getTags(tags, record);
tags.add(THIS_TYPE);
// evaluate the groups
List<String> groups = new ArrayList<String>();
HelperMethods.getGroups(groups, record);
// evaluate the custom fields
Map<String, String> customFields = new HashMap<String, String>();
if(record.getExtras() != null)
customFields = record.getExtras();
// automatically retrieve the other ones
HelperMethods.getExtras(customFields, record);
// add the type
customFields.put(HelperMethods.PRODUCT_TYPE, THIS_TYPE);
// retrieve the user's email and fullname
String authorMail = HelperMethods.getUserEmail(context, SecurityTokenProvider.instance.get());
String authorFullname = HelperMethods.getUserFullname(context, SecurityTokenProvider.instance.get());
if(authorMail == null || authorFullname == null){
logger.debug("Author fullname or mail missing, cannot continue");
responseBean.setId(null);
status = Status.INTERNAL_SERVER_ERROR;
throw new Exception("Sorry but there was not possible to retrieve your fullname/email!");
}else{
// evaluate the resources
List<ResourceBean> resources = HelperMethods.getResourcesFromBean(record, username);
boolean setPublic = false;
// check the license id
String license = null;
if(record.getLicense() == null || record.getLicense().isEmpty())
license = DEFAULT_STOCK_LICENSE;
else
if(HelperMethods.existsLicenseId(record.getLicense()))
license = record.getLicense();
else throw new Exception("Please check the license id!");
long version = record.getVersion() == null ? 1 : record.getVersion();
// create the product
id = catalogue.createCKanDataset(
catalogue.getApiKeyFromUsername(username),
futureTitle,
organization,
authorFullname,
authorMail,
record.getMaintainer(),
record.getMaintainerContact(),
version,
record.getDescription(),
license,
tags,
customFields,
resources,
setPublic);
if(id != null){
logger.info("Product created! Id is " + id);
responseBean.setId(id);
status = Status.CREATED;
responseBean.setError(null);
responseBean.setDatasetUrl(catalogue.getPortletUrl() + "?path=/dataset/" + futureName);
if(!groups.isEmpty()){
logger.info("Launching thread for association to the list of groups " + groups);
new AssociationToGroupThread(groups, id, organization, username, catalogue).start();
}
}
}
}
}
}
}
}catch(Exception e){
logger.error("Failed to create stock record", e);
responseBean.setError(e.getMessage());
}
return Response.status(status).entity(responseBean).build();
}
@DELETE
@Path("delete-product")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response deleteStock(@NotNull(message="missing input value") @Valid DeleteProductBean recordToDelete) throws ValidationException{
// retrieve context and username
Caller caller = AuthorizationProvider.instance.get();
String username = caller.getClient().getId();
String context = ScopeProvider.instance.get();
ResponseCreationBean responseBean = new ResponseCreationBean();
Status status = Status.INTERNAL_SERVER_ERROR;
// check it is a stock ...
logger.info("Received call to delete product with id " + recordToDelete.getId() + ", checking if it is a stock");
try{
DataCatalogue catalogue = HelperMethods.getDataCatalogueRunningInstance(context);
if(catalogue == null){
status = Status.INTERNAL_SERVER_ERROR;
responseBean.setId(null);
throw new Exception("There was a problem while serving your request");
}
// retrieve the catalogue instance
CkanDataset stockInCkan = catalogue.getDataset(recordToDelete.getId(), catalogue.getApiKeyFromUsername(username));
if(stockInCkan == null){
status = Status.NOT_FOUND;
responseBean.setId(null);
throw new Exception("There was a problem while serving your request. This product was not found");
}
// get extras and check there is the field Assessment distribution area that is mandatory for stock
if(stockInCkan.getExtrasAsHashMap().containsKey("Stock Name")){
logger.warn("Ok, this is a stock, removing it");
boolean deleted = catalogue.deleteProduct(stockInCkan.getId(), catalogue.getApiKeyFromUsername(username), true);
if(deleted){
logger.info("Stock DELETED AND PURGED!");
status = Status.OK;
responseBean.setId(stockInCkan.getId());
}
else{
status = Status.INTERNAL_SERVER_ERROR;
throw new Exception("Request failed, sorry");
}
}else{
status = Status.BAD_REQUEST;
throw new Exception("The id you are using doesn't belong to a Stock product!");
}
}catch(Exception e){
logger.error("Failed to delete this ", e);
status = Status.INTERNAL_SERVER_ERROR;
responseBean.setError(e.getMessage());
}
return Response.status(status).entity(responseBean).build();
}
}