description use storage file

This commit is contained in:
Efstratios Giannopoulos 2024-02-06 15:03:49 +02:00
parent fd974d3ee4
commit f7dc3e5a32
7 changed files with 302 additions and 67 deletions

View File

@ -48,6 +48,9 @@ public class AuditableAction {
public static final EventId Description_PublicQuery = new EventId(6004, "Description_PublicQuery"); public static final EventId Description_PublicQuery = new EventId(6004, "Description_PublicQuery");
public static final EventId Description_PublicLookup = new EventId(6005, "Description_PublicLookup"); public static final EventId Description_PublicLookup = new EventId(6005, "Description_PublicLookup");
public static final EventId Description_PersistStatus = new EventId(6006, "Description_PersistStatus"); public static final EventId Description_PersistStatus = new EventId(6006, "Description_PersistStatus");
public static final EventId Description_UploadFieldFiles = new EventId(6007, "Description_UploadFieldFiles");
public static final EventId Description_GetFieldFile = new EventId(6008, "Description_GetFieldFile");
public static final EventId Reference_Query = new EventId(7000, "Reference_Query"); public static final EventId Reference_Query = new EventId(7000, "Reference_Query");
public static final EventId Reference_Lookup = new EventId(7001, "Reference_Lookup"); public static final EventId Reference_Lookup = new EventId(7001, "Reference_Lookup");

View File

@ -0,0 +1,74 @@
package eu.eudat.model.persist;
import eu.eudat.commons.validation.BaseValidator;
import eu.eudat.convention.ConventionService;
import eu.eudat.errorcode.ErrorThesaurusProperties;
import gr.cite.tools.validation.specification.Specification;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Scope;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
public class DescriptionFieldFilePersist {
private UUID descriptionTemplateId;
public static final String _descriptionTemplateId = "descriptionTemplateId";
private String fieldId;
public static final String _fieldId = "fieldId";
public UUID getDescriptionTemplateId() {
return descriptionTemplateId;
}
public void setDescriptionTemplateId(UUID descriptionTemplateId) {
this.descriptionTemplateId = descriptionTemplateId;
}
public String getFieldId() {
return fieldId;
}
public void setFieldId(String fieldId) {
this.fieldId = fieldId;
}
@Component(PersistValidator.ValidatorName)
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public static class PersistValidator extends BaseValidator<DescriptionFieldFilePersist> {
public static final String ValidatorName = "DescriptionFieldFilePersistValidator";
private final MessageSource messageSource;
protected PersistValidator(ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource) {
super(conventionService, errors);
this.messageSource = messageSource;
}
@Override
protected Class<DescriptionFieldFilePersist> modelClass() {
return DescriptionFieldFilePersist.class;
}
@Override
protected List<Specification> specifications(DescriptionFieldFilePersist item) {
return Arrays.asList(
this.spec()
.must(() -> this.isValidGuid(item.getDescriptionTemplateId()))
.failOn(DescriptionFieldFilePersist._descriptionTemplateId).failWith(messageSource.getMessage("Validation_Required", new Object[]{DescriptionFieldFilePersist._descriptionTemplateId}, LocaleContextHolder.getLocale())),
this.spec()
.must(() -> !this.isEmpty(item.getFieldId()))
.failOn(DescriptionFieldFilePersist._fieldId).failWith(messageSource.getMessage("Validation_Required", new Object[]{DescriptionFieldFilePersist._fieldId}, LocaleContextHolder.getLocale()))
);
}
}
}

View File

@ -1,7 +1,9 @@
package eu.eudat.service.description; package eu.eudat.service.description;
import com.fasterxml.jackson.core.JsonProcessingException; import eu.eudat.data.StorageFileEntity;
import eu.eudat.model.Description; import eu.eudat.model.Description;
import eu.eudat.model.StorageFile;
import eu.eudat.model.persist.DescriptionFieldFilePersist;
import eu.eudat.model.persist.DescriptionPersist; import eu.eudat.model.persist.DescriptionPersist;
import eu.eudat.model.persist.DescriptionStatusPersist; import eu.eudat.model.persist.DescriptionStatusPersist;
import gr.cite.tools.exception.MyApplicationException; import gr.cite.tools.exception.MyApplicationException;
@ -10,6 +12,7 @@ import gr.cite.tools.exception.MyNotFoundException;
import gr.cite.tools.exception.MyValidationException; import gr.cite.tools.exception.MyValidationException;
import gr.cite.tools.fieldset.FieldSet; import gr.cite.tools.fieldset.FieldSet;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.multipart.MultipartFile;
import javax.management.InvalidApplicationException; import javax.management.InvalidApplicationException;
import java.io.IOException; import java.io.IOException;
@ -26,5 +29,6 @@ public interface DescriptionService {
ResponseEntity<byte[]> export(UUID id, String exportType) throws InvalidApplicationException, IOException; ResponseEntity<byte[]> export(UUID id, String exportType) throws InvalidApplicationException, IOException;
StorageFile uploadFieldFile(DescriptionFieldFilePersist model, MultipartFile file, FieldSet fields) throws IOException;
StorageFileEntity getFieldFile(UUID descriptionId, UUID storageFileId);
} }

