diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/file/FileEnvelope.java b/dmp-backend/core/src/main/java/eu/eudat/model/file/FileEnvelope.java index 3b5b25e39..ac1bb1a31 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/model/file/FileEnvelope.java +++ b/dmp-backend/core/src/main/java/eu/eudat/model/file/FileEnvelope.java @@ -7,7 +7,7 @@ import java.io.File; */ public class FileEnvelope { private String filename; - private File file; + private byte[] file; public String getFilename() { return filename; @@ -17,11 +17,11 @@ public class FileEnvelope { this.filename = filename; } - public File getFile() { + public byte[] getFile() { return file; } - public void setFile(File file) { + public void setFile(byte[] file) { this.file = file; } } diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/description/DescriptionServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/service/description/DescriptionServiceImpl.java index 5d384c28e..ec6c29407 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/description/DescriptionServiceImpl.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/description/DescriptionServiceImpl.java @@ -730,7 +730,7 @@ public class DescriptionServiceImpl implements DescriptionService { FileEnvelope fileEnvelope = this.fileTransformerService.exportDescription(id, exportType); headers.add("Content-Disposition", "attachment;filename=" + fileEnvelope.getFilename()); - byte[] data = Files.readAllBytes(fileEnvelope.getFile().toPath()); + byte[] data = fileEnvelope.getFile(); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); return new ResponseEntity<>(data, headers, HttpStatus.OK); } diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpServiceImpl.java index 8e44298e1..7da59e9b5 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpServiceImpl.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpServiceImpl.java @@ -506,7 +506,7 @@ public class DmpServiceImpl implements DmpService { FileEnvelope fileEnvelope = this.fileTransformerService.exportDmp(id, exportType); headers.add("Content-Disposition", "attachment;filename=" + fileEnvelope.getFilename()); - byte[] data = Files.readAllBytes(fileEnvelope.getFile().toPath()); + byte[] data = fileEnvelope.getFile(); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); return new ResponseEntity<>(data, headers, HttpStatus.OK); } diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/language/LanguageServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/service/language/LanguageServiceImpl.java index 2975ac6bc..47892b25b 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/language/LanguageServiceImpl.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/language/LanguageServiceImpl.java @@ -27,7 +27,6 @@ import jakarta.persistence.EntityManager; import org.slf4j.LoggerFactory; import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; -import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; import javax.management.InvalidApplicationException; @@ -50,13 +49,12 @@ public class LanguageServiceImpl implements LanguageService { private final ConventionService conventionService; private final MessageSource messageSource; private final ErrorThesaurusProperties errors; - private final Environment environment; private final StorageFileService storageFileService; public LanguageServiceImpl( EntityManager entityManager, AuthorizationService authorizationService, DeleterFactory deleterFactory, BuilderFactory builderFactory, - ConventionService conventionService, MessageSource messageSource, ErrorThesaurusProperties errors, Environment environment, StorageFileService storageFileService){ + ConventionService conventionService, MessageSource messageSource, ErrorThesaurusProperties errors, StorageFileService storageFileService){ this.entityManager = entityManager; this.authorizationService = authorizationService; this.deleterFactory = deleterFactory; @@ -64,7 +62,6 @@ public class LanguageServiceImpl implements LanguageService { this.conventionService = conventionService; this.messageSource = messageSource; this.errors = errors; - this.environment = environment; this.storageFileService = storageFileService; } diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/storage/StorageFileService.java b/dmp-backend/core/src/main/java/eu/eudat/service/storage/StorageFileService.java index 9b250176d..35926f360 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/storage/StorageFileService.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/storage/StorageFileService.java @@ -1,6 +1,7 @@ package eu.eudat.service.storage; import eu.eudat.commons.enums.StorageType; +import eu.eudat.commons.enums.SupportiveMaterialFieldType; import eu.eudat.model.StorageFile; import eu.eudat.model.persist.StorageFilePersist; import gr.cite.tools.fieldset.FieldSet; @@ -39,6 +40,8 @@ public interface StorageFileService extends ApplicationListener { + return this.getFaq(language); + } + case About -> { + return this.getAbout(language); + } + case Glossary -> { + return this.getGlossary(language); + } + case TermsOfService -> { + return this.getTermsOfService(language); + } + case UserGuide -> { + return this.getUserGuide(language); + } + default -> throw new InternalError("unknown type: " + type); + } + } + + @Override public byte[] getUserGuide(String language) { return this.getLocalized(this.config.getMaterialFiles().getUserGuide(), this.config.getMaterialFiles().getUserGuideNamePattern(), language); diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/supportivematerial/SupportiveMaterialCacheService.java b/dmp-backend/core/src/main/java/eu/eudat/service/supportivematerial/SupportiveMaterialCacheService.java index c12c5d99a..6a71c4d0b 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/supportivematerial/SupportiveMaterialCacheService.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/supportivematerial/SupportiveMaterialCacheService.java @@ -1,6 +1,7 @@ package eu.eudat.service.supportivematerial; +import eu.eudat.commons.enums.SupportiveMaterialFieldType; import gr.cite.tools.cache.CacheService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -16,23 +17,17 @@ public class SupportiveMaterialCacheService extends CacheService keyParts = new HashMap<>(); - keyParts.put("$material$", name.toLowerCase(Locale.ROOT)); - //keyParts.put("$material_content$", new String(content, StandardCharsets.UTF_8).toLowerCase(Locale.ROOT)); + keyParts.put("$lang$", language.toLowerCase(Locale.ROOT)); + keyParts.put("$type$", type.name().toLowerCase(Locale.ROOT)); return this.generateKey(keyParts); } diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/supportivematerial/SupportiveMaterialService.java b/dmp-backend/core/src/main/java/eu/eudat/service/supportivematerial/SupportiveMaterialService.java index 57396f1ae..2dad40227 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/supportivematerial/SupportiveMaterialService.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/supportivematerial/SupportiveMaterialService.java @@ -1,5 +1,6 @@ package eu.eudat.service.supportivematerial; +import eu.eudat.commons.enums.SupportiveMaterialFieldType; import eu.eudat.model.SupportiveMaterial; import eu.eudat.model.persist.SupportiveMaterialPersist; import gr.cite.tools.exception.MyApplicationException; @@ -19,7 +20,7 @@ import org.springframework.http.ResponseEntity; public interface SupportiveMaterialService { - ResponseEntity getResponseEntity(String lang, Stream paths) throws IOException; + byte[] loadFromFile(String language, SupportiveMaterialFieldType type) throws IOException; SupportiveMaterial persist(SupportiveMaterialPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JAXBException; diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/supportivematerial/SupportiveMaterialServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/service/supportivematerial/SupportiveMaterialServiceImpl.java index 0c9cd9569..208fed715 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/supportivematerial/SupportiveMaterialServiceImpl.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/supportivematerial/SupportiveMaterialServiceImpl.java @@ -3,6 +3,7 @@ package eu.eudat.service.supportivematerial; import eu.eudat.authorization.AuthorizationFlags; import eu.eudat.authorization.Permission; import eu.eudat.commons.enums.IsActive; +import eu.eudat.commons.enums.SupportiveMaterialFieldType; import eu.eudat.convention.ConventionService; import eu.eudat.data.SupportiveMaterialEntity; import eu.eudat.model.SupportiveMaterial; @@ -11,6 +12,7 @@ import eu.eudat.model.deleter.SupportiveMaterialDeleter; import eu.eudat.model.persist.SupportiveMaterialPersist; import eu.eudat.query.SupportiveMaterialQuery; import eu.eudat.service.dmpblueprint.DmpBlueprintServiceImpl; +import eu.eudat.service.storage.StorageFileService; import gr.cite.commons.web.authz.service.AuthorizationService; import gr.cite.tools.data.builder.BuilderFactory; import gr.cite.tools.data.deleter.DeleterFactory; @@ -57,11 +59,12 @@ public class SupportiveMaterialServiceImpl implements SupportiveMaterialService{ private final MessageSource messageSource; private final QueryFactory queryFactory; private final SupportiveMaterialCacheService supportiveMaterialCacheService; + private final StorageFileService storageFileService; public SupportiveMaterialServiceImpl( - EntityManager entityManager, AuthorizationService authorizationService, DeleterFactory deleterFactory, BuilderFactory builderFactory, - ConventionService conventionService, MessageSource messageSource, QueryFactory queryFactory, - SupportiveMaterialCacheService supportiveMaterialCacheService + EntityManager entityManager, AuthorizationService authorizationService, DeleterFactory deleterFactory, BuilderFactory builderFactory, + ConventionService conventionService, MessageSource messageSource, QueryFactory queryFactory, + SupportiveMaterialCacheService supportiveMaterialCacheService, StorageFileService storageFileService ) { this.entityManager = entityManager; this.authorizationService = authorizationService; @@ -71,50 +74,23 @@ public class SupportiveMaterialServiceImpl implements SupportiveMaterialService{ this.messageSource = messageSource; this.queryFactory = queryFactory; this.supportiveMaterialCacheService = supportiveMaterialCacheService; + this.storageFileService = storageFileService; } - public ResponseEntity getResponseEntity(String lang, Stream paths) throws IOException { - List result = paths.filter(Files::isRegularFile) - .map(Path::toString).collect(Collectors.toList()); - - String fileName = result.stream().filter(about -> about.contains("_" + lang)).findFirst().orElse(null); - - if (fileName == null) { - fileName = result.stream().filter(about -> about.contains("_en")).findFirst().get(); - } - - SupportiveMaterialCacheService.SupportiveMaterialCacheValue supportiveMaterialCacheItem = this.supportiveMaterialCacheService.lookup(this.supportiveMaterialCacheService.buildKey(fileName)); - + public byte[] loadFromFile(String language, SupportiveMaterialFieldType type) { + SupportiveMaterialCacheService.SupportiveMaterialCacheValue supportiveMaterialCacheItem = this.supportiveMaterialCacheService.lookup(this.supportiveMaterialCacheService.buildKey(language, type)); + if(supportiveMaterialCacheItem == null){ - InputStream is = new FileInputStream(fileName); - - // Path path = Paths.get(fileName); - - byte[] content = new byte[is.available()]; - is.read(content); - is.close(); - - supportiveMaterialCacheItem = new SupportiveMaterialCacheService.SupportiveMaterialCacheValue(fileName, content); + byte[] content = this.storageFileService.getSupportiveMaterial(type, language); + if (content == null) throw new MyNotFoundException("Material not found"); + + supportiveMaterialCacheItem = new SupportiveMaterialCacheService.SupportiveMaterialCacheValue(language, type, content); this.supportiveMaterialCacheService.put(supportiveMaterialCacheItem); } - HttpHeaders responseHeaders = new HttpHeaders(); - responseHeaders.setContentLength(supportiveMaterialCacheItem.getContent().length); - responseHeaders.setContentType(MediaType.TEXT_HTML); - responseHeaders.set("Content-Disposition", "attachment;filename=" + fileName); - responseHeaders.set("Access-Control-Expose-Headers", "Content-Disposition"); - responseHeaders.get("Access-Control-Expose-Headers").add("Content-Type"); - - return new ResponseEntity<>(supportiveMaterialCacheItem.getContent(), responseHeaders, HttpStatus.OK); + return supportiveMaterialCacheItem.getContent(); } -// public void persist(SupportiveMaterialPersist model) throws IOException { -// this.supportiveMaterialCacheService.evict(model.getName()); -// OutputStream os = new FileOutputStream(model.getName()); -// os.write(model.getHtml().getBytes()); -// os.close(); -// } - public SupportiveMaterial persist(SupportiveMaterialPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JAXBException{ logger.debug(new MapLogEntry("persisting data").And("model", model).And("fields", fields)); diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/transformer/FileTransformerService.java b/dmp-backend/core/src/main/java/eu/eudat/service/transformer/FileTransformerService.java index 15d6e13d5..29b19344f 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/transformer/FileTransformerService.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/transformer/FileTransformerService.java @@ -32,7 +32,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; -import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; import org.springframework.web.reactive.function.client.ExchangeFilterFunction; import org.springframework.web.reactive.function.client.WebClient; @@ -55,7 +54,6 @@ public class FileTransformerService { private final FileTransformerConfigurationCache fileTransformerConfigurationCache; private final AuthorizationService authorizationService; private final ConventionService conventionService; - private final Environment environment; private final WebClient.Builder webClientBuilder; private final EntityDoiService doiService; private final ApplicationContext applicationContext; @@ -66,13 +64,12 @@ public class FileTransformerService { @Autowired - public FileTransformerService(TransformerProperties transformerProperties, TokenExchangeCacheService tokenExchangeCacheService, FileTransformerConfigurationCache fileTransformerConfigurationCache, WebClient.Builder builder, EntityManager entityManager, AuthorizationService authorizationService, ConventionService conventionService, Environment environment, DmpQuery dmpQuery, EntityDoiQuery doiQuery, EntityDoiService doiService, ApplicationContext applicationContext, JsonHandlingService jsonHandlingService, QueryFactory queryFactory, BuilderFactory builderFactory, StorageFileService storageFileService) { + public FileTransformerService(TransformerProperties transformerProperties, TokenExchangeCacheService tokenExchangeCacheService, FileTransformerConfigurationCache fileTransformerConfigurationCache, WebClient.Builder builder, EntityManager entityManager, AuthorizationService authorizationService, ConventionService conventionService, DmpQuery dmpQuery, EntityDoiQuery doiQuery, EntityDoiService doiService, ApplicationContext applicationContext, JsonHandlingService jsonHandlingService, QueryFactory queryFactory, BuilderFactory builderFactory, StorageFileService storageFileService) { this.transformerProperties = transformerProperties; this.tokenExchangeCacheService = tokenExchangeCacheService; this.fileTransformerConfigurationCache = fileTransformerConfigurationCache; this.authorizationService = authorizationService; this.conventionService = conventionService; - this.environment = environment; this.webClientBuilder = builder; this.doiService = doiService; this.applicationContext = applicationContext; @@ -142,11 +139,7 @@ public class FileTransformerService { FileEnvelope fileEnvelope = repository.exportDmp(dmpFileTransformerModel); eu.eudat.model.file.FileEnvelope result = new eu.eudat.model.file.FileEnvelope(); byte[] data = storageFileService.readByFileRefAsBytesSafe(fileEnvelope.getFile(), StorageType.Transformer); - File temp = new File(environment.getProperty("path.path") + UUID.randomUUID()); - try (FileOutputStream fos = new FileOutputStream(temp)) { - fos.write(data); - } - result.setFile(temp); + result.setFile(data); result.setFilename(fileEnvelope.getFilename()); return result; } @@ -164,11 +157,7 @@ public class FileTransformerService { FileEnvelope fileEnvelope = repository.exportDescription(descriptionFileTransformerModel, format); eu.eudat.model.file.FileEnvelope result = new eu.eudat.model.file.FileEnvelope(); byte[] data = this.storageFileService.readByFileRefAsBytesSafe(fileEnvelope.getFile(), StorageType.Transformer); - File temp = new File(environment.getProperty("path.path") + UUID.randomUUID()); - try (FileOutputStream fos = new FileOutputStream(temp)) { - fos.write(data); - } - result.setFile(temp); + result.setFile(data); result.setFilename(fileEnvelope.getFilename()); return result; } diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/FileTransformerController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/FileTransformerController.java index 43f6ff731..a21b2be12 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/FileTransformerController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/FileTransformerController.java @@ -57,7 +57,7 @@ public class FileTransformerController { FileEnvelope fileEnvelope = this.fileTransformerService.exportDmp(requestModel.getId(), requestModel.getFormat()); headers.add("Content-Disposition", "attachment;filename=" + fileEnvelope.getFilename()); - byte[] data = Files.readAllBytes(fileEnvelope.getFile().toPath()); + byte[] data = fileEnvelope.getFile(); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); return new ResponseEntity<>(data, headers, HttpStatus.OK); } @@ -69,7 +69,7 @@ public class FileTransformerController { FileEnvelope fileEnvelope = this.fileTransformerService.exportDescription(requestModel.getId(), requestModel.getFormat()); headers.add("Content-Disposition", "attachment;filename=" + fileEnvelope.getFilename()); - byte[] data = Files.readAllBytes(fileEnvelope.getFile().toPath()); + byte[] data = fileEnvelope.getFile(); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); return new ResponseEntity<>(data, headers, HttpStatus.OK); } diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/SupportiveMaterialController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/SupportiveMaterialController.java index 1ff3c0007..b99505c77 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/SupportiveMaterialController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/SupportiveMaterialController.java @@ -1,8 +1,12 @@ package eu.eudat.controllers; import com.fasterxml.jackson.core.JsonProcessingException; +import com.tdunning.math.stats.Sort; import eu.eudat.audit.AuditableAction; import eu.eudat.authorization.AuthorizationFlags; +import eu.eudat.commons.enums.SupportiveMaterialFieldType; +import eu.eudat.service.storage.StorageFileService; +import gr.cite.tools.fieldset.BaseFieldSet; import gr.cite.tools.validation.ValidationFilterAnnotation; import eu.eudat.data.SupportiveMaterialEntity; import eu.eudat.model.SupportiveMaterial; @@ -30,8 +34,9 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; -import org.springframework.core.env.Environment; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -39,11 +44,7 @@ import javax.management.InvalidApplicationException; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.*; -import java.util.stream.Stream; @RestController @RequestMapping(path = {"/api/supportive-material"}) @@ -51,7 +52,6 @@ public class SupportiveMaterialController { private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(SupportiveMaterialController.class)); - private Environment environment; private final BuilderFactory builderFactory; @@ -64,21 +64,17 @@ public class SupportiveMaterialController { private final MessageSource messageSource; private final SupportiveMaterialService supportiveMaterialService; - - private final AuthorizationService authorizationService; + @Autowired - public SupportiveMaterialController(Environment environment, SupportiveMaterialService supportiveMaterialService, BuilderFactory builderFactory, - AuditService auditService, CensorFactory censorFactory, QueryFactory queryFactory, MessageSource messageSource, - AuthorizationService authorizationService) { - this.environment = environment; + public SupportiveMaterialController(SupportiveMaterialService supportiveMaterialService, BuilderFactory builderFactory, + AuditService auditService, CensorFactory censorFactory, QueryFactory queryFactory, MessageSource messageSource) { this.supportiveMaterialService = supportiveMaterialService; this.builderFactory = builderFactory; this.auditService = auditService; this.censorFactory = censorFactory; this.queryFactory = queryFactory; this.messageSource = messageSource; - this.authorizationService = authorizationService; } @PostMapping("query") @@ -94,7 +90,7 @@ public class SupportiveMaterialController { this.auditService.track(AuditableAction.SupportiveMaterial_Query, "lookup", lookup); - return new QueryResult(models, count); + return new QueryResult(models, count); } @GetMapping("{id}") @@ -116,21 +112,41 @@ public class SupportiveMaterialController { return model; } - @PostMapping("public") - public ResponseEntity queryPublic(@RequestBody SupportiveMaterialLookup lookup) throws IOException { + @GetMapping("get-payload/{type}/{language}") + public ResponseEntity getPayload(@PathVariable("type") Short type, @PathVariable("type") String language) throws IOException { logger.debug("querying {}", SupportiveMaterial.class.getSimpleName()); - this.censorFactory.censor(SupportiveMaterialCensor.class).censor(lookup.getProject(), null); - SupportiveMaterialQuery query = lookup.enrich(this.queryFactory).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic); - List data = query.collectAs(lookup.getProject()); - if (data.size() == 1) { - return new ResponseEntity<>(data.get(0).getPayload().getBytes(), HttpStatus.OK); - } + SupportiveMaterialQuery query = this.queryFactory.query(SupportiveMaterialQuery.class).types(SupportiveMaterialFieldType.of(type)).languageCodes(language).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic); + List data = query.collectAs(new BaseFieldSet().ensure(SupportiveMaterial._id).ensure(SupportiveMaterial._payload)); + byte[] content; + if (data.size() == 1) content = data.getFirst().getPayload().getBytes(); + else content = this.supportiveMaterialService.loadFromFile(language, SupportiveMaterialFieldType.of(type)); - try (Stream paths = Files.walk(Paths.get(Objects.requireNonNull(this.environment.getProperty(lookup.getTypes().stream().toList().get(0).name().toLowerCase() + ".path"))))) { - return this.supportiveMaterialService.getResponseEntity(lookup.getLanguageCodes().get(0), paths); - } + HttpHeaders responseHeaders = new HttpHeaders(); + responseHeaders.setContentLength(content.length); + responseHeaders.setContentType(MediaType.TEXT_HTML); + responseHeaders.set("Content-Disposition", "attachment;filename=" + SupportiveMaterialFieldType.of(type).name().toLowerCase(Locale.ROOT) + "_" + language + "html"); + responseHeaders.set("Access-Control-Expose-Headers", "Content-Disposition"); + responseHeaders.get("Access-Control-Expose-Headers").add("Content-Type"); + + return new ResponseEntity<>(content, responseHeaders, HttpStatus.OK); + } + + @GetMapping("public/get-payload/{type}/{language}") + public ResponseEntity getPayloadPublic(@PathVariable("type") Short type, @PathVariable("type") String language) throws IOException { + logger.debug("querying {}", SupportiveMaterial.class.getSimpleName()); + + byte[] content = this.supportiveMaterialService.loadFromFile(language, SupportiveMaterialFieldType.of(type)); + + HttpHeaders responseHeaders = new HttpHeaders(); + responseHeaders.setContentLength(content.length); + responseHeaders.setContentType(MediaType.TEXT_HTML); + responseHeaders.set("Content-Disposition", "attachment;filename=" + SupportiveMaterialFieldType.of(type).name().toLowerCase(Locale.ROOT) + "_" + language + "html"); + responseHeaders.set("Access-Control-Expose-Headers", "Content-Disposition"); + responseHeaders.get("Access-Control-Expose-Headers").add("Content-Type"); + + return new ResponseEntity<>(content, responseHeaders, HttpStatus.OK); } @PostMapping("persist") diff --git a/dmp-backend/web/src/main/resources/config/application-docker.properties b/dmp-backend/web/src/main/resources/config/application-docker.properties deleted file mode 100644 index 5f5d310b0..000000000 --- a/dmp-backend/web/src/main/resources/config/application-docker.properties +++ /dev/null @@ -1,133 +0,0 @@ -dmp.domain = http://localhost:8080 - -####################PERSISTENCE OVERRIDES CONFIGURATIONS########## -database.url=jdbc:postgresql://dmp-db:5432/dmptool -database.username=dmptool -database.password=CHANGEME - -####################ELASTIIC SEARCH TAGS OVERRIDES CONFIGURATIONS########## -elasticsearch.host = opendmp-elastic -elasticsearch.port = 9200 -elasticsearch.username=elastic -elasticsearch.password= -elasticsearch.index=dmps -elasticsearch.usingssl=false -elasticsearch.certPath= -elasticsearch.certKey= -elasticsearch.innerHitsSize=100 - -####################ELK OVERRIDES CONFIGURATIONS########## -#http-logger.server-address = http://logstash:31311 - -####################PDF OVERRIDES CONFIGURATIONS########## -pdf.converter.url=http://opendmp-pdf:3000/ - -####################CONFIGURATION FILES OVERRIDES CONFIGURATIONS########## -configuration.externalUrls=externalUrls/ExternalUrls.xml -configuration.h2020template=documents/h2020.docx -configuration.h2020datasettemplate=documents/h2020_dataset.docx -configuration.configurable_login_providers=configurableLoginProviders.json -configuration.pid_links=pidLinks.json - -####################EMAIL FILE TEMPLATES OVERRIDES CONFIGURATIONS########## -email.invite=classpath:templates/email/email.html -email.confirmation=classpath:templates/email/emailConfirmation.html -email.merge=classpath:templates/email/emailMergeConfirmation.html -email.unlink=classpath:templates/email/emailUnlinkConfirmation.html -email.dataset.template=classpath:templates/email/emailAdmin.html - -####################INVITATION MAIL CONFIGURATIONS############## -####################GENERIC MAIL CONFIGURATIONS################# -mail.subject=Invitation to DMP Plan {dmpname} -mail.from=opendmp-dev@cite.gr - -####################DATASET TEMPLATE MAIL CONFIGURATIONS################# -admin.mail.subject=You have been invited to the Dataset Template {templateName} - -####################SPRING MAIL CONFIGURATIONS################# -spring.mail.default-encoding=UTF-8 -spring.mail.host= -spring.mail.username= -spring.mail.password= -spring.mail.port=25 -spring.mail.protocol=smtp -spring.mail.test-connection=false -spring.mail.properties.mail.smtp.auth=false -spring.mail.properties.mail.smtp.starttls.enable=true - -#############FACEBOOK LOGIN CONFIGURATIONS######### -facebook.login.clientId= -facebook.login.clientSecret= -facebook.login.namespace= - -#############GOOGLE LOGIN CONFIGURATIONS######### -google.login.clientId= - -#############LINKEDIN LOGIN CONFIGURATIONS######### -linkedin.login.clientId= -linkedin.login.clientSecret= -linkedin.login.redirect_uri=http://localhost:8080/login/linkedin -linkedin.login.user_info_url=https://api.linkedin.com/v2/me -linkedin.login.user_email=https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~)) -linkedin.login.access_token_url=https://www.linkedin.com/uas/oauth2/accessToken - -#############TWITTER LOGIN CONFIGURATIONS######### -twitter.login.clientId= -twitter.login.clientSecret= -twitter.login.redirect_uri=http://localhost:8080/login/twitter - -#############B2 ACCESS CONFIGURATIONS######### -b2access.externallogin.user_info_url=https://b2access-integration.fz-juelich.de:443/oauth2/userinfo -b2access.externallogin.access_token_url=https://b2access-integration.fz-juelich.de:443/oauth2/token -b2access.externallogin.redirect_uri=http://localhost:8080/api/oauth/authorized/b2access -b2access.externallogin.clientid= -b2access.externallogin.clientSecret= - -#############ORCID CONFIGURATIONS######### -orcid.login.client_id= -orcid.login.client_secret= -orcid.login.access_token_url=https://orcid.org/oauth/token -orcid.login.redirect_uri=http://localhost:8080/login/external/orcid - -#############OPENAIRE CONFIGURATIONS######### -openaire.login.client_id= -openaire.login.client_secret= -openaire.login.access_token_url=https://aai.openaire.eu/oidc/token -openaire.login.redirect_uri=http://localhost:8080/login/openaire -openaire.login.user_info_url=https://aai.openaire.eu/oidc/userinfo - -#############CONFIRMATION EMAIL CONFIGURATIONS######### -conf_email.expiration_time_seconds=14400 -conf_email.subject=OpenDMP email confirmation - -#############ZENODO CONFIGURATIONS######### -zenodo.login.access_token_url=https://sandbox.zenodo.org/oauth/token -zenodo.login.client_id= -zenodo.login.client_secret= -zenodo.login.redirect_uri=http://localhost:8080/login/external/zenodo - -#############CONTACT EMAIL CONFIGURATIONS######### -contact_email.mail= -logging.config=classpath:logging/logback-${spring.profiles.active}.xml -language.path=i18n/ - -##########################MISC########################################## -#############USER GUIDE######### -userguide.path=user-guide/ - -#############NOTIFICATION######### -notification.rateInterval=30000 -notification.maxRetries=10 -notification.modified.subject=[OpenDMP] The {name} has been modified -notification.publish.subject=[OpenDMP] The {name} has been published -notification.finalised.subject=[OpenDMP] The {name} has been finalised -notification.modifiedFinalised.subject=[OpenDMP] The {name} has been modified and finalised - -#############TEMP######### -temp.temp=tmp/ -file.storage=storage/ -spring.servlet.multipart.max-file-size=10MB -spring.servlet.multipart.max-request-size=10MB - -#############PROMETHEUS######### -endpoints.prometheus.sensitive: false \ No newline at end of file diff --git a/dmp-backend/web/src/main/resources/config/application-production.properties b/dmp-backend/web/src/main/resources/config/application-production.properties deleted file mode 100644 index 46a32086b..000000000 --- a/dmp-backend/web/src/main/resources/config/application-production.properties +++ /dev/null @@ -1,102 +0,0 @@ -dmp.domain = https://opendmp.eu - -####################PERSISTENCE OVERRIDES CONFIGURATIONS########## -database.url=jdbc:postgresql://dmp-db:5432/dmptool -database.username=dmptool -database.password=CHANGEME - -####################ELASTIIC SEARCH TAGS OVERRIDES CONFIGURATIONS########## -elasticsearch.host = tags-elastic-search -elasticsearch.port = 9200 -elasticsearch.username=elastic -elasticsearch.password= -elasticsearch.index=dmps -elasticsearch.innerHitsSize=100 - -####################PDF OVERRIDES CONFIGURATIONS########## -pdf.converter.url=http://docsbox-web/ - -####################CONFIGURATION FILES OVERRIDES CONFIGURATIONS########## -configuration.externalUrls=externalUrls/ExternalUrls.xml -configuration.h2020template=documents/h2020.docx -configuration.h2020datasettemplate=documents/h2020_dataset.docx -configuration.configurable_login_providers=ConfigurableLoginProviders.json -configuration.doi_funder=DOI_Funder.json -configuration.pid_links=pidLinks.json - -####################SPRING MAIL CONFIGURATIONS################# -spring.mail.default-encoding=UTF-8 -spring.mail.host= -spring.mail.username= -spring.mail.password= -spring.mail.port=25 -spring.mail.protocol=smtp -spring.mail.test-connection=false -spring.mail.properties.mail.smtp.auth=false -spring.mail.properties.mail.smtp.starttls.enable=true - -#############FACEBOOK LOGIN CONFIGURATIONS######### -facebook.login.clientId= -facebook.login.clientSecret= -facebook.login.namespace=opendmp - -#############GOOGLE LOGIN CONFIGURATIONS######### -google.login.clientId= - -#############LINKEDIN LOGIN CONFIGURATIONS######### -linkedin.login.clientId= -linkedin.login.clientSecret= -linkedin.login.redirect_uri=https://opendmp.eu/login/linkedin -linkedin.login.user_info_url=https://api.linkedin.com/v2/me -linkedin.login.user_email=https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~)) -linkedin.login.access_token_url=https://www.linkedin.com/uas/oauth2/accessToken - -#############TWITTER LOGIN CONFIGURATIONS######### -twitter.login.clientId= -twitter.login.clientSecret= -twitter.login.redirect_uri=https://opendmp.eu/login/twitter - -#############B2 ACCESS CONFIGURATIONS######### -b2access.externallogin.user_info_url=https://b2access-integration.fz-juelich.de:443/oauth2/userinfo -b2access.externallogin.access_token_url=https://b2access-integration.fz-juelich.de:443/oauth2/token -b2access.externallogin.redirect_uri=https://opendmp.eu/api/oauth/authorized/b2access -b2access.externallogin.clientid= -b2access.externallogin.clientSecret= - -#############ORCID CONFIGURATIONS######### -orcid.login.client_id= -orcid.login.client_secret= -orcid.login.access_token_url=https://orcid.org/oauth/token -orcid.login.redirect_uri=https://opendmp.eu/login/external/orcid - -#############OPENAIRE CONFIGURATIONS######### -openaire.login.client_id= -openaire.login.client_secret= -openaire.login.access_token_url= -openaire.login.redirect_uri= -openaire.login.user_info_url= - -#############SPRING DATASOURCE CONFIGURATIONS######### -spring.datasource.maxIdle: 10 -spring.datasource.max-active: 70 -spring.datasource.max-wait: 10000 -spring.datasource.validationQuery: select 1 -spring.datasource.removeAbandoned: true -spring.datasource.removeAbandonedTimeout: 1 -spring.datasource.logAbandoned: true -spring.datasource.testOnBorrow: true -spring.datasource.testOnConnect: false -spring.datasource.testWhileIdle: false - -#############CONFIRMATION EMAIL CONFIGURATIONS######### -conf_email.expiration_time_seconds=14400 -conf_email.subject=OpenDMP email confirmation - -#############ZENODO CONFIGURATIONS######### -zenodo.url=https://zenodo.org/api/ -zenodo.access_token= - -#############CONTACT EMAIL CONFIGURATIONS######### -contact_email.mail= - -language.path=i18n/ \ No newline at end of file diff --git a/dmp-backend/web/src/main/resources/config/cache.yml b/dmp-backend/web/src/main/resources/config/cache.yml index 5f2b1abfb..c717f36b0 100644 --- a/dmp-backend/web/src/main/resources/config/cache.yml +++ b/dmp-backend/web/src/main/resources/config/cache.yml @@ -64,7 +64,7 @@ cache: keyPattern: user_by_subject_$subject$:v0 supportiveMaterial: name: supportiveMaterial - keyPattern: supportive_material_$material$:v0 + keyPattern: supportive_material_$type$_$lang$:v0 Reference: name: Reference keyPattern: reference_$type$_$criteria$:v0 diff --git a/dmp-backend/web/src/main/resources/config/security.yml b/dmp-backend/web/src/main/resources/config/security.yml index e9bcfc699..2494d97ef 100644 --- a/dmp-backend/web/src/main/resources/config/security.yml +++ b/dmp-backend/web/src/main/resources/config/security.yml @@ -2,7 +2,7 @@ web: security: enabled: true authorized-endpoints: [ api ] - allowed-endpoints: [ api/public, api/description/public, api/language/public, api/contact-support/public, api/dashboard/public ] + allowed-endpoints: [ api/public, api/description/public, /api/supportive-material/public, api/language/public, api/contact-support/public, api/dashboard/public ] idp: api-key: enabled: false diff --git a/dmp-frontend/src/app/core/query/supportive-material.lookup.ts b/dmp-frontend/src/app/core/query/supportive-material.lookup.ts index 43537e1a4..a92082dd1 100644 --- a/dmp-frontend/src/app/core/query/supportive-material.lookup.ts +++ b/dmp-frontend/src/app/core/query/supportive-material.lookup.ts @@ -23,4 +23,4 @@ export interface SupportiveMaterialFilter { isActive: IsActive[]; types: SupportiveMaterialFieldType[]; languageCodes: string[]; -} \ No newline at end of file +} diff --git a/dmp-frontend/src/app/core/services/supportive-material/supportive-material.service.ts b/dmp-frontend/src/app/core/services/supportive-material/supportive-material.service.ts index ac5e2380a..ccdfd5301 100644 --- a/dmp-frontend/src/app/core/services/supportive-material/supportive-material.service.ts +++ b/dmp-frontend/src/app/core/services/supportive-material/supportive-material.service.ts @@ -10,20 +10,43 @@ import { catchError } from "rxjs/operators"; import { nameof } from "ts-simple-nameof"; import { ConfigurationService } from "../configuration/configuration.service"; import { BaseHttpV2Service } from "../http/base-http-v2.service"; +import { SupportiveMaterialFieldType } from "@app/core/common/enum/supportive-material-field-type"; +import { BaseHttpParams } from "@common/http/base-http-params"; +import { InterceptorType } from "@common/http/interceptors/interceptor-type"; +import { AuthService } from "../auth/auth.service"; @Injectable() export class SupportiveMaterialService { constructor( private http: BaseHttpV2Service, - private configurationService: ConfigurationService + private configurationService: ConfigurationService, + private authService: AuthService ) { } private get apiBase(): string { return `${this.configurationService.server}supportive-material`; } - queryPublic(q: SupportiveMaterialLookup): Observable> { - return this.http.post>(`${this.apiBase}/public`, q, { responseType: 'blob', observe: 'response' }); + getPayload(type: SupportiveMaterialFieldType, language: string): Observable> { + if (this.authService.isLoggedIn() && this.authService.currentAccountIsAuthenticated() ) { + return this.getPayloadLogin(type, language); + } else { + return this.getPayloadPublic(type, language); + } + } + + getPayloadLogin(type: SupportiveMaterialFieldType, language: string): Observable> { + const url = `${this.apiBase}/get-payload/${type}/${language}`; + return this.http.get>(url, { responseType: 'blob', observe: 'response' }); + } + + getPayloadPublic(type: SupportiveMaterialFieldType, language: string): Observable> { + const url = `${this.apiBase}/public/get-payload/${type}/${language}`; + const params = new BaseHttpParams(); + params.interceptorContext = { + excludedInterceptors: [InterceptorType.AuthToken] + }; + return this.http.get(url, { params: params, responseType: 'blob', observe: 'response' }); } query(q: SupportiveMaterialLookup): Observable> { @@ -79,4 +102,4 @@ export class SupportiveMaterialService { return lookup; } -} \ No newline at end of file +} diff --git a/dmp-frontend/src/app/ui/about/about.component.ts b/dmp-frontend/src/app/ui/about/about.component.ts index e7799089e..44e3a2286 100644 --- a/dmp-frontend/src/app/ui/about/about.component.ts +++ b/dmp-frontend/src/app/ui/about/about.component.ts @@ -25,7 +25,7 @@ export class AboutComponent extends BaseComponent implements OnInit { private languageService: LanguageService, private matomoService: MatomoService, private translate: TranslateService, - private router: Router + private router: Router, ) { super(); } ngOnInit() { @@ -33,11 +33,8 @@ export class AboutComponent extends BaseComponent implements OnInit { this.translate.onLangChange.subscribe((event: LangChangeEvent) => { this.router.navigate(['/reload'], { skipLocationChange: true }).then(() => this.router.navigate(['/about'])); }); - const lookup = SupportiveMaterialService.DefaultSupportiveMaterialLookup(); - lookup.languageCodes = [this.languageService.getCurrentLanguage()]; - lookup.types = [SupportiveMaterialFieldType.About]; - this.supportiveMaterialService.queryPublic(lookup) + this.supportiveMaterialService.getPayload(SupportiveMaterialFieldType.About, this.languageService.getCurrentLanguage()) .pipe(takeUntil(this._destroyed)) .subscribe(response => { const blob = new Blob([response.body], { type: 'text/html' }); diff --git a/dmp-frontend/src/app/ui/faq/faq-content/faq-content.component.ts b/dmp-frontend/src/app/ui/faq/faq-content/faq-content.component.ts index c5b64e42b..ffc5ecb95 100644 --- a/dmp-frontend/src/app/ui/faq/faq-content/faq-content.component.ts +++ b/dmp-frontend/src/app/ui/faq/faq-content/faq-content.component.ts @@ -28,11 +28,8 @@ export class FaqContentComponent extends BaseComponent implements OnInit { ngOnInit() { this.matomoService.trackPageView('FAQ'); - const lookup = SupportiveMaterialService.DefaultSupportiveMaterialLookup(); - lookup.languageCodes = [this.languageService.getCurrentLanguage()]; - lookup.types = [SupportiveMaterialFieldType.Faq]; - this.supportiveMaterialService.queryPublic(lookup) + this.supportiveMaterialService.getPayload(SupportiveMaterialFieldType.Faq, this.languageService.getCurrentLanguage()) .pipe(takeUntil(this._destroyed)) .subscribe(response => { const blob = new Blob([response.body], { type: 'text/html' }); diff --git a/dmp-frontend/src/app/ui/glossary/glossary-content/glossary-content.component.ts b/dmp-frontend/src/app/ui/glossary/glossary-content/glossary-content.component.ts index 4e101f9ba..a6945cd14 100644 --- a/dmp-frontend/src/app/ui/glossary/glossary-content/glossary-content.component.ts +++ b/dmp-frontend/src/app/ui/glossary/glossary-content/glossary-content.component.ts @@ -36,11 +36,7 @@ export class GlossaryContentComponent extends BaseComponent implements OnInit { this.router.navigate(['/reload'], { skipLocationChange: true }).then(() => this.router.navigate(['/glossary'])); }); - const lookup = SupportiveMaterialService.DefaultSupportiveMaterialLookup(); - lookup.languageCodes = [this.languageService.getCurrentLanguage()]; - lookup.types = [SupportiveMaterialFieldType.Glossary]; - - this.supportiveMaterialService.queryPublic(lookup) + this.supportiveMaterialService.getPayload(SupportiveMaterialFieldType.Glossary, this.languageService.getCurrentLanguage()) .pipe(takeUntil(this._destroyed)) .subscribe(response => { const blob = new Blob([response.body], { type: 'text/html' }); diff --git a/dmp-frontend/src/app/ui/sidebar/sidebar-footer/terms/terms.component.ts b/dmp-frontend/src/app/ui/sidebar/sidebar-footer/terms/terms.component.ts index 02c540e09..027298717 100644 --- a/dmp-frontend/src/app/ui/sidebar/sidebar-footer/terms/terms.component.ts +++ b/dmp-frontend/src/app/ui/sidebar/sidebar-footer/terms/terms.component.ts @@ -33,11 +33,8 @@ export class TermsComponent extends BaseComponent implements OnInit { this.translate.onLangChange.subscribe((event: LangChangeEvent) => { this.router.navigate(['/reload'], { skipLocationChange: true }).then(() => this.router.navigate(['/terms-and-conditions'])); }); - const lookup = SupportiveMaterialService.DefaultSupportiveMaterialLookup(); - lookup.languageCodes = [this.languageService.getCurrentLanguage()]; - lookup.types = [SupportiveMaterialFieldType.TermsOfService]; - this.supportiveMaterialService.queryPublic(lookup) + this.supportiveMaterialService.getPayload(SupportiveMaterialFieldType.TermsOfService, this.languageService.getCurrentLanguage()) .pipe(takeUntil(this._destroyed)) .subscribe(response => { const blob = new Blob([response.body], { type: 'text/html' }); diff --git a/dmp-frontend/src/app/ui/user-guide/user-guide-content/user-guide-content.component.ts b/dmp-frontend/src/app/ui/user-guide/user-guide-content/user-guide-content.component.ts index 6b4f9acf7..ca783df75 100644 --- a/dmp-frontend/src/app/ui/user-guide/user-guide-content/user-guide-content.component.ts +++ b/dmp-frontend/src/app/ui/user-guide/user-guide-content/user-guide-content.component.ts @@ -51,11 +51,7 @@ export class UserGuideContentComponent extends BaseComponent implements OnInit { this.translate.onLangChange.subscribe((event: LangChangeEvent) => { this.router.navigate(['/reload'], { skipLocationChange: true }).then(() => this.router.navigate(['/user-guide'])); }); - const lookup = SupportiveMaterialService.DefaultSupportiveMaterialLookup(); - lookup.languageCodes = [this.languageService.getCurrentLanguage()]; - lookup.types = [SupportiveMaterialFieldType.UserGuide]; - - this.supportiveMaterialService.queryPublic(lookup) + this.supportiveMaterialService.getPayload(SupportiveMaterialFieldType.UserGuide, this.languageService.getCurrentLanguage()) .pipe(takeUntil(this._destroyed)) .subscribe(response => { const blob = new Blob([response.body], { type: 'text/html' });