+
+
+

{{ 'ABOUT.WELCOME' | translate }}

+

{{ 'ABOUT.WELCOME-MESSAGE' | translate }}

+
+
+
@@ -14,7 +20,7 @@
-
+
- - -
-
+
settings

{{roleDisplay(dmp.users).toUpperCase()}}

-
- +
+ storage diff --git a/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.ts b/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.ts index e41f78acd..77f63bd4d 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.ts +++ b/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.ts @@ -18,6 +18,7 @@ export class DmpListingItemComponent implements OnInit { @Input() dmp: DmpListingModel; @Input() showDivider: boolean = true; + @Input() isPublic: boolean; @Output() onClick: EventEmitter = new EventEmitter(); isDraft: boolean; From 88e34e1ec1d8ddf78b97c1adc84b78c1e41066ab Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Wed, 1 Apr 2020 18:17:17 +0300 Subject: [PATCH 02/60] Removed external Tags --- .../main/java/eu/eudat/controllers/TagController.java | 8 ++++---- .../java/eu/eudat/logic/managers/CommonsManager.java | 4 ++-- .../java/eu/eudat/logic/proxy/config/ExternalUrls.java | 6 +++--- .../eu/eudat/logic/proxy/fetching/RemoteFetcher.java | 4 ++-- .../data/externalurl/ExternalSourcesConfiguration.java | 4 ++-- .../src/main/resources/externalUrls/ExternalUrls.xml | 10 +++++----- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/TagController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/TagController.java index dd54267e9..029e1ba08 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/TagController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/TagController.java @@ -31,13 +31,13 @@ import java.util.stream.Collectors; @RequestMapping(value = {"/api"}) public class TagController extends BaseController { - private Repository datasetRepository; +// private Repository datasetRepository; private Environment environment; @Autowired - public TagController(ApiContext apiContext, Repository tagRepository, Environment environment) { + public TagController(ApiContext apiContext, /*Repository tagRepository, */Environment environment) { super(apiContext); - this.datasetRepository = tagRepository; +// this.datasetRepository = tagRepository; this.environment = environment; } @@ -48,7 +48,7 @@ public class TagController extends BaseController { //ExternalUrlCriteria externalUrlCriteria = new ExternalUrlCriteria(query); /*List> remoteRepos = this.getApiContext().getOperationsContext().getRemoteFetcher().getTags(externalUrlCriteria, type); TagExternalSourcesModel researchersExternalSourcesModel = new TagExternalSourcesModel().fromExternalItem(remoteRepos);*/ - List tags = this.getApiContext().getOperationsContext().getDatasetRepository().query(new DatasetCriteria()).stream().map(Dataset::getTags).flatMap(Collection::stream).filter(StreamDistinctBy.distinctByKey(Tag::getId)).collect(Collectors.toList()); + List tags = this.getApiContext().getOperationsContext().getElasticRepository().getDatasetRepository().query(new DatasetCriteria()).stream().map(Dataset::getTags).flatMap(Collection::stream).filter(StreamDistinctBy.distinctByKey(Tag::getId)).collect(Collectors.toList()); return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem>().payload(tags).status(ApiMessageCode.NO_MESSAGE)); } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/CommonsManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/CommonsManager.java index 94df54e41..3948216de 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/CommonsManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/CommonsManager.java @@ -20,8 +20,8 @@ public class CommonsManager { .map(item-> new ExternalSourcesConfiguration.ExternalSourcesUrlModel(item.getKey(),item.getLabel())).collect(Collectors.toList())); externalSourcesConfiguration.setServices(configLoader.getExternalUrls().getServices().getUrls().stream() .map(item-> new ExternalSourcesConfiguration.ExternalSourcesUrlModel(item.getKey(),item.getLabel())).collect(Collectors.toList())); - externalSourcesConfiguration.setTags(configLoader.getExternalUrls().getTags().getUrls().stream() - .map(item-> new ExternalSourcesConfiguration.ExternalSourcesUrlModel(item.getKey(),item.getLabel())).collect(Collectors.toList())); + /*externalSourcesConfiguration.setTags(configLoader.getExternalUrls().getTags().getUrls().stream() + .map(item-> new ExternalSourcesConfiguration.ExternalSourcesUrlModel(item.getKey(),item.getLabel())).collect(Collectors.toList()));*/ return externalSourcesConfiguration; } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/ExternalUrls.java b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/ExternalUrls.java index eb04c9a4a..f7e38ba20 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/ExternalUrls.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/ExternalUrls.java @@ -22,7 +22,7 @@ public class ExternalUrls implements Serializable { ResearcherUrls researchers; OrganisationUrls organisations; DatasetUrls datasets; - TagUrls tags; + /*TagUrls tags;*/ FunderUrls funders; @@ -66,14 +66,14 @@ public class ExternalUrls implements Serializable { } - public TagUrls getTags() { + /*public TagUrls getTags() { return tags; } @XmlElement(name = "tags") public void setTags(TagUrls tags) { this.tags = tags; - } + }*/ public OrganisationUrls getOrganisations() { diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java index 19dd8192e..cd29be9e8 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/fetching/RemoteFetcher.java @@ -108,14 +108,14 @@ public class RemoteFetcher { return getAll(urlConfigs, fetchStrategy, externalUrlCriteria); } - @Cacheable("tags") + /*@Cacheable("tags") public List> getTags(ExternalUrlCriteria externalUrlCriteria, String key) throws NoURLFound, HugeResultSet { List urlConfigs = key != null && !key.isEmpty() ? configLoader.getExternalUrls().getTags().getUrls().stream().filter(item -> item.getKey().equals(key)).collect(Collectors.toList()) : configLoader.getExternalUrls().getTags().getUrls(); FetchStrategy fetchStrategy = configLoader.getExternalUrls().getTags().getFetchMode(); return getAll(urlConfigs, fetchStrategy, externalUrlCriteria); - } + }*/ @Cacheable("externalDatasets") public List> getDatasets(ExternalUrlCriteria externalUrlCriteria, String key) throws NoURLFound, HugeResultSet { diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/externalurl/ExternalSourcesConfiguration.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/externalurl/ExternalSourcesConfiguration.java index c9e8df87d..2f8778b0b 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/externalurl/ExternalSourcesConfiguration.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/externalurl/ExternalSourcesConfiguration.java @@ -37,7 +37,7 @@ public class ExternalSourcesConfiguration { private List dataRepositories; private List services; private List externalDatasets; - private List tags; + /* private List tags; public List getTags() { return tags; @@ -45,7 +45,7 @@ public class ExternalSourcesConfiguration { public void setTags(List tags) { this.tags = tags; - } + }*/ public List getRegistries() { return registries; diff --git a/dmp-backend/web/src/main/resources/externalUrls/ExternalUrls.xml b/dmp-backend/web/src/main/resources/externalUrls/ExternalUrls.xml index de3d38152..2d731694f 100644 --- a/dmp-backend/web/src/main/resources/externalUrls/ExternalUrls.xml +++ b/dmp-backend/web/src/main/resources/externalUrls/ExternalUrls.xml @@ -65,7 +65,7 @@ FIRST - + + –> - FIRST - + FIRST <!– EITHER 'FIRST' OR 'ALL' –> + --> From 1c4b0ba87a168adfba5025219599a072c6c88d4f Mon Sep 17 00:00:00 2001 From: Diamantis Tziotzios Date: Thu, 2 Apr 2020 13:32:14 +0300 Subject: [PATCH 03/60] fb login provider fix --- dmp-frontend/src/app/ui/auth/login/login.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dmp-frontend/src/app/ui/auth/login/login.component.ts b/dmp-frontend/src/app/ui/auth/login/login.component.ts index d439a234f..f71c64bf9 100644 --- a/dmp-frontend/src/app/ui/auth/login/login.component.ts +++ b/dmp-frontend/src/app/ui/auth/login/login.component.ts @@ -188,7 +188,7 @@ export class LoginComponent extends BaseComponent implements OnInit, AfterViewIn error => this.loginService.onLogInError(error) ); } - }, { scope: 'user_friends,email' }); + }, { scope: 'email' }); } public hasConfigurableProviders(): boolean { From 71ccd768967874ef546c1184326a49a34d497299 Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Thu, 2 Apr 2020 17:22:41 +0300 Subject: [PATCH 04/60] Fixed and improved file export system --- .../main/java/eu/eudat/controllers/DMPs.java | 15 +++--- .../controllers/DatasetWizardController.java | 26 +++++----- .../managers/DataManagementPlanManager.java | 48 +++++++++++-------- .../DataManagementProfileManager.java | 7 ++- .../eudat/logic/managers/DatasetManager.java | 28 ++++++----- .../logic/managers/DatasetProfileManager.java | 12 ++--- .../ExportXmlBuilderDatasetProfile.java | 5 +- .../dmpXml/ExportXmlBuilderDmpProfile.java | 5 +- 8 files changed, 83 insertions(+), 63 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java index 777537751..109ff34c2 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java @@ -19,6 +19,7 @@ import eu.eudat.logic.proxy.config.configloaders.ConfigLoader; import eu.eudat.logic.security.claims.ClaimedAuthorities; import eu.eudat.logic.services.ApiContext; import eu.eudat.logic.services.operations.DatabaseRepository; +import eu.eudat.logic.utilities.documents.helpers.FileEnvelope; import eu.eudat.models.data.datasetprofile.DatasetProfileListingModel; import eu.eudat.models.data.datasetwizard.DatasetsToBeFinalized; import eu.eudat.models.data.dmp.DataManagementPlan; @@ -209,22 +210,22 @@ public class DMPs extends BaseController { public @ResponseBody ResponseEntity getPDFDocument(@PathVariable String id, @RequestHeader("Content-Type") String contentType, @ClaimedAuthorities(claims = {Authorities.ADMIN, Authorities.MANAGER, Authorities.USER, Authorities.ANONYMOUS}) Principal principal) throws IllegalAccessException, IOException, InstantiationException, InterruptedException { - File file = this.dataManagementPlanManager.getWordDocument(id, principal, configLoader); - String name = file.getName().substring(0, file.getName().length() - 5); - File pdffile = datasetManager.convertToPDF(file, environment, name); + FileEnvelope file = this.dataManagementPlanManager.getWordDocument(id, principal, configLoader); + String name = file.getFilename().substring(0, file.getFilename().length() - 5); + File pdffile = datasetManager.convertToPDF(file, environment); InputStream resource = new FileInputStream(pdffile); - logger.info("Mime Type of " + file.getName() + " is " + - new MimetypesFileTypeMap().getContentType(file)); + logger.info("Mime Type of " + name + " is " + + new MimetypesFileTypeMap().getContentType(file.getFile())); HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.setContentLength(pdffile.length()); responseHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM); - responseHeaders.set("Content-Disposition", "attachment;filename=" + pdffile.getName()); + responseHeaders.set("Content-Disposition", "attachment;filename=" + name + ".pdf"); responseHeaders.set("Access-Control-Expose-Headers", "Content-Disposition"); responseHeaders.get("Access-Control-Expose-Headers").add("Content-Type"); byte[] content = org.apache.poi.util.IOUtils.toByteArray(resource); resource.close(); - Files.deleteIfExists(file.toPath()); + Files.deleteIfExists(file.getFile().toPath()); Files.deleteIfExists(pdffile.toPath()); return new ResponseEntity<>(content, responseHeaders, HttpStatus.OK); } diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/DatasetWizardController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/DatasetWizardController.java index bed8c804a..c2b9abc43 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/DatasetWizardController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/DatasetWizardController.java @@ -12,6 +12,7 @@ import eu.eudat.logic.proxy.config.configloaders.ConfigLoader; import eu.eudat.logic.security.claims.ClaimedAuthorities; import eu.eudat.logic.services.ApiContext; import eu.eudat.logic.services.forms.VisibilityRuleService; +import eu.eudat.logic.utilities.documents.helpers.FileEnvelope; import eu.eudat.models.data.datasetwizard.DataManagentPlanListingModel; import eu.eudat.models.data.datasetwizard.DatasetWizardModel; import eu.eudat.models.data.dmp.AssociatedProfile; @@ -20,6 +21,7 @@ import eu.eudat.models.data.listingmodels.DataManagementPlanOverviewModel; import eu.eudat.models.data.security.Principal; import eu.eudat.models.data.user.composite.PagedDatasetProfile; import eu.eudat.types.ApiMessageCode; +import eu.eudat.types.Authorities; import org.apache.poi.util.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -82,24 +84,24 @@ public class DatasetWizardController extends BaseController { @Transactional @RequestMapping(method = RequestMethod.GET, value = {"{id}"}, produces = "application/json") public @ResponseBody - ResponseEntity getSingle(@PathVariable String id, @RequestHeader("Content-Type") String contentType, Principal principal) throws IllegalAccessException, IOException, InstantiationException { + ResponseEntity getSingle(@PathVariable String id, @RequestHeader("Content-Type") String contentType, @ClaimedAuthorities(claims = {Authorities.ADMIN, Authorities.MANAGER, Authorities.USER, Authorities.ANONYMOUS}) Principal principal) throws IllegalAccessException, IOException, InstantiationException { try { if (contentType.equals("application/xml")) { VisibilityRuleService visibilityRuleService = this.getApiContext().getUtilitiesService().getVisibilityRuleService(); return this.datasetManager.getDocument(id, visibilityRuleService, contentType, principal); } else if (contentType.equals("application/msword")) { - File file = datasetManager.getWordDocumentFile(this.configLoader, id, this.getApiContext().getUtilitiesService().getVisibilityRuleService(), principal); - InputStream resource = new FileInputStream(file); + FileEnvelope file = datasetManager.getWordDocumentFile(this.configLoader, id, this.getApiContext().getUtilitiesService().getVisibilityRuleService(), principal); + InputStream resource = new FileInputStream(file.getFile()); HttpHeaders responseHeaders = new HttpHeaders(); - responseHeaders.setContentLength(file.length()); + responseHeaders.setContentLength(file.getFile().length()); responseHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM); - responseHeaders.set("Content-Disposition", "attachment;filename=" + file.getName()); + responseHeaders.set("Content-Disposition", "attachment;filename=" + file.getFilename()); responseHeaders.set("Access-Control-Expose-Headers", "Content-Disposition"); responseHeaders.get("Access-Control-Expose-Headers").add("Content-Type"); byte[] content = IOUtils.toByteArray(resource); resource.close(); - Files.deleteIfExists(file.toPath()); + Files.deleteIfExists(file.getFile().toPath()); return new ResponseEntity<>(content, responseHeaders, HttpStatus.OK); @@ -151,25 +153,25 @@ public class DatasetWizardController extends BaseController { @RequestMapping(method = RequestMethod.GET, value = {"/getPDF/{id}"}) public @ResponseBody - ResponseEntity getPDFDocument(@PathVariable String id, Principal principal) throws IllegalAccessException, IOException, InstantiationException, InterruptedException { - File file = datasetManager.getWordDocumentFile(this.configLoader, id, this.getApiContext().getUtilitiesService().getVisibilityRuleService(), principal); - String fileName = file.getName(); + ResponseEntity getPDFDocument(@PathVariable String id, @ClaimedAuthorities(claims = {Authorities.ADMIN, Authorities.MANAGER, Authorities.USER, Authorities.ANONYMOUS}) Principal principal) throws IllegalAccessException, IOException, InstantiationException, InterruptedException { + FileEnvelope file = datasetManager.getWordDocumentFile(this.configLoader, id, this.getApiContext().getUtilitiesService().getVisibilityRuleService(), principal); + String fileName = file.getFilename(); if (fileName.endsWith(".docx")){ fileName = fileName.substring(0, fileName.length() - 5); } - File pdffile = datasetManager.convertToPDF(file, environment, fileName); + File pdffile = datasetManager.convertToPDF(file, environment); InputStream resource = new FileInputStream(pdffile); HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.setContentLength(pdffile.length()); responseHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM); - responseHeaders.set("Content-Disposition", "attachment;filename=" + pdffile.getName()); + responseHeaders.set("Content-Disposition", "attachment;filename=" + fileName + ".pdf"); responseHeaders.set("Access-Control-Expose-Headers", "Content-Disposition"); responseHeaders.get("Access-Control-Expose-Headers").add("Content-Type"); byte[] content = IOUtils.toByteArray(resource); resource.close(); - Files.deleteIfExists(file.toPath()); + Files.deleteIfExists(file.getFile().toPath()); Files.deleteIfExists(pdffile.toPath()); return new ResponseEntity<>(content, responseHeaders, diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java index 7032411f4..af0f0d226 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java @@ -235,11 +235,11 @@ public class DataManagementPlanManager { return; } - public File getWordDocument(String id, Principal principal, ConfigLoader configLoader) throws IOException { + public FileEnvelope getWordDocument(String id, Principal principal, ConfigLoader configLoader) throws IOException { return this.getWordDocument(id, principal, configLoader, false); } - public File getWordDocument(String id, Principal principal, ConfigLoader configLoader, Boolean versioned) throws IOException { + public FileEnvelope getWordDocument(String id, Principal principal, ConfigLoader configLoader, Boolean versioned) throws IOException { WordBuilder wordBuilder = new WordBuilder(); VisibilityRuleService visibilityRuleService = this.utilitiesService.getVisibilityRuleService(); DatasetWizardModel dataset = new DatasetWizardModel(); @@ -392,12 +392,16 @@ public class DataManagementPlanManager { fileName = dmpEntity.getLabel(); } fileName = fileName.replaceAll("[^a-zA-Z0-9+ ]", ""); - File exportFile = new File(this.environment.getProperty("temp.temp") + fileName + ".docx"); + FileEnvelope exportEnvelope = new FileEnvelope(); + exportEnvelope.setFilename(fileName + ".docx"); + String uuid = UUID.randomUUID().toString(); + File exportFile = new File(this.environment.getProperty("temp.temp") + uuid + ".docx"); FileOutputStream out = new FileOutputStream(exportFile); document.write(out); out.close(); + exportEnvelope.setFile(exportFile); - return exportFile; + return exportEnvelope; } /*public File getPdfDocument(String id) throws InstantiationException, IllegalAccessException, InterruptedException, IOException { @@ -1033,9 +1037,10 @@ public class DataManagementPlanManager { if (!dmp.isPublic() && dmp.getUsers().stream().filter(userInfo -> userInfo.getUser().getId() == principal.getId()).collect(Collectors.toList()).size() == 0) throw new UnauthorisedException(); List datasets = dmp.getDataset().stream().collect(Collectors.toList()); - String fileName = dmp.getLabel(); - fileName = fileName.replaceAll("[^a-zA-Z0-9+ ]", ""); - File xmlFile = new File(this.environment.getProperty("temp.temp") + fileName + ".xml"); + /*String fileName = dmp.getLabel(); + fileName = fileName.replaceAll("[^a-zA-Z0-9+ ]", "");*/ + String uuid = UUID.randomUUID().toString(); + File xmlFile = new File(this.environment.getProperty("temp.temp") + uuid + ".xml"); BufferedWriter writer = new BufferedWriter(new FileWriter(xmlFile, true)); Document xmlDoc = XmlBuilder.getDocument(); Element dmpElement = xmlDoc.createElement("dmp"); @@ -1156,7 +1161,7 @@ public class DataManagementPlanManager { writer.close(); FileEnvelope fileEnvelope = new FileEnvelope(); fileEnvelope.setFile(xmlFile); - fileEnvelope.setFilename(dmp.getLabel()); + fileEnvelope.setFilename(dmp.getLabel() + ".xml"); return fileEnvelope; } @@ -1172,7 +1177,8 @@ public class DataManagementPlanManager { mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); String fileName = dmp.getLabel(); fileName = fileName.replaceAll("[^a-zA-Z0-9+ ]", ""); - File file = new File(this.environment.getProperty("temp.temp") + fileName + ".json"); + String uuid = UUID.randomUUID().toString(); + File file = new File(this.environment.getProperty("temp.temp") + uuid + ".json"); OutputStream output = new FileOutputStream(file); try { // mapper.writeValue(file, rdaExportModel); @@ -1187,7 +1193,7 @@ public class DataManagementPlanManager { HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.setContentLength(file.length()); responseHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM); - responseHeaders.set("Content-Disposition", "attachment;filename=" + file.getName()); + responseHeaders.set("Content-Disposition", "attachment;filename=" + fileName + ".json"); responseHeaders.set("Access-Control-Expose-Headers", "Content-Disposition"); responseHeaders.get("Access-Control-Expose-Headers").add("Content-Type"); @@ -1198,28 +1204,28 @@ public class DataManagementPlanManager { } public ResponseEntity getDocument(String id, String contentType, Principal principal, ConfigLoader configLoader) throws InstantiationException, IllegalAccessException, IOException { - File file; + FileEnvelope file; switch (contentType) { case "application/xml": - file = getXmlDocument(id, principal).getFile(); + file = getXmlDocument(id, principal); break; case "application/msword": file = getWordDocument(id, principal, configLoader); break; default: - file = getXmlDocument(id, principal).getFile(); + file = getXmlDocument(id, principal); } - InputStream resource = new FileInputStream(file); + InputStream resource = new FileInputStream(file.getFile()); HttpHeaders responseHeaders = new HttpHeaders(); - responseHeaders.setContentLength(file.length()); + responseHeaders.setContentLength(file.getFile().length()); responseHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM); - responseHeaders.set("Content-Disposition", "attachment;filename=" + file.getName()); + responseHeaders.set("Content-Disposition", "attachment;filename=" + file.getFilename()); responseHeaders.set("Access-Control-Expose-Headers", "Content-Disposition"); responseHeaders.get("Access-Control-Expose-Headers").add("Content-Type"); byte[] content = org.apache.poi.util.IOUtils.toByteArray(resource); resource.close(); - Files.deleteIfExists(file.toPath()); + Files.deleteIfExists(file.getFile().toPath()); return new ResponseEntity<>(content, responseHeaders, HttpStatus.OK); @@ -1598,15 +1604,15 @@ public class DataManagementPlanManager { fileHeaders.setContentType(MediaType.MULTIPART_FORM_DATA); LinkedMultiValueMap addFileMap = new LinkedMultiValueMap<>(); - File file = getWordDocument(id.toString(), principal, configLoader); - addFileMap.add("filename", file.getName()); - FileSystemResource fileSystemResource = new FileSystemResource(file); + FileEnvelope file = getWordDocument(id.toString(), principal, configLoader); + addFileMap.add("filename", file.getFilename()); + FileSystemResource fileSystemResource = new FileSystemResource(file.getFile()); addFileMap.add("file", fileSystemResource); HttpEntity> addFileMapRequest = new HttpEntity<>(addFileMap, fileHeaders); String addFileUrl = links.get("files") + "?access_token=" + this.environment.getProperty("zenodo.access_token"); ResponseEntity addFileResponse = restTemplate.postForEntity(addFileUrl, addFileMapRequest, String.class); - Files.deleteIfExists(file.toPath()); + Files.deleteIfExists(file.getFile().toPath()); // Third post call to Zenodo to publish the entry and return the DOI. String publishUrl = links.get("publish") + "?access_token=" + this.environment.getProperty("zenodo.access_token"); diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementProfileManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementProfileManager.java index 983165034..d9ee45421 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementProfileManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementProfileManager.java @@ -24,6 +24,7 @@ import eu.eudat.logic.services.ApiContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; @@ -49,11 +50,13 @@ public class DataManagementProfileManager { private ApiContext apiContext; private DatabaseRepository databaseRepository; + private Environment environment; @Autowired - public DataManagementProfileManager(ApiContext apiContext) { + public DataManagementProfileManager(ApiContext apiContext, Environment environment) { this.apiContext = apiContext; this.databaseRepository = apiContext.getOperationsContext().getDatabaseRepository(); + this.environment = environment; } public DataTableData getPaged(DataManagementPlanProfileTableRequest dataManagementPlanProfileTableRequest, Principal principal) throws Exception { @@ -114,7 +117,7 @@ public class DataManagementProfileManager { public FileEnvelope getXmlDocument(DataManagementPlanProfileListingModel dmpProfile, String label) throws InstantiationException, IllegalAccessException, IOException { ExportXmlBuilderDmpProfile xmlBuilder = new ExportXmlBuilderDmpProfile(); - File file = xmlBuilder.build(dmpProfile); + File file = xmlBuilder.build(dmpProfile, environment); FileEnvelope fileEnvelope = new FileEnvelope(); fileEnvelope.setFile(file); fileEnvelope.setFilename(label); diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetManager.java index 6883663a2..a30f89ab1 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetManager.java @@ -402,7 +402,7 @@ public class DatasetManager { visibilityRuleService.buildVisibilityContext(pagedDatasetProfile.getRules()); wordBuilder.build(document, pagedDatasetProfile, visibilityRuleService); String label = datasetEntity.getLabel().replaceAll("[^a-zA-Z0-9+ ]", ""); - File exportFile = new File(label + ".docx"); +// File exportFile = new File(label + ".docx"); // Removes the top empty headings. for (int i = 0; i < 6; i++) { @@ -446,19 +446,23 @@ public class DatasetManager { // return exportFile; } - public File getWordDocumentFile(ConfigLoader configLoader, String id, VisibilityRuleService visibilityRuleService, Principal principal) throws IOException { + public FileEnvelope getWordDocumentFile(ConfigLoader configLoader, String id, VisibilityRuleService visibilityRuleService, Principal principal) throws IOException { eu.eudat.data.entities.Dataset datasetEntity = databaseRepository.getDatasetDao().find(UUID.fromString(id), HintedModelFactory.getHint(DatasetWizardModel.class)); if (!datasetEntity.getDmp().isPublic() && datasetEntity.getDmp().getUsers() .stream().filter(userInfo -> userInfo.getUser().getId() == principal.getId()) .collect(Collectors.toList()).size() == 0) throw new UnauthorisedException(); String label = datasetEntity.getLabel().replaceAll("[^a-zA-Z0-9+ ]", ""); - File exportFile = new File(this.environment.getProperty("temp.temp") + label + ".docx"); + FileEnvelope exportEnvelope = new FileEnvelope(); + exportEnvelope.setFilename(label + ".docx"); + String uuid = UUID.randomUUID().toString(); + File exportFile = new File(this.environment.getProperty("temp.temp") + uuid + ".docx"); XWPFDocument document = getWordDocument(configLoader, datasetEntity, visibilityRuleService); FileOutputStream out = new FileOutputStream(exportFile); document.write(out); out.close(); - return exportFile; + exportEnvelope.setFile(exportFile); + return exportEnvelope; } public String getWordDocumentText (Dataset datasetEntity) throws Exception { @@ -488,17 +492,19 @@ public class DatasetManager { File file = xmlBuilder.build(pagedDatasetProfile, datasetEntity.getProfile().getId(), visibilityRuleService, environment); FileEnvelope fileEnvelope = new FileEnvelope(); fileEnvelope.setFile(file); - fileEnvelope.setFilename(datasetEntity.getLabel()); + String label = datasetEntity.getLabel().replaceAll("[^a-zA-Z0-9+ ]", ""); + fileEnvelope.setFilename(label); return fileEnvelope; } - public File convertToPDF(File file, Environment environment, String label) throws IOException, InterruptedException { + public File convertToPDF(FileEnvelope file, Environment environment) throws IOException, InterruptedException { LinkedMultiValueMap map = new LinkedMultiValueMap<>(); - map.add("files", new FileSystemResource(file)); - map.add("filename", label + ".pdf"); + String uuid = UUID.randomUUID().toString(); + map.add("files", new FileSystemResource(file.getFile())); + map.add("filename", uuid + ".pdf"); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA); - headers.add("Content-disposition", "attachment; filename=" + label + ".pdf"); + headers.add("Content-disposition", "attachment; filename=" + uuid + ".pdf"); headers.add("Content-type", "application/pdf"); HttpEntity> requestEntity = new HttpEntity>( @@ -507,11 +513,11 @@ public class DatasetManager { byte[] queueResult = new RestTemplate().postForObject(environment.getProperty("pdf.converter.url") + "convert/office" , requestEntity, byte[].class); - File resultPdf = new File(label + ".pdf"); + File resultPdf = new File(environment.getProperty("temp.temp") + uuid + ".pdf"); FileOutputStream output = new FileOutputStream(resultPdf); IOUtils.write(queueResult, output); output.close(); - Files.deleteIfExists(file.toPath()); + Files.deleteIfExists(file.getFile().toPath()); return resultPdf; } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetProfileManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetProfileManager.java index 81693e917..9a171ade0 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetProfileManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DatasetProfileManager.java @@ -21,10 +21,10 @@ import eu.eudat.models.data.entities.xmlmodels.datasetprofiledefinition.Field; import eu.eudat.models.data.externaldataset.ExternalAutocompleteFieldModel; import eu.eudat.models.data.helpers.common.DataTableData; import eu.eudat.queryable.QueryableList; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; import org.springframework.http.*; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; @@ -34,12 +34,10 @@ import org.w3c.dom.Element; import javax.activation.MimetypesFileTypeMap; import javax.xml.xpath.*; -import java.io.IOException; +import java.io.*; import java.nio.file.Files; import java.util.*; -import java.io.*; - @Component public class DatasetProfileManager { @@ -47,11 +45,13 @@ public class DatasetProfileManager { private ApiContext apiContext; private DatabaseRepository databaseRepository; + private Environment environment; @Autowired - public DatasetProfileManager(ApiContext apiContext) { + public DatasetProfileManager(ApiContext apiContext, Environment environment) { this.apiContext = apiContext; this.databaseRepository = apiContext.getOperationsContext().getDatabaseRepository(); + this.environment = environment; } public eu.eudat.models.data.admin.composite.DatasetProfile getDatasetProfile(String id) { @@ -142,7 +142,7 @@ public class DatasetProfileManager { public FileEnvelope getXmlDocument(eu.eudat.models.data.user.composite.DatasetProfile datatasetProfile, String label) throws InstantiationException, IllegalAccessException, IOException { ExportXmlBuilderDatasetProfile xmlBuilder = new ExportXmlBuilderDatasetProfile(); - File file = xmlBuilder.build(datatasetProfile); + File file = xmlBuilder.build(datatasetProfile, environment); FileEnvelope fileEnvelope = new FileEnvelope(); fileEnvelope.setFile(file); fileEnvelope.setFilename(label); diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/datasetProfileXml/ExportXmlBuilderDatasetProfile.java b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/datasetProfileXml/ExportXmlBuilderDatasetProfile.java index 6a53063d5..28e7f911b 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/datasetProfileXml/ExportXmlBuilderDatasetProfile.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/datasetProfileXml/ExportXmlBuilderDatasetProfile.java @@ -8,6 +8,7 @@ import eu.eudat.models.data.user.components.datasetprofile.FieldSet; import eu.eudat.models.data.user.components.datasetprofile.Section; import eu.eudat.logic.utilities.builders.XmlBuilder; +import org.springframework.core.env.Environment; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -22,9 +23,9 @@ import java.util.UUID; public class ExportXmlBuilderDatasetProfile { - public File build(eu.eudat.models.data.user.composite.DatasetProfile datasetProfile) throws IOException { + public File build(eu.eudat.models.data.user.composite.DatasetProfile datasetProfile, Environment environment) throws IOException { - File xmlFile = new File(UUID.randomUUID() + ".xml"); + File xmlFile = new File(environment.getProperty("temp.temp") + UUID.randomUUID() + ".xml"); BufferedWriter writer = new BufferedWriter(new FileWriter(xmlFile, true)); Document xmlDoc = XmlBuilder.getDocument(); // Element root = xmlDoc.createElement("root"); diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/dmpXml/ExportXmlBuilderDmpProfile.java b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/dmpXml/ExportXmlBuilderDmpProfile.java index 344d4924a..212facc14 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/dmpXml/ExportXmlBuilderDmpProfile.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/dmpXml/ExportXmlBuilderDmpProfile.java @@ -4,6 +4,7 @@ import eu.eudat.logic.utilities.builders.XmlBuilder; import eu.eudat.models.data.entities.xmlmodels.dmpprofiledefinition.DataManagementPlanProfile; import eu.eudat.models.data.listingmodels.DataManagementPlanProfileListingModel; +import org.springframework.core.env.Environment; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -16,9 +17,9 @@ import java.util.UUID; public class ExportXmlBuilderDmpProfile { - public File build(DataManagementPlanProfileListingModel dmpProfile) throws IOException { + public File build(DataManagementPlanProfileListingModel dmpProfile, Environment environment) throws IOException { - File xmlFile = new File(UUID.randomUUID() + ".xml"); + File xmlFile = new File(environment.getProperty("temp.temp") + UUID.randomUUID() + ".xml"); BufferedWriter writer = new BufferedWriter(new FileWriter(xmlFile, true)); Document xmlDoc = XmlBuilder.getDocument(); Element root = xmlDoc.createElement("root"); From 194ae2ccf014ac60daa159fb8c3f3a5bf77765bf Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Fri, 3 Apr 2020 13:37:16 +0300 Subject: [PATCH 05/60] Fixed minor issues with dmp index and dmp compact listing --- .../java/eu/eudat/elastic/entities/Dmp.java | 20 ++++++++++--------- .../criteria/dmp-criteria.component.ts | 4 +++- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/dmp-backend/elastic/src/main/java/eu/eudat/elastic/entities/Dmp.java b/dmp-backend/elastic/src/main/java/eu/eudat/elastic/entities/Dmp.java index 7f51d36ae..6c98bab17 100644 --- a/dmp-backend/elastic/src/main/java/eu/eudat/elastic/entities/Dmp.java +++ b/dmp-backend/elastic/src/main/java/eu/eudat/elastic/entities/Dmp.java @@ -212,15 +212,17 @@ public class Dmp implements ElasticEntity { builder.field(MapKey.LASTVERSION.getName(), this.lastVersion); builder.field(MapKey.LASTPUBLICVERSION.getName(), this.lastPublicVersion); builder.field(MapKey.ISPUBLIC.getName(), this.isPublic); - builder.startArray(MapKey.DATASETS.getName()); - this.datasets.forEach(dataset -> { - try { - dataset.toElasticEntity(builder); - } catch (IOException e) { - logger.error(e.getMessage(), e); - } - }); - builder.endArray(); + if (datasets != null) { + builder.startArray(MapKey.DATASETS.getName()); + this.datasets.forEach(dataset -> { + try { + dataset.toElasticEntity(builder); + } catch (IOException e) { + logger.error(e.getMessage(), e); + } + }); + builder.endArray(); + } builder.field(MapKey.GRANT.getName(), this.grant.toString()); builder.field(MapKey.GRANTSTATUS.getName(), this.grantStatus); builder.endObject(); diff --git a/dmp-frontend/src/app/ui/dmp/listing/criteria/dmp-criteria.component.ts b/dmp-frontend/src/app/ui/dmp/listing/criteria/dmp-criteria.component.ts index 1aaefee4b..a073e4ca8 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/criteria/dmp-criteria.component.ts +++ b/dmp-frontend/src/app/ui/dmp/listing/criteria/dmp-criteria.component.ts @@ -22,6 +22,8 @@ import { map, takeUntil } from 'rxjs/operators'; import { AuthService } from '@app/core/services/auth/auth.service'; import { isNullOrUndefined } from 'util'; import { DatasetService } from '@app/core/services/dataset/dataset.service'; +import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; +import { Observable } from 'rxjs'; @Component({ selector: 'app-dmp-criteria-component', @@ -173,7 +175,7 @@ export class DmpCriteriaComponent extends BaseCriteriaComponent implements OnIni return this.userService.getCollaboratorsPaged(collaboratorsRequestItem).pipe(map(x => x.data)); } - filterDatasetTemplate(query: string) { + filterDatasetTemplate(query: string): Observable { const fields: Array = new Array(); fields.push('asc'); const datasetTemplateRequestItem: DataTableRequest = new DataTableRequest(0, null, { fields: fields }); From 4d59821b6c2b1228fedbc72e5ed6b6ccf9a96b1d Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Fri, 3 Apr 2020 17:04:53 +0300 Subject: [PATCH 06/60] Allow twitter oauth to login without email (ask when logging in) --- .../twitter/TwitterTokenValidator.java | 18 +++++++++++++----- .../twitter-login/twitter-login.component.ts | 8 +++++++- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/security/validators/twitter/TwitterTokenValidator.java b/dmp-backend/web/src/main/java/eu/eudat/logic/security/validators/twitter/TwitterTokenValidator.java index 88aba641f..43f4d98df 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/security/validators/twitter/TwitterTokenValidator.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/security/validators/twitter/TwitterTokenValidator.java @@ -39,7 +39,8 @@ public class TwitterTokenValidator implements TokenValidator { @Override public Principal validateToken(LoginInfo credentials) throws NonValidTokenException, IOException, GeneralSecurityException, NullEmailException { - String verifier = (String) credentials.getData(); + String verifier = (String) ((Map)credentials.getData()).get("verifier"); + String email = (String) ((Map) credentials.getData()).get("email"); OAuthToken oAuthToken = new OAuthToken(credentials.getTicket(), verifier); AuthorizedRequestToken authorizedRequestToken = new AuthorizedRequestToken(oAuthToken, verifier); OAuthToken finalOauthToken = this.twitterServiceProvider.getOAuthOperations().exchangeForAccessToken(authorizedRequestToken, null); @@ -48,11 +49,18 @@ public class TwitterTokenValidator implements TokenValidator { LoginProviderUser user = new LoginProviderUser(); Map values = twitterTemplate.getRestTemplate().getForObject("https://api.twitter.com/1.1/account/verify_credentials.json?include_email=true", Map.class); - if (values.get("email") == null) - throw new UnauthorisedException("Cannot login user.Twitter account did not provide email"); - user.setEmail((String) values.get("email")); + if (values.get("email") == null) { +// throw new UnauthorisedException("Cannot login user.Twitter account did not provide email"); + user.setIsVerified(false); //TODO + if (email != null && !email.isEmpty()) { + user.setEmail(email); + } + } + else { + user.setEmail((String) values.get("email")); + user.setIsVerified(true); //TODO + } user.setAvatarUrl(profile.getProfileImageUrl()); - user.setIsVerified(true); //TODO user.setId("" + profile.getId()); user.setName(profile.getName()); user.setProvider(TokenValidatorFactoryImpl.LoginProvider.TWITTER); diff --git a/dmp-frontend/src/app/ui/auth/login/twitter-login/twitter-login.component.ts b/dmp-frontend/src/app/ui/auth/login/twitter-login/twitter-login.component.ts index fdf7f7657..2fe80b094 100644 --- a/dmp-frontend/src/app/ui/auth/login/twitter-login/twitter-login.component.ts +++ b/dmp-frontend/src/app/ui/auth/login/twitter-login/twitter-login.component.ts @@ -9,6 +9,8 @@ import { BaseComponent } from '@common/base/base.component'; import { environment } from 'environments/environment'; import { takeUntil } from 'rxjs/operators'; import { ConfigurationService } from '@app/core/services/configuration/configuration.service'; +import { FormControl } from '@angular/forms'; +import { stringify } from 'querystring'; @Component({ selector: 'app-twitter-login', @@ -17,6 +19,7 @@ import { ConfigurationService } from '@app/core/services/configuration/configura export class TwitterLoginComponent extends BaseComponent implements OnInit { private returnUrl: string; + private emailFormControl = new FormControl(''); constructor( private route: ActivatedRoute, @@ -50,7 +53,10 @@ export class TwitterLoginComponent extends BaseComponent implements OnInit { } public twitterLogin(token: string, verifier: string) { - this.authService.login({ ticket: token, provider: AuthProvider.Twitter, data: verifier }) + const data = { + email: this.emailFormControl.value, verifier: verifier + }; + this.authService.login({ ticket: token, provider: AuthProvider.Twitter, data: data }) .pipe(takeUntil(this._destroyed)) .subscribe( res => this.loginService.onLogInSuccess(res, this.returnUrl), From 5b1c6971035102cdfd9470422da54515f94cad0d Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Fri, 3 Apr 2020 18:40:03 +0300 Subject: [PATCH 07/60] Add Zenodo Login and the ability to use it's access token for DOI creation --- .../main/java/eu/eudat/controllers/Login.java | 25 ++++-- .../model/models/PrincipalBuilder.java | 15 ++++ .../managers/DataManagementPlanManager.java | 15 ++-- .../Zenodo/ZenodoCustomProvider.java | 8 ++ .../Zenodo/ZenodoCustomProviderImpl.java | 72 +++++++++++++++ .../customproviders/Zenodo/ZenodoUser.java | 49 ++++++++++ .../validators/TokenValidatorFactoryImpl.java | 14 ++- .../zenodo/ZenodoTokenValidator.java | 57 ++++++++++++ .../zenodo/helpers/ZenodoRequest.java | 12 +++ .../zenodo/helpers/ZenodoResponseToken.java | 38 ++++++++ .../AbstractAuthenticationService.java | 13 ++- ...erifiedUserEmailAuthenticationService.java | 15 ++++ .../VerifiedUserAuthenticationService.java | 15 ++++ .../data/loginprovider/LoginProviderUser.java | 18 ++++ .../eudat/models/data/security/Principal.java | 19 ++++ .../config/application-devel.properties | 4 + .../src/app/core/common/enum/auth-provider.ts | 3 +- .../login-providers.model.ts | 6 ++ .../core/model/zenodo/zenodo-token.model.ts | 6 ++ .../ui/auth/login/img/zenodo-white-200.png | Bin 0 -> 2383 bytes .../app/ui/auth/login/login.component.html | 6 ++ .../app/ui/auth/login/login.component.scss | 19 ++++ .../src/app/ui/auth/login/login.component.ts | 9 ++ .../src/app/ui/auth/login/login.module.ts | 4 +- .../src/app/ui/auth/login/login.routing.ts | 4 +- .../zenodo-login/zenodo-login.component.html | 0 .../zenodo-login/zenodo-login.component.scss | 0 .../zenodo-login/zenodo-login.component.ts | 85 ++++++++++++++++++ dmp-frontend/src/assets/config/config.json | 7 +- 29 files changed, 518 insertions(+), 20 deletions(-) create mode 100644 dmp-backend/web/src/main/java/eu/eudat/logic/security/customproviders/Zenodo/ZenodoCustomProvider.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/logic/security/customproviders/Zenodo/ZenodoCustomProviderImpl.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/logic/security/customproviders/Zenodo/ZenodoUser.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/logic/security/validators/zenodo/ZenodoTokenValidator.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/logic/security/validators/zenodo/helpers/ZenodoRequest.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/logic/security/validators/zenodo/helpers/ZenodoResponseToken.java create mode 100644 dmp-frontend/src/app/core/model/zenodo/zenodo-token.model.ts create mode 100644 dmp-frontend/src/app/ui/auth/login/img/zenodo-white-200.png create mode 100644 dmp-frontend/src/app/ui/auth/login/zenodo-login/zenodo-login.component.html create mode 100644 dmp-frontend/src/app/ui/auth/login/zenodo-login/zenodo-login.component.scss create mode 100644 dmp-frontend/src/app/ui/auth/login/zenodo-login/zenodo-login.component.ts diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/Login.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/Login.java index 78304aa20..16af6f14f 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/Login.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/Login.java @@ -22,6 +22,9 @@ import eu.eudat.logic.security.validators.orcid.ORCIDTokenValidator; import eu.eudat.logic.security.validators.orcid.helpers.ORCIDRequest; import eu.eudat.logic.security.validators.orcid.helpers.ORCIDResponseToken; import eu.eudat.logic.security.validators.twitter.TwitterTokenValidator; +import eu.eudat.logic.security.validators.zenodo.ZenodoTokenValidator; +import eu.eudat.logic.security.validators.zenodo.helpers.ZenodoRequest; +import eu.eudat.logic.security.validators.zenodo.helpers.ZenodoResponseToken; import eu.eudat.logic.services.operations.authentication.AuthenticationService; import eu.eudat.models.data.helpers.responses.ResponseItem; import eu.eudat.models.data.login.Credentials; @@ -54,28 +57,34 @@ public class Login { private LinkedInTokenValidator linkedInTokenValidator; private OpenAIRETokenValidator openAIRETokenValidator; private ConfigurableProviderTokenValidator configurableProviderTokenValidator; + private ZenodoTokenValidator zenodoTokenValidator; private ConfigLoader configLoader; // private Logger logger; private UserManager userManager; + @Autowired - public Login(CustomAuthenticationProvider customAuthenticationProvider, AuthenticationService nonVerifiedUserAuthenticationService, - TwitterTokenValidator twitterTokenValidator, LinkedInTokenValidator linkedInTokenValidator, B2AccessTokenValidator b2AccessTokenValidator, - ORCIDTokenValidator orcidTokenValidator, OpenAIRETokenValidator openAIRETokenValidator, ConfigurableProviderTokenValidator configurableProviderTokenValidator, ConfigLoader configLoader, UserManager userManager/*, Logger logger*/) { + public Login(CustomAuthenticationProvider customAuthenticationProvider, + AuthenticationService nonVerifiedUserAuthenticationService, TwitterTokenValidator twitterTokenValidator, + B2AccessTokenValidator b2AccessTokenValidator, ORCIDTokenValidator orcidTokenValidator, + LinkedInTokenValidator linkedInTokenValidator, OpenAIRETokenValidator openAIRETokenValidator, + ConfigurableProviderTokenValidator configurableProviderTokenValidator, ZenodoTokenValidator zenodoTokenValidator, + ConfigLoader configLoader, UserManager userManager) { this.customAuthenticationProvider = customAuthenticationProvider; this.nonVerifiedUserAuthenticationService = nonVerifiedUserAuthenticationService; this.twitterTokenValidator = twitterTokenValidator; - this.linkedInTokenValidator = linkedInTokenValidator; this.b2AccessTokenValidator = b2AccessTokenValidator; this.orcidTokenValidator = orcidTokenValidator; + this.linkedInTokenValidator = linkedInTokenValidator; this.openAIRETokenValidator = openAIRETokenValidator; this.configurableProviderTokenValidator = configurableProviderTokenValidator; + this.zenodoTokenValidator = zenodoTokenValidator; this.configLoader = configLoader; -// this.logger = logger; this.userManager = userManager; } + @Transactional @RequestMapping(method = RequestMethod.POST, value = {"/externallogin"}, consumes = "application/json", produces = "application/json") public @ResponseBody @@ -128,6 +137,12 @@ public class Login { return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().payload(this.configurableProviderTokenValidator.getAccessToken(configurableProviderRequest)).status(ApiMessageCode.NO_MESSAGE)); } + @RequestMapping(method = RequestMethod.POST, value = {"/zenodoRequestToken"}, produces = "application/json", consumes = "application/json") + public @ResponseBody + ResponseEntity> ZenodoRequestToken(@RequestBody ZenodoRequest zenodoRequest) { + return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().payload(this.zenodoTokenValidator.getAccessToken(zenodoRequest)).status(ApiMessageCode.NO_MESSAGE)); + } + @RequestMapping(method = RequestMethod.POST, value = {"/me"}, consumes = "application/json", produces = "application/json") public @ResponseBody ResponseEntity> authMe(Principal principal) throws NullEmailException { diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/builders/model/models/PrincipalBuilder.java b/dmp-backend/web/src/main/java/eu/eudat/logic/builders/model/models/PrincipalBuilder.java index 133d5e179..35ce34035 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/builders/model/models/PrincipalBuilder.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/builders/model/models/PrincipalBuilder.java @@ -4,6 +4,7 @@ import eu.eudat.logic.builders.Builder; import eu.eudat.models.data.security.Principal; import eu.eudat.types.Authorities; +import java.time.Instant; import java.util.Date; import java.util.Set; import java.util.UUID; @@ -22,6 +23,8 @@ public class PrincipalBuilder extends Builder { private String culture; private String language; private String timezone; + private String zenodoToken; + private Instant zenodoDuration; public PrincipalBuilder id(UUID id) { this.id = id; @@ -68,6 +71,16 @@ public class PrincipalBuilder extends Builder { return this; } + public PrincipalBuilder zenodoToken(String zenodoToken) { + this.zenodoToken = zenodoToken; + return this; + } + + public PrincipalBuilder zenodoDuration(Instant zenodoDuration) { + this.zenodoDuration = zenodoDuration; + return this; + } + @Override public Principal build() { Principal principal = new Principal(); @@ -80,6 +93,8 @@ public class PrincipalBuilder extends Builder { principal.setCulture(culture); principal.setLanguage(language); principal.setTimezone(timezone); + principal.setZenodoToken(zenodoToken); + principal.setZenodoDuration(zenodoDuration); return principal; } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java index af0f0d226..2eed39326 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java @@ -1538,6 +1538,7 @@ public class DataManagementPlanManager { if (dmp.getDoi() != null) throw new Exception("DMP already has a DOI"); + String zenodoToken = principal.getZenodoToken() != null && !principal.getZenodoToken().isEmpty() ? principal.getZenodoToken() : this.environment.getProperty("zenodo.access_token"); // First step, post call to Zenodo, to create the entry. RestTemplate restTemplate = new RestTemplate(); HttpHeaders headers = new HttpHeaders(); @@ -1562,34 +1563,34 @@ public class DataManagementPlanManager { String previousDOI = this.getPreviousDOI(dmp.getGroupId(), dmp.getId()); try { if (previousDOI == null) { - String createUrl = this.environment.getProperty("zenodo.url") + "deposit/depositions" + "?access_token=" + this.environment.getProperty("zenodo.access_token"); + String createUrl = this.environment.getProperty("zenodo.url") + "deposit/depositions" + "?access_token=" + zenodoToken; createResponse = restTemplate.postForEntity(createUrl, request, Map.class).getBody(); links = (LinkedHashMap) createResponse.get("links"); } else { //It requires more than one step to create a new version //First, get the deposit related to the concept DOI - String listUrl = this.environment.getProperty("zenodo.url") + "deposit/depositions" + "?q=conceptdoi:\"" + previousDOI + "\"&access_token=" + this.environment.getProperty("zenodo.access_token"); + String listUrl = this.environment.getProperty("zenodo.url") + "deposit/depositions" + "?q=conceptdoi:\"" + previousDOI + "\"&access_token=" + zenodoToken; ResponseEntity listResponses = restTemplate.getForEntity(listUrl, Map[].class); createResponse = listResponses.getBody()[0]; links = (LinkedHashMap) createResponse.get("links"); //Second, make the new version (not in the links?) - String newVersionUrl = links.get("self") + "/actions/newversion" + "?access_token=" + this.environment.getProperty("zenodo.access_token"); + String newVersionUrl = links.get("self") + "/actions/newversion" + "?access_token=" + zenodoToken; createResponse = restTemplate.postForObject(newVersionUrl, null, Map.class); links = (LinkedHashMap) createResponse.get("links"); //Third, get the new deposit - String latestDraftUrl = links.get("latest_draft") + "?access_token=" + this.environment.getProperty("zenodo.access_token"); + String latestDraftUrl = links.get("latest_draft") + "?access_token=" + zenodoToken; createResponse = restTemplate.getForObject(latestDraftUrl, Map.class); links = (LinkedHashMap) createResponse.get("links"); //At this point it might fail to perform the next requests so enclose them with try catch try { //Forth, update the new deposit's metadata - String updateUrl = links.get("self") + "?access_token=" + this.environment.getProperty("zenodo.access_token"); + String updateUrl = links.get("self") + "?access_token=" + zenodoToken; restTemplate.put(updateUrl, request); //And finally remove pre-existing files from it - String fileListUrl = links.get("self") + "/files" + "?access_token=" + this.environment.getProperty("zenodo.access_token"); + String fileListUrl = links.get("self") + "/files" + "?access_token=" + zenodoToken; ResponseEntity fileListResponse = restTemplate.getForEntity(fileListUrl, Map[].class); for (Map file : fileListResponse.getBody()) { - String fileDeleteUrl = links.get("self") + "/files/" + file.get("id") + "?access_token=" + this.environment.getProperty("zenodo.access_token"); + String fileDeleteUrl = links.get("self") + "/files/" + file.get("id") + "?access_token=" + zenodoToken; restTemplate.delete(fileDeleteUrl); } }catch (Exception e) { diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/security/customproviders/Zenodo/ZenodoCustomProvider.java b/dmp-backend/web/src/main/java/eu/eudat/logic/security/customproviders/Zenodo/ZenodoCustomProvider.java new file mode 100644 index 000000000..b14c3a963 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/security/customproviders/Zenodo/ZenodoCustomProvider.java @@ -0,0 +1,8 @@ +package eu.eudat.logic.security.customproviders.Zenodo; + +import eu.eudat.logic.security.validators.orcid.helpers.ORCIDResponseToken; +import eu.eudat.logic.security.validators.zenodo.helpers.ZenodoResponseToken; + +public interface ZenodoCustomProvider { + ZenodoResponseToken getAccessToken(String code, String clientId, String clientSecret, String redirectUri); +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/security/customproviders/Zenodo/ZenodoCustomProviderImpl.java b/dmp-backend/web/src/main/java/eu/eudat/logic/security/customproviders/Zenodo/ZenodoCustomProviderImpl.java new file mode 100644 index 000000000..b527af2fe --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/security/customproviders/Zenodo/ZenodoCustomProviderImpl.java @@ -0,0 +1,72 @@ +package eu.eudat.logic.security.customproviders.Zenodo; + +import com.fasterxml.jackson.databind.ObjectMapper; +import eu.eudat.logic.security.validators.orcid.helpers.ORCIDResponseToken; +import eu.eudat.logic.security.validators.zenodo.helpers.ZenodoResponseToken; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +import java.io.IOException; +import java.util.Collections; +import java.util.Map; + +@Component("ZenodoCustomProvider") +public class ZenodoCustomProviderImpl implements ZenodoCustomProvider { + private static final Logger logger = LoggerFactory.getLogger(ZenodoCustomProviderImpl.class); + + private Environment environment; + + @Autowired + public ZenodoCustomProviderImpl(Environment environment) { + this.environment = environment; + } + + @Override + public ZenodoResponseToken getAccessToken(String code, String clientId, String clientSecret, String redirectUri) { + RestTemplate restTemplate = new RestTemplate(); + HttpHeaders headers = new HttpHeaders(); + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + headers.setContentType(MediaType.MULTIPART_FORM_DATA); + + MultiValueMap map = new LinkedMultiValueMap<>(); + map.add("client_id", clientId); + map.add("client_secret", clientSecret); + map.add("grant_type", "authorization_code"); + map.add("code", code); + map.add("redirect_uri", redirectUri); + HttpEntity> request = new HttpEntity<>(map, headers); + + try { + Map values = restTemplate.postForObject(this.environment.getProperty("zenodo.login.access_token_url"), request, Map.class); + ZenodoResponseToken zenodoResponseToken = new ZenodoResponseToken(); + Map user = (Map) values.get("user"); + zenodoResponseToken.setUserId((String) user.get("id")); + zenodoResponseToken.setEmail((String) user.get("email")); + zenodoResponseToken.setExpiresIn((Integer) values.get("expires_in")); + zenodoResponseToken.setAccessToken((String) values.get("access_token")); + + return zenodoResponseToken; + } catch (HttpClientErrorException ex) { + logger.error(ex.getResponseBodyAsString(), ex); + } + + return null; + } + + private HttpHeaders createBearerAuthHeaders(String accessToken) { + return new HttpHeaders() {{ + String authHeader = "Bearer " + accessToken; + set("Authorization", authHeader); + }}; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/security/customproviders/Zenodo/ZenodoUser.java b/dmp-backend/web/src/main/java/eu/eudat/logic/security/customproviders/Zenodo/ZenodoUser.java new file mode 100644 index 000000000..cbcb95928 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/security/customproviders/Zenodo/ZenodoUser.java @@ -0,0 +1,49 @@ +package eu.eudat.logic.security.customproviders.Zenodo; + +import java.util.Map; + +public class ZenodoUser { + private String userId; + private String email; + private String accessToken; + private Integer expiresIn; + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getEmail() { + return email; + } + public void setEmail(String email) { + this.email = email; + } + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public Integer getExpiresIn() { + return expiresIn; + } + + public void setExpiresIn(Integer expiresIn) { + this.expiresIn = expiresIn; + } + + public ZenodoUser getZenodoUser(Object data) { + this.userId = (String) ((Map) data).get("userId"); + this.email = (String) ((Map) data).get("email"); + this.accessToken = (String) ((Map) data).get("accessToken"); + this.expiresIn = (Integer) ((Map) data).get("expiresIn"); + return this; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/security/validators/TokenValidatorFactoryImpl.java b/dmp-backend/web/src/main/java/eu/eudat/logic/security/validators/TokenValidatorFactoryImpl.java index 9b594c96e..c079d24a5 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/security/validators/TokenValidatorFactoryImpl.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/security/validators/TokenValidatorFactoryImpl.java @@ -6,6 +6,7 @@ import eu.eudat.logic.security.customproviders.ConfigurableProvider.Configurable import eu.eudat.logic.security.customproviders.LinkedIn.LinkedInCustomProvider; import eu.eudat.logic.security.customproviders.ORCID.ORCIDCustomProvider; import eu.eudat.logic.security.customproviders.OpenAIRE.OpenAIRECustomProvider; +import eu.eudat.logic.security.customproviders.Zenodo.ZenodoCustomProvider; import eu.eudat.logic.security.validators.b2access.B2AccessTokenValidator; import eu.eudat.logic.security.validators.configurableProvider.ConfigurableProviderTokenValidator; import eu.eudat.logic.security.validators.facebook.FacebookTokenValidator; @@ -14,6 +15,7 @@ import eu.eudat.logic.security.validators.linkedin.LinkedInTokenValidator; import eu.eudat.logic.security.validators.openaire.OpenAIRETokenValidator; import eu.eudat.logic.security.validators.orcid.ORCIDTokenValidator; import eu.eudat.logic.security.validators.twitter.TwitterTokenValidator; +import eu.eudat.logic.security.validators.zenodo.ZenodoTokenValidator; import eu.eudat.logic.services.operations.authentication.AuthenticationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; @@ -23,7 +25,7 @@ import org.springframework.stereotype.Service; @Service("tokenValidatorFactory") public class TokenValidatorFactoryImpl implements TokenValidatorFactory { public enum LoginProvider { - GOOGLE(1), FACEBOOK(2), TWITTER(3), LINKEDIN(4), NATIVELOGIN(5), B2_ACCESS(6), ORCID(7), OPENAIRE(8), CONFIGURABLE(9); + GOOGLE(1), FACEBOOK(2), TWITTER(3), LINKEDIN(4), NATIVELOGIN(5), B2_ACCESS(6), ORCID(7), OPENAIRE(8), CONFIGURABLE(9), ZENODO(10); private int value; @@ -55,6 +57,8 @@ public class TokenValidatorFactoryImpl implements TokenValidatorFactory { return OPENAIRE; case 9: return CONFIGURABLE; + case 10: + return ZENODO; default: throw new RuntimeException("Unsupported LoginProvider"); } @@ -69,12 +73,15 @@ public class TokenValidatorFactoryImpl implements TokenValidatorFactory { private OpenAIRECustomProvider openAIRECustomProvider; private ConfigurableProviderCustomProvider configurableProviderCustomProvider; private ConfigLoader configLoader; + private ZenodoCustomProvider zenodoCustomProvider; @Autowired public TokenValidatorFactoryImpl( Environment environment, AuthenticationService nonVerifiedUserAuthenticationService, B2AccessCustomProvider b2AccessCustomProvider, - ORCIDCustomProvider orcidCustomProvider, LinkedInCustomProvider linkedInCustomProvider, OpenAIRECustomProvider openAIRECustomProvider, ConfigurableProviderCustomProvider configurableProviderCustomProvider, ConfigLoader configLoader) { + ORCIDCustomProvider orcidCustomProvider, LinkedInCustomProvider linkedInCustomProvider, OpenAIRECustomProvider openAIRECustomProvider, + ConfigurableProviderCustomProvider configurableProviderCustomProvider, ConfigLoader configLoader, + ZenodoCustomProvider zenodoCustomProvider) { this.environment = environment; this.nonVerifiedUserAuthenticationService = nonVerifiedUserAuthenticationService; this.b2AccessCustomProvider = b2AccessCustomProvider; @@ -83,6 +90,7 @@ public class TokenValidatorFactoryImpl implements TokenValidatorFactory { this.openAIRECustomProvider = openAIRECustomProvider; this.configurableProviderCustomProvider = configurableProviderCustomProvider; this.configLoader = configLoader; + this.zenodoCustomProvider = zenodoCustomProvider; } public TokenValidator getProvider(LoginProvider provider) { @@ -103,6 +111,8 @@ public class TokenValidatorFactoryImpl implements TokenValidatorFactory { return new OpenAIRETokenValidator(this.environment, this.nonVerifiedUserAuthenticationService, this.openAIRECustomProvider); case CONFIGURABLE: return new ConfigurableProviderTokenValidator(this.configurableProviderCustomProvider, this.nonVerifiedUserAuthenticationService, this.configLoader); + case ZENODO: + return new ZenodoTokenValidator(this.environment, this.nonVerifiedUserAuthenticationService, this.zenodoCustomProvider); default: throw new RuntimeException("Login Provider Not Implemented"); } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/security/validators/zenodo/ZenodoTokenValidator.java b/dmp-backend/web/src/main/java/eu/eudat/logic/security/validators/zenodo/ZenodoTokenValidator.java new file mode 100644 index 000000000..2708a96b2 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/security/validators/zenodo/ZenodoTokenValidator.java @@ -0,0 +1,57 @@ +package eu.eudat.logic.security.validators.zenodo; + +import eu.eudat.exceptions.security.NonValidTokenException; +import eu.eudat.exceptions.security.NullEmailException; +import eu.eudat.logic.security.customproviders.ORCID.ORCIDCustomProvider; +import eu.eudat.logic.security.customproviders.ORCID.ORCIDUser; +import eu.eudat.logic.security.customproviders.Zenodo.ZenodoCustomProvider; +import eu.eudat.logic.security.customproviders.Zenodo.ZenodoUser; +import eu.eudat.logic.security.validators.TokenValidator; +import eu.eudat.logic.security.validators.zenodo.helpers.ZenodoRequest; +import eu.eudat.logic.security.validators.zenodo.helpers.ZenodoResponseToken; +import eu.eudat.logic.services.operations.authentication.AuthenticationService; +import eu.eudat.models.data.login.LoginInfo; +import eu.eudat.models.data.loginprovider.LoginProviderUser; +import eu.eudat.models.data.security.Principal; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.security.GeneralSecurityException; + +@Component("zenodoTokenValidator") +public class ZenodoTokenValidator implements TokenValidator { + + private ZenodoCustomProvider zenodoCustomProvider; + private Environment environment; + private AuthenticationService nonVerifiedUserAuthenticationService; + + @Autowired + public ZenodoTokenValidator(Environment environment, AuthenticationService nonVerifiedUserAuthenticationService, ZenodoCustomProvider zenodoCustomProvider) { + this.environment = environment; + this.nonVerifiedUserAuthenticationService = nonVerifiedUserAuthenticationService; + this.zenodoCustomProvider = zenodoCustomProvider; + } + + @Override + public Principal validateToken(LoginInfo credentials) throws NonValidTokenException, IOException, GeneralSecurityException, NullEmailException { + ZenodoUser zenodoUser = new ZenodoUser().getZenodoUser(credentials.getData()); + LoginProviderUser user = new LoginProviderUser(); + user.setId(zenodoUser.getUserId()); + user.setName(zenodoUser.getEmail()); + user.setEmail(zenodoUser.getEmail()); + user.setZenodoId(zenodoUser.getAccessToken()); + user.setZenodoExpire(zenodoUser.getExpiresIn()); + user.setProvider(credentials.getProvider()); + user.setSecret(credentials.getTicket()); + return this.nonVerifiedUserAuthenticationService.Touch(user); + } + + public ZenodoResponseToken getAccessToken(ZenodoRequest zenodoRequest) { + return this.zenodoCustomProvider.getAccessToken(zenodoRequest.getCode() + , this.environment.getProperty("zenodo.login.client_id") + , this.environment.getProperty("zenodo.login.client_secret") + , this.environment.getProperty("zenodo.login.redirect_uri")); + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/security/validators/zenodo/helpers/ZenodoRequest.java b/dmp-backend/web/src/main/java/eu/eudat/logic/security/validators/zenodo/helpers/ZenodoRequest.java new file mode 100644 index 000000000..c1f4ea32a --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/security/validators/zenodo/helpers/ZenodoRequest.java @@ -0,0 +1,12 @@ +package eu.eudat.logic.security.validators.zenodo.helpers; + +public class ZenodoRequest { + private String code; + + public String getCode() { + return code; + } + public void setCode(String code) { + this.code = code; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/security/validators/zenodo/helpers/ZenodoResponseToken.java b/dmp-backend/web/src/main/java/eu/eudat/logic/security/validators/zenodo/helpers/ZenodoResponseToken.java new file mode 100644 index 000000000..5b437cdfb --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/security/validators/zenodo/helpers/ZenodoResponseToken.java @@ -0,0 +1,38 @@ +package eu.eudat.logic.security.validators.zenodo.helpers; + +public class ZenodoResponseToken { + private String userId; + private String email; + private Integer expiresIn; + private String accessToken; + + public String getUserId() { + return userId; + } + public void setUserId(String userId) { + this.userId = userId; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public Integer getExpiresIn() { + return expiresIn; + } + + public void setExpiresIn(Integer expiresIn) { + this.expiresIn = expiresIn; + } + + public String getAccessToken() { + return accessToken; + } + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/authentication/AbstractAuthenticationService.java b/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/authentication/AbstractAuthenticationService.java index cb7506ab6..fc09056fa 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/authentication/AbstractAuthenticationService.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/authentication/AbstractAuthenticationService.java @@ -20,6 +20,7 @@ import org.slf4j.LoggerFactory; import org.springframework.core.env.Environment; import org.springframework.transaction.annotation.Transactional; +import java.time.Instant; import java.util.*; public abstract class AbstractAuthenticationService implements AuthenticationService { @@ -132,7 +133,7 @@ public abstract class AbstractAuthenticationService implements AuthenticationSer userInfo = this.apiContext.getOperationsContext().getBuilderFactory().getBuilder(UserInfoBuilder.class) .name(profile.getName()).verified_email(profile.getIsVerified()) .email(profile.getEmail()).created(new Date()).lastloggedin(new Date()) - .additionalinfo("{\"data\":{\"avatar\":{\"url\":\"" + profile.getAvatarUrl() + "\"}}}") + .additionalinfo("{\"data\":{\"avatar\":{\"url\":\"" + profile.getAvatarUrl() + "\"}},{\"zenodoToken\":\"" + profile.getZenodoId() + "\", \"expirationDate\": \"" + Instant.now().plusSeconds(profile.getZenodoExpire()).toEpochMilli() + "\"}") .authorization_level((short) 1).usertype((short) 1) .build(); @@ -149,7 +150,15 @@ public abstract class AbstractAuthenticationService implements AuthenticationSer } else { Map additionalInfo = userInfo.getAdditionalinfo() != null ? new JSONObject(userInfo.getAdditionalinfo()).toMap() : new HashMap<>(); - additionalInfo.put("avatarUrl", profile.getAvatarUrl()); + if (profile.getAvatarUrl() != null && !profile.getAvatarUrl().isEmpty() && !profile.getAvatarUrl().equals("null")) { + additionalInfo.put("avatarUrl", profile.getAvatarUrl()); + } + if (profile.getZenodoId() != null && !profile.getZenodoId().isEmpty() && !profile.getZenodoId().equals("null")) { + additionalInfo.put("zenodoToken", profile.getZenodoId()); + } + if (profile.getZenodoExpire() != null) { + additionalInfo.put("expirationDate", Instant.now().plusSeconds(profile.getZenodoExpire()).toEpochMilli()); + } userInfo.setLastloggedin(new Date()); userInfo.setAdditionalinfo(new JSONObject(additionalInfo).toString()); Set credentials = userInfo.getCredentials(); diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/authentication/NonVerifiedUserEmailAuthenticationService.java b/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/authentication/NonVerifiedUserEmailAuthenticationService.java index 62c5f60ae..159bbb235 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/authentication/NonVerifiedUserEmailAuthenticationService.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/authentication/NonVerifiedUserEmailAuthenticationService.java @@ -11,6 +11,7 @@ import eu.eudat.types.Authorities; import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; +import java.time.Instant; import java.util.Date; import java.util.HashSet; import java.util.List; @@ -33,6 +34,18 @@ public class NonVerifiedUserEmailAuthenticationService extends AbstractAuthentic } catch (Exception e) { avatarUrl = ""; } + String zenodoToken; + try { + zenodoToken = user.getAdditionalinfo() != null ? new ObjectMapper().readTree(user.getAdditionalinfo()).get("zenodoToken").asText() : ""; + } catch (Exception e) { + zenodoToken = ""; + } + Instant zenodoDuration; + try { + zenodoDuration = user.getAdditionalinfo() != null ? Instant.ofEpochMilli(new ObjectMapper().readTree(user.getAdditionalinfo()).get("expirationDate").asLong()) : Instant.now(); + } catch (Exception e) { + zenodoDuration = Instant.now(); + } String culture; try { culture = user.getAdditionalinfo() != null ? new ObjectMapper().readTree(user.getAdditionalinfo()).get("culture").get("name").asText() : ""; @@ -58,6 +71,8 @@ public class NonVerifiedUserEmailAuthenticationService extends AbstractAuthentic .culture(culture) .language(language) .timezone(timezone) + .zenodoToken(zenodoToken) + .zenodoDuration(zenodoDuration) .build(); List userRoles = apiContext.getOperationsContext().getDatabaseRepository().getUserRoleDao().getUserRoles(user); diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/authentication/VerifiedUserAuthenticationService.java b/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/authentication/VerifiedUserAuthenticationService.java index acbb3dc86..c03e81934 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/authentication/VerifiedUserAuthenticationService.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/authentication/VerifiedUserAuthenticationService.java @@ -20,6 +20,7 @@ import org.json.JSONObject; import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; +import java.time.Instant; import java.util.*; @@ -42,6 +43,18 @@ public class VerifiedUserAuthenticationService extends AbstractAuthenticationSer } catch (Exception e) { avatarUrl = ""; } + String zenodoToken; + try { + zenodoToken = user.getAdditionalinfo() != null ? new ObjectMapper().readTree(user.getAdditionalinfo()).get("zenodoToken").asText() : ""; + } catch (Exception e) { + zenodoToken = ""; + } + Instant zenodoDuration; + try { + zenodoDuration = user.getAdditionalinfo() != null ? Instant.ofEpochMilli(new ObjectMapper().readTree(user.getAdditionalinfo()).get("expirationDate").asLong()) : Instant.now(); + } catch (Exception e) { + zenodoDuration = Instant.now(); + } String culture; try { culture = user.getAdditionalinfo() != null ? new ObjectMapper().readTree(user.getAdditionalinfo()).get("culture").get("name").asText() : ""; @@ -67,6 +80,8 @@ public class VerifiedUserAuthenticationService extends AbstractAuthenticationSer .culture(culture) .language(language) .timezone(timezone) + .zenodoToken(zenodoToken) + .zenodoDuration(zenodoDuration) .build(); List userRoles = apiContext.getOperationsContext().getDatabaseRepository().getUserRoleDao().getUserRoles(user); diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/loginprovider/LoginProviderUser.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/loginprovider/LoginProviderUser.java index e1b0a6d41..13f5b9371 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/loginprovider/LoginProviderUser.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/loginprovider/LoginProviderUser.java @@ -11,6 +11,8 @@ public class LoginProviderUser { private String avatarUrl; private boolean isVerified; private TokenValidatorFactoryImpl.LoginProvider provider; + private String zenodoId; + private Integer zenodoExpire; public String getId() { return id; @@ -67,4 +69,20 @@ public class LoginProviderUser { public void setAvatarUrl(String avatarUrl) { this.avatarUrl = avatarUrl; } + + public String getZenodoId() { + return zenodoId; + } + + public void setZenodoId(String zenodoId) { + this.zenodoId = zenodoId; + } + + public Integer getZenodoExpire() { + return zenodoExpire; + } + + public void setZenodoExpire(Integer zenodoExpire) { + this.zenodoExpire = zenodoExpire; + } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/security/Principal.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/security/Principal.java index 5399b5466..f0e017e84 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/security/Principal.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/security/Principal.java @@ -3,6 +3,7 @@ package eu.eudat.models.data.security; import com.fasterxml.jackson.annotation.JsonIgnore; import eu.eudat.types.Authorities; +import java.time.Instant; import java.util.*; import java.util.stream.Collectors; @@ -17,6 +18,8 @@ public class Principal { private String culture; private String language; private String timezone; + private String zenodoToken; + private Instant zenodoDuration; public UUID getId() { return id; @@ -86,6 +89,22 @@ public class Principal { this.timezone = timezone; } + public String getZenodoToken() { + return zenodoToken; + } + + public void setZenodoToken(String zenodoToken) { + this.zenodoToken = zenodoToken; + } + + public Instant getZenodoDuration() { + return zenodoDuration; + } + + public void setZenodoDuration(Instant zenodoDuration) { + this.zenodoDuration = zenodoDuration; + } + @JsonIgnore public Set getAuthz() { return this.authorities; diff --git a/dmp-backend/web/src/main/resources/config/application-devel.properties b/dmp-backend/web/src/main/resources/config/application-devel.properties index 59d292b11..7051f6667 100644 --- a/dmp-backend/web/src/main/resources/config/application-devel.properties +++ b/dmp-backend/web/src/main/resources/config/application-devel.properties @@ -69,6 +69,10 @@ conf_email.subject=OpenDMP email confirmation #############ZENODO CONFIGURATIONS######### zenodo.url=https://sandbox.zenodo.org/api/ zenodo.access_token= +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:4200/login/external/zenodo #############CONTACT EMAIL CONFIGURATIONS######### contact_email.mail= diff --git a/dmp-frontend/src/app/core/common/enum/auth-provider.ts b/dmp-frontend/src/app/core/common/enum/auth-provider.ts index b8b70efd8..11c36b2a9 100644 --- a/dmp-frontend/src/app/core/common/enum/auth-provider.ts +++ b/dmp-frontend/src/app/core/common/enum/auth-provider.ts @@ -7,5 +7,6 @@ export enum AuthProvider { B2Access = 6, ORCID = 7, OpenAire = 8, - Configurable = 9 + Configurable = 9, + Zenodo = 10 } diff --git a/dmp-frontend/src/app/core/model/configuration-models/login-providers.model.ts b/dmp-frontend/src/app/core/model/configuration-models/login-providers.model.ts index 8c7751e2c..15474bdce 100644 --- a/dmp-frontend/src/app/core/model/configuration-models/login-providers.model.ts +++ b/dmp-frontend/src/app/core/model/configuration-models/login-providers.model.ts @@ -42,6 +42,11 @@ export class LoginProviders { return this._openAireConfiguration; } + private _zenodoConfiguration: LoginConfiguration; + get zenodoConfiguration(): LoginConfiguration { + return this._zenodoConfiguration; + } + public static parseValue(value: any): LoginProviders { const obj: LoginProviders = new LoginProviders(); obj._enabled = value.enabled; @@ -52,6 +57,7 @@ export class LoginProviders { obj._b2accessConfiguration = value.b2accessConfiguration; obj._orcidConfiguration = value.orcidConfiguration; obj._openAireConfiguration = value.openAireConfiguration; + obj._zenodoConfiguration = value.zenodoConfiguration; return obj; } } diff --git a/dmp-frontend/src/app/core/model/zenodo/zenodo-token.model.ts b/dmp-frontend/src/app/core/model/zenodo/zenodo-token.model.ts new file mode 100644 index 000000000..0ddb251d6 --- /dev/null +++ b/dmp-frontend/src/app/core/model/zenodo/zenodo-token.model.ts @@ -0,0 +1,6 @@ +export class ZenodoToken { + userId: string; + expiresIn: number; + accessToken:string; + email: string; +} diff --git a/dmp-frontend/src/app/ui/auth/login/img/zenodo-white-200.png b/dmp-frontend/src/app/ui/auth/login/img/zenodo-white-200.png new file mode 100644 index 0000000000000000000000000000000000000000..5fb49be6e056112979c675e44fe46bd7e908390d GIT binary patch literal 2383 zcmb7`c{tRI8pnq$!$CF2zBgjx$S%7qBW6fuqB@kNED2d_j3sNvB};>d;>_uXW-Nm# zTTH1OoGCP7Dl{hhG6rW#V@$4l?tSk4`~LAR&-1>|`+c7GpYP`%UY@SflFE`G5J(!~ z21oDL!Ts<8i|yx&QPwT{MJd7MLc-bT&;(3STnNZ9IQnvkCL$^*ECd}A6pW1>3b6%& zz?%rTqj%z`wTBXSWL;!)A~2T>93328`sK)FAUs&i1@%r7C$5fysvm>GrSs0e0HbE_ z=8Ch7P_iR8d^UuQ)AOL2LU5E(;*3P6yH|#f)pSUTq2NwQJLwsz9yVdLSH7FUZvIi< zT_3=B=VPvY-{X`Jh+Fyv0!jx7frNxX!Xh9MFbI4IbVw7V=>T#_|9kMi?(dbvVHU6n zROK%N+b_3e^t;LvB*JZ$UFi}1F?8(;BT@a%GH&2iKXD0J?^cI*@p++s$xj?X;18sa z-xP#J($l9aqm=elTx9;Mh8`GDxGe|h=zfpU+Ok1sg$76v@$U;0(sz3^yxn*7a3hf( z)_Dnsh)t47Ngv|vmT{^nenU6HVbrMxF6C;f43%FZBhPmKZLxqh_F^7}bF z$!!vva=zFgwrAK55q(!#s=6oj1hE{bd5joyo=vt7kA?eV@cvqAiyu?NN)45CwF(C3 zaPwPAjMq~yf_@w=XdUEd0ZHP_n&a1(;^_H>i(UBllhEQYo1M7y;rEdzjcFavE`}*s zdVM>U{()$*A74nHhAIa{}NXj>mC(Z*$!ynA2{wvpwoxfjBuS z|3=Tg2K4ZxO^Qn6VAdBgL{@7bt1~K&@XSi}ullL)Cx@6g{BT~U73^^uE@|Y*S5u&& zOrTQxbG8cmfYz3AHuu5qo*(^iPQny+Bf~7Q>aO+O9r$;3Lr0XsK*jLtSvrI+Pqzn# zfw9ZY(~5Ms+?_RZ;~MVmgkw*1zCxnaR?Em&o=MiW1{1E~eiwK;YxQU^7v|1Z78e?? zO(K+Yp!} z?2@+}z?9KG%KanJj3W+opR>G|kr&Eeq!Dj(^j$~dmYoW(Jb1)m-D9xyT$#=HsLj17 zi*Vb{V5_0}u zWBwv+V+v|_i$yrobXc=%Y-~ez0XFADf2tIkoH^3Ed~MkEB+ql;`g+=9T5KA9w!L;~ zQc(!6vRisT>H~(ln+&i7aC>C&QAUgYy1?6s+1Xb=FG0p)t5a?;f;yrt{0N&Qg5oW` zUt(6w`Gz`8t({gB_aXz)n^8#FV=JJp!i45fz9fCzc)WUG<3^TUSKbY&Wt4MjswNfb zwI*aT&>}#}d29&%cJ)9ufBoQCWLhQ{LL&ZF@q8*MM^E-lklOmpD-NiW(~J6(H<>pH z7TQXS%`Jsk?^q{oy7&90%m z)!Z%-*0yr@kh5*q(nk>m`|$A<D7v&@O#TTmOCr{J8|WLN$?@lv!%CwJ5uyKPD$@&yrR5PN@0s-wL(F~tmD`1 z)3hfF`0GZtkv~Sg%Oe;6xN~ktV+1>1j9WdPT2or-q*#4`LL;w3(n6!ZTD3^jx0Ve3-#RzlmuDx08Tubx@vej&O;+QWRiR*^R-9eO?8MY8ed;k~uVt z2~b1K42ey`wZ{umny!2nBkmP~W|VGT0!$qToODstyO8zZAr3W%>)cOqa@o5#<3XHg zEW7!dsHe!g2zfUepxv8XCnL2kl6ap>keskxV4AKOn)GQs=}0`!+CGZrjC_9!!;geu z^&S5hY;z9xQrqdFp|{kOwt8XO%nWLC@{GI6>qV?oL+yaeP>E3i1{9J5i@!7xrd{ic zoQot$Mae28wssB?qGn6^4|a{p-E|kVYt^T-d65q`6=EVXXA>*jI~u9jOQ~i<-k8ITjo5hQ%2eCfa=+fG~DkTi%UoD%n=EKU7uWp6h z;asCnquG?r>6!$M@B)|mSC5^3_5HKsDfZc5ej~b!e;KTe)_d! literal 0 HcmV?d00001 diff --git a/dmp-frontend/src/app/ui/auth/login/login.component.html b/dmp-frontend/src/app/ui/auth/login/login.component.html index d8be9c88b..dd1c8fc9e 100644 --- a/dmp-frontend/src/app/ui/auth/login/login.component.html +++ b/dmp-frontend/src/app/ui/auth/login/login.component.html @@ -54,6 +54,12 @@
+
+
+