argos/dmp-backend/web/src/main/java/eu/eudat/controllers/StorageFileController.java

156 lines
8.0 KiB
Java

package eu.eudat.controllers;
import eu.eudat.audit.AuditableAction;
import eu.eudat.authorization.AuthorizationFlags;
import eu.eudat.authorization.Permission;
import eu.eudat.commons.enums.StorageType;
import eu.eudat.commons.scope.user.UserScope;
import eu.eudat.convention.ConventionService;
import eu.eudat.data.StorageFileEntity;
import eu.eudat.model.StorageFile;
import eu.eudat.model.builder.StorageFileBuilder;
import eu.eudat.model.persist.StorageFilePersist;
import eu.eudat.query.StorageFileQuery;
import eu.eudat.service.storage.StorageFileProperties;
import eu.eudat.service.storage.StorageFileService;
import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.tools.auditing.AuditService;
import gr.cite.tools.data.builder.BuilderFactory;
import gr.cite.tools.data.query.QueryFactory;
import gr.cite.tools.exception.MyApplicationException;
import gr.cite.tools.exception.MyForbiddenException;
import gr.cite.tools.exception.MyNotFoundException;
import gr.cite.tools.fieldset.BaseFieldSet;
import gr.cite.tools.fieldset.FieldSet;
import gr.cite.tools.logging.LoggerService;
import gr.cite.tools.logging.MapLogEntry;
import gr.cite.tools.validation.ValidatorFactory;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.LoggerFactory;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.net.URLConnection;
import java.time.Duration;
import java.util.*;
@RestController
@RequestMapping(path = "api/storage-file")
public class StorageFileController {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(StorageFileController.class));
private final AuditService auditService;
private final QueryFactory queryFactory;
private final BuilderFactory builderFactory;
private final MessageSource messageSource;
private final StorageFileService storageFileService;
private final StorageFileProperties config;
private final UserScope userScope;
private final AuthorizationService authorizationService;
private final ConventionService conventionService;
private final ValidatorFactory validatorFactory;
public StorageFileController(
AuditService auditService,
QueryFactory queryFactory,
BuilderFactory builderFactory, MessageSource messageSource,
StorageFileService storageFileService,
StorageFileProperties config,
UserScope userScope,
AuthorizationService authorizationService, ConventionService conventionService, ValidatorFactory validatorFactory) {
this.auditService = auditService;
this.queryFactory = queryFactory;
this.builderFactory = builderFactory;
this.messageSource = messageSource;
this.storageFileService = storageFileService;
this.config = config;
this.userScope = userScope;
this.authorizationService = authorizationService;
this.conventionService = conventionService;
this.validatorFactory = validatorFactory;
}
@GetMapping("{id}")
public StorageFile get(@PathVariable("id") UUID id, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException {
logger.debug(new MapLogEntry("retrieving " + StorageFile.class.getSimpleName()).And("id", id).And("fields", fieldSet));
this.authorizationService.authorizeForce(Permission.BrowseStorageFile);
StorageFileQuery query = this.queryFactory.query(StorageFileQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).ids(id);
StorageFile model = this.builderFactory.builder(StorageFileBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(fieldSet, query.firstAs(fieldSet));
if (model == null)
throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, StorageFile.class.getSimpleName()}, LocaleContextHolder.getLocale()));
this.auditService.track(AuditableAction.StorageFile_Query, Map.ofEntries(
new AbstractMap.SimpleEntry<String, Object>("id", id),
new AbstractMap.SimpleEntry<String, Object>("fields", fieldSet)
));
return model;
}
@PostMapping("upload-temp-files")
@Transactional
public List<StorageFile> uploadTempFiles(@RequestParam("files") MultipartFile[] files) throws IOException {
logger.debug("upload temp files");
this.authorizationService.authorizeForce(Permission.EditStorageFile);
List<StorageFile> addedFiles = new ArrayList<>();
for (MultipartFile file : files) {
StorageFilePersist storageFilePersist = new StorageFilePersist();
storageFilePersist.setName(FilenameUtils.removeExtension(file.getOriginalFilename()));
storageFilePersist.setExtension(FilenameUtils.getExtension(file.getOriginalFilename()));
storageFilePersist.setMimeType(URLConnection.guessContentTypeFromName(file.getOriginalFilename()));
storageFilePersist.setOwnerId(this.userScope.getUserIdSafe());
storageFilePersist.setStorageType(StorageType.Temp);
storageFilePersist.setLifetime(Duration.ofSeconds(this.config.getTempStoreLifetimeSeconds()));
this.validatorFactory.validator(StorageFilePersist.StorageFilePersistValidator.class).validateForce(storageFilePersist);
StorageFile persisted = this.storageFileService.persistBytes(storageFilePersist, file.getBytes(), new BaseFieldSet(StorageFile._id, StorageFile._name));
addedFiles.add(persisted);
}
this.auditService.track(AuditableAction.StorageFile_Upload, "models", addedFiles);
return addedFiles;
}
@GetMapping("download/{id}")
public ResponseEntity<byte[]> get(@PathVariable("id") UUID id) throws MyApplicationException, MyForbiddenException, MyNotFoundException {
logger.debug(new MapLogEntry("download" ).And("id", id));
this.authorizationService.authorizeForce(Permission.BrowseStorageFile);
StorageFileEntity storageFile = this.queryFactory.query(StorageFileQuery.class).ids(id).firstAs(new BaseFieldSet().ensure(StorageFile._createdAt, StorageFile._fullName, StorageFile._mimeType, StorageFile._extension));
if (storageFile == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, StorageFile.class.getSimpleName()}, LocaleContextHolder.getLocale()));
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.StorageFile_Download, Map.ofEntries(
new AbstractMap.SimpleEntry<String, Object>("id", id)
));
String contentType = storageFile.getMimeType();
if (this.conventionService.isNullOrEmpty(contentType)) contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE;
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.setContentLength(file.length);
responseHeaders.setContentType(MediaType.valueOf(contentType));
responseHeaders.set("Content-Disposition", "attachment; filename=\"" + storageFile.getName() + (storageFile.getExtension().startsWith(".") ? "" : ".") + storageFile.getExtension() + "\"");
responseHeaders.set("Access-Control-Expose-Headers", "Content-Disposition");
responseHeaders.get("Access-Control-Expose-Headers").add("Content-Type");
return new ResponseEntity<>(file, responseHeaders, HttpStatus.OK);
}
}