View File

@ -10,7 +10,7 @@ import eu.eudat.commons.scope.user.UserScope;
import eu.eudat.commons.types.description.*; import eu.eudat.commons.types.description.*;
import eu.eudat.commons.types.descriptionreference.DescriptionReferenceDataEntity; import eu.eudat.commons.types.descriptionreference.DescriptionReferenceDataEntity;
import eu.eudat.commons.types.descriptiontemplate.FieldSetEntity; import eu.eudat.commons.types.descriptiontemplate.FieldSetEntity;
import eu.eudat.commons.types.dmpreference.DmpReferenceDataEntity; import eu.eudat.commons.types.descriptiontemplate.fielddata.UploadDataEntity;
import eu.eudat.commons.types.notification.*; import eu.eudat.commons.types.notification.*;
import eu.eudat.commons.types.reference.DefinitionEntity; import eu.eudat.commons.types.reference.DefinitionEntity;
import eu.eudat.configurations.notification.NotificationProperties; import eu.eudat.configurations.notification.NotificationProperties;
@ -23,35 +23,33 @@ import eu.eudat.integrationevent.outbox.notification.NotifyIntegrationEvent;
import eu.eudat.integrationevent.outbox.notification.NotifyIntegrationEventHandler; import eu.eudat.integrationevent.outbox.notification.NotifyIntegrationEventHandler;
import eu.eudat.model.*; import eu.eudat.model.*;
import eu.eudat.model.builder.DescriptionBuilder; import eu.eudat.model.builder.DescriptionBuilder;
import eu.eudat.model.builder.StorageFileBuilder;
import eu.eudat.model.deleter.DescriptionDeleter; import eu.eudat.model.deleter.DescriptionDeleter;
import eu.eudat.model.deleter.DescriptionReferenceDeleter; import eu.eudat.model.deleter.DescriptionReferenceDeleter;
import eu.eudat.model.deleter.DescriptionTagDeleter; import eu.eudat.model.deleter.DescriptionTagDeleter;
import eu.eudat.model.file.FileEnvelope; import eu.eudat.model.file.FileEnvelope;
import eu.eudat.model.persist.DescriptionPersist; import eu.eudat.model.persist.*;
import eu.eudat.model.persist.DescriptionReferencePersist;
import eu.eudat.model.persist.DescriptionStatusPersist;
import eu.eudat.model.persist.ReferencePersist;
import eu.eudat.model.persist.descriptionproperties.*; import eu.eudat.model.persist.descriptionproperties.*;
import eu.eudat.model.persist.descriptionreference.DescriptionReferenceDataPersist; import eu.eudat.model.persist.descriptionreference.DescriptionReferenceDataPersist;
import eu.eudat.model.persist.dmpreference.DmpReferenceDataPersist;
import eu.eudat.model.persist.referencedefinition.DefinitionPersist; import eu.eudat.model.persist.referencedefinition.DefinitionPersist;
import eu.eudat.query.*; import eu.eudat.query.*;
import eu.eudat.service.elastic.ElasticService; import eu.eudat.service.elastic.ElasticService;
import eu.eudat.service.storage.StorageFileProperties;
import eu.eudat.service.storage.StorageFileService;
import eu.eudat.service.transformer.FileTransformerService; import eu.eudat.service.transformer.FileTransformerService;
import gr.cite.commons.web.authz.service.AuthorizationService; import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.tools.data.builder.BuilderFactory; import gr.cite.tools.data.builder.BuilderFactory;
import gr.cite.tools.data.deleter.DeleterFactory; import gr.cite.tools.data.deleter.DeleterFactory;
import gr.cite.tools.data.query.Ordering; import gr.cite.tools.data.query.Ordering;
import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.data.query.QueryFactory;
import gr.cite.tools.exception.MyApplicationException; import gr.cite.tools.exception.*;
import gr.cite.tools.exception.MyForbiddenException;
import gr.cite.tools.exception.MyNotFoundException;
import gr.cite.tools.exception.MyValidationException;
import gr.cite.tools.fieldset.BaseFieldSet; import gr.cite.tools.fieldset.BaseFieldSet;
import gr.cite.tools.fieldset.FieldSet; import gr.cite.tools.fieldset.FieldSet;
import gr.cite.tools.logging.LoggerService; import gr.cite.tools.logging.LoggerService;
import gr.cite.tools.logging.MapLogEntry; import gr.cite.tools.logging.MapLogEntry;
import gr.cite.tools.validation.ValidatorFactory;
import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManager;
import org.apache.commons.io.FilenameUtils;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -62,10 +60,14 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.unit.DataSize;
import org.springframework.web.multipart.MultipartFile;
import javax.management.InvalidApplicationException; import javax.management.InvalidApplicationException;
import java.io.IOException; import java.io.IOException;
import java.net.URLConnection;
import java.nio.file.Files; import java.nio.file.Files;
import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -74,52 +76,41 @@ import java.util.stream.Collectors;
public class DescriptionServiceImpl implements DescriptionService { public class DescriptionServiceImpl implements DescriptionService {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(DescriptionServiceImpl.class)); private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(DescriptionServiceImpl.class));
private final EntityManager entityManager; private final EntityManager entityManager;
private final AuthorizationService authorizationService; private final AuthorizationService authorizationService;
private final DeleterFactory deleterFactory; private final DeleterFactory deleterFactory;
private final BuilderFactory builderFactory; private final BuilderFactory builderFactory;
private final ConventionService conventionService; private final ConventionService conventionService;
private final ErrorThesaurusProperties errors; private final ErrorThesaurusProperties errors;
private final MessageSource messageSource; private final MessageSource messageSource;
private final EventBroker eventBroker; private final EventBroker eventBroker;
private final QueryFactory queryFactory; private final QueryFactory queryFactory;
private final JsonHandlingService jsonHandlingService; private final JsonHandlingService jsonHandlingService;
private final UserScope userScope; private final UserScope userScope;
private final XmlHandlingService xmlHandlingService; private final XmlHandlingService xmlHandlingService;
private final FileTransformerService fileTransformerService; private final FileTransformerService fileTransformerService;
private final NotifyIntegrationEventHandler eventHandler; private final NotifyIntegrationEventHandler eventHandler;
private final NotificationProperties notificationProperties; private final NotificationProperties notificationProperties;
private final ElasticService elasticService; private final ElasticService elasticService;
private final ValidatorFactory validatorFactory;
private final StorageFileProperties storageFileConfig;
private final StorageFileService storageFileService;
@Autowired @Autowired
public DescriptionServiceImpl( public DescriptionServiceImpl(
EntityManager entityManager, EntityManager entityManager,
AuthorizationService authorizationService, AuthorizationService authorizationService,
DeleterFactory deleterFactory, DeleterFactory deleterFactory,
BuilderFactory builderFactory, BuilderFactory builderFactory,
ConventionService conventionService, ConventionService conventionService,
ErrorThesaurusProperties errors, ErrorThesaurusProperties errors,
MessageSource messageSource, MessageSource messageSource,
EventBroker eventBroker, EventBroker eventBroker,
QueryFactory queryFactory, QueryFactory queryFactory,
JsonHandlingService jsonHandlingService, JsonHandlingService jsonHandlingService,
UserScope userScope, UserScope userScope,
XmlHandlingService xmlHandlingService, NotifyIntegrationEventHandler eventHandler, NotificationProperties notificationProperties, FileTransformerService fileTransformerService, ElasticService elasticService) { XmlHandlingService xmlHandlingService, NotifyIntegrationEventHandler eventHandler, NotificationProperties notificationProperties, FileTransformerService fileTransformerService, ElasticService elasticService, ValidatorFactory validatorFactory, StorageFileProperties storageFileConfig, StorageFileService storageFileService) {
this.entityManager = entityManager; this.entityManager = entityManager;
this.authorizationService = authorizationService; this.authorizationService = authorizationService;
this.deleterFactory = deleterFactory; this.deleterFactory = deleterFactory;
@ -136,6 +127,9 @@ public class DescriptionServiceImpl implements DescriptionService {
this.notificationProperties = notificationProperties; this.notificationProperties = notificationProperties;
this.fileTransformerService = fileTransformerService; this.fileTransformerService = fileTransformerService;
this.elasticService = elasticService; this.elasticService = elasticService;
this.validatorFactory = validatorFactory;
this.storageFileConfig = storageFileConfig;
this.storageFileService = storageFileService;
} }
//region Persist //region Persist
@ -405,7 +399,15 @@ public class DescriptionServiceImpl implements DescriptionService {
FieldEntity data = new FieldEntity(); FieldEntity data = new FieldEntity();
if (persist == null) return data; if (persist == null) return data;
if (FieldType.isTextType(fieldType)) data.setTextValue(persist.getTextValue()); if (FieldType.isTextType(fieldType)) {
if (FieldType.UPLOAD.equals(fieldType)){
StorageFile storageFile = this.storageFileService.copyToStorage(UUID.fromString(persist.getTextValue()), StorageType.Main, true, new BaseFieldSet().ensure(StorageFile._id));
this.storageFileService.updatePurgeAt(storageFile.getId(), null);
data.setTextValue(storageFile.getId().toString());
} else {
data.setTextValue(persist.getTextValue());
}
}
else if (FieldType.isDateType(fieldType)) data.setDateValue(persist.getDateValue()); else if (FieldType.isDateType(fieldType)) data.setDateValue(persist.getDateValue());
else if (FieldType.isTextListType(fieldType)) data.setTextListValue(persist.getTextListValue()); else if (FieldType.isTextListType(fieldType)) data.setTextListValue(persist.getTextListValue());
else if (FieldType.isExternalIdentifierType(fieldType) && persist.getExternalIdentifier() != null) data.setExternalIdentifier(this.buildExternalIdentifierEntity(persist.getExternalIdentifier())); else if (FieldType.isExternalIdentifierType(fieldType) && persist.getExternalIdentifier() != null) data.setExternalIdentifier(this.buildExternalIdentifierEntity(persist.getExternalIdentifier()));
@ -702,14 +704,78 @@ public class DescriptionServiceImpl implements DescriptionService {
@Override @Override
public ResponseEntity<byte[]> export(UUID id, String exportType) throws InvalidApplicationException, IOException { public ResponseEntity<byte[]> export(UUID id, String exportType) throws InvalidApplicationException, IOException {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
String type = exportType;
FileEnvelope fileEnvelope = this.fileTransformerService.exportDescription(id, type); FileEnvelope fileEnvelope = this.fileTransformerService.exportDescription(id, exportType);
headers.add("Content-Disposition", "attachment;filename=" + fileEnvelope.getFilename()); headers.add("Content-Disposition", "attachment;filename=" + fileEnvelope.getFilename());
byte[] data = Files.readAllBytes(fileEnvelope.getFile().toPath()); byte[] data = Files.readAllBytes(fileEnvelope.getFile().toPath());
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
return new ResponseEntity<>(data, headers, HttpStatus.OK); return new ResponseEntity<>(data, headers, HttpStatus.OK);
} }
//endregion //endregion
@Override
public StorageFile uploadFieldFile(DescriptionFieldFilePersist model, MultipartFile file, FieldSet fields) throws IOException {
this.authorizationService.authorizeForce(Permission.EditDescription);
DescriptionTemplateEntity descriptionTemplate = this.queryFactory.query(DescriptionTemplateQuery.class).ids(model.getDescriptionTemplateId()).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).first();
if (descriptionTemplate == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getDescriptionTemplateId(), DescriptionTemplate.class.getSimpleName()}, LocaleContextHolder.getLocale()));
eu.eudat.commons.types.descriptiontemplate.DefinitionEntity definition = this.xmlHandlingService.fromXmlSafe(eu.eudat.commons.types.descriptiontemplate.DefinitionEntity.class, descriptionTemplate.getDefinition());
if (definition == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getDescriptionTemplateId(), eu.eudat.commons.types.descriptiontemplate.DefinitionEntity.class.getSimpleName()}, LocaleContextHolder.getLocale()));
eu.eudat.commons.types.descriptiontemplate.FieldEntity fieldEntity = definition.getFieldById(model.getFieldId()).stream().filter(x -> x != null && x.getData() != null && x.getData().getFieldType().equals(FieldType.UPLOAD)).findFirst().orElse(null);
if (fieldEntity == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getFieldId(), eu.eudat.commons.types.descriptiontemplate.FieldEntity.class.getSimpleName()}, LocaleContextHolder.getLocale()));
UploadDataEntity uploadDataEntity = (UploadDataEntity)fieldEntity.getData();
if (DataSize.ofBytes(file.getSize()).equals(DataSize.ofMegabytes(uploadDataEntity.getMaxFileSizeInMB()))) {
throw new MyValidationException("The uploaded file is too large");
}
if(!this.conventionService.isListNullOrEmpty(uploadDataEntity.getTypes())) {
boolean isContentTypeAccepted = false;
for (UploadDataEntity.UploadDataOptionEntity option: uploadDataEntity.getTypes()) {
if(Objects.equals(file.getContentType(), option.getValue())) {
isContentTypeAccepted = true;
break;
}
}
if (!isContentTypeAccepted){
throw new MyValidationException("The uploaded file has an unaccepted type");
}
}
StorageFilePersist storageFilePersist = new StorageFilePersist();
storageFilePersist.setName(FilenameUtils.removeExtension(file.getName()));
storageFilePersist.setExtension(FilenameUtils.getExtension(file.getName()));
storageFilePersist.setMimeType(URLConnection.guessContentTypeFromName(file.getName()));
storageFilePersist.setOwnerId(this.userScope.getUserIdSafe());
storageFilePersist.setStorageType(StorageType.Temp);
storageFilePersist.setLifetime(Duration.ofSeconds(this.storageFileConfig.getTempStoreLifetimeSeconds()));
this.validatorFactory.validator(StorageFilePersist.StorageFilePersistValidator.class).validateForce(storageFilePersist);
return this.storageFileService.persistBytes(storageFilePersist, file.getBytes(), BaseFieldSet.build(fields, StorageFile._id, StorageFile._name));
}
@Override
public StorageFileEntity getFieldFile(UUID descriptionId, UUID storageFileId) {
this.authorizationService.authorizeForce(Permission.BrowseDescription);
DescriptionEntity descriptionEntity = this.queryFactory.query(DescriptionQuery.class).isActive(IsActive.Active).ids(descriptionId).first();
if (descriptionEntity == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{descriptionId, Description.class.getSimpleName()}, LocaleContextHolder.getLocale()));
DmpDescriptionTemplateEntity dmpDescriptionTemplateEntity = this.queryFactory.query(DmpDescriptionTemplateQuery.class).ids(descriptionEntity.getDmpDescriptionTemplateId()).isActive(IsActive.Active).first();
if (dmpDescriptionTemplateEntity == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{descriptionEntity.getDmpDescriptionTemplateId(), DmpDescriptionTemplate.class.getSimpleName()}, LocaleContextHolder.getLocale()));
DmpEntity dmpEntity = this.queryFactory.query(DmpQuery.class).ids(dmpDescriptionTemplateEntity.getDmpId()).isActive(IsActive.Active).first();
if (dmpEntity == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{dmpDescriptionTemplateEntity.getDmpId(), Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale()));
if (!dmpEntity.getAccessType().equals(DmpAccessType.Public))
{
boolean isDmpUser = this.queryFactory.query(DmpUserQuery.class).dmpIds(dmpEntity.getId()).userIds(this.userScope.getUserIdSafe()).isActives(IsActive.Active).count() > 0;
if (!isDmpUser) throw new MyUnauthorizedException();
}
StorageFileEntity storageFile = this.queryFactory.query(StorageFileQuery.class).ids(storageFileId).first();
if (storageFile == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{storageFileId, StorageFile.class.getSimpleName()}, LocaleContextHolder.getLocale()));
return storageFile;
}
} }

