package eu.europeana.cloud.service.mcs.rest; import eu.europeana.cloud.common.model.File; import eu.europeana.cloud.common.model.Representation; import eu.europeana.cloud.service.aas.authentication.SpringUserUtils; import eu.europeana.cloud.service.mcs.RecordService; import eu.europeana.cloud.service.mcs.Storage; import eu.europeana.cloud.service.mcs.exception.*; import eu.europeana.cloud.service.mcs.rest.storage.selector.PreBufferedInputStream; import eu.europeana.cloud.service.mcs.rest.storage.selector.StorageSelector; import org.apache.commons.io.IOUtils; import org.glassfish.jersey.media.multipart.FormDataParam; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.acls.domain.BasePermission; import org.springframework.security.acls.domain.ObjectIdentityImpl; import org.springframework.security.acls.domain.PrincipalSid; import org.springframework.security.acls.model.MutableAcl; import org.springframework.security.acls.model.MutableAclService; import org.springframework.security.acls.model.ObjectIdentity; import org.springframework.stereotype.Component; import javax.ws.rs.Consumes; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import java.io.InputStream; import java.util.UUID; import static eu.europeana.cloud.common.web.ParamConstants.*; import static eu.europeana.cloud.service.mcs.rest.storage.selector.PreBufferedInputStream.wrap; /** * Handles uploading the file when representation is not created yet. */ @Path("/records/{" + P_CLOUDID + "}/representations/{" + P_REPRESENTATIONNAME + "}/files") @Component @Scope("request") public class FileUploadResource { @Autowired private RecordService recordService; @Autowired private MutableAclService mutableAclService; @Autowired private Integer objectStoreSizeThreshold; private final String REPRESENTATION_CLASS_NAME = Representation.class .getName(); /** * * Creates representation, uploads file and persists this representation in one request * @param uriInfo * @param globalId cloudId * @param schema representation name * @param fileName file name * @param providerId providerId * @param mimeType mimeType of uploaded file * @param data uploaded file content * @return * @throws RepresentationNotExistsException * @throws CannotModifyPersistentRepresentationException * @throws FileNotExistsException * @throws RecordNotExistsException * @throws ProviderNotExistsException * @throws FileAlreadyExistsException * @throws AccessDeniedOrObjectDoesNotExistException * @throws CannotPersistEmptyRepresentationException * * @summary Upload file for non existing representation */ @POST @Consumes(MediaType.MULTIPART_FORM_DATA) @PreAuthorize("isAuthenticated()") public Response sendFile(@Context UriInfo uriInfo, @PathParam(P_CLOUDID) String globalId, @PathParam(P_REPRESENTATIONNAME) String schema, @FormDataParam(F_FILE_NAME) String fileName, @FormDataParam(F_PROVIDER) String providerId, @FormDataParam(F_FILE_MIME) String mimeType, @FormDataParam(F_FILE_DATA) InputStream data) throws RepresentationNotExistsException, CannotModifyPersistentRepresentationException, FileNotExistsException, RecordNotExistsException, ProviderNotExistsException, FileAlreadyExistsException, AccessDeniedOrObjectDoesNotExistException, CannotPersistEmptyRepresentationException { ParamUtil.require(F_FILE_NAME,fileName); ParamUtil.require(F_PROVIDER,providerId); ParamUtil.require(F_FILE_DATA, data); ParamUtil.require(F_FILE_MIME, mimeType); PreBufferedInputStream prebufferedInputStream = wrap(data, objectStoreSizeThreshold); Storage storage = new StorageSelector(prebufferedInputStream, mimeType).selectStorage(); Representation representation = null; representation = recordService.createRepresentation(globalId, schema, providerId); addPrivilegesToRepresentation(representation); File file = addFileToRepresentation(representation, prebufferedInputStream, mimeType, fileName, storage); persistRepresentation(representation); EnrichUriUtil.enrich(uriInfo, globalId, schema, representation.getVersion(), file); return Response.created(file.getContentUri()).tag(file.getMd5()).build(); } private void addPrivilegesToRepresentation(Representation representation) { String creatorName = SpringUserUtils.getUsername(); if (creatorName != null) { ObjectIdentity versionIdentity = new ObjectIdentityImpl( REPRESENTATION_CLASS_NAME, representation.getCloudId() + "/" + representation.getRepresentationName() + "/" + representation.getVersion()); MutableAcl versionAcl = mutableAclService .createAcl(versionIdentity); versionAcl.insertAce(0, BasePermission.READ, new PrincipalSid( creatorName), true); versionAcl.insertAce(1, BasePermission.WRITE, new PrincipalSid( creatorName), true); versionAcl.insertAce(2, BasePermission.DELETE, new PrincipalSid( creatorName), true); versionAcl.insertAce(3, BasePermission.ADMINISTRATION, new PrincipalSid(creatorName), true); mutableAclService.updateAcl(versionAcl); } } private File addFileToRepresentation(Representation representation, InputStream data, String mimeType, String fileName, Storage storage) throws RepresentationNotExistsException, FileAlreadyExistsException, CannotModifyPersistentRepresentationException { File f = new File(); f.setMimeType(mimeType); f.setFileStorage(storage); if (fileName != null) { try { File temp = recordService.getFile(representation.getCloudId(), representation.getRepresentationName(), representation.getVersion(), fileName); if (temp != null) { throw new FileAlreadyExistsException(fileName); } } catch (FileNotExistsException e) { // file does not exist, so continue and add it } } if (fileName == null) { fileName = UUID.randomUUID().toString(); } f.setFileName(fileName); recordService.putContent(representation.getCloudId(), representation.getRepresentationName(), representation.getVersion(), f, data); IOUtils.closeQuietly(data); return f; } private void persistRepresentation(Representation representation) throws CannotModifyPersistentRepresentationException, CannotPersistEmptyRepresentationException, RepresentationNotExistsException { recordService.persistRepresentation(representation.getCloudId(), representation.getRepresentationName(), representation.getVersion()); } }