View File

@ -16,8 +16,8 @@ import java.util.UUID;
public interface StorageFileService extends ApplicationListener<ApplicationReadyEvent> { public interface StorageFileService extends ApplicationListener<ApplicationReadyEvent> {
StorageFile persistBytes(StorageFilePersist model, byte[] payload, FieldSet fields) throws IOException; StorageFile persistBytes(StorageFilePersist model, byte[] payload, FieldSet fields) throws IOException;
StorageFile persistString(StorageFilePersist model, String payload, FieldSet fields, Charset charset) throws IOException; StorageFile persistString(StorageFilePersist model, String payload, FieldSet fields, Charset charset) throws IOException;
boolean moveToStorage(UUID fileId, StorageType storageType); StorageFile moveToStorage(UUID fileId, StorageType storageType, boolean replaceDestination, FieldSet fields);
boolean copyToStorage(UUID fileId, StorageType storageType); StorageFile copyToStorage(UUID fileId, StorageType storageType, boolean replaceDestination, FieldSet fields);
boolean exists(UUID fileId); boolean exists(UUID fileId);

View File

@ -93,7 +93,7 @@ public class StorageFileServiceImpl implements StorageFileService {
this.entityManager.persist(storageFile); this.entityManager.persist(storageFile);
this.entityManager.flush(); this.entityManager.flush();
return this.builderFactory.builder(StorageFileBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).build(BaseFieldSet.build(fields, Description._id), storageFile); return this.builderFactory.builder(StorageFileBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).build(BaseFieldSet.build(fields, StorageFile._id), storageFile);
} }
@Override @Override
@ -104,6 +104,7 @@ public class StorageFileServiceImpl implements StorageFileService {
private StorageFileEntity buildDataEntry(StorageFilePersist model) { private StorageFileEntity buildDataEntry(StorageFilePersist model) {
StorageFileEntity data = new StorageFileEntity(); StorageFileEntity data = new StorageFileEntity();
data.setId(UUID.randomUUID());
data.setFileRef(UUID.randomUUID().toString().replaceAll("-", "").toLowerCase(Locale.ROOT)); data.setFileRef(UUID.randomUUID().toString().replaceAll("-", "").toLowerCase(Locale.ROOT));
data.setName(model.getName()); data.setName(model.getName());
data.setOwnerId(model.getOwnerId()); data.setOwnerId(model.getOwnerId());
@ -117,42 +118,74 @@ public class StorageFileServiceImpl implements StorageFileService {
} }
@Override @Override
public boolean moveToStorage(UUID fileId, StorageType storageType) { public StorageFile moveToStorage(UUID fileId, StorageType storageType, boolean replaceDestination, FieldSet fields) {
try { try {
StorageFileEntity storageFile = this.entityManager.find(StorageFileEntity.class, fileId); StorageFileEntity storageFile = this.entityManager.find(StorageFileEntity.class, fileId);
if (storageFile == null) return false; if (storageFile == null) return null;
this.authorizeForce(storageFile, StorageFilePermission.Read); this.authorizeForce(storageFile, StorageFilePermission.Read);
File file = new File(this.filePath(storageFile.getFileRef(), storageFile.getStorageType())); File file = new File(this.filePath(storageFile.getFileRef(), storageFile.getStorageType()));
if (!file.exists()) return false; if (!file.exists()) return null;
File destinationFile = new File(this.filePath(storageFile.getFileRef(), storageFile.getStorageType())); File destinationFile = new File(this.filePath(storageFile.getFileRef(), storageFile.getStorageType()));
if (file.exists() && !replaceDestination) return null;
boolean fileCopied = FileCopyUtils.copy(file, destinationFile) > 0; boolean fileCopied = FileCopyUtils.copy(file, destinationFile) > 0;
if (!fileCopied) return false; if (!fileCopied) return null;
return file.delete();
storageFile.setStorageType(storageType);
this.entityManager.merge(storageFile);
file.delete();
this.entityManager.merge(storageFile);
return this.builderFactory.builder(StorageFileBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).build(BaseFieldSet.build(fields, StorageFile._id), storageFile);
} }
catch (Exception ex) { catch (Exception ex) {
logger.warn("problem reading byte content of storage file " + fileId, ex); logger.warn("problem reading byte content of storage file " + fileId, ex);
return false; return null;
} }
} }
@Override @Override
public boolean copyToStorage(UUID fileId, StorageType storageType) { public StorageFile copyToStorage(UUID fileId, StorageType storageType, boolean replaceDestination, FieldSet fields) {
try { try {
StorageFileEntity storageFile = this.entityManager.find(StorageFileEntity.class, fileId); StorageFileEntity storageFile = this.entityManager.find(StorageFileEntity.class, fileId);
if (storageFile == null) return false; if (storageFile == null) return null;
this.authorizeForce(storageFile, StorageFilePermission.Read); this.authorizeForce(storageFile, StorageFilePermission.Read);
File file = new File(this.filePath(storageFile.getFileRef(), storageFile.getStorageType())); File file = new File(this.filePath(storageFile.getFileRef(), storageFile.getStorageType()));
if (!file.exists()) return false; if (!file.exists()) return null;
File destinationFile = new File(this.filePath(storageFile.getFileRef(), storageType));
if (file.exists() && !replaceDestination) return null;
boolean fileCopied = FileCopyUtils.copy(file, destinationFile) > 0;
if (!fileCopied) return null;
StorageFileEntity data = new StorageFileEntity();
data.setId(UUID.randomUUID());
data.setFileRef(storageFile.getFileRef());
data.setName(storageFile.getName());
data.setOwnerId(storageFile.getOwnerId());
data.setExtension(storageFile.getExtension());
data.setStorageType(storageFile.getStorageType());
data.setMimeType(storageFile.getMimeType());
data.setCreatedAt(Instant.now());
data.setPurgeAt(storageFile.getPurgeAt());
this.entityManager.persist(data);
this.entityManager.merge(storageFile);
return this.builderFactory.builder(StorageFileBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).build(BaseFieldSet.build(fields, StorageFile._id), storageFile);
File destinationFile = new File(this.filePath(storageFile.getFileRef(), storageFile.getStorageType()));
return FileCopyUtils.copy(file, destinationFile) > 0;
} }
catch (Exception ex) { catch (Exception ex) {
logger.warn("problem reading byte content of storage file " + fileId, ex); logger.warn("problem reading byte content of storage file " + fileId, ex);
return false; return null;
} }
} }

View File

@ -1,11 +1,19 @@
package eu.eudat.controllers.v2; package eu.eudat.controllers.v2;
import com.fasterxml.jackson.core.JsonProcessingException;
import eu.eudat.audit.AuditableAction; import eu.eudat.audit.AuditableAction;
import eu.eudat.authorization.AuthorizationFlags; import eu.eudat.authorization.AuthorizationFlags;
import eu.eudat.authorization.Permission;
import eu.eudat.commons.enums.DmpAccessType; import eu.eudat.commons.enums.DmpAccessType;
import eu.eudat.commons.enums.DmpStatus; import eu.eudat.commons.enums.DmpStatus;
import eu.eudat.commons.enums.IsActive; import eu.eudat.commons.enums.IsActive;
import eu.eudat.commons.enums.StorageType;
import eu.eudat.convention.ConventionService;
import eu.eudat.data.StorageFileEntity;
import eu.eudat.model.StorageFile;
import eu.eudat.model.persist.DescriptionFieldFilePersist;
import eu.eudat.model.persist.StorageFilePersist;
import eu.eudat.service.storage.StorageFileService;
import gr.cite.tools.fieldset.BaseFieldSet;
import gr.cite.tools.validation.ValidationFilterAnnotation; import gr.cite.tools.validation.ValidationFilterAnnotation;
import eu.eudat.model.Description; import eu.eudat.model.Description;
import eu.eudat.model.Dmp; import eu.eudat.model.Dmp;
@ -21,7 +29,6 @@ import eu.eudat.query.DmpQuery;
import eu.eudat.query.lookup.DescriptionLookup; import eu.eudat.query.lookup.DescriptionLookup;
import eu.eudat.service.description.DescriptionService; import eu.eudat.service.description.DescriptionService;
import eu.eudat.service.elastic.ElasticQueryHelperService; import eu.eudat.service.elastic.ElasticQueryHelperService;
import eu.eudat.service.transformer.FileTransformerService;
import gr.cite.tools.auditing.AuditService; import gr.cite.tools.auditing.AuditService;
import gr.cite.tools.data.builder.BuilderFactory; import gr.cite.tools.data.builder.BuilderFactory;
import gr.cite.tools.data.censor.CensorFactory; import gr.cite.tools.data.censor.CensorFactory;
@ -32,15 +39,22 @@ import gr.cite.tools.exception.MyNotFoundException;
import gr.cite.tools.fieldset.FieldSet; import gr.cite.tools.fieldset.FieldSet;
import gr.cite.tools.logging.LoggerService; import gr.cite.tools.logging.LoggerService;
import gr.cite.tools.logging.MapLogEntry; import gr.cite.tools.logging.MapLogEntry;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.context.MessageSource; import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.management.InvalidApplicationException; import javax.management.InvalidApplicationException;
import java.io.IOException; import java.io.IOException;
import java.net.URLConnection;
import java.time.Duration;
import java.util.*; import java.util.*;
import static eu.eudat.authorization.AuthorizationFlags.Public; import static eu.eudat.authorization.AuthorizationFlags.Public;
@ -63,14 +77,16 @@ public class DescriptionController {
private final MessageSource messageSource; private final MessageSource messageSource;
private final ElasticQueryHelperService elasticQueryHelperService; private final ElasticQueryHelperService elasticQueryHelperService;
private final StorageFileService storageFileService;
private final ConventionService conventionService;
public DescriptionController( public DescriptionController(
BuilderFactory builderFactory, BuilderFactory builderFactory,
AuditService auditService, AuditService auditService,
DescriptionService descriptionService, DescriptionService descriptionService,
CensorFactory censorFactory, CensorFactory censorFactory,
QueryFactory queryFactory, QueryFactory queryFactory,
MessageSource messageSource, MessageSource messageSource,
ElasticQueryHelperService elasticQueryHelperService) { ElasticQueryHelperService elasticQueryHelperService, StorageFileService storageFileService, ConventionService conventionService) {
this.builderFactory = builderFactory; this.builderFactory = builderFactory;
this.auditService = auditService; this.auditService = auditService;
this.descriptionService = descriptionService; this.descriptionService = descriptionService;
@ -78,6 +94,8 @@ public class DescriptionController {
this.queryFactory = queryFactory; this.queryFactory = queryFactory;
this.messageSource = messageSource; this.messageSource = messageSource;
this.elasticQueryHelperService = elasticQueryHelperService; this.elasticQueryHelperService = elasticQueryHelperService;
this.storageFileService = storageFileService;
this.conventionService = conventionService;
} }
@PostMapping("public/query") @PostMapping("public/query")
@ -192,4 +210,41 @@ public class DescriptionController {
return this.descriptionService.export(id, exportType); return this.descriptionService.export(id, exportType);
} }
@PostMapping("field-file/upload")
@Transactional
@ValidationFilterAnnotation(validator = DescriptionFieldFilePersist.PersistValidator.ValidatorName, argumentName = "model")
public StorageFile uploadFieldFiles(@RequestParam("file") MultipartFile file, @RequestParam("model") DescriptionFieldFilePersist model, FieldSet fieldSet) throws IOException {
logger.debug(new MapLogEntry("uploadFieldFiles" + Description.class.getSimpleName()).And("model", model).And("fieldSet", fieldSet));
StorageFile persisted = this.descriptionService.uploadFieldFile(model, file, fieldSet);
this.auditService.track(AuditableAction.Description_UploadFieldFiles, Map.ofEntries(
new AbstractMap.SimpleEntry<String, Object>("model", model),
new AbstractMap.SimpleEntry<String, Object>("fields", fieldSet)
));
return persisted;
}
@GetMapping("{id}/field-file/{fileId}")
public ResponseEntity<ByteArrayResource> getFieldFile(@PathVariable("id") UUID id, @PathVariable("fileId") UUID fileId) throws MyApplicationException, MyForbiddenException, MyNotFoundException {
logger.debug(new MapLogEntry("get Field File" + Description.class.getSimpleName()).And("id", id).And("fileId", fileId));
StorageFileEntity storageFile = this.descriptionService.getFieldFile(id, fileId);
byte[] file = this.storageFileService.readAsBytesSafe(id);
if (file == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, StorageFile.class.getSimpleName()}, LocaleContextHolder.getLocale()));
this.auditService.track(AuditableAction.Description_GetFieldFile, Map.ofEntries(
new AbstractMap.SimpleEntry<String, Object>("id", id)
));
String contentType = storageFile.getMimeType();
if (this.conventionService.isNullOrEmpty(contentType)) contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE;
return ResponseEntity.ok()
.contentType(MediaType.valueOf(contentType))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + storageFile.getName() + (storageFile.getExtension().startsWith(".") ? "" : ".") + storageFile.getExtension() + "\"")
.body(new ByteArrayResource(file));
}
} }