From 989f07787c3dec9ad8ffba3ef687148df8fca973 Mon Sep 17 00:00:00 2001 From: "k.triantafyllou" Date: Mon, 11 Jul 2022 16:34:06 +0300 Subject: [PATCH 01/13] Fix autocomplete in multiplicity items by using parent field id. --- .../components/form-field/form-field.component.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-field/form-field.component.ts b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-field/form-field.component.ts index f0bcb2a5e..23320fe92 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-field/form-field.component.ts +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-field/form-field.component.ts @@ -379,8 +379,12 @@ export class FormFieldComponent extends BaseComponent implements OnInit { searchFromAutocomplete(query: string) { const autocompleteRequestItem: RequestItem = new RequestItem(); autocompleteRequestItem.criteria = new DatasetExternalAutocompleteCriteria(); - - autocompleteRequestItem.criteria.fieldID = this.form.get('id').value; + let parseIdArray: string[] = this.form.get('id').value.split('_'); + if(parseIdArray.length > 1) { + autocompleteRequestItem.criteria.fieldID = parseIdArray[parseIdArray.length - 1]; + } else { + autocompleteRequestItem.criteria.fieldID = this.form.get('id').value; + } if (typeof this.datasetProfileId === 'string') { autocompleteRequestItem.criteria.profileID = this.datasetProfileId; } else if (this.datasetProfileId != null) { From b21693bff10f6cddd1ca1924739df8dc90fb28ad Mon Sep 17 00:00:00 2001 From: "k.triantafyllou" Date: Mon, 11 Jul 2022 16:49:09 +0300 Subject: [PATCH 02/13] Change all buttons width: 101px to min-width: 101px --- .../dialog-confirmation-upload-profiles.component.scss | 6 +++--- .../dialog-confirmation-upload-profiles.component.scss | 6 +++--- .../contact/contact-content/contact-content.component.scss | 2 +- .../dataset-copy-dialogue.component.scss | 4 ++-- .../prefill-dataset/prefill-dataset.component.scss | 2 +- .../ui/dmp/clone/clone-dialog/clone-dialog.component.scss | 2 +- .../dataset-preview/dataset-preview-dialog.component.scss | 2 +- .../dmp-finalize-dialog/dmp-finalize-dialog.component.scss | 2 +- .../upload-dialogue/dmp-upload-dialogue.component.scss | 4 ++-- .../start-new-dataset-dialog.component.scss | 6 +++--- .../src/app/ui/faq/dialog/faq-dialog.component.scss | 2 +- .../add-account/add-account-dialog.component.scss | 2 +- .../form-validation-errors-dialog.component.scss | 6 +++--- 13 files changed, 23 insertions(+), 23 deletions(-) diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.scss b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.scss index 63c42f81e..179e7eb4b 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.scss +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.scss @@ -7,7 +7,7 @@ background: #ffffff 0% 0% no-repeat padding-box; border: 1px solid #b5b5b5; border-radius: 30px; - width: 101px; +min-width: 101px; height: 43px; color: #212121; font-weight: 500; @@ -18,7 +18,7 @@ border: 1px solid #129d99; border-radius: 30px; opacity: 1; - width: 101px; +min-width: 101px; height: 43px; color: #129d99; font-weight: 500; @@ -99,4 +99,4 @@ .close-btn:hover{ cursor: pointer; -} \ No newline at end of file +} diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.scss b/dmp-frontend/src/app/ui/admin/dmp-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.scss index 63c42f81e..179e7eb4b 100644 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.scss +++ b/dmp-frontend/src/app/ui/admin/dmp-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.scss @@ -7,7 +7,7 @@ background: #ffffff 0% 0% no-repeat padding-box; border: 1px solid #b5b5b5; border-radius: 30px; - width: 101px; +min-width: 101px; height: 43px; color: #212121; font-weight: 500; @@ -18,7 +18,7 @@ border: 1px solid #129d99; border-radius: 30px; opacity: 1; - width: 101px; +min-width: 101px; height: 43px; color: #129d99; font-weight: 500; @@ -99,4 +99,4 @@ .close-btn:hover{ cursor: pointer; -} \ No newline at end of file +} diff --git a/dmp-frontend/src/app/ui/contact/contact-content/contact-content.component.scss b/dmp-frontend/src/app/ui/contact/contact-content/contact-content.component.scss index be18850f2..70089c0ca 100644 --- a/dmp-frontend/src/app/ui/contact/contact-content/contact-content.component.scss +++ b/dmp-frontend/src/app/ui/contact/contact-content/contact-content.component.scss @@ -52,7 +52,7 @@ img { border: 1px solid #B5B5B5; border-radius: 30px; opacity: 1; - width: 101px; +min-width: 101px; height: 43px; color: #212121; font-weight: 500; diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component.scss b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component.scss index 9dcfec19b..bed07edff 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component.scss +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component.scss @@ -14,7 +14,7 @@ background: #ffffff 0% 0% no-repeat padding-box; border: 1px solid #b5b5b5; border-radius: 30px; - width: 101px; +min-width: 101px; height: 43px; color: #212121; font-weight: 500; @@ -25,7 +25,7 @@ border: 1px solid #129d99; border-radius: 30px; opacity: 1; - width: 101px; +min-width: 101px; height: 43px; color: #129d99; font-weight: 500; diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/prefill-dataset/prefill-dataset.component.scss b/dmp-frontend/src/app/ui/dataset/dataset-wizard/prefill-dataset/prefill-dataset.component.scss index 727031a7c..55a2a967c 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/prefill-dataset/prefill-dataset.component.scss +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/prefill-dataset/prefill-dataset.component.scss @@ -37,7 +37,7 @@ border: 1px solid #f7dd72; border-radius: 30px; opacity: 1; - width: 101px; + min-width: 101px; height: 43px; color: #212121; font-weight: 500; diff --git a/dmp-frontend/src/app/ui/dmp/clone/clone-dialog/clone-dialog.component.scss b/dmp-frontend/src/app/ui/dmp/clone/clone-dialog/clone-dialog.component.scss index c1d49452c..2ef15d145 100644 --- a/dmp-frontend/src/app/ui/dmp/clone/clone-dialog/clone-dialog.component.scss +++ b/dmp-frontend/src/app/ui/dmp/clone/clone-dialog/clone-dialog.component.scss @@ -33,7 +33,7 @@ } .cancel-btn { - width: 101px; + min-width: 101px; height: 43px; background: #ffffff; border: 1px solid #b5b5b5; diff --git a/dmp-frontend/src/app/ui/dmp/dataset-preview/dataset-preview-dialog.component.scss b/dmp-frontend/src/app/ui/dmp/dataset-preview/dataset-preview-dialog.component.scss index 439b988ed..cf8386431 100644 --- a/dmp-frontend/src/app/ui/dmp/dataset-preview/dataset-preview-dialog.component.scss +++ b/dmp-frontend/src/app/ui/dmp/dataset-preview/dataset-preview-dialog.component.scss @@ -37,7 +37,7 @@ border: 1px solid #129d99; border-radius: 30px; opacity: 1; - width: 101px; + min-width: 101px; height: 43px; color: #ffffff; font-weight: 500; diff --git a/dmp-frontend/src/app/ui/dmp/editor/dmp-finalize-dialog/dmp-finalize-dialog.component.scss b/dmp-frontend/src/app/ui/dmp/editor/dmp-finalize-dialog/dmp-finalize-dialog.component.scss index acc9b6b95..0491b676f 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/dmp-finalize-dialog/dmp-finalize-dialog.component.scss +++ b/dmp-frontend/src/app/ui/dmp/editor/dmp-finalize-dialog/dmp-finalize-dialog.component.scss @@ -120,7 +120,7 @@ } .cancel-btn { - width: 101px; +min-width: 101px; height: 43px; background: #ffffff; border: 1px solid #b5b5b5; diff --git a/dmp-frontend/src/app/ui/dmp/listing/upload-dialogue/dmp-upload-dialogue.component.scss b/dmp-frontend/src/app/ui/dmp/listing/upload-dialogue/dmp-upload-dialogue.component.scss index b4e6fdf6c..b959e43c7 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/upload-dialogue/dmp-upload-dialogue.component.scss +++ b/dmp-frontend/src/app/ui/dmp/listing/upload-dialogue/dmp-upload-dialogue.component.scss @@ -29,7 +29,7 @@ background: #ffffff 0% 0% no-repeat padding-box; border: 1px solid #b5b5b5; border-radius: 30px; - width: 101px; +min-width: 101px; height: 43px; color: #212121; font-weight: 500; @@ -40,7 +40,7 @@ border: 1px solid #129d99; border-radius: 30px; opacity: 1; - width: 101px; +min-width: 101px; height: 43px; color: #129d99; font-weight: 500; diff --git a/dmp-frontend/src/app/ui/dmp/start-new-dataset-dialogue/start-new-dataset-dialog.component.scss b/dmp-frontend/src/app/ui/dmp/start-new-dataset-dialogue/start-new-dataset-dialog.component.scss index 0f1479b22..fae608bac 100644 --- a/dmp-frontend/src/app/ui/dmp/start-new-dataset-dialogue/start-new-dataset-dialog.component.scss +++ b/dmp-frontend/src/app/ui/dmp/start-new-dataset-dialogue/start-new-dataset-dialog.component.scss @@ -55,7 +55,7 @@ background: #ffffff 0% 0% no-repeat padding-box; border: 1px solid #b5b5b5; border-radius: 30px; - width: 101px; +min-width: 101px; height: 43px; color: #212121; font-weight: 500; @@ -66,7 +66,7 @@ border: 1px solid #129d99; border-radius: 30px; opacity: 1; - width: 101px; +min-width: 101px; height: 43px; color: #129d99; font-weight: 500; @@ -81,7 +81,7 @@ border: 1px solid #b5b5b5; border-radius: 30px; opacity: 1; - width: 101px; +min-width: 101px; height: 43px; color: #b5b5b5; font-weight: 500; diff --git a/dmp-frontend/src/app/ui/faq/dialog/faq-dialog.component.scss b/dmp-frontend/src/app/ui/faq/dialog/faq-dialog.component.scss index 54960fccf..df5ad000c 100644 --- a/dmp-frontend/src/app/ui/faq/dialog/faq-dialog.component.scss +++ b/dmp-frontend/src/app/ui/faq/dialog/faq-dialog.component.scss @@ -34,7 +34,7 @@ background: #ffffff 0% 0% no-repeat padding-box; border: 1px solid #b5b5b5; border-radius: 30px; - width: 101px; +min-width: 101px; height: 43px; color: #212121; font-weight: 500; diff --git a/dmp-frontend/src/app/ui/user-profile/add-account/add-account-dialog.component.scss b/dmp-frontend/src/app/ui/user-profile/add-account/add-account-dialog.component.scss index f5f248a49..27349f01c 100644 --- a/dmp-frontend/src/app/ui/user-profile/add-account/add-account-dialog.component.scss +++ b/dmp-frontend/src/app/ui/user-profile/add-account/add-account-dialog.component.scss @@ -30,7 +30,7 @@ } .cancel-btn { - width: 101px; + min-width: 101px; height: 43px; background: #ffffff; border: 1px solid #b5b5b5; diff --git a/dmp-frontend/src/common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component.scss b/dmp-frontend/src/common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component.scss index d160835c5..c1ead4385 100644 --- a/dmp-frontend/src/common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component.scss +++ b/dmp-frontend/src/common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component.scss @@ -51,7 +51,7 @@ background: #ffffff 0% 0% no-repeat padding-box; border: 1px solid #b5b5b5; border-radius: 30px; - width: 101px; +min-width: 101px; height: 43px; color: #212121; font-weight: 500; @@ -62,7 +62,7 @@ border: 1px solid #129d99; border-radius: 30px; opacity: 1; - width: 101px; +min-width: 101px; height: 43px; color: #129d99; font-weight: 500; @@ -72,7 +72,7 @@ border: 1px solid #b5b5b5; border-radius: 30px; opacity: 1; - width: 101px; +min-width: 101px; height: 43px; color: #b5b5b5; font-weight: 500; From 9b4c7aeb6f25ca7a721a1a1a95eae153a67b7580 Mon Sep 17 00:00:00 2001 From: "konstantina.galouni" Date: Tue, 12 Jul 2022 12:52:04 +0300 Subject: [PATCH 03/13] DataManagementPlanManager.java: #7893 - Added description of Datasets on DMP exported word file. --- .../java/eu/eudat/logic/managers/DataManagementPlanManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 f4c4070eb..a88c62ad2 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 @@ -1315,7 +1315,7 @@ public class DataManagementPlanManager { // }*/ // // -// wordBuilder.addParagraphContent(datasetEntity.getDescription(), document, ParagraphStyle.HTML, BigInteger.ZERO); + wordBuilder.addParagraphContent(datasetEntity.getDescription(), document, ParagraphStyle.HTML, BigInteger.ZERO); // Dataset Description custom style. XWPFParagraph datasetDescriptionParagraph = document.createParagraph(); From a2228a5fb662060464461bdb624d0091fab8e1a3 Mon Sep 17 00:00:00 2001 From: "konstantina.galouni" Date: Tue, 26 Jul 2022 17:00:54 +0300 Subject: [PATCH 04/13] #7597, #7893, #7895, #7898: Updated DMP template file (h2020.docx) for export | Added Dataset template file (h2020_dataset.docx) for export | Updated indentation on exported docs. 1. h2020.docx, h2020_dataset.docx: Updated DMP template & Added Dataset template. 2. application.properties, application-devel.properties, application-production.properties, application-staging.properties: Added property for dataset template file path configuration.h2020datasettemplate=documents/h2020_dataset.docx 3. ConfigLoader.java: Added method XWPFDocument getDatasetDocument(); 4. DefaultConfigLoader.java: Added fiedls and methods for loading Dataset template (h2020_dataset.docx). 5. DataManagementPlanManager.java, DatasetManager.java, , HtmlToWorldBuilder.java, WordBuilder.java: Updated header/footer/first page in exports for DMPs and Datasets | Updated indentation in exports. --- .../managers/DataManagementPlanManager.java | 39 +++- .../eudat/logic/managers/DatasetManager.java | 74 +++++-- .../config/configloaders/ConfigLoader.java | 1 + .../configloaders/DefaultConfigLoader.java | 24 ++ .../documents/word/HtmlToWorldBuilder.java | 52 ++++- .../utilities/documents/word/WordBuilder.java | 207 +++++++++++------- .../config/application-devel.properties | 1 + .../config/application-production.properties | 1 + .../config/application-staging.properties | 1 + .../resources/config/application.properties | 1 + .../src/main/resources/documents/h2020.docx | Bin 43734 -> 20460 bytes .../resources/documents/h2020_dataset.docx | Bin 0 -> 20313 bytes 12 files changed, 286 insertions(+), 115 deletions(-) create mode 100644 dmp-backend/web/src/main/resources/documents/h2020_dataset.docx 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 a88c62ad2..e3ad07e0e 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 @@ -1190,7 +1190,17 @@ public class DataManagementPlanManager { if (!dmpEntity.isPublic() && dmpEntity.getUsers().stream().filter(userInfo -> userInfo.getUser().getId() == principal.getId()).collect(Collectors.toList()).size() == 0) throw new UnauthorisedException(); - wordBuilder.fillFirstPage(dmpEntity, document); + wordBuilder.fillFirstPage(dmpEntity, null, document); + +// int powered_pos = document.getParagraphs().size() - 3; + int powered_pos = wordBuilder.findPosOfPoweredBy(document); + XWPFParagraph powered_par = null; + XWPFParagraph argos_img_par = null; + if(powered_pos != -1) { + powered_par = document.getParagraphArray(powered_pos); + argos_img_par = document.getParagraphArray(powered_pos + 1); + } + // // DMP info on top of the document. // wordBuilder.addParagraphContent("Data Management Plan Information", document, ParagraphStyle.HEADER1, BigInteger.ZERO); @@ -1252,7 +1262,7 @@ public class DataManagementPlanManager { // Custom style for the Dataset title. //wordBuilder.addParagraphContent("Title: " + datasetEntity.getLabel(), document, ParagraphStyle.HEADER1, BigInteger.ZERO); XWPFParagraph datasetLabelParagraph = document.createParagraph(); - datasetLabelParagraph.setStyle("Heading2"); +// datasetLabelParagraph.setStyle("Heading2"); datasetLabelParagraph.setSpacingBetween(1.0); XWPFRun runDatasetTitle1 = datasetLabelParagraph.createRun(); runDatasetTitle1.setText("Title: "); @@ -1261,12 +1271,12 @@ public class DataManagementPlanManager { //runDatasetTitle1.setFontSize(12); XWPFRun runDatasetTitle = datasetLabelParagraph.createRun(); runDatasetTitle.setText(datasetEntity.getLabel()); - //runDatasetTitle.setColor("2E75B6"); + runDatasetTitle.setColor("116a78"); //runDatasetTitle.setBold(true); //runDatasetTitle.setFontSize(12); XWPFParagraph datasetTemplateParagraph = document.createParagraph(); - datasetTemplateParagraph.setStyle("Heading3"); +// datasetTemplateParagraph.setStyle("Heading3"); XWPFRun runDatasetTemplate1 = datasetTemplateParagraph.createRun(); runDatasetTemplate1.setText("Template: "); runDatasetTemplate1.setColor("000000"); @@ -1274,7 +1284,7 @@ public class DataManagementPlanManager { //runDatasetTemplate1.setFontSize(12); XWPFRun runDatasetTemplate = datasetTemplateParagraph.createRun(); runDatasetTemplate.setText(datasetEntity.getProfile().getLabel()); - //runDatasetTemplate.setColor("2E75B6"); + runDatasetTemplate.setColor("116a78"); //runDatasetTemplate.setBold(true); //runDatasetTemplate.setFontSize(12); @@ -1315,11 +1325,11 @@ public class DataManagementPlanManager { // }*/ // // - wordBuilder.addParagraphContent(datasetEntity.getDescription(), document, ParagraphStyle.HTML, BigInteger.ZERO); + wordBuilder.addParagraphContent(datasetEntity.getDescription(), document, ParagraphStyle.HTML, BigInteger.ZERO, 0); // Dataset Description custom style. XWPFParagraph datasetDescriptionParagraph = document.createParagraph(); - datasetDescriptionParagraph.setStyle("Heading3"); + datasetDescriptionParagraph.setStyle("Heading4"); datasetDescriptionParagraph.setSpacingBetween(1.5); XWPFRun datasetDescriptionRun = datasetDescriptionParagraph.createRun(); datasetDescriptionRun.setText("Dataset Description"); @@ -1345,7 +1355,20 @@ public class DataManagementPlanManager { // document.removeBodyElement(0); // } - wordBuilder.fillFooter(dmpEntity, document); + + if(powered_pos != -1) { + document.getLastParagraph().setPageBreak(false); + document.createParagraph(); + document.setParagraph(powered_par, document.getParagraphs().size() - 1); + + document.createParagraph(); + document.setParagraph(argos_img_par, document.getParagraphs().size() - 1); + + document.removeBodyElement(powered_pos + 1); + document.removeBodyElement(powered_pos + 1); + } + + wordBuilder.fillFooter(dmpEntity, document, false); String fileName = "DMP_" + dmpEntity.getGrant().getLabel(); if (versioned) { 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 871c59e3c..145439921 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 @@ -396,29 +396,45 @@ public class DatasetManager { return pagedDatasetProfile; } - private XWPFDocument getWordDocument(ConfigLoader configLoader, eu.eudat.data.entities.Dataset datasetEntity, VisibilityRuleService visibilityRuleService) throws IOException { + private XWPFDocument getWordDocument(ConfigLoader configLoader, eu.eudat.data.entities.Dataset datasetEntity, VisibilityRuleService visibilityRuleService, Principal principal) throws IOException { WordBuilder wordBuilder = new WordBuilder(this.environment); DatasetWizardModel dataset = new DatasetWizardModel(); - XWPFDocument document = configLoader.getDocument(); + XWPFDocument document = configLoader.getDatasetDocument(); - wordBuilder.addParagraphContent(datasetEntity.getLabel(), document, ParagraphStyle.HEADER1, BigInteger.ZERO); + eu.eudat.data.entities.DMP dmpEntity = datasetEntity.getDmp(); + + if (!dmpEntity.isPublic() && dmpEntity.getUsers().stream().filter(userInfo -> userInfo.getUser().getId() == principal.getId()).collect(Collectors.toList()).size() == 0) + throw new UnauthorisedException(); + + wordBuilder.fillFirstPage(dmpEntity, datasetEntity, document); + wordBuilder.fillFooter(dmpEntity, document, true); + + int powered_pos = wordBuilder.findPosOfPoweredBy(document); + XWPFParagraph powered_par = null; + XWPFParagraph argos_img_par = null; + if(powered_pos != -1) { + powered_par = document.getParagraphArray(powered_pos); + argos_img_par = document.getParagraphArray(powered_pos + 1); + } + +// wordBuilder.addParagraphContent(datasetEntity.getLabel(), document, ParagraphStyle.HEADER1, BigInteger.ZERO); // Space below Dataset title. - XWPFParagraph parBreakDataset = document.createParagraph(); - - XWPFParagraph datasetTemplateParagraph = document.createParagraph(); - datasetTemplateParagraph.setStyle("Heading2"); - XWPFRun runDatasetTemplate1 = datasetTemplateParagraph.createRun(); - runDatasetTemplate1.setText("Template: "); - runDatasetTemplate1.setBold(true); - runDatasetTemplate1.setFontSize(12); - XWPFRun runDatasetTemplate = datasetTemplateParagraph.createRun(); - runDatasetTemplate.setText(datasetEntity.getProfile().getLabel()); - runDatasetTemplate.setColor("2E75B6"); - runDatasetTemplate.setBold(true); - runDatasetTemplate.setFontSize(12); - - wordBuilder.addParagraphContent(datasetEntity.getDescription(), document, ParagraphStyle.HTML, BigInteger.ZERO); +// XWPFParagraph parBreakDataset = document.createParagraph(); +// +// XWPFParagraph datasetTemplateParagraph = document.createParagraph(); +// datasetTemplateParagraph.setStyle("Heading2"); +// XWPFRun runDatasetTemplate1 = datasetTemplateParagraph.createRun(); +// runDatasetTemplate1.setText("Template: "); +// runDatasetTemplate1.setBold(true); +// runDatasetTemplate1.setFontSize(12); +// XWPFRun runDatasetTemplate = datasetTemplateParagraph.createRun(); +// runDatasetTemplate.setText(datasetEntity.getProfile().getLabel()); +// runDatasetTemplate.setColor("2E75B6"); +// runDatasetTemplate.setBold(true); +// runDatasetTemplate.setFontSize(12); +// +// wordBuilder.addParagraphContent(datasetEntity.getDescription(), document, ParagraphStyle.HTML, BigInteger.ZERO); /*XWPFParagraph externalReferencesParagraph = document.createParagraph(); externalReferencesParagraph.setStyle("Heading2"); @@ -460,7 +476,7 @@ public class DatasetManager { properties = jObject.toMap(); } - wordBuilder.addParagraphContent("Dataset Description", document, ParagraphStyle.HEADER2, BigInteger.ZERO); +// wordBuilder.addParagraphContent("Dataset Description", document, ParagraphStyle.HEADER2, BigInteger.ZERO); PagedDatasetProfile pagedDatasetProfile = getPagedProfile(dataset, datasetEntity); visibilityRuleService.setProperties(properties); visibilityRuleService.buildVisibilityContext(pagedDatasetProfile.getRules()); @@ -469,8 +485,20 @@ public class DatasetManager { // File exportFile = new File(label + ".docx"); // Removes the top empty headings. - for (int i = 0; i < 6; i++) { - document.removeBodyElement(0); +// for (int i = 0; i < 6; i++) { +// document.removeBodyElement(0); +// } + + if(powered_pos != -1) { + document.getLastParagraph().setPageBreak(false); + document.createParagraph(); + document.setParagraph(powered_par, document.getParagraphs().size() - 1); + + document.createParagraph(); + document.setParagraph(argos_img_par, document.getParagraphs().size() - 1); + + document.removeBodyElement(powered_pos + 1); + document.removeBodyElement(powered_pos + 1); } return document; @@ -493,7 +521,7 @@ public class DatasetManager { properties = jObject.toMap(); } - wordBuilder.addParagraphContent("Dataset Description", document, ParagraphStyle.HEADER2, BigInteger.ZERO); + wordBuilder.addParagraphContent("Dataset Description", document, ParagraphStyle.HEADER2, BigInteger.ZERO, 0); visibilityRuleService.setProperties(properties); visibilityRuleService.buildVisibilityContext(dataset.getDatasetProfileDefinition().getRules()); wordBuilder.build(document, dataset.getDatasetProfileDefinition(), visibilityRuleService); @@ -521,7 +549,7 @@ public class DatasetManager { 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); + XWPFDocument document = getWordDocument(configLoader, datasetEntity, visibilityRuleService, principal); FileOutputStream out = new FileOutputStream(exportFile); document.write(out); out.close(); diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/ConfigLoader.java b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/ConfigLoader.java index 4f8f3fe44..08dc4062c 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/ConfigLoader.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/ConfigLoader.java @@ -12,6 +12,7 @@ public interface ConfigLoader { ExternalUrls getExternalUrls(); List getRdaProperties(); XWPFDocument getDocument(); + XWPFDocument getDatasetDocument(); ConfigurableProviders getConfigurableProviders(); Map getKeyToSourceMap(); List getDOIFunders(); diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/DefaultConfigLoader.java b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/DefaultConfigLoader.java index 29dcb2f66..15c04e898 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/DefaultConfigLoader.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/proxy/config/configloaders/DefaultConfigLoader.java @@ -38,6 +38,7 @@ public class DefaultConfigLoader implements ConfigLoader { private ExternalUrls externalUrls; private List rdaProperties; private XWPFDocument document; + private XWPFDocument datasetDocument; private ConfigurableProviders configurableProviders; private Map keyToSourceMap; private List doiFunders = new ArrayList<>(); @@ -103,6 +104,24 @@ public class DefaultConfigLoader implements ConfigLoader { } } + private void setDatasetDocument() { + String filePath = environment.getProperty("configuration.h2020datasettemplate"); + logger.info("Loaded also config file: " + filePath); + InputStream is = null; + try { + is = getStreamFromPath(filePath); + this.datasetDocument = new XWPFDocument(is); + } catch (IOException | NullPointerException e) { + logger.error(e.getMessage(), e); + } finally { + try { + if (is != null) is.close(); + } catch (IOException e) { + logger.warn("Warning: Could not close a stream after reading from file: " + filePath, e); + } + } + } + private void setConfigurableProviders() { String filePath = environment.getProperty("configuration.configurable_login_providers"); logger.info("Loaded also config file: " + filePath); @@ -183,6 +202,11 @@ public class DefaultConfigLoader implements ConfigLoader { return document; } + public XWPFDocument getDatasetDocument() { + this.setDatasetDocument(); + return datasetDocument; + } + public ConfigurableProviders getConfigurableProviders() { if (configurableProviders == null) { configurableProviders = new ConfigurableProviders(); diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/HtmlToWorldBuilder.java b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/HtmlToWorldBuilder.java index 063ce4deb..8cc6368bb 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/HtmlToWorldBuilder.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/HtmlToWorldBuilder.java @@ -1,6 +1,7 @@ package eu.eudat.logic.utilities.documents.word; import org.apache.poi.xwpf.usermodel.*; +import org.apache.xmlbeans.XmlCursor; import org.jsoup.nodes.Document; import org.jsoup.nodes.Node; import org.jsoup.nodes.TextNode; @@ -22,15 +23,17 @@ public class HtmlToWorldBuilder implements NodeVisitor { private XWPFNumbering numbering; private Queue abstractNumId; private BigInteger numberingLevel; + private XmlCursor cursor; public static HtmlToWorldBuilder convert(XWPFDocument document, Document htmlDocument, float indentation) { XWPFParagraph paragraph = document.createParagraph(); - HtmlToWorldBuilder htmlToWorldBuilder = new HtmlToWorldBuilder(paragraph, indentation); + paragraph.setIndentFromLeft(Math.round(400 * indentation)); + HtmlToWorldBuilder htmlToWorldBuilder = new HtmlToWorldBuilder(paragraph, indentation, null); NodeTraversor.traverse(htmlToWorldBuilder, htmlDocument); return htmlToWorldBuilder; } - public HtmlToWorldBuilder(XWPFParagraph paragraph, float indentation) { + public HtmlToWorldBuilder(XWPFParagraph paragraph, float indentation, XmlCursor cursor) { this.paragraph = paragraph; this.run = this.paragraph.createRun(); this.dumpRun = false; @@ -40,6 +43,7 @@ public class HtmlToWorldBuilder implements NodeVisitor { this.abstractNumId = new ArrayDeque<>(); this.numberingLevel = BigInteger.valueOf(-1); this.setDefaultIndentation(); + this.cursor = cursor; } @Override @@ -96,7 +100,13 @@ public class HtmlToWorldBuilder implements NodeVisitor { break; case "div": case "p": - this.paragraph = this.paragraph.getDocument().createParagraph(); + if(this.cursor != null) { + this.paragraph = this.paragraph.getDocument().insertNewParagraph(this.cursor); + this.cursor = this.paragraph.getCTP().newCursor(); + this.cursor.toNextSibling(); + } else { + this.paragraph = this.paragraph.getDocument().createParagraph(); + } this.run = this.paragraph.createRun(); this.isIdentationUsed = false; this.setDefaultIndentation(); @@ -108,10 +118,15 @@ public class HtmlToWorldBuilder implements NodeVisitor { } break; case "blockquote": - this.paragraph = this.paragraph.getDocument().createParagraph(); + if(this.cursor != null) { + this.paragraph = this.paragraph.getDocument().insertNewParagraph(this.cursor); + this.cursor = this.paragraph.getCTP().newCursor(); + } else { + this.paragraph = this.paragraph.getDocument().createParagraph(); + } this.run = this.paragraph.createRun(); if (stringBooleanEntry.getValue()) { - this.paragraph.setIndentationLeft(720); + this.paragraph.setIndentationLeft(400); } else { this.isIdentationUsed = false; this.setDefaultIndentation(); @@ -121,7 +136,12 @@ public class HtmlToWorldBuilder implements NodeVisitor { if (stringBooleanEntry.getValue()) { createNumbering(STNumberFormat.BULLET); } else { - this.paragraph = this.paragraph.getDocument().createParagraph(); + if(this.cursor != null) { + this.paragraph = this.paragraph.getDocument().insertNewParagraph(this.cursor); + this.cursor = this.paragraph.getCTP().newCursor(); + } else { + this.paragraph = this.paragraph.getDocument().createParagraph(); + } this.run = this.paragraph.createRun(); this.isIdentationUsed = false; this.setDefaultIndentation(); @@ -133,7 +153,12 @@ public class HtmlToWorldBuilder implements NodeVisitor { if (stringBooleanEntry.getValue()) { createNumbering(STNumberFormat.DECIMAL); } else { - this.paragraph = this.paragraph.getDocument().createParagraph(); + if(this.cursor != null) { + this.paragraph = this.paragraph.getDocument().insertNewParagraph(this.cursor); + this.cursor = this.paragraph.getCTP().newCursor(); + } else { + this.paragraph = this.paragraph.getDocument().createParagraph(); + } this.run = this.paragraph.createRun(); this.isIdentationUsed = false; this.setDefaultIndentation(); @@ -143,8 +168,14 @@ public class HtmlToWorldBuilder implements NodeVisitor { break; case "li": if (stringBooleanEntry.getValue()) { - this.paragraph = this.paragraph.getDocument().createParagraph(); - this.paragraph.setIndentationLeft(Math.round(indentation * 720) * (numberingLevel.intValue() + 1)); + if(this.cursor != null) { + this.paragraph = this.paragraph.getDocument().insertNewParagraph(this.cursor); + this.cursor = this.paragraph.getCTP().newCursor(); + } else { + this.paragraph = this.paragraph.getDocument().createParagraph(); + } + // this.paragraph.setIndentationLeft(Math.round(indentation * 720) * (numberingLevel.intValue() + 1)); + this.paragraph.setIndentFromLeft(Math.round(numberingLevel.intValue() * 400 + this.indentation*400)); this.run = this.paragraph.createRun(); this.paragraph.setNumID(((ArrayDeque)abstractNumId).getLast()); } @@ -238,7 +269,8 @@ public class HtmlToWorldBuilder implements NodeVisitor { private void setDefaultIndentation() { if (!isIdentationUsed) { - this.paragraph.setIndentationLeft(Math.round(indentation * 720.0F)); +// this.paragraph.setIndentationLeft(Math.round(indentation * 720.0F)); + this.paragraph.setIndentFromLeft(Math.round(indentation * 400)); this.isIdentationUsed = true; } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java index a3a47d869..bc92b70e1 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import eu.eudat.data.entities.DMP; +import eu.eudat.data.entities.Dataset; import eu.eudat.data.entities.Organisation; import eu.eudat.data.entities.Researcher; import eu.eudat.logic.services.forms.VisibilityRuleService; @@ -19,10 +20,12 @@ import eu.eudat.models.data.user.composite.PagedDatasetProfile; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.util.Units; import org.apache.poi.xwpf.usermodel.*; +import org.apache.xmlbeans.XmlCursor; import org.json.JSONArray; import org.json.JSONException; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; +import org.jsoup.select.NodeTraversor; import org.openxmlformats.schemas.wordprocessingml.x2006.main.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -88,7 +91,8 @@ public class WordBuilder { }); this.options.put(ParagraphStyle.HTML, (mainDocumentPart, item) -> { Document htmlDoc = Jsoup.parse(((String)item).replaceAll("\n", "
")); - HtmlToWorldBuilder htmlToWorldBuilder = HtmlToWorldBuilder.convert(mainDocumentPart, htmlDoc, indent > 0 ? (indent/2.0F) * 0.8F : 0.8F); +// HtmlToWorldBuilder htmlToWorldBuilder = HtmlToWorldBuilder.convert(mainDocumentPart, htmlDoc, indent > 0 ? (indent/2.0F) * 0.8F : 0.8F); + HtmlToWorldBuilder htmlToWorldBuilder = HtmlToWorldBuilder.convert(mainDocumentPart, htmlDoc, this.indent); return htmlToWorldBuilder.getParagraph(); }); this.options.put(ParagraphStyle.TITLE, (mainDocumentPart, item) -> { @@ -228,19 +232,20 @@ public class WordBuilder { } public XWPFDocument build(XWPFDocument document, PagedDatasetProfile pagedDatasetProfile, VisibilityRuleService visibilityRuleService) throws IOException { - createPages(pagedDatasetProfile.getPages(), document, true, visibilityRuleService); - XWPFNumbering numbering = document.createNumbering(); - BigInteger tempNumId = BigInteger.ONE; - boolean found = false; - while (!found) { - Object o = numbering.getAbstractNum(tempNumId); - found = (o == null); - if (!found) tempNumId = tempNumId.add(BigInteger.ONE); - } - cTAbstractNum.setAbstractNumId(tempNumId); - XWPFAbstractNum abstractNum = new XWPFAbstractNum(cTAbstractNum); - BigInteger abstractNumID = numbering.addAbstractNum(abstractNum); - this.numId = numbering.addNum(abstractNumID); +// createPages(pagedDatasetProfile.getPages(), document, true, visibilityRuleService); +// XWPFNumbering numbering = document.createNumbering(); +// BigInteger tempNumId = BigInteger.ONE; +// boolean found = false; +// while (!found) { +// Object o = numbering.getAbstractNum(tempNumId); +// found = (o == null); +// if (!found) tempNumId = tempNumId.add(BigInteger.ONE); +// } +// cTAbstractNum.setAbstractNumId(tempNumId); +// XWPFAbstractNum abstractNum = new XWPFAbstractNum(cTAbstractNum); +// BigInteger abstractNumID = numbering.addAbstractNum(abstractNum); +// this.numId = numbering.addNum(abstractNumID); + createPages(pagedDatasetProfile.getPages(), document, false, visibilityRuleService); return document; } @@ -248,7 +253,7 @@ public class WordBuilder { private void createPages(List datasetProfilePages, XWPFDocument mainDocumentPart, Boolean createListing, VisibilityRuleService visibilityRuleService) { datasetProfilePages.forEach(item -> { try { - createSections(item.getSections(), mainDocumentPart, ParagraphStyle.HEADER4, 0, createListing, visibilityRuleService, item.getOrdinal() + 1, null); + createSections(item.getSections(), mainDocumentPart, ParagraphStyle.HEADER5, 0, createListing, visibilityRuleService, item.getOrdinal() + 1, null); } catch (Exception e) { logger.error(e.getMessage(), e); } @@ -263,13 +268,13 @@ public class WordBuilder { String tempSectionString = sectionString != null ? sectionString + "." + (section.getOrdinal() + 1) : "" + (section.getOrdinal() + 1); if (visibilityRuleService.isElementVisible(section.getId())) { if (!createListing) { - XWPFParagraph paragraph = addParagraphContent(page + "." + tempSectionString + " " + section.getTitle(), mainDocumentPart, style, numId); - CTDecimalNumber number = paragraph.getCTP().getPPr().getNumPr().addNewIlvl(); - number.setVal(BigInteger.valueOf(indent)); + XWPFParagraph paragraph = addParagraphContent(page + "." + tempSectionString + " " + section.getTitle(), mainDocumentPart, style, numId, indent); +// CTDecimalNumber number = paragraph.getCTP().getPPr().getNumPr().addNewIlvl(); +// number.setVal(BigInteger.valueOf(indent)); paragraphPos = mainDocumentPart.getPosOfParagraph(paragraph); } - createSections(section.getSections(), mainDocumentPart, ParagraphStyle.HEADER4, 1, createListing, visibilityRuleService, page, tempSectionString); - hasValue = createCompositeFields(section.getCompositeFields(), mainDocumentPart, 2, createListing, visibilityRuleService, page, tempSectionString); + createSections(section.getSections(), mainDocumentPart, ParagraphStyle.HEADER5, indent+1, createListing, visibilityRuleService, page, tempSectionString); + hasValue = createCompositeFields(section.getCompositeFields(), mainDocumentPart, indent+1, createListing, visibilityRuleService, page, tempSectionString); if (!hasValue && paragraphPos > -1) { mainDocumentPart.removeBodyElement(paragraphPos); @@ -290,19 +295,18 @@ public class WordBuilder { int paragraphPos = -1; int paragraphPosInner = -1; if (compositeField.getTitle() != null && !compositeField.getTitle().isEmpty() && !createListing) { - XWPFParagraph paragraph = addParagraphContent("\t" + page + "." + section + "." + (compositeField.getOrdinal() +1) + " " + compositeField.getTitle(), mainDocumentPart, ParagraphStyle.HEADER6, numId); - CTDecimalNumber number = paragraph.getCTP().getPPr().getNumPr().addNewIlvl(); - number.setVal(BigInteger.valueOf(indent)); + XWPFParagraph paragraph = addParagraphContent(page + "." + section + "." + (compositeField.getOrdinal() +1) + " " + compositeField.getTitle(), mainDocumentPart, ParagraphStyle.HEADER6, numId, indent); +// CTDecimalNumber number = paragraph.getCTP().getPPr().getNumPr().addNewIlvl(); +// number.setVal(BigInteger.valueOf(indent)); paragraphPos = mainDocumentPart.getPosOfParagraph(paragraph); if(compositeField.getMultiplicityItems() != null && !compositeField.getMultiplicityItems().isEmpty()){ -// addParagraphContent(c + ". ", mainDocumentPart, ParagraphStyle.HEADER6, numId); - XWPFParagraph paragraphInner = addParagraphContent(c + ". ", mainDocumentPart, ParagraphStyle.TEXT, numId); + XWPFParagraph paragraphInner = addParagraphContent(c + ". ", mainDocumentPart, ParagraphStyle.TEXT, numId, indent); paragraphPosInner = mainDocumentPart.getPosOfParagraph(paragraphInner); hasMultiplicityItems = true; multiplicityItems++; } } - hasValue = createFields(compositeField.getFields(), mainDocumentPart, 3, createListing, visibilityRuleService, hasMultiplicityItems); + hasValue = createFields(compositeField.getFields(), mainDocumentPart, indent, createListing, visibilityRuleService, hasMultiplicityItems); if(hasValue){ returnedValue = true; } else if(paragraphPosInner > -1){ @@ -317,13 +321,13 @@ public class WordBuilder { if(!createListing){ c++; // addParagraphContent(c + ". ", mainDocumentPart, ParagraphStyle.HEADER6, numId); - XWPFParagraph paragraphInner = addParagraphContent(c + ". ", mainDocumentPart, ParagraphStyle.TEXT, numId); + XWPFParagraph paragraphInner = addParagraphContent(c + ". ", mainDocumentPart, ParagraphStyle.TEXT, numId, indent); paragraphPosInner = mainDocumentPart.getPosOfParagraph(paragraphInner); hasMultiplicityItems = true; multiplicityItems++; } // hasValue = createFields(multiplicityFieldset.getFields(), mainDocumentPart, 3, createListing, visibilityRuleService, hasMultiplicityItems); - boolean hasValueInner = createFields(multiplicityFieldset.getFields(), mainDocumentPart, 3, createListing, visibilityRuleService, hasMultiplicityItems); + boolean hasValueInner = createFields(multiplicityFieldset.getFields(), mainDocumentPart, indent, createListing, visibilityRuleService, hasMultiplicityItems); // if(hasValue){ if(hasValueInner){ hasValue = true; @@ -342,9 +346,9 @@ public class WordBuilder { } } if (hasValue && compositeField.getHasCommentField() && compositeField.getCommentFieldValue() != null && !compositeField.getCommentFieldValue().isEmpty() && !createListing) { - XWPFParagraph paragraph = addParagraphContent("Comment:\n"+compositeField.getCommentFieldValue(), mainDocumentPart, ParagraphStyle.HTML, numId); - CTDecimalNumber number = paragraph.getCTP().getPPr().getNumPr().addNewIlvl(); - number.setVal(BigInteger.valueOf(indent)); + XWPFParagraph paragraph = addParagraphContent("Comment:\n"+compositeField.getCommentFieldValue(), mainDocumentPart, ParagraphStyle.HTML, numId, indent); +// CTDecimalNumber number = paragraph.getCTP().getPPr().getNumPr().addNewIlvl(); +// number.setVal(BigInteger.valueOf(indent)); } if (!hasValue && paragraphPos > -1) { mainDocumentPart.removeBodyElement(paragraphPos); @@ -373,10 +377,10 @@ public class WordBuilder { } if(isImage){ if (field.getValue() != null && !field.getValue().toString().isEmpty()) { - XWPFParagraph paragraph = addParagraphContent(mapper.convertValue(field.getValue(), Map.class), mainDocumentPart, ParagraphStyle.IMAGE, numId); + XWPFParagraph paragraph = addParagraphContent(mapper.convertValue(field.getValue(), Map.class), mainDocumentPart, ParagraphStyle.IMAGE, numId, 0); if (paragraph != null) { - CTDecimalNumber number = paragraph.getCTP().getPPr().getNumPr().addNewIlvl(); - number.setVal(BigInteger.valueOf(indent)); +// CTDecimalNumber number = paragraph.getCTP().getPPr().getNumPr().addNewIlvl(); +// number.setVal(BigInteger.valueOf(indent)); hasValue = true; } if(hasMultiplicityItems){ @@ -407,7 +411,7 @@ public class WordBuilder { String orcId = null; if(isResearcher && val.contains("orcid:")){ orcId = val.substring(val.indexOf(':') + 1, val.indexOf(')')); - val = val.substring(0, val.indexOf(':') + 1); + val = val.substring(0, val.indexOf(':') + 1) + " "; orcidResearcher = true; } format = "• " + val; @@ -423,7 +427,7 @@ public class WordBuilder { hasMultiplicityItems = false; } else{ - XWPFParagraph paragraph = addParagraphContent(format, mainDocumentPart, field.getViewStyle().getRenderStyle().equals("richTextarea") ? ParagraphStyle.HTML : ParagraphStyle.TEXT, numId); + XWPFParagraph paragraph = addParagraphContent(format, mainDocumentPart, field.getViewStyle().getRenderStyle().equals("richTextarea") ? ParagraphStyle.HTML : ParagraphStyle.TEXT, numId, indent); if(orcidResearcher){ XWPFHyperlinkRun run = paragraph.createHyperlinkRun("https://orcid.org/" + orcId); run.setText(orcId); @@ -432,8 +436,8 @@ public class WordBuilder { paragraph.createRun().setText(")"); } if (paragraph != null) { - CTDecimalNumber number = paragraph.getCTP().getPPr().getNumPr().addNewIlvl(); - number.setVal(BigInteger.valueOf(indent)); +// CTDecimalNumber number = paragraph.getCTP().getPPr().getNumPr().addNewIlvl(); +// number.setVal(BigInteger.valueOf(indent)); hasValue = true; } } @@ -451,10 +455,10 @@ public class WordBuilder { hasValue = true; } else{ - XWPFParagraph paragraph = addParagraphContent(format, mainDocumentPart, field.getViewStyle().getRenderStyle().equals("richTextarea") ? ParagraphStyle.HTML : ParagraphStyle.TEXT, numId); + XWPFParagraph paragraph = addParagraphContent(format, mainDocumentPart, field.getViewStyle().getRenderStyle().equals("richTextarea") ? ParagraphStyle.HTML : ParagraphStyle.TEXT, numId, indent); if (paragraph != null) { - CTDecimalNumber number = paragraph.getCTP().getPPr().getNumPr().addNewIlvl(); - number.setVal(BigInteger.valueOf(indent)); +// CTDecimalNumber number = paragraph.getCTP().getPPr().getNumPr().addNewIlvl(); +// number.setVal(BigInteger.valueOf(indent)); hasValue = true; } } @@ -487,14 +491,16 @@ public class WordBuilder { } } - public XWPFParagraph addParagraphContent(Object content, XWPFDocument mainDocumentPart, ParagraphStyle style, BigInteger numId) { + public XWPFParagraph addParagraphContent(Object content, XWPFDocument mainDocumentPart, ParagraphStyle style, BigInteger numId, int indent) { // this.indent = 0; if (content != null) { if (content instanceof String && ((String)content).isEmpty()) { return null; } + this.indent = indent; XWPFParagraph paragraph = this.options.get(style).apply(mainDocumentPart, content); if (paragraph != null) { + paragraph.setIndentFromLeft(400*indent); if (numId != null) { paragraph.setNumID(numId); } @@ -511,18 +517,19 @@ public class WordBuilder { for (int i = 0; i <= indent; i++) { textLevel += "%" + (i + 1) + "."; } + if (question) { cTLvl.addNewNumFmt().setVal(STNumberFormat.DECIMAL); - cTLvl.addNewLvlText().setVal(""); +// cTLvl.addNewLvlText().setVal(""); cTLvl.setIlvl(BigInteger.valueOf(indent)); } else if (!question && hasIndication) { cTLvl.addNewNumFmt().setVal(STNumberFormat.DECIMAL); - cTLvl.addNewLvlText().setVal(""); +// cTLvl.addNewLvlText().setVal(""); cTLvl.setIlvl(BigInteger.valueOf(indent)); } if (!question && !hasIndication) { cTLvl.addNewNumFmt().setVal(STNumberFormat.NONE); - cTLvl.addNewLvlText().setVal(""); +// cTLvl.addNewLvlText().setVal(""); cTLvl.setIlvl(BigInteger.valueOf(indent)); } } @@ -658,60 +665,112 @@ public class WordBuilder { return result; } - public void fillFirstPage(DMP dmpEntity, XWPFDocument document) { + public int findPosOfPoweredBy(XWPFDocument document) { + for (XWPFParagraph p : document.getParagraphs()) { + List runs = p.getRuns(); + if (runs != null) { + for (XWPFRun r : runs) { + String text = r.getText(0); + if (text != null) { + if (text.equals("Powered by")) { + return document.getPosOfParagraph(p) - 1; + } + } + } + } + } + return -1; + } + + public void fillFirstPage(DMP dmpEntity, Dataset datasetEntity, XWPFDocument document) { + int parPos = 0; + int descrParPos = -1; + XWPFParagraph descrPar = null; for(XWPFParagraph p: document.getParagraphs()){ List runs = p.getRuns(); if(runs != null){ for(XWPFRun r : runs){ String text = r.getText(0); if(text != null){ - if(text.contains("{ARGOS.DMP.VERSION}")){ - text = text.replace("{ARGOS.DMP.VERSION}", "VERSION " + dmpEntity.getVersion()); + if(text.contains("{ARGOS.DMP.TITLE}")) { + text = text.replace("{ARGOS.DMP.TITLE}", dmpEntity.getLabel()); r.setText(text, 0); - } - else if(text.contains("{ARGOS.DMP.FUNDER}")){ - text = text.replace("{ARGOS.DMP.FUNDER}", dmpEntity.getGrant().getFunder().getLabel()); + } else if(text.contains("{ARGOS.DMP.VERSION}")) { + text = text.replace("{ARGOS.DMP.VERSION}", "Version " + dmpEntity.getVersion()); r.setText(text, 0); - } - else if(text.contains("{ARGOS.DMP.GRANT}")){ - text = text.replace("{ARGOS.DMP.GRANT}", dmpEntity.getGrant().getLabel()); + } else if(datasetEntity != null && text.contains("{ARGOS.DATASET.TITLE}")) { + text = text.replace("{ARGOS.DATASET.TITLE}", datasetEntity.getLabel()); r.setText(text, 0); + } else if(datasetEntity != null && text.contains("{ARGOS.DATASET.DESCRIPTION}")) { + descrParPos = parPos; + descrPar = p; + text = text.replace("{ARGOS.DATASET.DESCRIPTION}", ""); + r.setText(text, 0); + } else if(text.equals("{ARGOS.DMP.RESEARCHERS}")) { + String researchersNames = ""; + Set researchers = dmpEntity.getResearchers(); + int i = 0; + for(Researcher researcher : researchers){ + i++; + researchersNames += researcher.getLabel() + (i < researchers.size() ? ", " : ""); + } + text = text.replace("{ARGOS.DMP.RESEARCHERS}", researchersNames); + r.setText(text, 0); + r.setFontSize(17); + } else if(text.equals("{ARGOS.DMP.ORGANIZATIONS}")) { + String organisationsNames = ""; + Set organisations = dmpEntity.getOrganisations(); + int i = 0; + for(Organisation organisation : organisations){ + i++; + organisationsNames += organisation.getLabel() + (i < organisations.size() ? ", " : ""); + } + text = text.replace("{ARGOS.DMP.ORGANIZATIONS}", organisationsNames); + r.setText(text, 0); + r.setFontSize(17); } } } } + parPos++; + } + if(descrParPos != -1 && datasetEntity.getDescription() != null) { + XmlCursor cursor = descrPar.getCTP().newCursor(); + cursor.toNextSibling(); + Document htmlDoc = Jsoup.parse(((String)datasetEntity.getDescription()).replaceAll("\n", "
")); + HtmlToWorldBuilder htmlToWorldBuilder = new HtmlToWorldBuilder(descrPar, 0, cursor); + NodeTraversor.traverse(htmlToWorldBuilder, htmlDoc); } - int researchers = dmpEntity.getResearchers().size(); - int organizations = dmpEntity.getOrganisations().size(); - if(researchers > 0 || organizations > 0){ + XWPFTable tbl = document.getTables().get(0); - for(int i = (Integer.max(researchers, organizations) - 1); i > 0; i--) - tbl.createRow(); Iterator it = tbl.getRows().iterator(); it.next(); // skip first row - for(Researcher researcher : dmpEntity.getResearchers()){ - if(it.hasNext()){ - XWPFRun run = it.next().getCell(0).getParagraphs().get(0).createRun(); - run.setText(researcher.getLabel()); - run.setFontSize(17); - } + if(it.hasNext()){ + XWPFParagraph p = it.next().getCell(0).getParagraphs().get(0); + XWPFRun run = p.createRun(); + run.setText(dmpEntity.getGrant().getFunder().getLabel()); + run.setFontSize(17); + p.setAlignment(ParagraphAlignment.CENTER); } it = tbl.getRows().iterator(); it.next(); - for(Organisation organisation : dmpEntity.getOrganisations()){ - if(it.hasNext()){ - XWPFParagraph p = it.next().getCell(1).getParagraphs().get(0); - XWPFRun run = p.createRun(); - run.setText(organisation.getLabel()); - run.setFontSize(17); - p.setAlignment(ParagraphAlignment.RIGHT); + if(it.hasNext()){ + XWPFParagraph p = it.next().getCell(1).getParagraphs().get(0); + XWPFRun run = p.createRun(); + String text = dmpEntity.getGrant().getLabel(); + String reference = dmpEntity.getGrant().getReference(); + if(reference != null) { + String[] parts = reference.split("::"); + text += parts.length > 1 ? "/ No "+parts[parts.length - 1] : ""; } + run.setText(text); + run.setFontSize(17); + p.setAlignment(ParagraphAlignment.CENTER); } - } } - public void fillFooter(DMP dmpEntity, XWPFDocument document) { + public void fillFooter(DMP dmpEntity, XWPFDocument document, boolean isDataset) { document.getFooterList().forEach(xwpfFooter -> { List runs = xwpfFooter.getParagraphs().get(0).getRuns(); if(runs != null){ 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 396776273..a23e14ccd 100644 --- a/dmp-backend/web/src/main/resources/config/application-devel.properties +++ b/dmp-backend/web/src/main/resources/config/application-devel.properties @@ -25,6 +25,7 @@ pdf.converter.url=http://localhost:3000/ configuration.externalUrls=externalUrls/ExternalUrls.xml configuration.rda=RDACommonStandards.txt configuration.h2020template=documents/h2020.docx +configuration.h2020datasettemplate=documents/h2020_dataset.docx configuration.configurable_login_providers=configurableLoginProviders.json configuration.doi_funder=DOI_Funder.json diff --git a/dmp-backend/web/src/main/resources/config/application-production.properties b/dmp-backend/web/src/main/resources/config/application-production.properties index 971e6be43..296798080 100644 --- a/dmp-backend/web/src/main/resources/config/application-production.properties +++ b/dmp-backend/web/src/main/resources/config/application-production.properties @@ -19,6 +19,7 @@ pdf.converter.url=http://docsbox-web/ configuration.externalUrls=externalUrls/ExternalUrls.xml configuration.rda=RDACommonStandards.txt configuration.h2020template=documents/h2020.docx +configuration.h2020datasettemplate=documents/h2020_dataset.docx configuration.configurable_login_providers=ConfigurableLoginProviders.json configuration.doi_funder=DOI_Funder.json diff --git a/dmp-backend/web/src/main/resources/config/application-staging.properties b/dmp-backend/web/src/main/resources/config/application-staging.properties index 8bafc9971..a783dd696 100644 --- a/dmp-backend/web/src/main/resources/config/application-staging.properties +++ b/dmp-backend/web/src/main/resources/config/application-staging.properties @@ -19,6 +19,7 @@ pdf.converter.url=http://docsbox-web/ configuration.externalUrls=externalUrls/ExternalUrls.xml configuration.rda=RDACommonStandards.txt configuration.h2020template=documents/h2020.docx +configuration.h2020datasettemplate=documents/h2020_dataset.docx configuration.configurable_login_providers=ConfigurableLoginProviders.json configuration.doi_funder=DOI_Funder.json diff --git a/dmp-backend/web/src/main/resources/config/application.properties b/dmp-backend/web/src/main/resources/config/application.properties index dafa101e4..67c57b4dd 100644 --- a/dmp-backend/web/src/main/resources/config/application.properties +++ b/dmp-backend/web/src/main/resources/config/application.properties @@ -50,6 +50,7 @@ elasticsearch.certKey= configuration.externalUrls=externalUrls/ExternalUrls.xml configuration.rda=RDACommonStandards.txt configuration.h2020template=documents/h2020.docx +configuration.h2020datasettemplate=documents/h2020_dataset.docx configuration.configurable_login_providers=ConfigurableLoginProviders.json configuration.doi_funder=DOI_Funder.json diff --git a/dmp-backend/web/src/main/resources/documents/h2020.docx b/dmp-backend/web/src/main/resources/documents/h2020.docx index 3b30f8d94847f81ab495f99ccdf97757c08544e2..9d5713b2629b18c679b773cdea3a0bd8222fc900 100644 GIT binary patch literal 20460 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 literal 43734 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 z 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

R^$xdK#_IpIzAzn* z6F@@FQuo+tqESeFK%4G`U7LQ~>lC~wtSC@WuF z?f59bdTaf_W^E6>|27URFoRw?U7IX=4udDo()=AU?uIRW7DZOEn=d1ua?FE3F8wqx z4y`?+fs+#zvYW~T{Lt#%q9^Ze-zmayF`u|seeEOROChMF(2n7X>xU!(LY}MP8-N!RR1Dd$cn7WIS~=t}{qjl~qROmHd5Q5_i>9MOA6i@FdxQSfxvL z(xFuP?;^qG2uLMbKwLO|&}D12>jD$%c1yTNk4=bGrRu-#R#PeVxaX=yl25v(wLy~G zaU$?eq;>DKCtQgnDi_=R5}Q?Y_$Ebhyup6ORYw}C+4+o*>N8&Etz@el?S*oVPpXA=IwhZ?~yF0h_g*QsY0NR&bJ4QbbpS4O@6$Y=0FY*YYwO# zFi{Py4SqiM;Wn_g{n^H^r(vM7q@Vy_`Tw1Q!j-JOZ{qp^Hv(GlYN*)G7rK8}9E{@6?`8R=&GAAEuU>AX&+>r^tVZ%o_%k|ZBYAEg&&+DB( zNAWI89-tTG+u@qp3L4+LYSWoWw;JLI5xt?(xkm*h44_XQ*_&i!?%v&|yD{^Q+O)?V zE!rRTSfZ+>#f>V7FvR0U)`mv=i+^pQ;g+)sNFYZUP>d3sZ=w1&Ha`a8|25Flj+p_e zvm)XlsAkx>%05oXoQja2DHDf-uZl51hm(Sx9Q*6dAD2+_Q4uEBCtjWCx+m)%uwhjx z2!?qij8TRdCmHKTCyqK)40v5_jbn;cdYgg5V40~{$fz+poc=(~heeU8h%cW}1al^+ z*0rv0On6=OKA_;hQux}mKoWU*P@K6QBLpuA_+4FkdL&-4Lk?rYW9MPd0DIBIByicQ zCv4fTM>IomL8QaGc~b1`5j8eCt5ki{?|nK<2|e9q1^ChpJfirqbrATw#0?Dk=3m4n z?4+-Jw0fTxYVg%#00Gkd^s;ceaL`=(cE^}tRunN|R_i$XH_Lnn4lWnCR7IyrQa$+i z@=T5fEXHsqviia0gHAGP6zt8kjrwA@n+6sPzJ4IlgnscWPqs8XbUb7gba0}!ET^C1 z+|ts+K$7=AR}2iH7o+G8xA4`dm%NpMm(e`ryWk8@YZ_u$(@%;va7d8EpU4Z4$T=!K z+VRgjpglP7=RO%vV?Me~NQ-=DHE<+`j3&Md4>^XiGC$Sm)hTTdXzMf#vOz z$xz?;0$U@uXuc&Zq*4Ue$f{EH!>Ax#1gmc1Tuqzuz~yvsYM3;45UQhR=Xc@W=E}F8 zi>&jV-ZL{xlbaunnIl+_pD&3vc6m&nM4tei;m^U`{+`hDdZ0D10NsTK=qhLO20dG- zh25FRf$PWN|2ocT#|i5E5ZG`N_wvNi#8{n)b;1a^l`uErQ0A1w#4fam8D0r@Yu z2~^(@YWq`ObFpw~o%zXDpzvBCMCo_*AoV%t{|j1_n9OGfK$8Hj|Bn80{WtWjf4c;T z8~8OrA# zWM*V!X30tbgCGMyKtKSbo4qOm{Ffip_q~q2k);C-_1|m7Y>zlF9X!~!N0xqyhfAZ9 zpkZA{$aI>hmv8j=C0LrIXrcPnrYvNuta8sUhL@uwg8Yr2AD!++@z~&?Wvzap{(5J< z+1pM}_3gn@O{O}gRRw~#$NH6{(!-F#G0(oq6QbHjsRV)ca}KxaqjWIn4Q_M5JFRAy zv>)fb*0X9>75?=N6vfV2F`r8jnSvTrm@p*jgNluDtfK{*MSg;QMt7QnFY(0^4BJN2 zuUEL29wx^z6Fmyi64dOFpc2lR`3C7o8=4A+uxiU+w}M6EKTjT0^UZeG?s`UYxuT|0 zg~H;pR=faZCBPvL>>mY>zulh(0sxTx9|8LHtzqEg;Amr|YGq0DZ%~;z8d=d%yINWP zgIPq>1Y|EQ{O>Dnq2)HIGd@8{4}=_+7)Wh_R;hpqxDn<13z$qw*X!mwhArCQLo<@c z?&NS6pwe8BAnBJ)R;umQj71L9(}f-XxO_{oydQrK!X8fuM6fM3rJvy6?C<(N(+t@w`^Q(WUa+FEqe^r_j6shdVz$27Q9WssCMZ;-TH(S~f_ zhqL-s4qG|7ntf_VZ*)NyR6)63xE(nLl(`@UzcfYz=z+suV?%+rKKVnPUC8zB^0 zt(*+wElFZ5EGytDjLN17e2fL~*}JW%r4!qZ>wyx>`*HP+XQ^z)8O+Ttq`*Ff@8ibP zY%JwJYT5-x&K2Q`-)m=t>5pdW1z94tRn54?6(jrOCx75{NMstp`ME$LdW+jzbS6MRxRBP3}bFIMNY0gou$ zA_;lx#B_c84-TO@Gq5}Q?XBSdO17bm!9O6-{9Akf+rS&s zs6`vA`2sEJ1eToP*_;IR+3x0&@qfXA@ga^_C8ReYJ<&VBY4#o<;y?4?LEOkmG>L` zGT?vJAQ8SP`o9F&*c<(YKSEwh=DV+XJ*iN7ZMDLr%!bDl?}#BH;bLxyyZD)}F~m2U$GS(c{64G%!hc?rL3AqCz1;Xk}W51Sq-1Dr-QkY)5TUILP_waWA_(| z+a)$htsdH*snRqMS+x5}6UF&JyaEs1F7ceB^R5X+F60J9k7J^{1E9KuN4 zHWkAjh|nwc5OHjzRI@2@5v~U#>ci#rw?`$B^Y3ba4X;6dOZG)OW65JDFW!sXLWMqZ+=N>$U1=S2)=dhKXJK|S&rbzo370bC02KITpKYdJpAXkC83RP>G5SzN4X{Cra^$Hzqr z1i9DL)emhk*T&oI9zphr+VoyB|B`IXwqK%^{RecPXzFS!8#JDYCc&JO;?tEV2+tNS zwMO+e)w9AgiQ>RrSu!)nL>{)4O7ep1&^l!{a5hP#sYPn;Nt41BMzBR2OZZy{O(VLx z!7?v^7-oqlmiMl*R!o_6?EN(n#dx;kZK#$OUV-c;_v$r8!mfA(-q6l9T+_fdW%_rQ zzt2^}cocxa``U{;Y^Ap2+|X7ekUv&mX#S2$R$-`D6yHEY|4X2Mego}dV{iEHare7_ zI9VB4JN{?rZHVuY37|zDyn3S$y=wGjF9LL?BW}Z#Y^3f zdt3G1y6UK(Xw)eUJ4a!U^bWHyy2AGnZcDEZ z`9Ly|uFr1HD+Iq#F*iUF(OC_8(Db|pQ^g#zFh2T~&w3Z`tR#J2DK4t`%e{GUZN35d z+Oj{JcP|j)@Os+sE^?jOmkq<>)C;2RXI4;n(r6QR0Yxz(&cN@-)|apyWA6Y& zu__mUKY~a!qZJqJ3|Dh0&WvtN#4G$Em|E2A7m|eA;)<&k4mFzN>P`562s2{Au=jKQ zNQw8-W~|ZuLX_xsAgN(pT9)Bo^il`yft3fD-EDuC(W;8I!<;z=^S$^I^$(XU=5J79 z=~wr!U2LNl*3T%m*U=2u87Bl@pZXCCYg5RS1H-?8)U>K z=ExMe7eo{qM?!)GpJw~uYG{FltIDM*$d{9A^&+UJb8&n~j9m#2XF#h124IpF)6oiu z1a9`tmkhDT9)?Q#U&4WO0s3;VcG(`GMFeArmIBM1vl~NZ#TW~}wZH=Q1t@SfSfnf< zXsfMHuy+VWAFN>`=5*M+2VK3xVN20uA=sVTIm+CI*v9)=P=yH~4vWqe8&SiyB`90I zs_nj$4dVPI$kEGUQvaJEwSO5R5dWh$7~5DoD(dN5{u3i6;-}2N85+Fu3XS%dIL(P4 zP!bO#K`2=RPmZV~X7ovvJY8(E(L~AL5GcX#AW9i|N_(L<`=GZ0LK8z;qCp_6_J~VqIuu2}!$RL#+0c(h!$aBX3jf0tw-8qJBOhkc86?DVHMy(8$-qQ`-Helmdsk6-^t(_78$O`IFDC zQ~Pr}zPNuzrx&AYOyik*}Sz|`;yi$R0ZK|~# zbMj{wI$yq6EQCR95{Rl7lqe^Y!#&CGgt@Tm_SM^{?t?sU?5nQeg*u=8NVUXnggw?- zE`wW(mns-Z)x%cDv5axwwCRizeYs6|Ll6iS6dm1*JkTsx3+ey$WcJgse66o1u+hor zEMUx4A&?LsV!CF%ADcpve5Ky%q=zvP&5d8bndK0_7cvOH+RHDBSEB#iy<)MJK+*te zfE6G6Y|&Mc%Ri_@+`^)=eQKLRnLgt>nf01JtW_}RfkgV1z@&BvguTDqzz;hM2WG^} z2rsC>9}BxI(TmdKthNJQzm#7&4$Cl$zY_kMrhNq7{qC)8LOy<<44zvO}A8 zFH4fE%f{EGbJY_0&IVCuLlBPUswvahGc+b6 z8AVc*(t>)}H5WA)z;I|7N<>U5kzqJj_k%4XB61PfHF3{shUaLUg+d7xAr~LgLJhY# ztz$pp?dc0#RVI(n5L_lU&-2UkPTw9l4@Q3F4(oJ*w)fMEP81KH5BJC8K_1P7YssF^ z+s&Mg&r2_~BK!4#ij23<*2m2U0kEgWb_^`eY>231+|L}ZUwpb?z=njA#B|Vf z3q*~3yu0W{^k9xUfkgKc7{<%KXR-ERR}k3%NY|(L+9NvwvXUrF09CmyVVPc6FQ>f*Vn)2>_4NEN#i&7kockXUC5{o zoRZxACAgK3sfDy8BgimjW9Xr@@(|{YjP2o1wMHi{vF8uQ^Sy(ACdN#oB&R4MDvR$a zaVoLWyN44L64>aXq^5Hw|EP+$Ey!a=9NA9f9!twKIiZQPTL z650lkodfUm8aiUTo@=7YNK;QlI|j&cug!iK#h2Z*p)Z2b&7h*B5);ooimg3f(dPxbVldA6X-2?44;YcnLNHD zmeD_`m|w&ok^);0so`1Mg#F8+N+99*(|s{W>fnd@op9xPiGEU*i*KyF#Pg4@q;v2n z0%4YET^`NBd{no{#zg>?V43GbN?VlMolJzYv0cY6{#>%0;F?LTFhY6-+qoa`n=3sk z)XUKoerLRD@pn_3>=2~y=O#1XM+dgUERxiCdr+Gzw_@BJUo{KOPqR=?c9_Z$Z)hN2 zIlCC%y@kN`Q?cG?hz^d6WD2@K)fE1597m?4huV)lrXWOGWp%jVJ25s}q6DT%9|KY1 zTn+6|a=!SkCE0%8b;&%(nJxnW#>}397SVWz53PuYkfZre_x=gMt8_=rjk#Bm)KG% z>Wu9pvN>S4kA>oIkO3wnrOki@#q%f)xnmklZ~gSlpdfcO-l>$l-9lg^v`lukp@`Vx z-$|DW6*O#K$XzMC!~_j!ay^l)6kFlhrTV_n|j6mRQHwnsry-=(Ec67o-Fi zCMh-Hd+ouJSoJ~UsL^tYy<`Pt?)O-Mhxhs9Tr3cxxlT$|*m~8{aP;F+LR-qBg7WR` z1$Qh`;t)VDr%@=a9I320o(VxFo5nx$DT;DAghuKCc=S8_#=no4B- zp{HHVMO<(SM~c5MLf6}u@u2Y7#!E}e^$t~xPYlW&yqhWi#l5EO} zn1&X;|I3kXkMh)t(F~YR7Bmfa#G{N2*xO#&&BF>04YF5Q51BUUa}t0Kl5QI2MLc?L z%F3j~1$Mh5JvT;1gb#~MLXgMa_E+u#YanoBiPifMqf&b}fgLyjbLj8c{5Fq=d&_wo zZJ0roENdT}t%j4|X$Z4!<3l+3uM|TpdB6r-V&N`aTa< zZ0|AsX#iMqNO20}1ZoKN!-=K?cVps!_N#dPM_)Ixf`e6slHCBAc<*^L!{Bw>MhS+N z)%!s2xsi5*Sg{Rn?iG9V_lht2@|YZlO@)nR?kLJ_#eEmad8>0JNh=H5gWX!*ZxO6T zx{p*WES*9UV#XvyYPtC8PbBC@ZtZaoOEJt;6oTvbaSbT!BL7IviXb z_fhMeSygu#VN311N|@oDx|FWYfCe#fW};-V1wKtR4XvUbYW7nOdRDQ=`V!C*Mc9z@ z5!yWU-^cQ9wqvB(Bg&~jCGn65ENJ8aOR5e@S!RPu&@42M0qG2FGXMh|%g02adm=91 zw12#M#`f_q=2vFh&6l-#W4LIM##T|}N!Wl+6nbp9W4+nma9VJZxlRTlwTGxov(DbZ zrCU&lRNdU|ozX6Eb;*Fhp*&eFJLhWBZGAy)M%E!244c)dJ)h=h4gz*ZqV7!Z_> z>+)&gTN@i%k8y@)W_B%IvIZ0q%A9K)3Q>IO2VPHg96NbaJqM}?Z9Z20oJ1K>#py+b zRqL1=X%l*Oc#|lIF0EX==t^)Yu^&VZYq$NJOI#{e@J8}A2Gsab7mH?RHOP#icV@8B zTB#vmsfPOKJL-B5NW)Um=Zy8eK9~-4;bPTfpN>2fp3160dW0iW>Yo3PsykU~f zd0ENH#>b#zM5s3%MoZp}w9z(&DgUSik;1-rvQd(Lz#l8Rg^(cHL1KviWY4@tbK5_Z zkXVeGwJDtwNiHv4L1h=;?Nx};l6bG3RCPCkx}~^olCJqk2V8@s)!ln0v3PgulF$ke z$T5;e+6k)IQ<6doW;%U}+MqtYib0hH+x!6H+>N}ow!mab&@)0%-05&pYLSXpuumEI zUO*8=l?Os$0Rc)g$;TG&YbE2PhDxs**BS~dOT-fCXobwcI6#bwArSp*`3Do8YEXY> zP{vtc9TtXC0q`wPKY3qKxWQGAb&gw0AcXbsk+Z?HEt+^56xad^Gp~W{aBkd51GQ3F zVSMXJE;I1^3I-Hl)3VFV0jg&o zfVN?|P{aEQ&pSui#8k5SFV55Y(jP2>3kM2HTr0P&C%cKZC?zHmE`rC)m|J9_Dw`~e z^^NK_=y8A4D2>AQons?1YVC}t0pgdW2Px@gYpKr+@Eu#A-!9Ceo0%!E;|;3$-DEi= zA_Q1atRj%}!e) zjqk){9`|2GroU@c|3oHZ8yiO>d-}i0d_nx0^%^a7(A5)i(B+aOWH88e6?kukW$OM=R{eh3+Lk{!hdHGJy?_{cp09W=v!pe{ zy#p7PW?nZtB}+1e7(;y#>PBSeI-}W%B*4gQA-O<9ObHPR$}%j-cWS8A3MhxKWHbVC zVN*Osi&2_BXNLSBmNTp9U!^Fl3tqS)tR-G4N>%JQLmSy86l8zSTUwFa2)=r$^Wfr- zvzsbW$~$zD2w-kYu=I0CW;ksjC|B5%DQ)o7Cdw?I`z8gEnaKSVv6<;Y)UpJk3O7T zJ|JR88YR%wtm%LNpxW4&J#^C-wTu^52aoAsQmuWQ0&txgk@#0Nm`Kq;)RTl>G( z(m9_}K|v}tERc`_Ky^&EC&f2YQ~@IqQH2F#)3{=t+HcX2V^$u@Z@6=0HB;ayeVck& zB##em#Zi%wuM-$OQafci8%+9s=cuEpu{pgt+z$M{ow^4!y@GY zF#;z3J-A(O!vWP}17xOpnIQO3%cIj@s7R z1SQ!?6UpZ15a7s6o zJ^#ms%~NX|&*j6qgUi&@-G}F<1U<__5x8A|sHo^M42&bCp94vCn!Ezg5DO)ORrjCS zgUn9Yk*=?%CancELc*USLG0?Zt~+uuXz3<7R>wLo(EB447;jlwZ(f@H0xLNfW(k*1 zgQyN&O@=WyjuG=Y)vliC`g5hlzxV8nlWb(awujHEja!=eTnOGyfoXFin)$`% z_a)l!5A2@tOGxzFtOP-03`q@_%JNU5<|$FLr0VZP%jft^!eL3dPNFagBe6V>a@&`Y z4>JKsg7}7KwclNY?Qst(Wy3g+@b-7R`$7P6{gcX&%yf?F5K`M6M9RR&NOfL#;6Avy z?E6c-FMGx;f=di=ZOj`==b6HFQ;zp-Z^4h31C3HSg?L3Ng-!Jc1IwO!LJT0af>HP& z5lH;y1xOYdmjN-LMNI{|R;G6B2S(hz6@fB&F?cHUaCuEJO4=C4BFz|D2wY)!mrGM~ zTRUf{#o7%@H`)&gwI)UF@Qev*<POSxLeYdflZl6=M4$XJp<-B_Y#y2mXONOE zO%a>1Z0vV|e=;FodBh1;{Dg_r;_+8ex%-`%-xszeRW~RWpq4rx?<#Gp;j#t6Ah)1V zHZ@V0*rY4RQAe<5s<(1BwZ6eyrk!;5sgj^|FEi<%^%-b7C8?pmj$E^&?a>F7Srh4L z)5_6IdcchW!>z7Cz#&aVMRC`=-zlzbS3~EvFE<$0qU_Jv09N6o=Ym}K> zbF>!b`Y;mn)A)%MKeFGTa)r~qpDv9U=`F9;Jq(yHMvu*;a2I`xp~1&jeaLovo%UC; z@6N4CX6}B&B^i7B<}Eo!NTbQN&DQw=FcX;1>ZzHIRE;+A#jj``*ynD~#(Gg~)I~O) z08Mxw8W1)@J|-VSvxDH$l>C-hZLN|yelh7a>=2(Hm1C95LgsXQ&iZoWO!v}0x~GBH zD`$o=wkzwTkG=8Zc~_Xp!FcVJ`xiW=oncxH=Mw~<&%}iDc`_l8C4=K=M)(*M9NY7r*2ip6?lg}jX%l?DY0K$kHB?op z|Kt){U*E#Pk!YyITzwoqeKdkD0d`P3{C&p1BRuoCp)xHRvF#wEq6+{Af& z^fjzcn5s8l@m&pY8~mA$94i%r0E06+dQCTZ9lgP~I5KbDxpb6YBScske| z8$4F4v*0q#&4@zc$gMx5q{_}Xo?x+bN~}Q)IPp6&k-B}1fz=5~_TfU455ECtAZ{Bz zU7xEjHpCR6*T%ileD~@YvYt zA)=bLghaKXr=W1n2&wuX<@A#vbtq%&$WzTRE?qp;Q-Lq(s>dJ}0P`XVILzGDz&i%6BWER zw@QsHK~DI_!rI38z%gw0^Mf5Dya}Q41&}}!dsAslzpFJ-Ra3Njf4108)G3UBpl9nw z0?9Sf_N&_y9ywmk#>?Ll_ROCJo2=<~5FyJw`=P6I5$DDqs7e{T&3oQ1S4RnC54Upu z&PXp&Gy}vmZfnIU+Jq#ke3XWGIU>IsMQ3SxDH=7^*OpdpT2(-Y7loqB=!6RHnJ;V~ zX=w){je$~YEAOLdMK@P0YTU`2g<;!mnLGc|uOVK;GdGfVn`*|abV(X1kyZL;N)wPk z+Jcb{u8zR5nMQ+D8yevSP@Rt|$5)9_e-ct5s zAX)T}?^e~J38Mu@>?PNkLgc>8o_NUDadyu*iDlF!7Mn$oT6etbtj}8pvxAHzF zsGALbyYB-#9c!RknGX=&mWYXIt@ZCkySh-N8@CXWW&~iTb>Y9dZZErfR0b=mIVJbV zI(RxxQy$YrZ1AmBLoBP5vKA)(LQ>8;3V(f1p-Dfq#V?O&qGJ(JO{|nt{#_GFJh4wfg-6ui3fbBgtY{Eu9k&5uhD*2$luSm^v7R~ zV~P4=>zQ@Aqo*ZCpsv$dm+>%m`^ym0&KabA700PG&5~GSpk(h4ecP}?Yb~aeR9e~O z6tsmNK@M5@z!_zFxDb$(&1tygCH@5v`Sbp-5W74O5YRJg?5K!Zj}6!N`xI>@sS{UB z;Dz1UScaWvyq{X5E^1TSL9ZCmG(lVDKiDVP!O_@q9~;7RBlajpN=|Xeri$Jl%J>BWL_8u?h2gILWA*1F?LWJJtSg?rIB`~};2 z;)rV7UThA|>k?UBF5#rfmwXMU2?+PYHY$r(jbu%EQ;AKlW~{Np3@+Eg%Hk6@x&K2Q zcpoaZ!~Vclq~1uC9_KuyTF$ONgl6KJb*=*)?N1Ny0kkdPW1if&;*b#<)OOaktJT(o zB;lw>t~VZxWDwUYvMx!qeg}Wkep52`R;OP~Myi@-{S&e(3p_`wk||_8^E>1y3p!k( ztzI-}8s=f76hD^U@^U);|8VKD9zsx4KTD;dNMNrM_t#kg{8}6*^XPb2R%Cj#I-J6B z|1~2XmylOnKxgJT7kPEYD>1V7=SKS@o%1})Ft2q)uH#wI=BUAFa*w^?c`-6FpRcY# zj3{|tcpTo$DpIfu5n2qliM|BckCrh~0&c?DX&rNPzkvbpPf!mACVA-~(6tnO&iy^L z4p?rPF{ST-BYR8q7S9>RYqXsVA>C9lqX}i5^9}*rkwaLBq7VMSjmDH^aaXFKB=4I*=|yIJjkmtt3WPKDey%qeQNxvG?Nj>377@Hw;E^qn*y`3a z9?7AIVDNDLHl$D2Vw&;7O`jvsD?u>`>}Z%y*TS2)L$NnXbtVs60F6})z~p9&UUBlh zgWr)(RdKJcmgZNtwX=;d7v!Yw|OAU~21xu3-j5DXI0xkho@aVx+$2nX42H=j4 zQCOybnTJCU3#K?!avr9+k$eOaZpf5fjBL=j;Ra7-TFj_8L1ejfguuJ@;mQI~L z>00Onc6Ix4r>6!7|6C;gz5?Wgv!fA(hvh25jHDvJ);LcJ{6ltA`BEs z9x#?pZ4=6Q#jbZPJ9oGfV#4vR7*v<@)jlRioou-xPz((H?lVf)e(?#`?558qT^b&F zx0YmisIjw@BE4&XyZjB-SpQ~LG|sPYx*|d7F@pDGE}tHOCbr^ACreRzyAkZRu{r~x zZ+|bT3DKJYyc)Qt09VSAK&+r4(Ch?rk!d4iRZ>Qq{_DP}o2@V{#Ij@U%derk6M)aI zuk*7_>`xjD$KE@?B~ir+Z&rIm$AW`}K)%B7>SF6hHNDyZ*(r7v?sn`+-e$etwf+2u z{A>X^gqnhUX*6KNVL>pWU@c4>6>at#hKS2Lh}TSlH`W^-{=pd%Ud1!uNOf zrpO{;L6H+!{#Bq~G>kdB%-R0I0`r^ISK8EnW_%i&*1B4Dfc&v|aj769f)hHXiX*t2 z?Bp|1mhO$Ek_BDZ_;)=zX=-&kthQ+4`c(`g5Z>LnVD?|r`T3WBMsZ=ltN@`LKfimn zWg#acMk6IQ_<1LW#;mZp)Cp;i>$fRIxAQNKD$Em>ygoBh zjeRA}PU<12(4Ro_o*0SovuZfwv7V0D`K9$%#~Fq3^s2!~9-a;0PtF@^swUS+k~0Mn z>7c>4oOt`27@&rl$5S*F*(G9reR<=Gr-a$SEtl(&Vx&;7gtJM5=Ptv@KP{7I$!SJ3 ziPweDZ^Qf}$lg+fDwddy{48_W;xo25t7e~fDD#)o-usWNPXzVLnW%P)i@NqK`U=+% zp`N5-nKXUEv@hyj2x+)87J+53Hx`RMAw%O1Dpfc6?W<$MTu}`-L#?r-EXI$iJago` zt<8z6y}rq+c

7f@vQXf(FQ4{V~~9qCabB?DT`_5&fgk0TV-wMHg@usdE{Lg`kX& zKDOPjzfLC+&Ec1VIPG(4!*hs_UW!lW$p+CvgMdf1p@FaKz8+4vCT`6YNlT@7^`-h& zYiPccRL%~trG7vOnqTkcW-O``&J)J>bip5di14N!ja2C-7A#j)YIb-UNTN_KF;QM& zxwYDqc#b+`ZbFhjTm@&Vypr6j{z6)yZ=36igf>+5=P+4bmA{ie_A8eAW83tDEy0HX z%~uo%A8v9L5`+w57Wg`v(&)G(vB@qVMoh;8PxvG-sx7xFd|dafv?+0P&Cvy_IPCen z>wBMtt~Z@3cbci@Go1;N7d_WwzYr=0m|R}`2C*2tc}m9$>TP9t2C1v1GL-=i&QiWA zdRjFVhM0!L>KJnzuEK8Yajv|$aUk5jrrvN}!p^A}FSvR7dk|TIxSF;_P`1F#Edx&cCWD=fuz=zZMcsOAk z4D?ToF-p9_Io9r91lcTxf!=#wwc0tOTFBf-U6_HNV4VoQ@OzJnV2+Dzl)oJ}(!J$o zxqaR`=Ee$Ng(Gpgq)V7+8OrVK7@Yx7w);n)!a1A(daauS#d&Hd9?;D;V$Ql^pI$7> zAp{4l3{8(tAstAOlKz0Y_t&{RL_ZJOnvAC?TLfg&h=JBESOcxSZxd7!z8*xS zWL|>7W@jRdh)x1Ss$33R-P~zqpk>ZNf*+upQqkepK&ubwIYzm7q^h~{eyq82oZ7ko zTfAs7F?bB9JS(P6ak^ai5RfSA<5{o8L8Ax-94$j;Z1E^j0zq~aO^kTBtkUBGmAVKu zGg*3&0jp1j0S+8r-$3vN^ko;z(V?g*6rpK_+6Np{*St;o-PnjP_VMP^#mT;8zX@K7 zU*V1Gj)r@r+@VMEc85FH8boc@s14#vo|Rap0Bi3ep5yUaaWxI|i31O!{#ZI?0sYx{ z8^yTCRw@boT`&@_${;YS|J?Y^dV`w4=ih>ngP!VxTejRp2DqK;;bG72PGk(%jO{8TcNO^o#zWGpQ=2IyewEgC_{PC7u_=3(hZ7Nw_gvEHS@-b3bqHDFg!&&W0>U+tD;fSPCydRY zdTX&=iM#U88JB^HAu1I+{Axcps52avUd#;E4o4$Ezq)Gk0S^t=-?N_*%_4WmzPN#u zi4aACbRYK>tHnVMO98|oOm^0Lw?2gvapRe7 zqaKG43CO8Z<%1Q<+?d&~#X0QY+CZ5}Pep_MBPn#_R5-4eTMQ9Q1aKG}5#vjp_E)@6lj(}qvw6k=c;a3>c1 z-e$9D^QMLh{kztYS^3&4RnSUdnHYxlb-<$R7*t~|!>{9(zN&0kHg)Q09BV%AU~G6C z(O~Ra`qOhjNO`0*rbq#0xdV@tTkJ_v104M# z=z@w-@wu|axJA%0H$%n7EFY_d3ptehi``lxQ&Pj`CtSWxeQfmt37JorDJ_;Jpc6*T zxzDglEf307!Y+>*R1pp?#g?(Zi+4!HgmvS$iOO*}$0Nz%6v`1Q>MEvFX7^ z15G|F8%t{S4Lud&wn?!?>0I^&^2a~N9P<--(u#P20uwNvtuhUablABEl$icPMLq=Y2OV)^KbF zGLIoO+(5k9*qFdEW#(-`-%)exmmHW=50QPV}>`l|tMMn3K8M0LpR< zB6I{(AQoMoyaKZSjb63@h;hArrF5Pt1ZG;Q#T5lKx$R~@{i(oV5L2iHn$+&Iz;8|e zJ9#T2^R_&zuLPg6eQPZb@x{gMLgBvVhE8ztM>iCRjv>OEAE4lq+_~IDcVIbQv9~SJ zZdaV}7dXQm;WbHgj#YWC+K4zei74~$ycAo)ZNhW&9I5(6ie&&esqBvBj~uP2^36k) z*8#TIj+VDh2kP8_+a-q(!~lIf2TT%iR~=!Q8dRUt2vR z0|obXUX5l*x-h6bzGyNIhdxI1CguMs@a(w#l8DfW#^gy@EwoMqX4i+L2M6CrWsK+K z6eLW_9+A1-yS;opv*+xZ7%EF!IEw1xuRcTYs@PcKiL3kPB=aOCNEFET=9Tfk+`NMO zkG)R^M>k8Of6g&qXh}HiF(Y;PO z=<@z?jVBKyYgsMARAOn59%kqR@_J^SorZh!5mj~8?RF@49(LW%@_dunjB~FN@voejBus>>dC-mV2Scm z+R`;SQzO)LBKF?oe%S{hrs>b`u|3v69q^Bxk&*f?WA9}OT`&WH`o|5?e*F~BqfjRu z%B0RQ6h(4wRym)F03h9qMzi5mA(^#_He{PVM4ugS@7qGmIfuo|x3nQyK}&@E4ym=d zH@u57lJzLhkw!kmv8)-d_^)xF5}!)JE$ zK&afPL$1%4W9^&kx6}9?FK$snSBGfw)mdjbT~!$qpEOQV2V1w6ILBXg@p{)5tFamf!AAZ>3`0MctVV<>OrBaidjiJ~k#2o_(OI`6^{I-a{Eq z^e1(3cA;VD=K1>*E=^cg&fWmL@@8tR8MzlDh=*Ed?p0Y*vCo8yzHe8SI%9C$-(7{Bw#3$#ftHH2xjCW z1oEnp!ud_(+$Hykc?c&|A_TJU<@5+nc{!D;Qr zr|WegT*8)h_J&lLjx~2)+z?k2ZrSK_;)JDc9rQ6{^-JE(7nRePm41Xj>NUu@W z`fj_tdcae`LV@~5=WEI{?}L2lOr`cV&YZ#Fh(pVhzjHCy#&ic9Yz=1jas9IB29K3u zEIu#|;0-T^zi623Ms%IkbvMvuis>3d+_QrvXG0S*Dgb#tOM-4lPq>4CS1>2Zb1yb1 z8~B9eqXB{H#%TJ4FtzAPm=0k#xtQiV+BDnz96N~PzY^X179rGG4kgF70Q^I>z!KdC z&BwOMqqq$TR?O)5$SU_V%Di-q3#GKjDT{c1yHy4OIql>c_aZ5~j;Z-FqoPO7>5*R7 z?!3*ggX+4tRbyN3smbFuY3~oO;FuL}Q8!SuWB@2`3ZziARxq7W6v{8XV3c1@K0l;{ zcM#(DkvF>twg?CW{N(6zx{FO^brpY-(#iw1R!x`qI_VTD0G@R!lK>N>0x5PEpNBg> zlemv60Or*)fC?L#K!%S_BBLi{L~yfvwn&onI0{ID#*QA6M>_&bC0{=X3sSlh_`f4x ziwMi&PE21C)WqB1h0tpBOVMR)P$Q0xID?4@-ClX}Ei(QQTA}t2C4~aQ3o*B70~8Tc zh769Y3(!9m3Y(N_hD#n(!M}DjJXSF1_J>Pd9J>;CYFm!uaE!zl>RGmeInK(wk|RD zI#Z4} zVNu3Z^1&Kgl-jR7A!Foljubidw*-vbksj}ZDev+MIULtdt;)>ht_{<5cKgp-lpo(m z>Mg(Im!#P3APp`}?SwCIG#7Hi)uJl;A~15D*69T5VR?;1lw*cTBO%3%;}>g2pl8@c zQ}Cu|AR{4~O+gRrW*|q`1SvxFkt*27fyUu0ihzwF>ht)&#W|TQ8BaD6vcKXdN^Ukb z3je>0bhm9JMTdHl%# zR{g&&_@kZ2{I7NWt~(n!e3QLmh`+NUgx|N!7-qc?h|kf#0d}66Y1Tx!PLWv5S1qWt zSTM~$$_kZ@t6ppgJ>&Mr<$2xMGMdBf(g5icBR*jH;;91O+!;N<;FL|d)?bK!QvY^0 zh7?cUYmCh0$f5Eu{@uu!iXiKWsdwFtUwA+Jc56%^OX_MHOM=svT7ax0n-gm#?;)mRLsXO(~Xw+lq)DQ95!WmEEmZ$8DHm zz}-;8=@qH8!|8i!T-+ZP4z>|3tGElh$6b$Iq0SBLKfKsUZN3SJD+P9sk7n+Q-ZRHb z73(4qR!9#uc5eIaEa_xn8pBskH=awBjgqc}T@y)p?>nf~fI7r2{I|;J%$jXo_Lpkr zQc#EFTt{t{7dY1I?l5gVspe%AA0?)hr={%g{du-JEI#ZWYZYD@RLk*f^-L-6DLjmE zXZCTm;TDPNM^ibIA^b0X5)*bO%O0iyV<=&@b#2iKnhwsx#4;iQ7-ehwNJnXHqaSgm zV^BcP#7^wLu2zinT>I=6?tOPgmWS^OL(ktdo2K|8%;V*+KRzP4N}F?BrrS;66v`YerJ;T6@-T;(&yI4 z&*)6bXG=kM(WRlALMBBNrjVH=}TH65pdsyVm!oH>N`rNUDNC}eotDlh=n55eewC)mTL zJFRm?cTyAx2ox-)=HXGSmsW7Rs})Qp-P|t=^J~zFB>=Gpq7``JRYnN$rU>!XyoSHD z3mD8A;u>O>|0FK^XQ68Qn+!+^pg4rl0HT%ed$`8qi!ycUNI@l zZeE+i*ebAm0!K+HaIxMKELUPKJCk&-sSDflI4oL-a%SB=^xM|;wi^U%S9RYixl%EQ z>P+;SqP|>xf;%E-S+%cj3to?R1{?eYZ$z|E{`1-fY+pX< za{>C~XS~W}%C?^RfBHD{Xeie>j!TiOWlge-&_%KoqsB$DjxE^}lOisYrtC{|Z$w6x zh8Up;Wt+(oLg;F;6*XjxB@#wyMAio3&bUtV&fI(Y&0lloe1Grr%|opI-uBV-*yeK0TSVa{m-DmA`S-&n#!r^IRF5>}a9k!g8`Vl!M7cZk*1Dgx!^gDx z_Hhx*x@Pxj8Ee8L>SHWV@n!BWb+@&{KcfA_)=D0sq&QC<>C@;D!vrTRke6Z}b-0S5 z6E)6Jq$0F<+f#U!p9|X^z=kZ(?vlx&o{T7l|Hy|)r_zGj8 zPF_d03}9-{M|^hA$C_6cX%DaPNO?*e?sVSk7)#9RzY=~>@Bu#rv$5QM7bc2d!8t9X z=FxgjZvS4y!^!a~{Oo;1B|-uC|L#1wMo8h1LR; z$nF#Hbm7Wj5$E8B%+)b-tPbSf(4d0N2_nj@1 zq=`Eswvx7_PBQ2HQWXQUAj!K+iGI7wOr|$fUTD|n+j0##y;u~AeAJpAT1(aMJZ)PB zCMo$3$;0=2+DN-|(Ok4UTVl^^qq_yr)$2a3p{l~}x~J_uaz}~3$zRpV@G)9>wp!)H zot6+*S7RZbI^RvzwIRlZn&&D7u5AbzS=&{G2wdDjbk$YM`l^?tt-pV6S3k(AJ#dvz zCtNMW`Q>;%45_7v8q`@zCP5yug#~~rYBOa_2gOq}@zVQ-OE8pyv;29mD&keE+QD*t z@E8{EjWDeuh#S|zR|#_?6R4ot>ZdDhNUa{-!r+HC^$IScnQUD;q2Bo}bF(`hIT55VXP?r*Y43t{GitZorBzvRAn;SK!Y!F>7nMi}a=2a&?$e0~i9)K1R%fd8`ggkW*i0Zd+MwS$J(#NeFhu`#|!ptvP6Ezw4D# z>e*YV_XnhTkxIBXDlb+GyysP# zW19YsHPOM+8n4FNFt1$v{%OGW7CYP!hvnbfK+kz2x&au|mcL9_mSEJ2EoQe!c*0Tzb}@Vfg0Ay(51d%^zn^gg<%Ksn}I@ z{IBL3F2zc7D@DbIQbDMs>Iro)Sj2llq(y0B);npz1McRGZ#vdtmwb3E#7IOagZHR{ zd=;_%Z*|*9mobZvUhfNE3P+EqrK{uD3lQ0J@DQB-Y9p4TU1#Yl)TS1VTP{K7$+edS z2O)+vra$LK zEb~F?4Jlrk+G1jA@G-n*r3|;{xCxBsDfC;F$4cMO<@YUJpxZ$@dJk1!q&D(8u3W3> zmVS}CPAysZ@(v~!Kf+VCv|7WRkF&1<&j~+X2sG`U^g!{+=1qqVdZ%cDCs9G@yssPF z6_@F6GRF%!3V6|6x-MM5Dia-J<8qSbn5KaPV0NJhPk&c>of^^_XuJmD=-~UZb7$l^ zV~UFf_bLU##S43I8gDGi_HDFj2@f}tK!zd)e7nz~?(}_+_(UCW=$^cPY4<(&|)kXvgvLn;UzK4Wz~iBysiNP9e^ zR4z>p=S|p7;rJoJN%28kn1E9IvUZU~-mh%1c-L2UxS@ka{%-*N&Sm7AO`)=WTX0`oL@xVJI^NfxYfpvRxSl`{fMTVY$)831R2RSz_X z(%lk_(Ba$CvvL7gQvjVj%rnrV6?St7z<+^N4s>!b7ouPM=L~+De^}MPhcV3K-%G2@ z=EYgPAFL^W-FW5!q#R`$z~(a?RyFXHrFZNZLDbq(Gy3 Date: Thu, 28 Jul 2022 11:23:39 +0300 Subject: [PATCH 05/13] Fix critical issue with open file handle leak on user guide folder --- .../controllers/UserGuideController.java | 47 ++++++++++--------- .../eudat/logic/managers/MetricsManager.java | 12 ++--- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/UserGuideController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/UserGuideController.java index 2a5dca57a..9e26cf92a 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/UserGuideController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/UserGuideController.java @@ -20,6 +20,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -41,32 +42,36 @@ public class UserGuideController { @RequestMapping(path = "{lang}", method = RequestMethod.GET ) public ResponseEntity getUserGuide(@PathVariable(name = "lang") String lang) throws IOException { - long files = Files.list(Paths.get(this.environment.getProperty("userguide.path"))).count(); - metricsManager.calculateValue(MetricNames.LANGUAGES, (int) files, null); - Stream walk = Files.walk(Paths.get(this.environment.getProperty("userguide.path"))); - List result = walk.filter(Files::isRegularFile) - .map(Path::toString).collect(Collectors.toList()); - - String fileName = result.stream().filter(guide -> guide.contains("_" + lang)).findFirst().orElse(null); - if (fileName == null) { - fileName = result.stream().filter(guide -> guide.contains("_en")).findFirst().get(); + long files = 0; + try (Stream paths = Files.list(Paths.get(Objects.requireNonNull(this.environment.getProperty("userguide.path"))))) { + files = paths.count(); } - InputStream is = new FileInputStream(fileName); + metricsManager.calculateValue(MetricNames.LANGUAGES, (int) files, null); + try (Stream paths = Files.walk(Paths.get(Objects.requireNonNull(this.environment.getProperty("userguide.path"))))) { + List result = paths.filter(Files::isRegularFile) + .map(Path::toString).collect(Collectors.toList()); - Path path = Paths.get(fileName); + String fileName = result.stream().filter(guide -> guide.contains("_" + lang)).findFirst().orElse(null); + if (fileName == null) { + fileName = result.stream().filter(guide -> guide.contains("_en")).findFirst().get(); + } + InputStream is = new FileInputStream(fileName); - HttpHeaders responseHeaders = new HttpHeaders(); - responseHeaders.setContentLength(is.available()); - responseHeaders.setContentType(MediaType.TEXT_HTML); - responseHeaders.set("Content-Disposition", "attachment;filename=" + path.getFileName().toString()); - responseHeaders.set("Access-Control-Expose-Headers", "Content-Disposition"); - responseHeaders.get("Access-Control-Expose-Headers").add("Content-Type"); + Path path = Paths.get(fileName); - byte[] content = new byte[is.available()]; - is.read(content); - is.close(); + HttpHeaders responseHeaders = new HttpHeaders(); + responseHeaders.setContentLength(is.available()); + responseHeaders.setContentType(MediaType.TEXT_HTML); + responseHeaders.set("Content-Disposition", "attachment;filename=" + path.getFileName().toString()); + responseHeaders.set("Access-Control-Expose-Headers", "Content-Disposition"); + responseHeaders.get("Access-Control-Expose-Headers").add("Content-Type"); - return new ResponseEntity<>(content, responseHeaders, HttpStatus.OK); + byte[] content = new byte[is.available()]; + is.read(content); + is.close(); + + return new ResponseEntity<>(content, responseHeaders, HttpStatus.OK); + } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/MetricsManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/MetricsManager.java index 63bac9c04..b39aebd6d 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/MetricsManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/MetricsManager.java @@ -17,15 +17,13 @@ import javax.annotation.PostConstruct; import javax.transaction.Transactional; import java.io.IOException; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.ZoneId; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -179,8 +177,10 @@ public class MetricsManager { calculateValue(MetricNames.USERS, (int) userManager.countActiveUsers().intValue(), MetricNames.LOGGEDIN); calculateValue(MetricNames.USERS, (int) userManager.countAllUsers().intValue(), MetricNames.TOTAL); - long files = Files.list(Paths.get(this.environment.getProperty("userguide.path"))).count(); - calculateValue(MetricNames.LANGUAGES, (int) files, null); + try (Stream paths = Files.list(Paths.get(Objects.requireNonNull(this.environment.getProperty("userguide.path"))))) { + long files = paths.count(); + calculateValue(MetricNames.LANGUAGES, (int) files, null); + } calculateValue(MetricNames.INSTALLATIONS, 1, null); calculateValue(MetricNames.NEXUS + MetricNames.INSTALLATIONS, 1, null); From 49e42e9cba3917726232fcd262b1bdca37d573cd Mon Sep 17 00:00:00 2001 From: "konstantina.galouni" Date: Thu, 28 Jul 2022 17:30:44 +0300 Subject: [PATCH 06/13] h2020_dataset.docx & WordBuilder.java & DataManagementPlanManager.java & DatasetManager.java: Updated footer of Dataset template to set title of DMP and Dataset. --- .../managers/DataManagementPlanManager.java | 2 +- .../eudat/logic/managers/DatasetManager.java | 2 +- .../utilities/documents/word/WordBuilder.java | 6 +++++- .../resources/documents/h2020_dataset.docx | Bin 20313 -> 20315 bytes 4 files changed, 7 insertions(+), 3 deletions(-) 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 e3ad07e0e..f492e2a9d 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 @@ -1368,7 +1368,7 @@ public class DataManagementPlanManager { document.removeBodyElement(powered_pos + 1); } - wordBuilder.fillFooter(dmpEntity, document, false); + wordBuilder.fillFooter(dmpEntity, null, document, false); String fileName = "DMP_" + dmpEntity.getGrant().getLabel(); if (versioned) { 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 145439921..20dd25807 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 @@ -407,7 +407,7 @@ public class DatasetManager { throw new UnauthorisedException(); wordBuilder.fillFirstPage(dmpEntity, datasetEntity, document); - wordBuilder.fillFooter(dmpEntity, document, true); + wordBuilder.fillFooter(dmpEntity, datasetEntity, document, true); int powered_pos = wordBuilder.findPosOfPoweredBy(document); XWPFParagraph powered_par = null; diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java index bc92b70e1..0d34203a3 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java @@ -770,7 +770,7 @@ public class WordBuilder { } } - public void fillFooter(DMP dmpEntity, XWPFDocument document, boolean isDataset) { + public void fillFooter(DMP dmpEntity, Dataset datasetEntity, XWPFDocument document, boolean isDataset) { document.getFooterList().forEach(xwpfFooter -> { List runs = xwpfFooter.getParagraphs().get(0).getRuns(); if(runs != null){ @@ -781,6 +781,10 @@ public class WordBuilder { text = text.replace("{ARGOS.DMP.TITLE}", dmpEntity.getLabel()); r.setText(text, 0); } + if(text.contains("{ARGOS.DATASET.TITLE}") && datasetEntity != null){ + text = text.replace("{ARGOS.DATASET.TITLE}", datasetEntity.getLabel()); + r.setText(text, 0); + } if(text.contains("{ARGOS.DMP.LICENSE}")){ try{ Map license = ((Map) mapper.readValue(dmpEntity.getExtraProperties(), Map.class).get("license")); diff --git a/dmp-backend/web/src/main/resources/documents/h2020_dataset.docx b/dmp-backend/web/src/main/resources/documents/h2020_dataset.docx index 1270a2895c87afa878a63381d0dbdd71ccec822e..4963e3c18449df7981886f8ea392fecc25523d39 100644 GIT binary patch delta 3578 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 delta 3668 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 S=zoi_h!-}zNmi+QvG{+a6=7%q From 19d8218dea42e35aa9e24753889adbcd7e7c6f79 Mon Sep 17 00:00:00 2001 From: argirok Date: Fri, 29 Jul 2022 10:39:39 +0300 Subject: [PATCH 07/13] Added pl.json and update localization files --- dmp-frontend/src/assets/i18n/de.json | 3 +- dmp-frontend/src/assets/i18n/en.json | 3 +- dmp-frontend/src/assets/i18n/es.json | 3 +- dmp-frontend/src/assets/i18n/gr.json | 3 +- dmp-frontend/src/assets/i18n/hr.json | 3 +- dmp-frontend/src/assets/i18n/pl.json | 1884 +++++++++++++++++ dmp-frontend/src/assets/i18n/pt.json | 3 +- dmp-frontend/src/assets/i18n/sk.json | 3 +- dmp-frontend/src/assets/i18n/sr.json | 3 +- dmp-frontend/src/assets/i18n/tr.json | 3 +- .../src/assets/resources/language.json | 4 + 11 files changed, 1906 insertions(+), 9 deletions(-) create mode 100644 dmp-frontend/src/assets/i18n/pl.json diff --git a/dmp-frontend/src/assets/i18n/de.json b/dmp-frontend/src/assets/i18n/de.json index 56158b077..9e0e2ed4e 100644 --- a/dmp-frontend/src/assets/i18n/de.json +++ b/dmp-frontend/src/assets/i18n/de.json @@ -178,7 +178,8 @@ "SLOVAK": "Slovak", "SERBIAN": "Serbian", "PORTUGUESE": "Portuguese", - "CROATIAN": "Croatian" + "CROATIAN": "Croatian", + "POLISH": "Polish" } }, "COOKIE": { diff --git a/dmp-frontend/src/assets/i18n/en.json b/dmp-frontend/src/assets/i18n/en.json index 28b58596c..6f563ad38 100644 --- a/dmp-frontend/src/assets/i18n/en.json +++ b/dmp-frontend/src/assets/i18n/en.json @@ -178,7 +178,8 @@ "SLOVAK": "Slovak", "SERBIAN": "Serbian", "PORTUGUESE": "Portuguese", - "CROATIAN": "Croatian" + "CROATIAN": "Croatian", + "POLISH": "Polish" } }, "COOKIE": { diff --git a/dmp-frontend/src/assets/i18n/es.json b/dmp-frontend/src/assets/i18n/es.json index 095827b6d..1c1d11e2d 100644 --- a/dmp-frontend/src/assets/i18n/es.json +++ b/dmp-frontend/src/assets/i18n/es.json @@ -178,7 +178,8 @@ "SLOVAK": "Eslovaco", "SERBIAN": "Serbio", "PORTUGUESE": "Portugués", - "CROATIAN": "Croatian" + "CROATIAN": "Croatian", + "POLISH": "Polish" } }, "COOKIE": { diff --git a/dmp-frontend/src/assets/i18n/gr.json b/dmp-frontend/src/assets/i18n/gr.json index 531b386a7..9cf4eca81 100644 --- a/dmp-frontend/src/assets/i18n/gr.json +++ b/dmp-frontend/src/assets/i18n/gr.json @@ -178,7 +178,8 @@ "SLOVAK": "Σλοβάκικα", "SERBIAN": "Σερβικά", "PORTUGUESE": "Πορτογαλικά", - "CROATIAN": "Κροατικά" + "CROATIAN": "Κροατικά", + "POLISH": "Πολωνικά" } }, "COOKIE": { diff --git a/dmp-frontend/src/assets/i18n/hr.json b/dmp-frontend/src/assets/i18n/hr.json index d3720b3bd..69b1ab7d2 100644 --- a/dmp-frontend/src/assets/i18n/hr.json +++ b/dmp-frontend/src/assets/i18n/hr.json @@ -178,7 +178,8 @@ "SLOVAK": "Slovački", "SERBIAN": "Srpski", "PORTUGUESE": "Portugalski", - "CROATIAN": "Hrvatski" + "CROATIAN": "Hrvatski", + "POLISH": "Polish" } }, "COOKIE": { diff --git a/dmp-frontend/src/assets/i18n/pl.json b/dmp-frontend/src/assets/i18n/pl.json new file mode 100644 index 000000000..32ef97254 --- /dev/null +++ b/dmp-frontend/src/assets/i18n/pl.json @@ -0,0 +1,1884 @@ +{ + "GENERAL": { + "VALIDATION": { + "REQUIRED": "Wymagane", + "GRANT-START-AFTER-END": "Data rozpoczęcia grantu nie może być późniejsza niż data jego zakończenia", + "PATTERN-_": "Znak \"_\" jest niedozwolony", + "URL": { + "LABEL": "URL", + "MESSAGE": "Proszę podać poprawny adres URL" + } + }, + "DELETE-CONFIRMATION": { + "TITLE": "Ostrzeżenie", + "MESSAGE": "Czy na pewno chcesz usunąć ten element", + "POSITIVE": "Tak", + "NEGATIVE": "Anuluj" + }, + "SNACK-BAR": { + "SUCCESSFUL-CREATION": "Utworzono pomyślnie", + "SUCCESSFUL-UPDATE": "Aktualizacja zakończona", + "SUCCESSFUL-LOGIN": "Zalogowano", + "SUCCESSFUL-LOGOUT": "Wylogowano", + "SUCCESSFUL-EMAIL-SEND": "Email został wysłany", + "SUCCESSFUL-COPY-TO-CLIPBOARD": "Skopiowano do schowka", + "UNSUCCESSFUL-LOGOUT": "Nie udało się wylogować", + "UNSUCCESSFUL-LOGIN": "Nie udało się zalogować", + "SUCCESSFUL-DATASET-PROFILE-DELETE": "Usunięto", + "UNSUCCESSFUL-DATASET-PROFILE-DELETE": "Tego szablonu nie można usunąć, ponieważ są z nim powiązane zbiory danych", + "SUCCESSFUL-DELETE": "Usunięto", + "UNSUCCESSFUL-DELETE": "Nie udało się usunąć", + "UNSUCCESSFUL-EMAIL-SEND": "Email nie został wysłany", + "UNSUCCESSFUL-REMOVE-TEMPLATE": "Nie udało się usunąć szablonu, co najmniej jeden zbiór danych tego DMP używa tego szablonu" + }, + "ERRORS": { + "HTTP-REQUEST-ERROR": "Wystąpił nieoczekiwany błąd" + }, + "NAMES": { + "DATASET": "Zbiór danych" + }, + "STATUSES": { + "EDIT": "Edytowane", + "FINALISED": "Ukończone" + }, + "FORM-VALIDATION-DISPLAY-DIALOG": { + "WARNING": "Ostrzeżenie!", + "THIS-FIELD": "Pole", + "HAS-ERROR": "ma błąd", + "REQUIRED": "Wymagany", + "EMAIL": "Niepoprawny e-mail", + "MIN-VALUE": "Minimalna wartość powinna wynosić {{min}}", + "MAX-VALUE": "Maksymalna wartość powinna wynosić {{max}}", + "ACTIONS": { + "CANCEL": "Zamknij" + } + }, + "CONFIRMATION-DIALOG": { + "DELETE-ITEM": "Usunąć ten element?", + "DELETE-USER": "Usunąć tego współpracownika?", + "FINALIZE-ITEM": "Zakończyć prace nad tym elementem?", + "UNFINALIZE-ITEM": "Cofnąć finalizację?", + "PUBLISH-ITEM": "Opublikować ten element?", + "ADD-DATASET": " Czy chcesz kontynuować, dodając zestaw danych do swojego DMP? Zawsze możesz dodać więcej zestawów danych za pomocą menu \"Dodaj zestaw danych (kreator)\".", + "ZENODO-DOI": "Czy chcesz utworzyć cyfrowy identyfikator obiektu (DOI) z kontem {{username}} dla DMP?", + "LEAVE-PAGE": "Jeśli opuścisz stronę, Twoje zmiany zostaną utracone.", + "LEAVE-WARNING": "Masz niezapisane zmiany!", + "PRIVACY-POLICY-NAMES": "Nazwiska wszystkich osób zaangażowanych w ten DMP będą widoczne publicznie. Czy zgadzasz się na to?", + "ACTIONS": { + "CONFIRM": "Tak", + "NO": "Nie", + "DELETE": "Usuń", + "REMOVE": "Usuń", + "CANCEL": "Anuluj", + "LEAVE": "Wyjdź", + "POLICY-AGREE": "Upublicznij nazwy", + "REQUIRED": "Wymagane zaznaczenie pola wyboru" + } + }, + "NOTIFICATION-DIALOG": { + "POPUP": { + "TITLE": "Brakujący zbiór danych", + "MESSAGE": "Należy utworzyć co najmniej jeden zestaw danych, aby kontynuować zapisywanie DMP.", + "CLOSE": "Zamknij" + } + }, + "START-NEW-DMP-DIALOG": { + "IMPORT": "Import", + "FUNCTION-SUPPORTS": "obsługuje", + "JSON-FILES": "pliki .json", + "PRODUCED": "utworzone", + "RDA-SPECIFICATIONS": "zgodnie ze specyfikacjami RDA", + "MACHINE-ACTIONABLE": "dla DMP uruchamianych automatycznie", + "UPLOAD-FILE": "Prześlij plik", + "REPLACE-FILE": "Przenieś plik" + }, + "INVITATION-DIALOG": { + "HINT": "Wpiszj przecinek lub wciśnij enter pomiędzy autorami", + "SUCCESS": "Zaproszenie wysłane", + "ERROR": "Nie udało się wysłać zaproszenia" + }, + "DMP-TO-DATASET-DIALOG": { + "FROM-DMP": "Utworzyłeś swój", + "DMP": "DMP", + "TO-DATASET": "Zostaniesz przeniesiony do", + "DATASET": "Zbioru danych", + "EDITOR": "edytora", + "START": "Zaczynamy" + }, + "ACTIONS": { + "VIEW-ALL": "Zobacz wszystko", + "SHOW-MORE": "Pokaż więcej", + "LOAD-MORE": "Załaduj więcej", + "SHOW-LESS": "Pokaż mniej", + "LOG-IN": "Zaloguj się", + "TAKE-A-TOUR": "Potrzebujesz pomocy? Skorzystaj z przewodnika" + }, + "PREPOSITIONS": { + "OF": "o" + }, + "TITLES": { + "PREFIX": "Argos - ", + "GENERAL": "Kreator planów zarządzania danymi", + "ABOUT": "O aplikacji", + "PRIVACY": "Polityka prywatności", + "OPENSOURCE-LICENCES": "Licencje Opensource", + "TERMS": "Warunki korzystania z usługi", + "COOKIES-POLICY": "Polityka dotycząca plików cookie", + "PLANS": "Moje DMP", + "EXPLORE-PLANS": "Opublikowane DMP", + "QUICK-WIZARD": "Nowy DMP (kreator)", + "PLANS-NEW": "Nowy DMP (ekspert)", + "DMP-NEW": "Nowy DMP", + "DATASETS": "Moje zbiory danych", + "EXPLORE": "Opublikowane zbiory danych", + "DATASETCREATEWIZARD": "Dodaj zbiór danych (kreator)", + "GRANTS": "Moje dotacje", + "DMP-PROFILES": "Szablony DMP", + "DATASET-PROFILES": "Szablony zbiorów danych", + "USERS": "Użytkownicy", + "PROFILE": "Mój profil", + "LOGIN": "Zaloguj", + "DMP-OVERVIEW": "Przegląd DMP", + "DMP-EDIT": "Edytuj DMP", + "DATASET-OVERVIEW": "Przegląd zbioru danych", + "DATASET-EDIT": "Wyświetl/edytuj zbiór danych", + "DMP-NEW-VERSION": "Nowa wersja DMP", + "DMP-CLONE": "Kopiuj DMP", + "DATASET-NEW": "Nowy zbiór danych", + "GRANT-NEW": "Nowa dotacja", + "GRANT-EDIT": "Wyświetl/edytuj dotację", + "DMP-PROFILE-NEW": "Nowy szablon DMP", + "DMP-PROFILE-EDIT": "Edytuj szablon DMP", + "DATASET-PROFILES-NEW": "Nowy szablon zbioru danych", + "DATASET-PROFILES-EDIT": "Edytuj szablon zbioru danych", + "EXPLORE-PLANS-OVERVIEW": "Podgląd opublikowanych DMP", + "DATASET-PUBLIC-EDIT": "Wyświetl opublikowany zbiór danych", + "DMP-PUBLIC-EDIT": "Wyświetl opublikowany DMP", + "DATASET-COPY": "Kopiuj zbiór danych", + "DATASET-UPDATE": "Aktualizuj zbiór danych", + "DATASET-PROFILES-NEW-VERSION": "Nowa wersja szablonu zbioru danych", + "DATASET-PROFILES-CLONE": "Nowy klon szablonu zbioru danych", + "LANGUAGE-EDITOR": "Edytor języka", + "GUIDE-EDITOR": "Edytor podręcznika użytkownika", + "LANGUAGE": "Język", + "SIGN-IN": "Zaloguj się na konto" + }, + "FILE-TYPES": { + "PDF": "PDF", + "XML": "XML", + "JSON": "RDA JSON", + "DOC": "Dokument" + }, + "LANGUAGES": { + "ENGLISH": "Angielski", + "GREEK": "Grecki", + "SPANISH": "Hiszpański", + "GERMAN": "Niemiecki", + "TURKISH": "Turecki", + "SLOVAK": "Słowacki", + "SERBIAN": "Serbski", + "PORTUGUESE": "Portugalski", + "CROATIAN": "Chorwacki", + "POLISH": "Polish" + } + }, + "COOKIE": { + "MESSAGE": "Ta strona korzysta z plików cookie w celu zwiększenia komfortu użytkowania.", + "DISMISS": "Akceptuj", + "DENY": "Odrzuć pliki cookies", + "LINK": "Dowiedz się więcej", + "POLICY": "Polityka dot. plików cookies" + }, + "EMAIL-CONFIRMATION": { + "EXPIRED-EMAIL": "Zaproszenie wysłane przez e-mail wygasło", + "CARD-TITLE": "e-mail", + "REQUEST-EMAIL-HEADER": "Prawie skończyliśmy! Proszę wpisać swój e-mail.", + "REQUEST-EMAIL-TEXT": "Warunkiem korzystania z aplikacji jest potwierdzenie", + "SUBMIT": "Prześlij", + "SENT-EMAIL-HEADER": "E-mail został wysłany! Sprawdź swoją skrzynkę", + "EMAIL-FOUND": "Adres e-mail został potwierdzony" + }, + "HOME": { + "DMPS": "DMPs", + "DATASETS": "Zbiory danych", + "LOGIN": { + "TITLE": "Login", + "TEXT": "Posiadanie konta w ARGOS nie jest wymagane" + } + }, + "NAV-BAR": { + "BREADCRUMB-ROOT": "Panel sterowania", + "TITLE": "ARGOS", + "GRANTS": "Dotacje", + "GRANT": "Dotacja", + "DMP": "DMP", + "DMPS": "DMPs", + "MY-DMPS": "Mój DMPs", + "DATASETS": "Zbiory danych", + "DATASET": "Zbiór danych", + "PUBLIC-DATASETS": "Poznaj ARGOS", + "USERS": "Użytkownicy", + "DATASETS-ADMIN": "Szablony zbiorów danych", + "DMP-PROFILES": "Szablony DMP", + "ABOUT": "O aplikacji", + "MY-DATASET-DESCRIPTIONS": "MOJE ZBIORY DANYCH", + "DATASET-DESCRIPTION-WIZARD": "Kreator zbioru danych", + "PUBLIC DATASETS": "OPUBLIKOWANE ZBIORY DANYCH", + "PUBLIC-DMPS": "OPUBLIKOWANE DMPS", + "HOME": "Strona główna", + "DMP-WIZARD": "Kreator DMP", + "DATASET-TEMPLATES": "SZABLONY ZBIORU DANYCH", + "TEMPLATE": "SZABLON", + "DMP-TEMPLATES": "SZABLON DMP", + "USERS-BREADCRUMB": "UŻYTKOWNICY", + "START-NEW-DMP": "Uruchom nowy DMP", + "START-NEW-DMP-TXT": "Rozpocznij od nowa lub kontynuuj pracę w Argos! Utwórz nowy DMP lub prześlij istniejący DMP do Argos", + "START-WIZARD": "Uruchom kreator", + "IMPORT-FROM-FILE": "Importuj z pliku", + "SEARCH": { + "DATASET": "Zbiór danych", + "DMP": "DMP", + "GRANT": "Dotacja", + "PUBLISHED": "Opublikowany" + } + }, + "SIDE-BAR": { + "GENERAL": "OGÓLNY", + "ABOUT": "O aplikacji", + "DASHBOARD": "Strona główna", + "DMP": "PLANY ZARZĄDZANIA DANYMI", + "MY-DMPS": "Moje DMPs", + "DATASETS": "ZBIÓR DANYCH", + "GRANTS": "DOTACJE", + "NEW DATASET": "Nowy zbiór danych", + "QUICK-WIZARD": "Nowy DMP (kreator)", + "QUICK-WIZARD-DATASET": "Dodaj zbiór danych (kreator)", + "ADD-EXPERT": "Nowy DMP (Expert)", + "MY-DATASET-DESC": "Opis mojego zbioru danych", + "MY-DATASETS": "Moje zbiory danych", + "MY-GRANTS": "Moje dotacje", + "HISTORY": "HISTORIA", + "HISTORY-VISITED": "OSTATNIO ODWIEDZANE", + "HISTORY-EDITED": "OSTATNIO EDYTOWANE", + "PUBLIC": "OPUBLIKOWANE", + "PUBLIC-DMPS": "Publiczne DMPs", + "PUBLIC-DESC": "Publiczne opisy zbiorów danych", + "ACCOUNT": "KONTO", + "ADMIN": "ADMINISTRATOR", + "DATASET-TEMPLATES": "Szablony zbiorów danych", + "DMP-TEMPLATES": "Szablony DMP", + "USERS": "Użytkownicy", + "LANGUAGE-EDITOR": "Edytor języka", + "GUIDE-EDITOR": "Edytor podręcznika użytkownika", + "CO-BRANDING": "Wspólne oznaczenie", + "SUPPORT": "Wsparcie", + "FEEDBACK": "Wyślij opinię" + }, + "DATASET-PROFILE-EDITOR": { + "TITLE": { + "NEW": "Nowy klient API", + "NEW-PROFILE": "Nowy szablon zbioru danych", + "NEW-PROFILE-VERSION": "Nowa wersja", + "NEW-PROFILE-CLONE": "Nowy klon" + }, + "FIELDS": { + "DATASET-TITLE": "Nazwa szablonu zbioru danych", + "DATASET-DESCRIPTION": "Opis", + "ROLES": "Role" + }, + "STEPS": { + "GENERAL-INFO": { + "TITLE": "Informacje ogólne", + "DATASET-TEMPLATE-NAME": "Nazwa szablonu zbioru danych", + "DATASET-TEMPLATE-NAME-HINT": "Tytuł określający szablon zbioru danych", + "DATASET-TEMPLATE-DESCRIPTION": "Opis", + "DATASET-TEMPLATE-DESCRIPTION-HINT": "Krótki opis roli, zakresu i celów zbioru danych", + "DATASET-TEMPLATE-LANGUAGE": "Język szablonu zbioru danych", + "DATASET-TEMPLATE-SELECT-LANGUAGE": "Wybierz język", + "DATASET-TEMPLATE-USERS": "Redaktorzy", + "DATASET-TEMPLATE-USERS-HINT": "Dodaj redaktorów i zapisz zmiany, aby ich powiadomić.", + "DATASET-TEMPLATE-REMOVE-USER": "Usuń redaktora", + "DATASET-TEMPLATE-NO-USERS-YET": "... Nie ma jeszcze redaktorów", + "DATASET-TEMPLATE-VALIDATE-AND-ADD-USER": "Zweryfikuj i dodaj redaktora", + "DATASET-TEMPLATE-DESCRIPTION-PLACEHOLDER": "Opis szablonu zbioru danych", + "UNTITLED": "Bez tytułu", + "QUESTION": "Pytanie", + "TEMPLATE-OUTLINE": "Zarys szablonu", + "ERRORS": { + "USER-NOT-FOUND": "Nie znaleziono użytkownika" + } + }, + "PAGE-INFO": { + "PAGE-NAME": "Nazwa rozdziału", + "PAGE-NAME-HINT": "Ustaw nazwę dla rozdziału w zbiorze danych", + "PAGE-DESCRIPTION": "Opis", + "PAGE-DESCRIPTION-HINT": "Opisz krótko treść rozdziału", + "ACTIONS": { + "CREATE-FIRST-PAGE": "Utwórz pierwszy rozdział", + "CREATE-NEW-SUBSECTION": "Sekcja", + "CREATE-NEW-SECTION": "Rozdział", + "CREATE-FIRST-SECTION": "Utwórz pierwszy rozdział", + "NOTHING-HERE-HINT": "Nic tu jeszcze nie ma", + "START-CREATING-PAGE-START": "Rozpocznij od", + "START-CREATING-PAGE-END": "tworzenie pierwszego rozdziału", + "CREATE-SECTION": "Utwórz sekcję" + }, + "PAGE": "Rozdział" + }, + "SECTION-INFO": { + "SECTION-NAME": "Nazwa sekcji", + "SECTION-NAME-HINT": "Ustaw nazwę dla sekcji", + "SECTION-DESCRIPTION": "Opis", + "SECTION-DESCRIPTION-HINT": "Opisz krótko treść sekcji.", + "SECTION": "Sekcja" + }, + "PAGES": { + "TITLE": "Opis rozdziału", + "PAGE-PREFIX": "Rozdział", + "PAGE-INPUT-TITLE": "Tytuł rozdziału", + "DATASET-DETAILS": "Szczegóły zbioru danych", + "EXTERNAL-REFERENCES": "Odniesienia zewnętrzne", + "DESCRIPTION": "Opis" + }, + "FORM": { + "TITLE": "Opis formularza", + "SECTION": { + "TITLE": "Informacje o sekcji", + "FIELDS": { + "ID": "Unikalny identyfikator sekcji", + "TITLE": "Nazwa sekcji", + "PAGE": "Strona, która ma się pojawić", + "ORDER": "Kolejność", + "DESCRIPTION": "Opis", + "FIELDS-TITLE": "Pola", + "SUB-SECTIONS-TITLE": "Podsekcje" + }, + "ACTIONS": { + "ADD-SUB-SECTION": "Dodaj podsekcję +", + "ADD-FIELD": "Dodaj pole +" + } + }, + "COMPOSITE-FIELD": { + "TITLE": "Informacje o polu złożonym", + "SIMPLE-FIELD-TITLE": "Informacje o polu", + "SUB-FIELDS-TITLE": "Pola potomne", + "FIELDS": { + "COMPOSITE-CHECKBOX": "Pole złożone", + "MULTIPLICITY-CHECKBOX": "Wielkość", + "COMMENT-CHECKBOX": "Dołącz pole komentarza", + "COMPOSITE-TITLE": "Nazwa pola złożonego", + "FIELD-TITLE": "Nazwa pola", + "DESCRIPTION": "Opis", + "EXTENDED-DESCRIPTION": "Rozszerzony opis", + "ADDITIONAL-INFORMATION": "Informacje dodatkowe", + "MULTIPLICITY-MIN": "$Minimalna wielokrotność$", + "MULTIPLICITY-MAX": "$Maksymalna wielokrotność$", + "MULTIPLICITY-PLACEHOLDER": "$Tekst zastępujący wielokrotność$", + "MULTIPLICITY-ADD-ONE-FIELD": "Dodaj więcej", + "ORDER": "Kolejność", + "COMMENT-PLACEHOLDER": "Proszę doprecyzować", + "COMMENT-HINT": "Podaj dodatkowe informacje lub uzasadnienie swojego wyboru", + "RDA-COMMON-STANDARDS": "Wspólne standardy RDA", + "EXPORT": "Uwzględnij w eksporcie" + }, + "ACTIONS": { + "ADD-CHILD-FIELD": "Dodaj pole podrzędne +" + } + }, + "FIELD": { + "FIELDS": { + "RULES-TITLE": "Pytania warunkowe", + "FIELD-RULES-VALUE": "Wartość", + "ID": "Unikalny identyfikator sekcji", + "VIEW-STYLE": "Typ", + "MULTIPLICITY-MIN": "$Minimalna wielokrotność$", + "MULTIPLICITY-MAX": "$Maksymalna wielokrotność$", + "ORDER": "Kolejność", + "DEFAULT-VALUE": "Wartość domyślna", + "VALIDATION": "Sprawdzenie", + "MULTIPLICITY-CHECKBOX": "$Wielokrotność$", + "FIELD-TEXT-AREA-TITLE": "Dane obszaru tekstowego", + "FIELD-TEXT-AREA-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-RICH-TEXT-AREA-TITLE": "Dane obszaru tekstu sformatowanego", + "FIELD-RICH-TEXT-AREA-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-UPLOAD-TITLE": "Prześlij", + "FIELD-UPLOAD-PLACEHOLDER": "Prześlij tekst zastępczy", + "FIELD-UPLOAD-MAX-FILE-SIZE": "Maksymalny rozmiar pliku (do {{maxfilesize}} megabajtów)", + "FIELD-UPLOAD-CUSTOM-FILETYPE": "Inne typy plików", + "FIELD-UPLOAD-SELECT-FILETYPE": "Wybierz typy plików", + "FIELD-UPLOAD-LABEL": "nazwa typu nośnika", + "FIELD-UPLOAD-VALUE": "wartość typu nośnika", + "FIELD-BOOLEAN-DECISION-TITLE": "Dane decyzji logicznej", + "FIELD-BOOLEAN-DECISION-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-CHECKBOX-TITLE": "Dane pola wyboru", + "FIELD-CHECKBOX-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-FREE-TEXT-TITLE": "Dane dotyczące tekstu niesformatowanego", + "FIELD-FREE-TEXT-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-COMBO-BOX-TYPE": "Typ Combo Box", + "FIELD-WORD-LIST-TITLE": "Dane dotyczące listy słów", + "FIELD-WORD-LIST-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-WORD-LIST-LABEL": "Etykieta", + "FIELD-WORD-LIST-VALUE": "Wartość", + "FIELD-INTERNAL-DMP-ENTITIES-TYPE": "$Typ wewnętrznego obiektu DMP$", + "FIELD-RESEARCHERS-TITLE": "Autouzupełnianie badaczy", + "FIELD-RESEARCHERS-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-DATASETS-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-DMPS-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-RADIO-BOX-TITLE": "Dane przełącznika opcji", + "FIELD-RADIO-BOX-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-RADIO-BOX-LABEL": "Etykieta", + "FIELD-RADIO-BOX-VALUE": "Wartość", + "FIELD-AUTOCOMPLETE-TITLE": "Autouzupełnianie danych", + "FIELD-AUTOCOMPLETE-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-AUTOCOMPLETE-SOURCE-TITLE": "Źródła", + "FIELD-AUTOCOMPLETE-ADD_SOURCE": "Dodaj źródło", + "FIELD-AUTOCOMPLETE-TYPE": "Typ źródła", + "FIELD-AUTOCOMPLETE-TYPE-UNCACHED": "$Bez danych tymczasowych$", + "FIELD-AUTOCOMPLETE-TYPE-CACHED": "$Z danymi tymczasowymi$", + "FIELD-AUTOCOMPLETE-LABEL": "Etykieta", + "FIELD-AUTOCOMPLETE-VALUE": "Wartość", + "FIELD-AUTOCOMPLETE-SOURCE": "Źródło", + "FIELD-AUTOCOMPLETE-URL": "Url", + "FIELD-AUTOCOMPLETE-OPTIONS-ROOT": "$Opcje główne$", + "FIELD-DATE-PICKER-TITLE": "Wybierz datę", + "FIELD-DATE-PICKER-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-DATE-PICKER-LABEL": "Etykieta", + "FIELD-DATE-PICKER-VALUE": "Wartość", + "FIELD-MULTIPLE-AUTOCOMPLETE": "$Powiel autouzupełnianie$", + "FIELD-MULTIPLE-WORDLIST": "Pole wielokrotnego wyboru", + "FIELD-CURRENCY-TITLE": "$Dane dotyczące częstotliwości użycia$", + "FIELD-CURRENCY-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-REGISTRIES-TITLE": "Metadane", + "FIELD-REGISTRIES-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-SERVICES-TITLE": "Dane usług", + "FIELD-SERVICES-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-ORGANIZATIONS-TITLE": "Dane organizacji", + "FIELD-ORGANIZATIONS-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-EXTERNAL-DATASETS-TITLE": "Dane zewnętrznych zbiorów danych", + "FIELD-EXTERNAL-DATASETS-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-DATA-REPOSITORIES-TITLE": "Dane repozytoriów danych", + "FIELD-DATA-REPOSITORIES-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-PUB-REPOSITORIES-TITLE": "Repozytoria publikacji", + "FIELD-PUB-REPOSITORIES-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-JOURNALS-REPOSITORIES-TITLE": "Dzienniki", + "FIELD-JOURNALS-REPOSITORIES-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-TAXONOMIES-TITLE": "Dane dotyczące taksonomii", + "FIELD-TAXONOMIES-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-LICENSES-TITLE": "Dane licencji", + "FIELD-LICENSES-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-PUBLICATIONS-TITLE": "Dane publikacji", + "FIELD-PUBLICATIONS-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-TAGS-TITLE": "Dane tagów", + "FIELD-TAGS-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-DATASET-IDENTIFIER-TITLE": "Dane identyfikatora zbioru danych", + "FIELD-DATASET-IDENTIFIER-PLACEHOLDER": "Wprowadź tekst zastępczy", + "FIELD-VALIDATOR-TITLE": "Walidator danych", + "FIELD-VALIDATOR-PLACEHOLDER": "Wprowadź tekst zastępczy", + "EXTERNAL-DATASET-TYPE-NAME": "Typ", + "EXTERNAL-DATASET-TYPES": { + "PRODUCED": "Utworzony zbiór danych", + "REUSED": "Ponownie wykorzystany zestaw danych", + "OTHER": "Inne" + } + }, + "ERROR-MESSAGES": { + "FIELD-OTHER-SOURCES-REQUIRED": "Należy podać co najmniej jedno źródło.", + "FIELD-RADIO-AT-LEAST-ONE-REQUIRED": "Należy podać co najmniej jedną opcję.", + "FIELD-SELECT-AT-LEAST-ONE-REQUIRED": "Należy podać co najmniej jedną opcję." + }, + "DEFAULT-VALUES": { + "NONE": "Brak", + "BOOLEAN-DECISION": { + "YES": "Tak", + "NO": "Nie" + }, + "CHECK-BOX": { + "CHECKED": "Zaznaczone", + "UNCHECKED": "Niezaznaczone" + } + }, + "ACTIONS": { + "ADD-RULE": "Dodaj regułę widoczności +" + }, + "STATUS": { + "CALCULATING-PREVIEW": "... generowanie podglądu", + "PREVIEW-UPDATED": "Podgląd zaktualizowany!" + } + }, + "RULE": { + "FIELDS": { + "RULE-TYPE": "Rodzaj reguły", + "TARGET": "Identyfikator pola", + "VALUE": "Wymagana wartość", + "RULE-IF": "Jeśli wartość wynosi", + "RULE-THEN": "następnie pokaż pytanie", + "FIELDSETS": "Pytania", + "FIELDS": "Wejścia" + }, + "HINTS": { + "ELEMENT-CHILD-OF-TARGET": "Ten element jest nadrzędny dla? wybranego wejścia.", + "ELEMENT-HIDDEN-FROM-ELEMENT": "Ten element ukrywa element lub element nadrzędny danych wejściowych, z których próbujesz zastosować regułę widoczności." + } + }, + "FORM-VALIDATION": { + "ERROR-MESSAGES": { + "PAGE-MUST-HAVE-SECTION": "Każdy rozdział musi mieć przynajmniej jedną sekcję.", + "NEEDS-MORE-INFORMATION": " potrzebuje więcej informacji.", + "MUST-HAVE-SECTION-OR-FIELDSET": " musi zawierać sekcję lub pytanie.", + "MISSING": "Brak", + "PROVIDE-PAGE-AND-SECTION": "Upewnij się, że wprowadzono rozdział i co najmniej jedną sekcję na rozdział." + } + }, + "TABLE-OF-CONTENTS": { + "ERROR-MESSAGES": { + "FIELDSET-MUST-HAVE-PARENT-SECTION": "Pytanie może być tylko w ramch sekcji.", + "INPUT-SECTION-SAME-LEVEL": "Nie może mieć pytania i sekcji na tym samym poziomie.", + "DRAG-NOT-SUPPORTED": "Funkcja przeciągnij i upuść sekcję nie obsługuje miejsca docelowego.", + "PAGE-ELEMENT-ONLY-TOP-LEVEL": "Elementy rozdziału mogą znajdować się tylko na najwyższym poziomie" + } + } + }, + "TOOLKIT": { + "GENERAL-TOOLS": "Narzędzia pytań", + "NEW-INPUT-SET": "Dodaj pytanie", + "CLONE": "Klonuj", + "DELETE": "Usuń" + } + }, + "ACTIONS": { + "SAVE": "Zapisz", + "SAVE-AND-CONTINUE": "Zapisz i kontynuuj", + "SAVE-AND-CLOSE": "Zapisz i zamknij", + "FINALIZE": "Zakończ", + "UPDATE": "Aktualizuj", + "UPDATE-AND-CONTINUE": "Aktualizuj i kontynuuj", + "UPDATE-AND-CLOSE": "Aktualizuj i zamknij", + "CANCEL": "Anuluj", + "DELETE": "Usuń", + "ADD-PAGE": "Dodaj stronę +", + "ADD-SECTION": "Dodaj sekcję +", + "VALIDATE": "Sprawdź", + "PREVIEW-AND-FINALIZE": "Zobacz podgląd i zakończ", + "BACK-TO-TOP": "Powrót do gory", + "FIELD": { + "MAKE-IT-REQUIRED": "Wymagaj wprowadzenia", + "ADD-VISIBILITY-RULE": "Ustaw pytanie warunkowe", + "DELETE-INPUT": "Usuń", + "PREVIEW": "Podgląd", + "NOT-INITIALIZED": "Jeszcze nie rozpoczęto", + "MOVE-UP": "Przenieś to wprowadzanie wyżej", + "MOVE-DOWN": "Przesuń to wprowadzenie poniżej" + }, + "FIELDSET": { + "ADD-INPUT": "Dodaj wprowadzenie", + "COMMENT-FIELD": "Pole komentarza", + "INCLUDE-COMMENT-FIELD": "Do podanego pytania dołączane jest pole komentarza.", + "ENABLE-MULTIPLICITY": "Użytkownik może udzielić więcej niż jednej odpowiedzi na dane pytanie.", + "MULTIPLICITY": "Wielokrotność", + "MORE": "Więcej..." + } + }, + "FEEDBACK-MESSAGES": { + "SAVE-SUCCESS": "Zmiany zostały zapisane." + }, + "ERRORS": { + "INVALID-VISIBILITY-RULES": { + "MESSAGE-START": "Wykryto nieprawidłowe reguły widoczności w ", + "MESSAGE-END": ". Czy chcesz je naprawić?", + "CONFIRM-YES": "Tak, usuń niepoprawne reguły", + "CONFIRM-NO": "Nie, zachowaj je", + "REMOVE-SUCCESS": "Nieprawidłowe reguły widoczności zostały usunięte." + } + } + }, + "GRANT-LISTING": { + "TITLE": "Dotacje", + "SUBTITLE": "Podtytuł dotacji", + "ACTIONS": { + "NEW": "Nowa dotacja" + } + }, + "DMP-LISTING": { + "DMP": "DMP", + "GRANT": "Dotacja", + "TITLE": "Plany zarządzania danymi", + "OWNER": "Właściciel", + "MEMBER": "Członek", + "CREATOR": "Twórca", + "EDITED": "Edytowano", + "FINALIZED": "Zakończone", + "PUBLISHED": "Opublikowane", + "VERSION": "Wersja", + "CONTAINED-DATASETS": "Zawarte zestawy danych", + "TEXT-INFO": "„Informacje w DMP pokazują, w jaki sposób zbiory danych zostały zebrane i/lub wygenerowane, w jaki sposób zostały przetworzone i przeanalizowane, tj. za pomocą jakich narzędzi, standardów, metodologii itp., ale także gdzie i w jaki sposób kopie zapasowe zbiorów danych są tworzone , opublikowane i zachowane, w tym wszelkie koszty związane z personelem zajmującym się przechowywaniem/zarządzaniem danymi lub koszty nabycia lub tworzenia usług zarządzania danymi.", + "TEXT-INFO-QUESTION": "Nie wiesz, jak DMP wygląda w praktyce? Przeglądaj publiczne DMP i", + "LINK-ZENODO": "Społeczność LIBER w Zenodo", + "GET-IDEA": "wpadnij na pomysł!", + "SORT-BY": "Sortuj według", + "COLUMNS": { + "NAME": "Nazwa", + "GRANT": "Dotacja", + "PROFILE": "Szablon", + "CREATION-TIME": "Czas utworzenia", + "ORGANISATIONS": "Organizacje", + "LATEST_VERSION": "Ostatnia wersja", + "ACTIONS": "Działania", + "DATASETS": "Zbiory danych", + "STATUS": "Status", + "PEOPLE": "Ludzie", + "VERSION": "Wersja" + }, + "ACTIONS": { + "NEW": "Nowy DMP", + "NEW-WITH-WIZARD": "Nowy DMP z wykorzystaniem kreatora", + "EDIT": "Edytuj", + "INVITE": "Zaproś współtwórców", + "INVITE-AUTHORS": "Zaproś autorów", + "INVITE-SHORT": "Zaproś", + "ADD-DATASET": "Dodaj zbiór danych do DMP", + "ADD-DATASET-DESCRIPTION": "Dodaj zbiór danych", + "ADD-DATASET-SHORT": "Dodaj zbiór danych", + "DATASETS": "Wyświetl na liście wszystkie zbiory danych DMP", + "NEW-VERSION": "Nowa wersja", + "START-NEW-VERSION": "Rozpocznij nową wersję", + "VIEW-VERSION": "Wszystkie wersje DMP", + "CLONE": "Klonuj", + "COPY": "Kopiuj", + "DELETE": "Usuń", + "DEPOSIT": "Przechowaj", + "EXPORT": "Eksportuj", + "MAKE-PUBLIC": "Upublicznij", + "PUBLISH": "Opublikuj", + "FINALIZE": "Zakończ", + "UNFINALIZE": "Cofnij finalizację", + "ADV-EXP": "Zaawansowany eksport", + "EXP-AS": "Eksportuj jako", + "DOWNLOAD-XML": "Pobierz XML", + "DOWNLOAD-DOCX": "Pobierz document", + "DOWNLOAD-PDF": "Pobierz PDF", + "SETTINGS": "Ustawienia", + "GETDOI": "Zdobądź DOI" + }, + "TOOLTIP": { + "DMP-STATUS": { + "DRAFT": "Prywatny dostęp - Edytowalny DMP", + "FINALIZED": "Prywatny dostęp - Zamknięty DMP", + "PUBLISHED": "Dostęp publiczny – Zamknięty DMP" + }, + "LEVEL-OF-ACCESS": "Poziom dostępu", + "INVOLVED-DATASETS": "Zaangażowane zbiory danych", + "TEMPLATES-INVOLVED": "Zaangażowane szablony zbiorów danych" + }, + "VIEW-ALL-VERSIONS": "Wszystkie wersje", + "EMPTY-LIST": "Nic tu jeszcze nie ma" + }, + "DMP-PUBLIC-LISTING": { + "TITLE": "Opublikowane plany zarządzania danymi", + "OWNER": "Właściciel", + "MEMBER": "Członek", + "CREATOR": "Twórca", + "VIEW-ONLY": "Tylko do wyświetlenia", + "TOOLTIP": { + "PUBLISHED": "Dostęp publiczny – Zamknięty DMP", + "INVOLVED-DATASETS": "Zaangażowane zbiory danych", + "TEMPLATES-INVOLVED": "Zaangażowane szablony zbiorów danych" + }, + "EMPTY-LIST": "Puste pole" + }, + "DMP-UPLOAD": { + "TITLE": "Importuj plan zarządzania danymi", + "UPLOAD-BUTTON": "Prześlij", + "UPLOAD-SUCCESS": "Import zakończył się pomyślnie", + "ACTIONS": { + "IMPORT": "Importuj", + "CANCEL": "Anuluj" + }, + "PLACEHOLDER": "Tytuł DMP" + }, + "DATASET-WIZARD": { + "TITLE": { + "NEW": "Nowy zbiór danych" + }, + "EDITOR": { + "FIELDS": { + "EXTERNAL-DATASET-TYPE": "Typ", + "EXTERNAL-AUTOCOMPLETE-SUBTITLE": "Źródło", + "EXTERNAL-AUTOCOMPLETE-NO-SOURCE": "Źródło nie zostało podane" + } + }, + "FIRST-STEP": { + "TITLE": "Informacje o zbiorze danych", + "DMP": "Plan zarządzania danymi", + "PROFILE": "Szablon zbioru danych", + "SUB-TITLE": "Utwórz w: " + }, + "SECOND-STEP": { + "TITLE": "Odniesienia zewnętrzne", + "EXTERNAL-HINT": "Lista wartości dostarczanych przez zewnętrzne źródła" + }, + "THIRD-STEP": { + "TITLE": "Opis" + }, + "ACTIONS": { + "NEXT": "Dalej", + "BACK": "Cofnij", + "CLOSE": "Zamknij", + "BACK-TO": "Powrót do", + "DELETE": "Usuń", + "GO-TO-GRANT": "Przejdź do zbioru danych dotacji", + "GO-TO-DMP": "Przejdź do zbioru danych DMP", + "SAVE": "Zapisz", + "SAVE-AND-CONTINUE": "Zapisz i kontynuuj", + "SAVE-AND-ADD": "Zapisz i dodaj nowy", + "SAVE-AND-CLOSE": "Zapisz i zamknij", + "SAVE-AND-FINALISE": "Zapisz i zakończ", + "FINALIZE": "Zakończ", + "REVERSE": "Cofnij zakończ", + "INFO": "Zbiory danych zamkniętych DMP nie mogą powrócić do niezakończonych", + "LOCK": "Zbiór danych jest zablokowany przez innego użytkownika", + "DOWNLOAD-PDF": "Pobierz PDF", + "DOWNLOAD-XML": "Pobierz XML", + "DOWNLOAD-DOCX": "Pobierz DOCX", + "COPY-DATASET": "Kopiuj zbiór danych", + "UPDATE-DATASET-PROFILE": "Aktualizuj szblon", + "VALIDATE": "Sprawdź", + "UNDO-FINALIZATION-QUESTION": "Cofnąć finalizację?", + "CONFIRM": "Tak", + "REJECT": "Nie" + }, + "MESSAGES": { + "DATASET-NOT-FOUND": "Zbiór danych nie istnieje", + "DATASET-NOT-ALLOWED": "Nie masz dostępu do tego zbioru danych", + "SUCCESS-UPDATE-DATASET-PROFILE": "Szablon zestawu danych został zaktualizowany ", + "MISSING-FIELDS": "Niektóre wymagane pola są niewypełnione. Sprawdź DMP i upewnij się, że udzielono odpowiedzi na wszystkie wymagane pytania, a adresy URL zawierają prawidłowe dane wejściowe. (Brakujące pola są zaznaczone na czerwono)", + "NO-FILES-SELECTED": "Nie zaznaczono pliku do przesłania", + "LARGE-FILE-OR-UNACCEPTED-TYPE": "Plik jest za duży lub jego typ nie jest obsługiwany.", + "MAX-FILE-SIZE": "Przesyłane pliki powinny mieć do {{maxfilesize}} MB.", + "ACCEPTED-FILE-TYPES": "Obsługiwane typy nośników to: " + }, + "UPLOAD": { + "UPLOAD-XML": "Importuj", + "UPLOAD-XML-FILE-TITLE": "Importuj szablon zbioru danych", + "UPLOAD-XML-NAME": "Nazwa szablonu zbioru danych", + "UPLOAD-XML-IMPORT": "Plik", + "UPLOAD-XML-FILE-CANCEL": "Anuluj" + }, + "DIALOGUE": { + "TITLE": "Skopiuj zbiór danych do DMP", + "DMP-SEARCH": { + "PLACEHOLDER": "Szukaj DMP" + }, + "COPY": "Kopiuj", + "CANCEL": "Anuluj", + "NEXT": "Dalej", + "ERROR-MESSAGE": "Nie zawiera tego szablonu zbioru danych" + }, + "LOCKED": { + "TITLE": "Zbiór danych jest zablokowany", + "MESSAGE": "W tej chwili ktoś inny modyfikuje ten zbiór danych. Możesz przeglądać ten zbiór danych, ale nie możesz wprowadzać żadnych zmian. Jeśli chcesz go zmodyfikować, wróć później." + } + }, + "DMP-OVERVIEW": { + "GRANT": "Dotacja", + "DMP-AUTHORS": "Autorzy DMP", + "RESEARCHERS": "Naukowcy", + "DATASETS-USED": "Użyte zbiory danych", + "COLLABORATORS": "Współpracownicy", + "PUBLIC": "Publiczny", + "PRIVATE": "Prywatny", + "LOCKED": "Zablokowany", + "UNLOCKED": "Odblokowany", + "YOU": "ty", + "LOCK": "Blokada", + "TOOLTIP": { + "LEVEL-OF-ACCESS": "Poziom dostępu", + "INVOLVED-DATASETS": "Zaangażowane zbiory danych", + "TEMPLATES-INVOLVED": "Zaangażowane szablony zbiorów danych" + }, + "ERROR": { + "DELETED-DMP": "Żądany DMP został usunięty", + "FORBIDEN-DMP": "Nie masz dostępu do tego DMP" + }, + "MULTIPLE-DIALOG": { + "ZENODO-LOGIN": "Zaloguj się za pomocą Zenodo", + "USE-DEFAULT": "Użyj domyślnego tokena" + }, + "LOCKED-DIALOG": { + "TITLE": "DMP jest zablokowany", + "MESSAGE": "W tej chwili ktoś inny modyfikuje ten zbiór danych. Możesz przeglądać ten zbiór danych, ale nie możesz wprowadzać żadnych zmian. Jeśli chcesz go zmodyfikować, wróć później." + } + }, + "DATASET-OVERVIEW": { + "DATASET-AUTHORS": "Autorzy zbioru danych", + "ERROR": { + "DELETED-DATASET": "Żądany zbiór danych został usunięty", + "FORBIDEN-DATASET": "Nie masz dostępu do tego zbioru danych" + }, + "LOCKED": { + "TITLE": "Zbiór danych jest zablokowany", + "MESSAGE": "W tej chwili ktoś inny modyfikuje ten zbiór danych. Możesz przeglądać ten zbiór danych, ale nie możesz wprowadzać żadnych zmian. Jeśli chcesz go zmodyfikować, wróć później." + }, + "FINALISE-POPUP": { + "MESSAGE": "Zostaniesz przekierowany do edytora zbioru danych, gdzie możesz sfinalizować wybrany zbiór danych. Czy chcesz kontynuować?", + "CONFIRM": "OK", + "CANCEL": "Anuluj" + } + }, + "DATASET-LISTING": { + "TITLE": "Zbiory danych", + "DATASET-DESCRIPTION": "Zbiór danych", + "SELECT-DATASETS-TO-CLONE": "Wybierz zbiory danych do uwzględnienia w nowym DMP. Wybrane zbiory danych będą dostępne do edycji.", + "SELECT-DATASETS-NONE": "Niedostępne zbiory danych dla tego DMP.", + "TEXT-INFO": "Zbiory danych są dokumentowane zgodnie ze wstępnie zdefiniowanymi szablonami, które ustalają zawartość opisów zbiorów danych. W Argos DMP może zawierać tyle opisów zbiorów danych, ile zbiorów danych dokumentuje. Przeglądaj", + "TEXT-INFO-REST": " w celu zapoznania się z zbiorami danych opisanymi w Argos DMPs", + "LINK-PUBLIC-DATASETS": "Publiczne zbiory danych", + "TEXT-INFO-PAR": "Nowe zbiory danych można dodawać do istniejących DMP w dowolnym momencie i opisywać za pomocą więcej niż jednego szablonu. Zbiory danych można również kopiować i ponownie wykorzystywać w innych DMP, a także usuwać bez negatywnego wpływu na DMP jako całość.", + "COLUMNS": { + "NAME": "Nazwa", + "REFERNCE": "Odniesienie", + "GRANT": "Dotacja", + "URI": "Uri", + "STATUS": "Status", + "DESCRIPTION": "Opis", + "CREATED": "Utworzony", + "PUBLISHED": "Opublikowane", + "FINALIZED": "Sfinalizowane", + "LAST-EDITED": "Ostatnia edycja", + "ACTIONS": "Działania", + "DMP": "DMP", + "PROFILE": "Szablon", + "DATAREPOSITORIES": "Repozytoria danych", + "REGISTRIES": "Rejestry", + "SERVICES": "Usługi" + }, + "ACTIONS": { + "EDIT": "Edytuj", + "MAKE-IT-PUBLIC": "Upublicznij", + "VIEW": "Widok", + "NEW": "Nowy zbiór danych", + "CREATE-NEW": "Utwórz nowy zbiór danych", + "EXPORT": "Eksportuj", + "INVITE-COLLABORATORS": "Zaproś współpracowników", + "INVITE-SHORT": "Zaproś" + }, + "STATES": { + "EDITED": "Edytowany", + "PUBLIC": "Publiczny", + "FINALIZED": "Zakończony", + "PUBLISHED": "Opublikowany" + }, + "TOOLTIP": { + "DATASET-STATUS": { + "DRAFT": "Prywatny dostęp - Edytowalny zbiór danych", + "FINALIZED": "Prywatny dostęp - Zamknięty zbiór danych" + }, + "DMP": "DMP", + "GRANT": "Dotacja", + "TEMPLATES-INVOLVED": "Szablon zbioru danych", + "VERSION": "Wersja DMP", + "PART-OF": "Część", + "TO-DMP": "Do DMP", + "DMP-FOR": "DMP dla" + }, + "EMPTY-LIST": "Jeszcze nic tu nie ma" + }, + "DATASET-PUBLIC-LISTING": { + "TITLE": "Opublikowane zbiory danych", + "TOOLTIP": { + "FINALIZED": "Prywatny dostęp - Zamknięty zbiór danych", + "DMP": "DMP", + "GRANT": "Dotacja", + "TEMPLATES-INVOLVED": "Szablon zbioru danych" + }, + "EMPTY-LIST": "Nic tu jeszcze nie ma" + }, + "DATASET-PROFILE-LISTING": { + "TITLE": "Szablon zbioru danych", + "COLUMNS": { + "NAME": "Nazwa", + "REFERNCE": "Odniesienie", + "GRANT": "Dotacja", + "URI": "Uri", + "ROLE": "Rola", + "TEMPLATE": "Szablon", + "ORGANIZATION": "Organizacja", + "STATUS": "Status", + "VISITED": "Odwiedzono", + "EDITED": "Edytowano", + "DESCRIPTION": "Opis", + "CREATED": "Utworzono", + "ACTIONS": "Działania", + "DMP": "DMP", + "PROFILE": "Szablon", + "DATAREPOSITORIES": "Repozytoria danych", + "REGISTRIES": "Rejestry", + "SERVICES": "Usługi" + }, + "ACTIONS": { + "EDIT": "Edytuj", + "MAKE-IT-PUBLIC": "Upublicznij", + "VIEW": "Widok", + "CLONE": "Klonuj", + "NEW-VERSION": "Nowa wersja", + "VIEW-VERSIONS": "Wszystkie wersje szablonów zbioru danych", + "DELETE": "Usuń", + "CREATE-DATASET-TEMPLATE": "Utwórz szablon zbioru danych" + } + }, + "DATASET-UPLOAD": { + "TITLE": "Importuj zbiór danych", + "UPLOAD-BUTTON": "Prześlij", + "ACTIONS": { + "IMPORT": "Importuj", + "CANCEL": "Anuluj" + }, + "PLACEHOLDER": "Tytuł zbioru danych", + "DATASET-PROFILE": { + "SELECT": "Wybierz szablon zbioru danych" + }, + "SNACK-BAR": { + "SUCCESSFUL-CREATION": "Zaimportowano", + "UNSUCCESSFUL": "Coś poszło nie tak" + } + }, + "DMP-PROFILE-EDITOR": { + "TITLE": { + "NEW": "Nowy szablon DMP", + "EDIT": "Edytuj" + }, + "FIELDS": { + "TITLE": "Pola", + "LABEL": "Nazwa", + "TYPE": "Typ", + "DATATYPE": "Typ danych", + "REQUIRED": "Wymagane", + "EXTERNAL-AUTOCOMPLETE": { + "TITLE": "Autouzupełnanie danych", + "MULTIPLE-AUTOCOMPLETE": "Wielokrotne autouzupełnianie", + "PLACEHOLDER": "Wprowadź symbol zastępczy", + "URL": "Url", + "OPTIONS-ROOT": "$Opcje główne$", + "LABEL": "Etykieta", + "VALUE": "Wartość" + } + }, + "ACTIONS": { + "SAVE": "Zapisz", + "CANCEL": "Anuluj", + "DELETE": "Usuń", + "FINALIZE": "Finalizuj", + "DOWNLOAD-XML": "Pobierz XML" + }, + "CONFIRM-DELETE-DIALOG": { + "MESSAGE": "Czy chcesz usunąć ten szablon DMP?", + "CONFIRM-BUTTON": "Tak, usuń", + "CANCEL-BUTTON": "Nie" + } + }, + "GRANT-EDITOR": { + "TITLE": { + "NEW": "Nowa dotacja", + "EDIT": "Edytuj" + }, + "FIELDS": { + "LABEL": "Tytuł", + "ABBREVIATION": "Skrót", + "URI": "URL", + "START": "Start", + "END": "Koniec", + "DESCRIPTION": "Opis", + "LOGO": "Logo dotacji" + }, + "ACTIONS": { + "SAVE": "Zapisz", + "CANCEL": "Cofnij", + "DELETE": "Usuń", + "GO-TO-DMPS": "Przejdź do DMP", + "VISIT-WEBSITE": "Odwiedź witrynę" + } + }, + "DMP-EDITOR": { + "TITLE": { + "NEW": "Nowy plan zarządzania danymi", + "EDIT": "Edytuj", + "EDIT-DMP": "Edytuj DMP", + "ADD-DATASET": "Dodawanie zbioru danych", + "EDIT-DATASET": "Edycja zbioru danych", + "CLONE-DMP": "Klonuj", + "NEW-VERSION": "Nowa wersja", + "CREATE-DATASET": "Tworzenie zbioru danych", + "SUBTITLE": "DOI", + "PREVIEW-DATASET": "Podgląd zbioru danych" + }, + "FIELDS": { + "NAME": "Tytuł DMP", + "RELATED-GRANT": "Dotacja pokrewna", + "DESCRIPTION": "Opis", + "DESCRIPTION-HINT": "Krótko opisz kontekst i cel DMP", + "ORGANISATIONS": "Organizacje", + "ORGANISATIONS-HINT": "Dodaj tutaj nazwy organizacji przyczyniających się do tworzenia i rewizji DMP", + "RESEARCHERS": "Naukowcy", + "RESEARCHERS-HINT": "Dodaj tutaj nazwiska osób, które wyprodukowały, przetworzyły, przeanalizowały dane opisane w DMP.", + "AUTHORS": "Autorzy", + "TEMPLATES": "Szablony", + "TEMPLATE": "Szablony DMP", + "DATASET-TEMPLATES": "Powiązane szablony zbiorów danych", + "SELECT-TEMPLATE": "Wybierz szablon, aby opisać swój zbiór danych", + "PROFILE": "Szablon DMP", + "PROJECT": "Projekt", + "GRANT": "Dotacja", + "GRANTS": "Dotacje", + "GRANTS-HINT": "Znajdź dotację na swoje badania lub dodaj nowy", + "FUNDER": "Jednostka finansująca", + "FUNDER-HINT": "Wybierz sponsora swoich badań lub dodaj nowego", + "FUNDING-ORGANIZATIONS": "Organizacje finansujące", + "PROJECT-HINT": "Projekty w Argos są postrzegane jako odrębne działania objęte dotacją lub wspólne działania w ramach różnych dotacji w schematach współpracy, np.: otwarte zaproszenie do wnoszenia wkładów. Proszę wypełnić je w celu uzyskania dotacji powiązanej z organizacją, jeśli projekt podlega tej kategorii. We wszystkich innych przypadkach należy zostawić puste pole, które zostanie uzupełnione automatycznie.", + "STATUS": "Status DMP", + "EXTERNAL-SOURCE-HINT": "Lista wartości dostarczanych przez zewnętrzne źródła", + "COLLABORATORS": "Współpracownicy", + "LANGUAGE": "Język", + "LANGUAGE-HINT": "Wybierz język swojego DMP", + "LICENSE": "Licencja", + "VISIBILITY": "Prawa dostępu", + "VISIBILITY-HINT": "Wybierz sposób wyświetlania DMP po opublikowaniu w Zenodo. Wybierając Otwarty dostęp, DMP będzie otwarty w Zenodo po dacie publikacji. Wybierając ograniczony dostęp, DMP zostanie ograniczony po publikacji.", + "PUBLICATION": "Data publikacji", + "CONTACT": "Kontakt", + "COST": "Koszty", + "DATASETS": "Zbiory danych" + }, + "ACTIONS": { + "GO-TO-GRANT": "Przejdź do dotacji DMP", + "GO-TO-DATASETS": "Przejdź do zbiorów danych", + "SAVE-CHANGES": "Zapisz zmiany", + "SAVE": "Zapisz", + "CANCEL": "Cofnij", + "DELETE": "Usuń", + "DELETE-DATASET": "Usuń zbiór danych", + "DISCARD": "Przerwij", + "FINALISE": "Finalizacja", + "LOCK": "DMP jest zablokowany przez innego użytkownika", + "PERMISSION": "Nie masz uprawnień do edycji tego DMP", + "INSERT-MANUALLY": "Wstaw ręcznie", + "CREATE-DATASET": "Utwórz nowy" + }, + "PLACEHOLDER": { + "DESCRIPTION": "Dodaj opis", + "ORGANIZATION": "Wybierz organizację", + "AUTHORS": "Wybierz autorów", + "RESEARCHERS": "Wybierz naukowców" + }, + "SNACK-BAR": { + "UNSUCCESSFUL-DOI": "Nie udało się utworzyć DOI", + "SUCCESSFUL-DOI": "Utworzono DOI", + "UNSUCCESSFUL-FINALIZE": "Nieudana finalizacja DMP" + }, + "DATASET-TEMPLATE-LIST": { + "TITLE": "Dostępne szablony zbioru danych", + "TEXT": "Wybrane profile zbioru danych: ", + "OK": "OK" + }, + "VISIBILITY": { + "PUBLIC": "Otwarty dostęp", + "RESTRICTED": "Ograniczony dostęp" + }, + "STEPPER": { + "USER-GUIDE": "Instrukcja krok po kroku", + "MAIN-INFO": "Główne informacje", + "FUNDING-INFO": "Finansowanie", + "DATASET-SELECTION": "Wybór zbioru danych", + "DATASET-INFO": "Informacje o zbiorze danych", + "LICENSE-INFO": "Licencja", + "DATASET": "Zbiór danych", + "PREVIOUS": "Poprzedni", + "NEXT": "Następny" + }, + "MAIN-INFO": { + "INTRO": "DMP w Argos składa się z kluczowych informacji o badaniach, takich jak zamysł, cele i zaangażowani naukowcy, ale także o dokumentacji zbiorów danych badawczych, które podkreślają podjęte kroki i środki stosowane w ramach działań związanych z zarządzaniem danymi", + "HINT": "Krótki opis treści, zakresu i celów DMP.", + "TYPING": "Wpisz więcej liter nazwy, aby łatwiej było znaleźć właściwą.", + "UNIQUE-IDENTIFIER": "Niepowtarzalny identyfikator", + "RESEARCHER-IDENTIFIER-EXISTS": "Identyfikator naukowca już istnieje.", + "ORGANISATION-IDENTIFIER-EXSTS": "Identyfikator organizacji już istnieje.", + "IDENTIFIER-EXISTS-RESEARCHER-LIST": "Ten identyfikator jest już używany przez naukowca figurującego na liście naukowców.", + "IDENTIFIER-EXISTS-ORGANISATION-LIST": "Ten identyfikator jest już używany przez organizację figurującą na liście organizacji.", + "SAVE": "Zapisz", + "CANCEL": "Anuluj" + }, + "FUNDING-INFO": { + "INTRO": "Używasz edytora DMP. Dodaj tutaj informacje o zakresie, finansowaniu, aktorach twojego DMP i zdecyduj o kwestiach dostępu i ponownego wykorzystania dla tworzonego przez ciebie wyniku DMP.", + "FIND": "Nie możesz znaleźć właściwego?", + "UNIQUE-IDENTIFIER": "Niepowtarzalny identyfikator", + "IDENTIFIER-FUNDER-EXISTS": "Jednostka finansująca o podanym identyfikatorze istnieje.", + "IDENTIFIER-GRANT-EXISTS": "Dotacja o podanym identyfikatorze istnieje.", + "IDENTIFIER-PROJECT-EXISTS": "Projekt o podanym identyfikatorze istnieje." + }, + "DATASET-INFO": { + "INTRO": "DMP w Argos składa się z kluczowych informacji o badaniach, takich jak zamysł, cele i zaangażowani naukowcy, ale także o dokumentacji zbiorów danych badawczych, która podkreśla podjęte kroki i środki zastosowane w ramach działań związanych z zarządzaniem danymi.", + "SECOND-INTRO": "Zbiory danych są dokumentowane zgodnie ze wstępnie zdefiniowanymi szablonami, które ustalają zawartość opisów zbiorów danych. W Argos DMP może zawierać tyle opisów zestawów danych, ile zestawów danych dokumentuje.", + "FIND": "Nie możesz znaleźć odpowiedniego?", + "HINT": "Wybierz szablon, aby opisać swoje zbiory danych. Możesz wybrać więcej niż jeden szablon." + }, + "LICENSE-INFO": { + "INTRO": "Każdy DMP może zawierać określone informacje licencyjne dotyczące zakresu otwartości i dostępności w ten sposób możesz określić, kto może zobaczyć twój zestaw danych i jak długo te dane będą prywatne", + "HINT": "Przypisz licencję do swojego DMP, wybierając najbardziej odpowiednią z listy.", + "TYPING": "Wpisz więcej liter nazwy, aby łatwiej było znaleźć właściwą." + }, + "DATASET-DESCRIPTION": { + "INTRO": "Według ogólnych zasad, twoje dane badawcze powinny być zgodne z FAIR, czyli możliwe do znalezienia, dostępne, interoperacyjne i wielokrotnego użytku. Zasady te poprzedzają wybory wdrożeniowe i niekoniecznie sugerują konkretną technologię, standard lub rozwiązanie wdrożeniowe. Ten szablon nie ma na celu ścisłej technicznej realizacji zasad FAIR, a raczej inspiruje się tą zasadą jako ogólną koncepcją." + }, + "CHANGES": "niezapisane zmiany", + "CLONE-DIALOG": { + "CLONE": "Klonuj", + "SAVE": "Zapisz", + "CANCEL": "Anuluj" + }, + "LOCKED": { + "TITLE": "DMP jest zablokowane", + "MESSAGE": "Ktoś inny modyfikuje w tej chwili DMP. Możesz przeglądać zbiór danych, ale nie możesz wprowadzać żadnych zmian." + } + }, + "DMP-PROFILE-LISTING": { + "TITLE": "Szablony DMP", + "CREATE-DMP-TEMPLATE": "Utwórz szablon DMP", + "COLUMNS": { + "NAME": "Nazwa", + "STATUS": "Status", + "CREATED": "Utworzony", + "PUBLISHED": "Opublikowany", + "LAST-EDITED": "Ostatnio edytowany" + }, + "UPLOAD": { + "UPLOAD-XML": "Import", + "UPLOAD-XML-FILE-TITLE": "Importuj szablon planu zarządzania danymi", + "UPLOAD-XML-NAME": "Nazwa szablonu DMP", + "UPLOAD-XML-IMPORT": "Plik", + "UPLOAD-XML-FILE-CANCEL": "Anuluj" + }, + "STATUS": { + "DRAFT": "Wersja robocza", + "FINALIZED": "Ukończony" + }, + "MESSAGES": { + "TEMPLATE-UPLOAD-SUCCESS": "Szablon przesłano " + } + }, + "DYNAMIC-FORM": { + "FIELDS": { + "LABEL": "Etykieta" + }, + "ACTIONS": { + "PREVIEW": "Podgląd", + "ADD-PAGE": "Dodaj stronę +", + "ADD-SECTION": "Dodaj sekcję +" + } + }, + "CRITERIA": { + "FILTERS": "Filtry", + "GRANTS": { + "LIKE": "Szukaj", + "PERIOD-FROM": "Początek dotacji", + "PERIOD-TO": "Koniec dotacji", + "GRANT-STATE-TYPE": "Status dotacji", + "TYPES": { + "NONE": "-", + "ON-GOING": "W trakcie", + "FINISHED": "Zakończone" + } + }, + "DATASET-PROFILE": { + "LIKE": "Szukaj", + "STATUS": "Status" + }, + "DATA-SETS": { + "PERIOD-FROM": "Start", + "PERIOD-TO": "Koniec", + "STATUS": "Status", + "NONE": "-", + "TAGS": "Tagi", + "SELECT-TAGS": "Wybierz tagi", + "LIKE": "Wyszukaj zbiory danych", + "DRAFT-LIKE": "Wyszukaj robocze zbiory danych", + "SELECT-GRANTS": "Wybierz dotację", + "ROLE": "Rola", + "ORGANIZATION": "Organizacja", + "SELECT-ORGANIZATIONS": "Wybierz organizacje", + "SELECT-SPEC": "Wybierz specyfikację zbioru danych", + "RELATED-GRANT": "Dotacja pokrewna", + "SELECT-DMP": "Wybierz DMP", + "RELATED-DMP": "Powiązane DMP", + "SELECT-COLLABORATORS": "Wybierz współpracowników", + "RELATED-COLLABORATORS": "Powiązani współpracownicy", + "SELECT-DATASET-TEMPLATES": "Wybierz szablony zbioru danych", + "RELATED-DATASET-TEMPLATES": "Szablony powiązanego zbioru danych", + "ALL-VERSIONS": "Ze wszystkich wersji" + }, + "DMP": { + "LIKE": "Wyszukaj DMP", + "GRANTS": "Dotacje", + "SELECT-GRANTS": "Wybierz dotacje", + "SELECT-COLLABORATORS": "Wybierz współpracowników", + "RELATED-COLLABORATORS": "Współpracownicy powiązani", + "SELECT-DATASET-TEMPLATES": "Wybierz szablony zbioru danych", + "RELATED-DATASET-TEMPLATES": "Szablony powiązanego zbioru danych" + }, + "USERS": { + "LABEL": "Szukaj", + "ROLE": "Rola", + "SHOW": "Pokaż" + }, + "SELECT": "Wybierz opcję", + "LIKE": "Szukaj" + }, + "DATASET-EDITOR": { + "TITLE": { + "NEW": "Nowy plan zarządzania danymi", + "EDIT": "Edytuj", + "INTRO": "Korzystasz z edytora zbioru danych. Odpowiedz tutaj na pytania opisujące twoje działania związane z zarządzaniem danymi.", + "INTRO-TIP": "Wskazówka: Dodaj nowe zbiory danych, aby opisać różne typy danych lub dane dyscyplinarne, aby uniknąć mieszania informacji." + }, + "FIELDS": { + "NAME": "Nazwa zbioru danych", + "TITLE": "Tytuł zbioru danych", + "DESCRIPTION": "Opis", + "PROFILE": "Szablon", + "URI": "Uri", + "DMP": "DMP", + "SELECT-DMP": "Wybierz DMP", + "DATAREPOSITORIES": "Repozytoria danych", + "REGISTRIES": "Rejestry", + "SERVICES": "Usługi", + "EXTERNAL-DATASETS": "Zewnętrzne zbiory danych", + "EXTERNAL-DATASETS-DESCRIPTION": "Zbiory danych związane ze zbiorem opisanym w DMP, wykorzystywane do jego utworzenia lub będące pochodną lub produktem ubocznym jego wykorzystania", + "EXTERNAL-DATASET-TYPE": "Typ zewnętrznego zbioru danych", + "EXTERNAL-DATASET-INFO": "Informacje o zewnętrznym zbiorze danych", + "DATAREPOSITORIES-INFO": "Informacje o repozytoriach danych", + "EXTERNAL-LINK": "Łącze zewnętrzne", + "TAGS": "Tagi", + "CREATE": "Utwórz nowy" + }, + "ACTIONS": { + "SAVE": "Zapisz", + "CANCEL": "Anuluj", + "DELETE": "Usuń", + "UPDATE": "Aktualizuj", + "DISCARD": { + "DISCARD-NEW-MESSAGE": "Wszystkie wprowadzone zmiany zostaną odrzucone i nastąpi przekierowanie z powrotem do Edytora DMP. Czy chcesz kontynuować?", + "DISCARD-NEW-CONFIRM": "Tak, odrzuć i usuń zbiór danych.", + "DISCARD-NEW-DENY": "Nie.", + "DISCARD-EDITED-MESSAGE": "Wszystkie niezapisane zmiany zostaną przywrócone do stanu początkowego i nastąpi przekierowanie z powrotem do Edytora DMP. Czy chcesz kontynuować?", + "DISCARD-EDITED-CONFIRM": "Tak, cofnij zmiany i wróć.", + "DISCARD-EDITED-DENY": "Nie" + } + }, + "PLACEHOLDER": { + "DESCRIPTION": "Wpisz opis", + "EXTERNAL-LINK": "Podaj zewnętrzny link URL" + }, + "HINT": { + "DESCRIPTION": "Krótko opisz kontekst i cel zbioru danych", + "TITLE": "Krótki opis tego, co ", + "TITLE-REST": "dotyczy zakresu i celów." + }, + "VERSION-DIALOG": { + "ABOUT": "Wersjonowanie jest zautomatyzowane.", + "QUESTION": "Wygląda na to, że twój szablon zbioru danych jest nieaktualny. Czy chcesz zaktualizować go do najnowszej wersji?" + }, + "ERRORS": { + "ERROR-OCCURED": "Wystąpił błąd.", + "MESSAGE": "Wiadomość: " + }, + "QUESTION": { + "EXTENDED-DESCRIPTION": { + "VIEW-MORE": "Wyświetl więcej", + "VIEW-LESS": "Wyświetl mniej" + } + } + }, + "DATASET-CREATE-WIZARD": { + "ACTIONS": { + "NEXT": "Następny", + "BACK": "Powrót", + "SAVE": "Zapisz" + }, + "FIRST-STEP": { + "TITLE": "DMP", + "PLACEHOLDER": "Wybierz istniejący DMP" + }, + "PREFILL-STEP": { + "TITLE": "Zainicjuj swój zbiór danych", + "PREFILL": "Wstępne uzupełnienie", + "OR": "LUB", + "HINT": "Wybierz zbiór danych z Zenodo, aby automatycznie pobrać odpowiedzi na niektóre pytania w swoim szablonie lub wpisz odpowiedzi na pytania ręcznie.", + "MANUALLY": "Ręcznie", + "PROFILE": "Szablon zbioru danych", + "PREFILLED-DATASET": "Wstępnie wypełniony zbiór danych", + "SEARCH": "Zacznij pisać, aby wyszukać zbiór danych lub oprogramowanie", + "NEXT": "Następny" + } + }, + "INVITATION-EDITOR": { + "TITLE": "Wyślij zaproszenia do ", + "AUTOCOMPLETE-USER": "Użytkownik", + "AUTOCOMPLETE-EMAIL": "Email", + "AUTOCOMPLETE-USER-EMAIL": "$Nowak lub nowak@domena.pl$", + "ACTIONS": { + "SEND-INVITATION": "Wyślij zaproszenia", + "CANCEL": "Anuluj" + } + }, + "USERS": { + "LISTING": { + "TITLE": "Użytkownicy", + "EMAIL": "Email", + "LAST-LOGGED-IN": "Ostatnio zalogowany", + "LABEL": "Etykieta", + "ROLES": "Role", + "NAME": "Nazwa", + "PERMISSIONS": "Uprawnienia", + "EXPORT": "Eksportuj użytkowników" + }, + "ACTIONS": { + "EDIT": "Edytuj", + "SAVE": "Zapisz" + } + }, + "TYPES": { + "APP-ROLE": { + "ADMIN": "Administrator", + "USER": "Użytkownik", + "MANAGER": "Menedżer", + "DATASET-TEMPLATE-EDITOR": "Edytor szablonów zbioru danych" + }, + "DMP-PROFILE-FIELD": { + "DATA-TYPE": { + "DATE": "Data", + "NUMBER": "Liczba", + "TEXT": "Tekst", + "EXTERNAL-AUTOCOMPLETE": "Autouzupełnianie zewnętrzne" + }, + "TYPE": { + "INPUT": "Wejście" + } + }, + "DATASET-STATUS": { + "DRAFT": "Projekt", + "FINALISED": "Sfinalizowane", + "ANY": "Dowolne", + "DRAFT-DESC": "Rejestracje wersji roboczych" + }, + "DATASET-ROLE": { + "OWNER": "Właściciel", + "MEMBER": "Członek", + "ANY": "Dowolne" + }, + "EXTERNAL-DATASET-TYPE": { + "SOURCE": "Źródło", + "SOURCES": "Źródła", + "SOURCE:": "Źródło", + "NO-SOURCE": "Nie wiąż ze źródłem", + "OUTPUT": "Wyjście", + "SELECT": "Wybierz" + }, + "DMP": { + "FINALISED": "Sfinalizowane", + "DRAFT": "Wersja robocza" + }, + "DMP-VISIBILITY": { + "VISIBILITY": "Widoczność", + "PUBLIC": "Opublikowane", + "FINALIZED": "Sfinalizowane", + "DRAFT": "Wersja robocza", + "ANY": "Dowolne" + }, + "DATASET-PROFILE-FIELD-VALIDATION-TYPE": { + "NONE": "Brak", + "REQUIRED": "Wymagane" + }, + "DATASET-PROFILE-FIELD-VIEW-STYLE": { + "BOOLEAN-DECISION": "Decyzja logiczna", + "CHECKBOX": "Pole wyboru", + "COMBO-BOX": "Combo Box", + "INTERNAL-DMP-ENTITIES": "Wewnętrzne podmioty DMP", + "FREE-TEXT": "Tekst niesformatowany", + "RADIO-BOX": "Pole jednokrotnego wyboru", + "TEXT-AREA": "Obszar tekstowy", + "RICH-TEXT-AREA": "Obszar tekstu sformatowanego", + "UPLOAD": "Prześlij", + "DATE-PICKER": "Wybór daty", + "EXTERNAL-DATASETS": "Zewnętrzne zbiory danych", + "DATA-REPOSITORIES": "Repozytoria danych", + "PUB-REPOSITORIES": "Repozytoria publikacji", + "JOURNALS-REPOSITORIES": "Czasopisma", + "TAXONOMIES": "Taksonomie", + "LICENSES": "Licencje", + "PUBLICATIONS": "Publikacje", + "REGISTRIES": "Metadane", + "SERVICES": "Usługi", + "TAGS": "Tagi", + "RESEARCHERS": "Naukowcy", + "ORGANIZATIONS": "Organizacje", + "DATASET-IDENTIFIER": "Identyfikator zbioru danych", + "CURRENCY": "Waluta", + "VALIDATION": "Walidator", + "OTHER": "Inne", + "SELECT": "Wybierz" + }, + "DATASET-PROFILE-UPLOAD-TYPE": { + "DOWNLOAD": "Pobierz plik" + }, + "DATASET-PROFILE-COMBO-BOX-TYPE": { + "WORD-LIST": "Lista słów", + "AUTOCOMPLETE": "Autouzupełnianie", + "EXTERNAL-SOURCE-HINT": "Lista wartości dostarczanych przez zewnętrzne źródła", + "ACTIONS": { + "YES": "Tak", + "NO": "Nie" + } + }, + "DATASET-PROFILE-INTERNAL-DMP-ENTITIES-TYPE": { + "RESEARCHERS": "Naukowcy", + "DMPS": "DMPs", + "DATASETS": "Zbiory danych", + "EXTERNAL-SOURCE-HINT": "Lista wartości dostarczanych przez zewnętrzne źródła" + }, + "DATASET-PROFILE-VALIDATOR": { + "ACTION": "Zatwierdź", + "REPOSITORIES-PLACEHOLDER": "Repozytoria" + }, + "DATASET-PROFILE-IDENTIFIER": { + "IDENTIFIER-TYPE": "Typ identyfikatora" + }, + "RECENT-ACTIVITY-ORDER": { + "CREATED": "Utworzony", + "LABEL": "Etykieta", + "MODIFIED": "Zmodyfikowany", + "FINALIZED": "Sfinalizowane", + "PUBLISHED": "Opublikowane", + "STATUS": "Status" + } + }, + "ADDRESEARCHERS-EDITOR": { + "TITLE": "Dodaj naukowca", + "FIRST_NAME": "Imię", + "LAST_NAME": "Nazwisko", + "ACTIONS": { + "SAVE": "Zapisz", + "CANCEL": "Anuluj" + } + }, + "ADDORGANIZATION-EDITOR": { + "TITLE": "Dodaj Organizację", + "NAME": "Nazwa", + "ACTIONS": { + "SAVE": "Zapisz", + "CANCEL": "Anuluj" + } + }, + "ADDEDITCOST-EDITOR": { + "ADD-TITLE": "Dodaj koszt", + "EDIT-TITLE": "Edytuj koszt", + "CODE": "Kod", + "DESCRIPTION": "Opis", + "TITLE": "Tytuł", + "VALUE": "Wartość", + "ACTIONS": { + "SAVE": "Zapisz", + "CANCEL": "Anuluj" + } + }, + "DMP-WIZARD": { + "FIRST-STEP": { + "DMP": "Edytor DMP", + "DATASETS": "Zbiory danych" + }, + "ACTIONS": { + "NEXT": "Dalej", + "BACK": "Cofnij", + "SAVE": "Zapisz" + } + }, + "DMP-RELATED-GRANT": { + "RELATED-GRANT": "Dotacja pokrewna" + }, + "DMP-RELATED-COLLABORATOR": { + "RELATED-COLLABORATOR": "Powiązany współpracownik", + "SELECT-COLLABORATORS": "Wybierz współpracowników" + }, + "DMP-RELATED-ORGANIZATION": { + "RELATED-ORGANIZATION": "Organizacja", + "SELECT-ORGANIZATIONS": "Wybierz organizacje" + }, + "DATASET-PROFILE": { + "PREVIEW": "Podgląd", + "FORM-DESCRIPTION": "Opis formularza", + "PAGES-DESCRIPTION": "Opis stron" + }, + "RECENT-ACTIVITY": { + "MY-TITLE-GRANT": "Moja ostatnia działalność w zakresie dotacji", + "MY-TITLE-DMP": "Moja ostatnia aktywność DMP", + "MY-TITLE-DATASET": "Moja ostatnia aktywność w zbiorze danych", + "LAST-VISITED-DMP": "Plan zarządzania danymi ostatniej wizyty", + "LAST-EDITED-DMP": "Ostatnio edytowany plan zarządzania danymi", + "LICENSE": "Poniższe DMP są publiczne na licencji ##" + }, + "FILE-UPLOADER": { + "DEFAULT": "Wybierz plik", + "GRANT": "", + "UPLOAD": "Prześlij" + }, + "URL-LISTING-COMPONENT": { + "SHOW-MORE": "Pokaż więcej" + }, + "HOMEPAGE": { + "OPEN-DMPS": { + "STATS": "Pulpit nawigacyjny ARGOS" + }, + "MY-DMPS": { + "STATS": "Mój panel" + } + }, + "ABOUT": { + "TITLE-DASHED": "-O-", + "TITLE": "O", + "MAIN-CONTENT": "Chcemy, aby Twoje dane badawcze były zgodne z FAIR, czyli możliwe do znalezienia, dostępne, interoperacyjne i wielokrotnego użytku. Zasady te poprzedzają wybory wdrożeniowe i niekoniecznie sugerują konkretną technologię, standard lub rozwiązanie wdrożeniowe", + "CONTRIBUTORS": "Współpracownicy", + "WELCOME": "Witamy w ARGOS", + "WELCOME-MESSAGE": "Twórz, łącz, udostępniaj plany zarządzania danymi" + }, + "FOOTER": { + "CONTACT-SUPPORT": "Kontakt z pomocą techniczną", + "FAQ": "Często zadawane pytania", + "GUIDE": "Podręcznik użytkownika", + "GLOSSARY": "Słowniczek", + "TERMS-OF-SERVICE": "Warunki świadczenia usług", + "ABOUT": "O", + "COOKIES-POLICY": "Polityka plików cookie", + "PRIVACY-POLICY": "Polityka prywatności" + }, + "GLOSSARY": { + "TITLE": "Słowinczek", + "TITLE-DASHED": "-Słowniczek-", + "CLOSE": "Zamknij" + }, + "FAQ": { + "TITLE": "Często zadawane pytania", + "TITLE-DASHED": "-Często zadawane pytania-", + "CLOSE": "Zamknij" + }, + "GUIDE": { + "TITLE": "Podręcznik użytkownika", + "TITLE-DASHED": "-Podręcznik użytkownika-", + "CLOSE": "Zamknij", + "SAVE": "Zapisz" + }, + "PRIVACY-POLICY": { + "TITLE": "-Polityka prywatności-", + "MAIN-CONTENT": "" + }, + "OPENSOURCE-LICENCES": { + "TITLE": "Licencje Open-source", + "MAIN-CONTENT": "" + }, + "TERMS-OF-SERVICE": { + "TITLE": "Warunki świadczenia usług", + "MAIN-CONTENT": "" + }, + "COOKIES-POLICY": { + "TITLE": "Polityka plików cookie" + }, + "CONTACT": { + "SUPPORT": { + "TITLE": "Skontaktuj się z pomocą techniczną", + "SUBTITLE": "Jak możemy ci pomóc?", + "SUBJECT": "Temat", + "DESCRIPTION": "Opis", + "CANCEL": "Anuluj", + "SEND": "Wyślij" + }, + "TITLE-DASHED": "-Skontaktuj się z pomocą techniczną-", + "GUIDE": "Przewodnik", + "HELP": "Pomoc", + "GLOSSARY": "Słowniczek" + }, + "LANGUAGE": { + "TITLE": "Język", + "TITLE-DASHED": "-Język-", + "CLOSE": "Zamknij" + }, + "DASHBOARD": { + "MY-GRANTS": "Moje Dotacje", + "GRANTS": "Dotacje", + "MY-DMPS": "Moje DMP", + "TITLE": "Co to jest ARGOS?", + "DMP-QUESTION": "Co to jest DMP w ARGOS?", + "INFO-TEXT": "ARGOS to otwarta, rozszerzalna usługa, która ułatwia zarządzanie, walidację, monitorowanie i konserwację oraz plany zarządzania danymi. Umożliwia podmiotom (naukowcom, menedżerom, nadzorcom itp.) tworzenie praktycznych DMP, które mogą być swobodnie wymieniane między infrastrukturami do realizacji określonych aspektów procesu zarządzania danymi zgodnie z intencjami i zaangażowaniem właścicieli danych.", + "INFO-DMP-TEXT": "Plan zarządzania danymi (DMP) to żywy dokument opisujący zbiory danych, które są generowane i/lub ponownie wykorzystywane w trakcie badań i po ich zakończeniu. DMP mają na celu dostarczenie naukowcom niezbędnych informacji do ponownego tworzenia, redystrybucji i zmiany przeznaczenia wyników badań, zapewniając w ten sposób ich ważność i wykorzystanie.", + "NEW-QUESTION": "Nowy w DMP? Odwiedź", + "START-YOUR-FIRST-DMP": "Uruchom swój pierwszy DMP", + "OPEN-AIR-GUIDE": "Przewodnik dla badaczy OpenAIRE", + "LEARN-MORE": "aby dowiedzieć się więcej o tym, jak je stworzyć!", + "ORGANIZATIONS": "Organizacje powiązane", + "DMPS": "DMP", + "MY-DATASETS": "Moje zbiory danych", + "DATASETS": "Zbiory danych", + "SEARCH": "SZUKAJ...", + "DATA-MANAGEMENT-PLANS": "PLANY ZARZĄDZANIA DANYMI", + "PERSONAL-USAGE": "Użytek osobisty", + "PUBLIC-USAGE": "Użytek publiczny", + "DATASET-DESCRIPTIONS": "Zbiory danych", + "DATASET-DESCRIPTIONS-DASHBOARD-TEXT": "Zbiory danych", + "PUBLIC-DMPS": "Publiczne DMP", + "PUBLIC-DATASETS": "Publiczne zbiory danych", + "RELATED-ORGANISATIONS": "Organizacje powiązane", + "DRAFTS": "Wersje robocze", + "ALL": "Wszystko", + "EMPTY-LIST": "Puste pole", + "LATEST-ACTIVITY": "Ostatnia aktywność", + "DMP-ABOUT-BEG": "DMP w Argos składa się z kluczowych informacji dotyczących badań, takich jak cel, zamierzenia i zaangażowani naukowcy, ale także z dokumentacji zbiorów danych badawczych, a mianowicie", + "DMP-ABOUT-END": ", które podkreślają podjęte kroki i środki stosowane w ramach działań związanych z zarządzaniem danymi.", + "SELECT-DMP": "Wybierz DMP dla swojego zbioru danych", + "ACTIONS": { + "ADD-DATASET-DESCRIPTION": "Dodaj zbiór danych", + "ADD-DATASET": "Dodaj zbiór danych", + "ADD-DMP-DESCRIPTION": "Dodaj opis DMP" + }, + "TOUR-GUIDE": { + "DMP": "To jest twój pulpit nawigacyjny. Możesz przeglądać i edytować wszystkie utworzone lub współtworzone przez ciebie DMP.", + "START-NEW": "Utwórz swój DMP za pomocą funkcji Uruchom nowy DMP.", + "IMPORT-DMP": "Możesz zaimportować DMP", + "START-WIZARD": "lub utwórz nowy w Argos.", + "DATASET": "To jest twój pulpit nawigacyjny. Możesz przeglądać i edytować wszystkie utworzone lub współtworzone przez ciebie zestawy danych.", + "NEW-DATASET": "Dzięki funkcji Dodaj zbiór danych możesz opisywać nowe zbiory danych w dowolnym momencie procesu badawczego.", + "GOT-IT": "Mam to!", + "LEAVE-TOUR": "Opuść przewodnik" + }, + "ADD-NEW-DATASET": { + "OPTIONS-NOT-ENOUGH": "Czy te opcje nie wystarczą?", + "START-NEW-DMP": "Rozpocznij nowy DMP" + } + }, + "USER-DIALOG": { + "USER-PROFILE": "Mój profil", + "USER-PROFILE-SETTINGS": "Ustawienia mojego Profilu...", + "EXIT": "Wyjście", + "LOG-OUT": "Wyloguj" + }, + "USER-PROFILE": { + "MERGING-EMAILS-DIALOG": { + "TITLE": "Zweryfikuj połączone konto", + "MESSAGE": "Wysłano wiadomość e-mail w celu weryfikacji tej akcji. Po zaakceptowaniu będzie można zobaczyć połączone konta. Ostatnie połączone konto e-mail będzie tym, które zawiera wszystkie twoje rejestry DMP i aktywność w Argos." + }, + "SETTINGS": { + "TITLE": "Ustawienia", + "TIMEZONE": "Strefa czasowa", + "CULTURE": "Kultura", + "LANGUAGE": "Język", + "CONNECTED-WITH": "Połączony z", + "NAME": "Nazwa", + "ORGANIZATION": "Organizacja", + "ROLE": "Rola", + "SELECT-ROLE": "Wybierz rolę", + "ACCOUNTS": "Konta", + "EMAILS": "E-maile", + "YOUR-EMAIL": "Twój e-mail" + }, + "ASSOCIATED-DMPS": "Powiązane DMP", + "DMPS": { + "SHOW-ALL": "Pokaż wszystko", + "CREATOR": "Twórca", + "MEMBER": "Członek" + }, + "ZENODO": { + "LOGIN": "Zaloguj się do Zenodo", + "LOGOUT": "Usuń Zenodo", + "AUTHORIZE": "Autoryzuj Zenodo", + "TITLE": "Konto Zenodo", + "DESCRIPTION": "Połączone konto Zenodo" + }, + "ROLE-ORGANIZATION": { + "FACULTY": "Wydział", + "LIBRARIAN": "Bibliotekarz", + "RESEARCHER": "Naukowiec", + "STUDENT": "Student (licencjat/inżynier, magister)", + "EARLY-CAREER-RESEARCHER": "Początkujący naukowiec (doktorant, student studiów podyplomowych)", + "RESEARCH-ADMINISTRATOR": "Administrator badań", + "REPOSITORY-MANAGER": "Menedżer repozytorium", + "RESEARCH-INFRASTRUCTURE": "Infrastruktura badawcza", + "SERVICE-PROVIDER": "Usługodawca", + "PUBLISHER": "Wydawca", + "RESEARCH-FUNDER": "Sponsor badań", + "POLICY-MAKER": "Prawodawca", + "SME-INDUSTRY": "MŚP/Przemysł", + "OTHER": "Inne" + }, + "ACTIONS": { + "SAVE": "Zapisz", + "LINK-NEW": "Połącz nowy", + "LINK-NEW-ACCOUNT": "Połącz nowe konto", + "ADD": "Dodaj", + "CANCEL": "Anuluj" + } + }, + "DATASET-REFERENCED-MODELS": { + "SERVICES": { + "TITLE": "Dodaj nową usługę", + "LABEL": "Etykieta", + "ABBREVIATION": "Skrót", + "URI": "Uri" + }, + "DATA-REPOSITORY": { + "TITLE": "Dodaj nowe repozytorium danych", + "LABEL": "Etykieta", + "ABBREVIATION": "Skrót", + "URI": "Uri" + }, + "EXTERNAL-DATASET": { + "TITLE": "Dodaj nowy zewnętrzny zbiór danych", + "LABEL": "Etykieta", + "ABBREVIATION": "Skrót" + }, + "REGISTRY": { + "TITLE": "Dodaj nowy rejestr", + "LABEL": "Etykieta", + "ABBREVIATION": "Skrót", + "URI": "Uri" + } + }, + "FACET-SEARCH": { + "FILTER": "Filtr", + "GRANT-STATUS": { + "TITLE": "Status dotacji", + "OPTIONS": { + "ANY": "Dowolne", + "ACTIVE": "Aktywny", + "INACTIVE": "Nieaktywny" + } + }, + "GRANT": { + "TITLE": "Dotacja pokrewna", + "FILTER": "Filtruj dotacje" + }, + "PROFILES": { + "TITLE": "Specyfikacja zbioru danych" + }, + "ROLE": { + "TITLE": "Rola", + "ANY": "Dowolne", + "OWNER": "Właściciel", + "MEMBER": "Członek" + }, + "DMP-ORGANISATIONS": { + "TITLE": "Organizacja", + "FILTER": "Filtruj organizacje" + } + }, + "DMP-FINALISE-DIALOG": { + "DMP": "DMP", + "DATASETS": "Zbiory danych", + "EMPTY": "Brak zbiorów danych dla tego DMP", + "SUBMIT": "Prześlij", + "FINALISE-TITLE": "Czy chcesz sfinalizować którykolwiek z następujących roboczych zestawów danych?", + "ALREADY-FINALISED-DATASETS": "Już sfinalizowano zbiory danych", + "NONE": "Brak", + "VALIDATION": { + "AT-LEAST-ONE-DATASET-FINALISED": "Musisz mieć co najmniej jeden sfinalizowany zestaw danych" + }, + "IMPACT": "Ta akcja/to działanie/ta funkcja? sfinalizuje twój DMP i nie będziesz mógł go ponownie edytować.", + "AFTER-FINALIZATION": "Po sfinalizowaniu DMP możesz go opublikować i będzie on publicznie dostępny dla narzędzia ARGOS.", + "INVALID": "Nieprawidłowy" + }, + "DRAFTS": { + "FOR-DMP": "Dla DMP:", + "FOR-GRANT": "Dla dotacji:" + }, + "QUICKWIZARD": { + "CREATE-ADD": { + "CREATE": { + "TITLE": "Utwórz nowy DMP", + "SUBTITLE": "Utwórz nowy DMP i opisz swoje zbiory danych przy pomocy naszego kreatora, który poprowadzi cię przez najistotniejsze elementy definicji DMP.", + "QUICKWIZARD_CREATE": { + "TITLE": "Kreator DMP", + "POST-SELECTION-INFO": "Ten kreator umożliwia utworzenie nowego DMP zawierającego tylko najbardziej niezbędne wymagane informacje , a następnie opisanie przynajmniej jednego zbioru danych zarządzanych w ramach tego DMP. Po zakończeniu pracy kreatora będziesz mieć mozliwość dalszej edycji DMP, uzyskania dostępu do jego zaawansowanych właściwości za pośrednictwem pełnego edytora DMP, a nawet dodania większej liczby zbiorów danych lub edytowania poprzednich.", + "ACTIONS": { + "DELETE": "Usuń", + "SAVE": "Zapisz", + "SAVE-AND-FINALIZE": "Zapisz i sfinalizuj", + "NEXT": "Dalej", + "BACK": "Powrót", + "CREATE-NEW-GRANT": "Dodaj dotację", + "EXIST-GRANT": "Skorzystaj z istniejącej dotacji", + "CREATE-NEW-FUNDER": "Dodaj sponsora", + "EXIST-FUNDER": "Wykorzystaj istniejącego sponsora", + "CREATE-NEW-PROJECT": "Dodaj projekt", + "EXIST-PROJECT": "Użyj istniejącego projektu" + }, + "FIRST-STEP": { + "TITLE": "Dotacja", + "ABOUT-GRANT": "Znajdź dotację, z którą powiązany jest twój DMP i połącz go z informacjami o sponsorach. Jeśli dotacja nie jest wymieniona lub tworzysz DMP dla propozycji dotacji lub do innych celów, użyj funkcji \"Dodaj dotację \"", + "ABOUT-NEW-GRANT": "Jeśli tworzysz DMP dla wniosku o dotację, użytku instytucjonalnego lub naukowego lub celów szkoleniowych i edukacyjnych, dodaj informacje poniżej, tworząc nową dotację.", + "ABOUT-FUNDER": "Znajdź podmiot finansujący, który chcesz powiązać z DMP, który zostanie utworzony, a następnie wybierz dotację, z którą powiązany jest podmiot finansujący. Jeśli podmiot finansujący nie znajduje się na liście, użyj opcji \"Dodaj podmiot finansujący\"", + "ABOUT-NEW-FUNDER": "Jeśli tworzysz DMP dla wniosku o dotację, użytku instytucjonalnego lub naukowego lub w celach szkoleniowych i edukacyjnych i chcesz powiązać go z podmiotem finansującym, którego nie ma na liście, utwórz nowy podmiot finansujący.", + "ABOUT-PROJECT": "Znajdź projekt, z którym powiązany jest Twój DMP. Jeśli projektu nie ma na liście, użyj funkcji \"Dodaj projekt\"", + "ABOUT-NEW-PROJECT": "", + "OR": "lub", + "FIELDS": { + "SELECT-GRANT": "Wybierz dotację, z którą powiązany jest DMP", + "SELECT-FUNDER": "Wybierz podmiot finansujący dotację, z którym powiązany jest DMP", + "SELECT-PROJECT": "Wybierz projekt, z którym powiązany jest DMP", + "GRANT-LABEL": "Nazwa dotacji", + "FUNDER-LABEL": "Nazwa podmiotu finansującego", + "PROJECT-LABEL": "Nazwa projektu", + "LABEL-HINT": "Dodaj nazwę dotacji, która pojawia się w zaproszeniu do składania wniosków o dotację", + "DESCRIPTION": "Opis", + "DESCRIPTION-HINT": "Krótko wyjaśnij cele i zadania grantu" + } + }, + "SECOND-STEP": { + "TITLE": "Profil DMP", + "ABOUT": "Plan zarządzania danymi składa się z zestawu pytań, na które należy odpowiedzieć na poziomie szczegółowości odpowiednim dla dotacji lub celu, dla którego tworzysz DMP. Treść każdego DMP różni się w zależności od wybranego szablonu zbioru danych, który zawiera zestaw dostosowanych pytań w odpowiedzi na wymagania polityki podmiotów finansujących, instytucji i środowisk badawczych.", + "NEW-TITLE": "", + "DMP-NAME": "DMP do dotacji: ", + "FIELDS": { + "NAME": "Tytuł DMP", + "DESCRIPTION": "Podsumowanie", + "DESCRIPTION-HINT": "Krótko opisz kontekst i cel DMP", + "PROFILE": "Szablon zbioru danych", + "PROFILE-HINT": "Wybierz szablon, aby opisać swoje zbiory danych. Jeśli chcesz wybrać wiele szablonów zbiorów danych, użyj funkcji \"Nowy DMP (ekspert)\". Możesz także dodać nowe zestawy danych w dowolnym momencie po utworzeniu DMP ", + "HELP": "Jeśli nie możesz znaleźć szablonu lub chcesz stworzyć spersonalizowany szablon dla swojej instytucji, społeczności badawczej lub potrzeb szkoleniowych, skontaktuj się z nami." + } + }, + "THIRD-STEP": { + "TITLE": "Zbiór danych", + "NEW-TITLE": "", + "DATASET-LABEL": "Tytuł zbioru danych", + "DATASET-NAME": "Zbiór danych: ", + "DATASET-NAME-FOR": " Dla DMP: ", + "LIST-BUTTON-TOOLTIP": "Lista zbiorów danych", + "ADD-BUTTON-TOOLTIP": "Dodaj zbiór danych" + } + } + }, + "ADD": { + "TITLE": "Dodaj zbiór danych do istniejącego DMP", + "DATASET-WIZARD": "Kreator zbioru danych", + "POST-SELECTION-INFO": "Ten kreator ułatwia proces dodawania nowych zbiorów danych do istniejących DMP, prowadząc cię przez cały proces i żądając tylko najbardziej istotnych informacji do wykonania zadania. Można uzyskać pełny dostęp do atrybutów zbioru danych za pośrednictwem menu dostępu do zbioru danych systemu.", + "SUBTITLE": "Ten kreator pozwala opisać dodatkowe zbiory danych zarządzane w kontekście DMP, dostarczając tylko niezbędne informacje do ich opisu.", + "CREATED": "Utworzono" + } + }, + "SAVE-DIALOG": { + "TITLE": "Czy chcesz dodać kolejny zestaw danych?", + "ACTIONS": { + "AFFIRMATIVE": "Tak", + "NEGATIVE": "Nie" + } + }, + "HINT": "(Sugerowana nazwa domyślna)" + }, + "DATASET-PROFILE-STATUS": { + "NONE": "Brak", + "DRAFT": "Projekt", + "FINALIZED": "Sfinalizowano", + "DELETED": "Usunięto" + } +} diff --git a/dmp-frontend/src/assets/i18n/pt.json b/dmp-frontend/src/assets/i18n/pt.json index 26a302ea3..8123b7bca 100644 --- a/dmp-frontend/src/assets/i18n/pt.json +++ b/dmp-frontend/src/assets/i18n/pt.json @@ -178,7 +178,8 @@ "SLOVAK": "Eslovaco", "SERBIAN": "Sérvio", "PORTUGUESE": "Português", - "CROATIAN": "Croatian" + "CROATIAN": "Croatian", + "POLISH": "Polish" } }, "COOKIE": { diff --git a/dmp-frontend/src/assets/i18n/sk.json b/dmp-frontend/src/assets/i18n/sk.json index d7a548057..06032b3d8 100644 --- a/dmp-frontend/src/assets/i18n/sk.json +++ b/dmp-frontend/src/assets/i18n/sk.json @@ -178,7 +178,8 @@ "SLOVAK": "Slovenčina", "SERBIAN": "Serbian", "PORTUGUESE": "Portuguese", - "CROATIAN": "Croatian" + "CROATIAN": "Croatian", + "POLISH": "Polish" } }, "COOKIE": { diff --git a/dmp-frontend/src/assets/i18n/sr.json b/dmp-frontend/src/assets/i18n/sr.json index 055b4af18..bd4751501 100644 --- a/dmp-frontend/src/assets/i18n/sr.json +++ b/dmp-frontend/src/assets/i18n/sr.json @@ -178,7 +178,8 @@ "SLOVAK": "slovački", "SERBIAN": "Serbian", "PORTUGUESE": "Portuguese", - "CROATIAN": "Croatian" + "CROATIAN": "Croatian", + "POLISH": "Polish" } }, "COOKIE": { diff --git a/dmp-frontend/src/assets/i18n/tr.json b/dmp-frontend/src/assets/i18n/tr.json index 8db9ee10e..a99da8a5b 100644 --- a/dmp-frontend/src/assets/i18n/tr.json +++ b/dmp-frontend/src/assets/i18n/tr.json @@ -178,7 +178,8 @@ "SLOVAK": "Slovakça", "SERBIAN": "Sırpça", "PORTUGUESE": "Portekizce", - "CROATIAN": "Croatian" + "CROATIAN": "Croatian", + "POLISH": "Polish" } }, "COOKIE": { diff --git a/dmp-frontend/src/assets/resources/language.json b/dmp-frontend/src/assets/resources/language.json index c91f6ea7a..38da65f22 100644 --- a/dmp-frontend/src/assets/resources/language.json +++ b/dmp-frontend/src/assets/resources/language.json @@ -34,5 +34,9 @@ { "label": "GENERAL.LANGUAGES.CROATIAN", "value": "hr" + }, + { + "label": "GENERAL.LANGUAGES.POLISH", + "value": "pl" } ] From 0d5f6de7c7ab1fe634d43ac86708b3d4c28c1e21 Mon Sep 17 00:00:00 2001 From: argirok Date: Fri, 29 Jul 2022 10:40:45 +0300 Subject: [PATCH 08/13] update language to Polski --- dmp-frontend/src/assets/i18n/pl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dmp-frontend/src/assets/i18n/pl.json b/dmp-frontend/src/assets/i18n/pl.json index 32ef97254..4dba630af 100644 --- a/dmp-frontend/src/assets/i18n/pl.json +++ b/dmp-frontend/src/assets/i18n/pl.json @@ -179,7 +179,7 @@ "SERBIAN": "Serbski", "PORTUGUESE": "Portugalski", "CROATIAN": "Chorwacki", - "POLISH": "Polish" + "POLISH": "Polski" } }, "COOKIE": { From 6a4d67de0c9b6d83ca7ab14132fbe5d61d7e0864 Mon Sep 17 00:00:00 2001 From: "konstantina.galouni" Date: Mon, 5 Sep 2022 14:19:15 +0300 Subject: [PATCH 09/13] faqs.html & faq-content.component.html: #7972 - Updated faqs according to document. --- .../faq-content/faq-content.component.html | 132 ++++++ .../src/assets/splash/about/faqs.html | 397 ++++++++++++++---- 2 files changed, 443 insertions(+), 86 deletions(-) diff --git a/dmp-frontend/src/app/ui/faq/faq-content/faq-content.component.html b/dmp-frontend/src/app/ui/faq/faq-content/faq-content.component.html index 7b30a95f3..28ff25f85 100644 --- a/dmp-frontend/src/app/ui/faq/faq-content/faq-content.component.html +++ b/dmp-frontend/src/app/ui/faq/faq-content/faq-content.component.html @@ -23,6 +23,16 @@ href="https://marketplace.eosc-portal.eu/services/argos?fromc=data-management" target="_blank">EOSC.

+
+

Is Argos designed for one specific funder, e.g. the EC/Horizon Europe?

+

+ Argos is a flexible tool, designed to accommodate all research performing + and research funding organisations’ policies and Research Data Management (RDM) needs. + It already supports templates for different authorities. + These templates are created by Admin users in Argos. + In addition, we currently work to provide non-administrative users with the capability + to modify templates according to their own needs. +


Why use Argos?

Argos is easy to use and navigate around. It familiarises users with the DMP process @@ -82,6 +92,13 @@ researchers and students the processes of RDM and DMP.


+

Can I exploit ARGOS DMPs?

+

+ Of course. If you want to compare DMPs or analyse DMP data, then we advise you to export the records in .xml. + This schema is the most complete as it includes all information held in a DMP: information provided by the Admin + when structuring the template and input provided by researchers when completing their DMPs. +

+

Manage Account

Log in and out of Argos

@@ -300,6 +317,28 @@ on them together.


+

+ Can scientists collaborate on the same DMP even though they may belong to different institutions (e.g. a hospital, a University, etc, collaborating on a project) and the dataset also "belongs" to different institutions? +

+

+ Of course. Argos supports collaborations across diverse teams. There are two most frequent ways that can address this question: +

+ A. Everyone works on the same DMP, but on different dataset descriptions +

+ In this case, each organisation makes its own dataset description(s) in a single DMP. + That means that the manager (i.e. person responsible for the DMP activity) creates a DMP in ARGOS + and shares it with everyone. If the DMP is shared with co-ownership rights, + then the people will be able to edit it and add their dataset descriptions at any time during the project. + If there is the need to control editing rights of people writing the DMPs, then the manager can create the dataset description(s) + and share these each time with the team members that are responsible for adding input for the specified datasets. +

+ B. Everyone works on their own DMP and content is later merged into one single DMP +

+ In this case, each organisation might work on their own DMP for the same project. + At one point, you need to decide which DMP is going to be the core for the work you perform, share co-ownership + between managers of all DMPs so they can copy all dataset descriptions of their DMPs in this single DMP document. +

+

How do I create an identical DMP or Dataset as a copy? @@ -367,6 +406,25 @@ does an Admin user do?”.


+

+ Can I create smaller versions of a template for project proposals? +

+

+ Yes, it is possible in Argos to create short versions of templates that can be used + for grant proposals, such as for Horizon Europe. + If you are interested in working with us to create this short version of any ARGOS template, + please contact us: argos@openaire.eu. +

+
+

+ Can I customise an existing template (e.g. for a specific institution)? +

+

+ Yes, you can. In the current version, this is possible for Admin users who have their own deployment on-premises or cloud. + Please note that this subject to change in the near future as we are working on a feature that will allow all users + to customise (remove/add/extend) specific questions on the template they are working on. +

+

What is a Dataset?

@@ -394,6 +452,35 @@ check “How do I create an identical DMP or Dataset as a copy?”.


+

+ It is not very clear to me when one should choose to add a dataset or to describe several "data products" in the same description. +

+

+ This is something that has to be tackled conceptually, from the author of the DMP. + If those "products" have their own lifetime and rules (IPR, Access rights, etc), they should be described as different datasets. + Alternative formats should not be treated as different datasets, unless they have other differences due to the format, too. + But, for instance, if you have datasets in CSV and JSON formats and under the same terms, they could be seen as one dataset description in the DMP. +

+
+

+ Can I add to my DMP information about datasets published on Zenodo? +

+

+ Argos offers a search to Zenodo for prefilling the DMP you are working with dataset metadata. + This search has been developed according to the rules set by Zenodo + and therefore has the same behaviour as when you are using the search bar on the Zenodo interface. + However, we understand the need to be able to find records with their PID, + hence we introduced some changes and now support searching DOIs from the Argos interface. +

+
+

+ Is it possible to describe a dataset that is not yet in a repository? +

+

+ Of course! You can choose to manually describe your dataset, e.g. for a dataset you are planning to produce, + instead of pre-filling the template with available metadata from a dataset that has already been shared and preserved in a repository. +

+

What are public DMPs and Datasets?

@@ -418,6 +505,17 @@ other users.


+

+ What is the difference between the DMP and the dataset export? +

+

+ DMP export contains all vital information for a DMP, including funding and dataset details, + while dataset export is a subset of the DMP export containing information only about a dataset described in the DMP. + Both DMP and Dataset exports are available in .pdf, .docx, .xml. + In addition, DMP export is available in the RDA .json format + to increase interoperability of ARGOS exchanged DMPs. +

+

Is there a storage allowance limitation for the DMPs and Dataset files? @@ -426,6 +524,40 @@ No, there is no storage limit or fee for either files stored in Argos.


+

+ Publishing DMPs +

+

+ Is it possible to publish DMPs in different repositories (so not Zenodo)? +

+

+ Yes, it is possible. + But, to have different repositories attached to the system, you will need your own on-premises or cloud deployment. + We are already working on that for DSpace and Dataverse repositories. +

+
+

+ Do you know that Zenodo has empty DMPs from ARGOS? +

+

+ Yes, we are aware of that. + Argos has no control over the DMPs that you generate and publish and thus can not be held accountable for empty DMPs. + Please remember that, as on all other occasions where you publish content, you should do so responsinbly. + If you have any questions regarding publishing DMPs, don’t hesitate to contact us at argos@openaire.eu. +

+
+

+ Once I upload a final version of a DMP to Zenodo, do I need to update this first final version from Zenodo or from Argos? +

+

+ Both options are possible according to how you have deposited the DMP in the first place. + If you have deposited your DMP with a token (i.e. from the ARGOS account on Zenodo), + then you won’t have editing rights on the Zenodo record, but you will still be able to make changes + on ARGOS by starting and depositing a new version of the published DMP. + However, if you have deposited your DMP using your own account on Zenodo (i.e. login to Zenodo with your own credentials), + then you are able to also make minor changes, e.g. on the title of the DMP, directly from the Zenodo interface. +

+

Troubleshooting

Can’t finalize a DMP diff --git a/dmp-frontend/src/assets/splash/about/faqs.html b/dmp-frontend/src/assets/splash/about/faqs.html index ace506821..ecc231a06 100644 --- a/dmp-frontend/src/assets/splash/about/faqs.html +++ b/dmp-frontend/src/assets/splash/about/faqs.html @@ -62,7 +62,6 @@ - @@ -80,7 +79,7 @@
+ aria-controls="collapseFAQ-1" class="collapsed">About ARGOS
@@ -90,7 +89,7 @@
+ aria-controls="collapseFAQ-1-1" class="collapsed">What is ARGOS?
@@ -118,10 +117,29 @@
+ aria-controls="collapseFAQ-1-1" class="collapsed">Is Argos designed for one specific funder, e.g. the EC/Horizon Europe? +
+
+ Argos is a flexible tool, designed to accommodate all research performing + and research funding organisations’ policies and Research Data Management (RDM) needs. + It already supports templates for different authorities. + These templates are created by Admin users in Argos. + In addition, we currently work to provide non-administrative users with the capability + to modify templates according to their own needs. +
+
+
+
+
+ +
+
Argos is easy to use and navigate around. It familiarises users with the DMP process and provides guidance on basic RDM concepts so that users find useful resources to @@ -139,11 +157,11 @@
-
+
Argos is designed as a tool for inclusive use by researchers, students, funders, research communities and institutions. It can be used in the context of research @@ -167,11 +185,11 @@
-
+
Argos consists of two main functionalities: DMPs and Datasets. Argos can be used for: @@ -201,6 +219,21 @@
+
+ +
+
+ Of course. If you want to compare DMPs or analyse DMP data, then we advise you to export the records in .xml. + This schema is the most complete as it includes all information held in a DMP: information provided by the Admin + when structuring the template and input provided by researchers when completing their DMPs. +
+
+
@@ -208,7 +241,7 @@
+ aria-controls="collapseFAQ-2" class="collapsed">Manage Account
@@ -217,7 +250,7 @@
+ aria-controls="collapseFAQ-2-1" class="collapsed">Log in and out of Argos
@@ -231,7 +264,7 @@
+ aria-controls="collapseFAQ-2-2" class="collapsed">Create an administrator account
@@ -246,7 +279,7 @@
+ aria-controls="collapseFAQ-2-3" class="collapsed">Switch from administrator account
@@ -262,7 +295,7 @@
+ aria-controls="collapseFAQ-2-4" class="collapsed">Change your email
@@ -277,7 +310,7 @@
+ aria-controls="collapseFAQ-2-5" class="collapsed">Switch between accounts
@@ -295,7 +328,7 @@
+ aria-controls="collapseFAQ-2-6" class="collapsed">Delete your account
@@ -312,7 +345,7 @@
+ aria-controls="collapseFAQ-3" class="collapsed">Accounts access and safety
@@ -321,7 +354,7 @@ @@ -336,7 +369,7 @@
+ aria-controls="collapseFAQ-3-2" class="collapsed">Can’t login to ARGOS
@@ -350,7 +383,7 @@
+ aria-controls="collapseFAQ-3-3" class="collapsed">Accessing Argos
@@ -375,7 +408,7 @@
+ aria-controls="collapseFAQ-4" class="collapsed">Argos User Roles
@@ -384,7 +417,7 @@
+ aria-controls="collapseFAQ-4-1" class="collapsed">Who is the author of a DMP?
@@ -398,7 +431,7 @@ @@ -416,7 +449,7 @@
+ aria-controls="collapseFAQ-4-3" class="collapsed">What is the role of a researcher in Argos?
@@ -430,7 +463,7 @@
+ aria-controls="collapseFAQ-4-4" class="collapsed">Can a researcher be a DMP author?
@@ -444,7 +477,7 @@
+ aria-controls="collapseFAQ-4-5" class="collapsed">What does an Admin user do?
@@ -464,7 +497,7 @@
+ aria-controls="collapseFAQ-5" class="collapsed">Creating DMPs
@@ -473,7 +506,7 @@ @@ -490,7 +523,7 @@ @@ -505,7 +538,7 @@ @@ -520,7 +553,7 @@
+ aria-controls="collapseFAQ-5-4" class="collapsed">Can I create my own templates in Argos?
@@ -534,7 +567,7 @@ @@ -565,7 +598,7 @@ @@ -580,7 +613,7 @@
+ aria-controls="collapseFAQ-5-7" class="collapsed">How do I invite collaborators?
@@ -594,11 +627,40 @@
+ aria-controls="collapseFAQ-5-8" class="collapsed">Can scientists collaborate on the same DMP even though they may belong to different institutions (e.g. a hospital, a University, etc, collaborating on a project) and the dataset also "belongs" to different institutions? +
+
+ Of course. Argos supports collaborations across diverse teams. There are two most frequent ways that can address this question: +

+ A. Everyone works on the same DMP, but on different dataset descriptions +

+ In this case, each organisation makes its own dataset description(s) in a single DMP. + That means that the manager (i.e. person responsible for the DMP activity) creates a DMP in ARGOS + and shares it with everyone. If the DMP is shared with co-ownership rights, + then the people will be able to edit it and add their dataset descriptions at any time during the project. + If there is the need to control editing rights of people writing the DMPs, then the manager can create the dataset description(s) + and share these each time with the team members that are responsible for adding input for the specified datasets. +

+ B. Everyone works on their own DMP and content is later merged into one single DMP +

+ In this case, each organisation might work on their own DMP for the same project. + At one point, you need to decide which DMP is going to be the core for the work you perform, share co-ownership + between managers of all DMPs so they can copy all dataset descriptions of their DMPs in this single DMP document. +
+
+
+
+ +
DMPs and Datasets can be cloned and used in different research contexts. Existing DMPs presenting similarities with new ones, can be cloned, changed name and @@ -612,11 +674,11 @@
-
+
Versioning in Argos is both an internal and an external process. That means that versioning happens both in the Argos environment when editing the DMP, and outside @@ -637,7 +699,7 @@
+ aria-controls="collapseFAQ-6" class="collapsed">DMPs and Datasets
@@ -646,7 +708,7 @@
+ aria-controls="collapseFAQ-6-1" class="collapsed">What is the DMP?
@@ -667,7 +729,7 @@
+ aria-controls="collapseFAQ-6-2" class="collapsed">How do I find which Dataset template to use?
@@ -684,7 +746,7 @@
+ aria-controls="collapseFAQ-6-3" class="collapsed">How do I create my own Dataset template?
@@ -701,10 +763,41 @@
+ aria-controls="collapseFAQ-6-4" class="collapsed">Can I create smaller versions of a template for project proposals?
+
+ Yes, it is possible in Argos to create short versions of templates that can be used + for grant proposals, such as for Horizon Europe. + If you are interested in working with us to create this short version of any ARGOS template, + please contact us: argos@openaire.eu. +
+
+
+
+ +
+
+ Yes, you can. In the current version, this is possible for Admin users who have their own deployment on-premises or cloud. + Please note that this subject to change in the near future as we are working on a feature that will allow all users + to customise (remove/add/extend) specific questions on the template they are working on. +
+
+
+
+ +
A Dataset in Argos is an editor with set up questions that support the creation of descriptions of how data are / have been handled, managed and curated throughout the @@ -719,11 +812,11 @@
-
+
You don’t necessarily need to have many Datasets in a DMP. However, you might be producing a plethora of data during your research that are diverse in type and/ or @@ -739,11 +832,61 @@
-
+
+
+ This is something that has to be tackled conceptually, from the author of the DMP. + If those "products" have their own lifetime and rules (IPR, Access rights, etc), they should be described as different datasets. + Alternative formats should not be treated as different datasets, unless they have other differences due to the format, too. + But, for instance, if you have datasets in CSV and JSON formats and under the same terms, they could be seen as one dataset description in the DMP. +
+
+
+
+ +
+
+ Argos offers a search to Zenodo for prefilling the DMP you are working with dataset metadata. + This search has been developed according to the rules set by Zenodo + and therefore has the same behaviour as when you are using the search bar on the Zenodo interface. + However, we understand the need to be able to find records with their PID, + hence we introduced some changes and now support searching DOIs from the Argos interface. +
+
+
+
+ +
+
+ Of course! You can choose to manually describe your dataset, e.g. for a dataset you are planning to produce, + instead of pre-filling the template with available metadata from a dataset that has already been shared and preserved in a repository. +
+
+
+
+ +
Public DMPs and Public Datasets are collections of openly available Argos outputs. That means that DMP owners and members are making their DMP and/or Dataset outputs @@ -756,12 +899,12 @@
-
+
No, it is not. You can choose how your DMP is displayed in Argos from the “Visibility” option. Choosing Public will immediately locate your DMP in the “Public @@ -775,12 +918,30 @@
+
+
+ DMP export contains all vital information for a DMP, including funding and dataset details, + while dataset export is a subset of the DMP export containing information only about a dataset described in the DMP. + Both DMP and Dataset exports are available in .pdf, .docx, .xml. + In addition, DMP export is available in the RDA .json format + to increase interoperability of ARGOS exchanged DMPs. +
+
+
+
+ -
+
No, there is no storage limit or fee for either files stored in Argos.
@@ -793,7 +954,7 @@
+ aria-controls="collapseFAQ-7" class="collapsed">Publishing DMPs
@@ -802,10 +963,74 @@
+ aria-controls="collapseFAQ-7-1" class="collapsed">Is it possible to publish DMPs in different repositories (so not Zenodo)? +
+
+ Yes, it is possible. + But, to have different repositories attached to the system, you will need your own on-premises or cloud deployment. + We are already working on that for DSpace and Dataverse repositories. +
+
+
+
+ +
+
+ Yes, we are aware of that. + Argos has no control over the DMPs that you generate and publish and thus can not be held accountable for empty DMPs. + Please remember that, as on all other occasions where you publish content, you should do so responsinbly. + If you have any questions regarding publishing DMPs, don’t hesitate to contact us at argos@openaire.eu. +
+
+
+
+ +
+
+ Both options are possible according to how you have deposited the DMP in the first place. + If you have deposited your DMP with a token (i.e. from the ARGOS account on Zenodo), + then you won’t have editing rights on the Zenodo record, but you will still be able to make changes + on ARGOS by starting and depositing a new version of the published DMP. + However, if you have deposited your DMP using your own account on Zenodo (i.e. login to Zenodo with your own credentials), + then you are able to also make minor changes, e.g. on the title of the DMP, directly from the Zenodo interface. +
+
+
+
+
+
+
+
+ +
+
+
+
+ +
You might be experiencing this problem because there are incomplete mandatory fields in your DMP. Please check for those fields, fill in with appropriate information and @@ -816,11 +1041,11 @@
-
+
DMPs can be shared with many colleagues in support of collaborative writing, but DMPs should be worked by one person at a time. Argos will inform you if another @@ -832,11 +1057,11 @@
-
+
You need to have a Zenodo login to perform a deposit. Please sign up in Zenodo or use the token option to publish your DMPs and get a DOI. @@ -849,20 +1074,20 @@
-
+
-
+
Yes, it is. The OpenDMP software that Argos has deployed upon is open source code available under Apache 2.0 license. You may find more information about the software @@ -873,11 +1098,11 @@
-
+
Of course! Please feel free to suggest new features and to actively contribute to Argos development via pull requests in Gitea. @@ -887,11 +1112,11 @@
-
+
Argos takes all necessary steps in handling and protecting personal and sensitive information. Please check the Argos Terms of Service and Privacy Policy. @@ -901,11 +1126,11 @@
-
+
Please find all information about Argos Terms of Service and Privacy, here. Additionally, you may find Argos Cookies policy, here. @@ -915,12 +1140,12 @@
-
+
Unless there are any contractual or institutional agreements stating ownership of outputs produced in the context of a project/ collaboration, owners of Argos outputs @@ -932,11 +1157,11 @@
-
+
Please find all information about Argos Terms of Service and Privacy, here. Additionally, you may find Argos Cookies policy, here. From 5087a37e15410fa540f059a6d57bd2316aa14576 Mon Sep 17 00:00:00 2001 From: Aldo Mihasi Date: Tue, 13 Sep 2022 10:35:56 +0300 Subject: [PATCH 10/13] dockerization --- .env | 11 +- .gitignore | 2 + README.md | 63 +++++++ dmp-backend/Docker/dmp-backend.env | 2 +- dmp-backend/Dockerfile | 8 +- .../ProductionDatabaseConfiguration.java | 2 +- .../DynamicFunderConfigurationProdImpl.java | 2 +- .../DynamicGrantConfigurationProdImpl.java | 2 +- .../DynamicProjectConfigurationProdImpl.java | 2 +- .../commons/datafield/UploadData.java | 3 +- ...operties => application-docker.properties} | 80 +++++++-- .../config/application-production.properties | 101 ----------- .../resources/config/application.properties | 2 +- ...logback-staging.xml => logback-docker.xml} | 0 .../resources/logging/logback-production.xml | 33 ---- dmp-frontend/Dockerfile | 21 +-- dmp-frontend/mime.types | 1 + docker-compose.dev.yml | 168 ------------------ docker-compose.override.yml | 90 ++++++++++ docker-compose.yml | 78 +++++++- 20 files changed, 313 insertions(+), 358 deletions(-) create mode 100644 README.md rename dmp-backend/web/src/main/resources/config/{application-staging.properties => application-docker.properties} (52%) delete mode 100644 dmp-backend/web/src/main/resources/config/application-production.properties rename dmp-backend/web/src/main/resources/logging/{logback-staging.xml => logback-docker.xml} (100%) delete mode 100644 dmp-backend/web/src/main/resources/logging/logback-production.xml delete mode 100644 docker-compose.dev.yml create mode 100644 docker-compose.override.yml diff --git a/.env b/.env index 31c132e98..1e68e910f 100644 --- a/.env +++ b/.env @@ -1,6 +1,5 @@ -TAG=6.3.0 -ENV=prod -PROFILE=production -AOT=aot -ELASTIC_VERSION=6.3.0 -ELASTIC_PASSWORD=changeme +PROFILE=docker + +# Version of Elastic products +ELK_VERSION=7.17.4 +STACK_VERSION=7.17.4 diff --git a/.gitignore b/.gitignore index b6c15ce08..2190e52ff 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,5 @@ ELK.Docker/shared/data-elk/ .settings/ bin/ *.classpath +openDMP/dmp-backend/uploads/ +openDMP/dmp-backend/tmp/ diff --git a/README.md b/README.md new file mode 100644 index 000000000..2f4e8f27d --- /dev/null +++ b/README.md @@ -0,0 +1,63 @@ +# Using Docker Compose with Argos + +ARGOS is an open extensible service that simplifies the management, validation, monitoring and maintenance and of Data Management Plans. It allows actors (researchers, managers, supervisors etc) to create actionable DMPs that may be freely exchanged among infrastructures for carrying out specific aspects of the Data management process in accordance with the intentions and commitment of Data owners. + +## Before running the docker compose commands, configurations must be set + +### Database + +First of all, database must be configured + +The only file that has to be changed is **/dmp-db-scema/Docker/dmp-db.env** + +```bash +ADMIN_USER: Admin username (app) +ADMIN_PASSWORD: Admin password (app) + +POSTGRES_DB: database name +POSTGRES_USER: Admin username (database) +POSTGRES_PASSWORD: Admin password (database) +``` + +### Backend + +Secondly, a few more options should be asigned + +The file **/dmp-backend/web/src/main/resources/config/application-docker.properties** contains all the necessary properties + +Values to be modified: +```bash +database.url: the url that is used to connect to database (JDBC based) +database.username: database admin username +database.password: database admin password + +elasticsearch.*(optional): setup elastic, check Elasticsearch(optional) section below + +google.login.clientId(optional): google as login provider +``` +**NOTE:** if you want to configure and integrate other providers, check this reference [Setup configurable login](https://code-repo.d4science.org/MaDgiK-CITE/argos/wiki/Page-2A:-Setup-configurable-login) + +If you provide google.login.clientId, then the same value should be set in the field named **loginProviders.googleConfiguration.clientId** which belongs to **/dmp-frontend/src/assets/config/config.json** + +## You are ready to build and run the entire application using Docker-compose + +1. Go to the project's root directory +2. Type in the **Terminal** `docker volume create --name=dmpdata` +3. Type in the **Terminal** `docker-compose up -d --build` +4. After it's complete your application is running on [http://localhost:8080](http://localhost:8080) + +### Elasticsearch(optional) +If you want to set up elasticsearch, you will need the password for the **elastic** user + +After your application is running, type in the **Terminal** `docker exec -it elasticsearch /bin/sh` + +Run the command `cat data/passwords.txt` in the shell and save its output + +Finally, run `exit` to get back to your terminal + +The elastic's password that you get has to be set in the **elasticsearch.password** property in the backend configuration + +Rerun the application + +1. Type in the **Terminal** `docker-compose down` +2. Type in the **Terminal** `docker-compose up -d --build` \ No newline at end of file diff --git a/dmp-backend/Docker/dmp-backend.env b/dmp-backend/Docker/dmp-backend.env index eada87b0c..50fb7881d 100644 --- a/dmp-backend/Docker/dmp-backend.env +++ b/dmp-backend/Docker/dmp-backend.env @@ -1 +1 @@ -PROFILE=staging \ No newline at end of file +PROFILE=docker \ No newline at end of file diff --git a/dmp-backend/Dockerfile b/dmp-backend/Dockerfile index b79a77070..54c70beae 100644 --- a/dmp-backend/Dockerfile +++ b/dmp-backend/Dockerfile @@ -1,22 +1,22 @@ -FROM maven:3-jdk-8-alpine AS MAVEN_BUILD +FROM maven:3-jdk-11 AS MAVEN_BUILD COPY pom.xml /build/ COPY data /build/data/ COPY elastic /build/elastic/ -COPY logging /build/logging/ +#COPY logging /build/logging/ COPY queryable /build/queryable/ COPY web /build/web/ WORKDIR /build/ -RUN mvn package +RUN mvn package -q -FROM openjdk:8-jre-alpine +FROM amazoncorretto:11 WORKDIR /app COPY --from=MAVEN_BUILD /build/web/target/web-1.0-SNAPSHOT.jar /app.jar diff --git a/dmp-backend/web/src/main/java/eu/eudat/configurations/ProductionDatabaseConfiguration.java b/dmp-backend/web/src/main/java/eu/eudat/configurations/ProductionDatabaseConfiguration.java index e26ca6732..f293c5d06 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/configurations/ProductionDatabaseConfiguration.java +++ b/dmp-backend/web/src/main/java/eu/eudat/configurations/ProductionDatabaseConfiguration.java @@ -24,7 +24,7 @@ import java.util.Properties; */ @Configuration @EnableTransactionManagement -@Profile({ "production", "staging" }) +@Profile({ "production", "staging", "docker" }) @ComponentScan(basePackages = {"eu.eudat.data.entities"}) public class ProductionDatabaseConfiguration { diff --git a/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicfunder/DynamicFunderConfigurationProdImpl.java b/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicfunder/DynamicFunderConfigurationProdImpl.java index 1e8adbfdc..4e06d2d84 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicfunder/DynamicFunderConfigurationProdImpl.java +++ b/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicfunder/DynamicFunderConfigurationProdImpl.java @@ -20,7 +20,7 @@ import java.util.LinkedList; import java.util.List; @Service("dynamicFunderConfiguration") -@Profile({ "production", "staging" }) +@Profile({ "production", "staging", "docker" }) public class DynamicFunderConfigurationProdImpl implements DynamicFunderConfiguration { private static final Logger logger = LoggerFactory.getLogger(DynamicFunderConfigurationProdImpl.class); diff --git a/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicgrant/DynamicGrantConfigurationProdImpl.java b/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicgrant/DynamicGrantConfigurationProdImpl.java index db6d0c0ec..bdfc63b5b 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicgrant/DynamicGrantConfigurationProdImpl.java +++ b/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicgrant/DynamicGrantConfigurationProdImpl.java @@ -24,7 +24,7 @@ import java.util.List; * Created by ikalyvas on 3/23/2018. */ @Service("dynamicGrantConfiguration") -@Profile({ "production", "staging" }) +@Profile({ "production", "staging", "docker" }) public class DynamicGrantConfigurationProdImpl implements DynamicGrantConfiguration { private static final Logger logger = LoggerFactory.getLogger(DynamicGrantConfigurationProdImpl.class); diff --git a/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicproject/DynamicProjectConfigurationProdImpl.java b/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicproject/DynamicProjectConfigurationProdImpl.java index f3ad8c010..bd4cb625f 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicproject/DynamicProjectConfigurationProdImpl.java +++ b/dmp-backend/web/src/main/java/eu/eudat/configurations/dynamicproject/DynamicProjectConfigurationProdImpl.java @@ -21,7 +21,7 @@ import java.util.LinkedList; import java.util.List; @Service("dynamicProjectConfiguration") -@Profile({ "production", "staging" }) +@Profile({ "production", "staging", "docker" }) public class DynamicProjectConfigurationProdImpl implements DynamicProjectConfiguration{ private static final Logger logger = LoggerFactory.getLogger(DynamicProjectConfigurationProdImpl.class); diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/components/commons/datafield/UploadData.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/components/commons/datafield/UploadData.java index c3b0dad59..a43153256 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/components/commons/datafield/UploadData.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/components/commons/datafield/UploadData.java @@ -85,7 +85,8 @@ public class UploadData extends FieldData { this.setLabel(((Map) data).get("label")); Object maxFileSizeInMB = ((Map) data).get("maxFileSizeInMB"); if(maxFileSizeInMB instanceof String){ // template export - this.setMaxFileSizeInMB(Integer.valueOf((String)maxFileSizeInMB)); + if(!((String)maxFileSizeInMB).isEmpty()) + this.setMaxFileSizeInMB(Integer.valueOf((String)maxFileSizeInMB)); } else if(maxFileSizeInMB instanceof Integer){ // template preview this.setMaxFileSizeInMB((Integer)maxFileSizeInMB); diff --git a/dmp-backend/web/src/main/resources/config/application-staging.properties b/dmp-backend/web/src/main/resources/config/application-docker.properties similarity index 52% rename from dmp-backend/web/src/main/resources/config/application-staging.properties rename to dmp-backend/web/src/main/resources/config/application-docker.properties index a783dd696..1bb017e6e 100644 --- a/dmp-backend/web/src/main/resources/config/application-staging.properties +++ b/dmp-backend/web/src/main/resources/config/application-docker.properties @@ -1,4 +1,4 @@ -dmp.domain = https://devel.opendmp.eu +dmp.domain = http://localhost:8080 ####################PERSISTENCE OVERRIDES CONFIGURATIONS########## database.url=jdbc:postgresql://dmp-db:5432/dmptool @@ -6,40 +6,58 @@ database.username=dmptool database.password=CHANGEME ####################ELASTIIC SEARCH TAGS OVERRIDES CONFIGURATIONS########## -elasticsearch.host = tags-elastic-search +elasticsearch.host = opendmp-elastic elasticsearch.port = 9200 elasticsearch.username=elastic elasticsearch.password= elasticsearch.index=dmps +elasticsearch.usingssl=false +elasticsearch.certPath= +elasticsearch.certKey= + +####################ELK OVERRIDES CONFIGURATIONS########## +#http-logger.server-address = http://logstash:31311 ####################PDF OVERRIDES CONFIGURATIONS########## -pdf.converter.url=http://docsbox-web/ +pdf.converter.url=http://opendmp-pdf:3000/ ####################CONFIGURATION FILES OVERRIDES CONFIGURATIONS########## configuration.externalUrls=externalUrls/ExternalUrls.xml configuration.rda=RDACommonStandards.txt configuration.h2020template=documents/h2020.docx configuration.h2020datasettemplate=documents/h2020_dataset.docx -configuration.configurable_login_providers=ConfigurableLoginProviders.json +configuration.configurable_login_providers=configurableLoginProviders.json configuration.doi_funder=DOI_Funder.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.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=hermes.local.cite.gr +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 +facebook.login.namespace= #############GOOGLE LOGIN CONFIGURATIONS######### google.login.clientId= @@ -47,7 +65,7 @@ google.login.clientId= #############LINKEDIN LOGIN CONFIGURATIONS######### linkedin.login.clientId= linkedin.login.clientSecret= -linkedin.login.redirect_uri=https://devel.opendmp.eu/login/linkedin +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 @@ -55,16 +73,12 @@ 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://devel.opendmp.eu/login/twitter - -#############CONFIRMATION EMAIL CONFIGURATIONS######### -conf_email.expiration_time_seconds=14400 -conf_email.subject=OpenDMP email confirmation +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=https://devel.opendmp.eu/api/oauth/authorized/b2access +b2access.externallogin.redirect_uri=http://localhost:8080/api/oauth/authorized/b2access b2access.externallogin.clientid= b2access.externallogin.clientSecret= @@ -72,20 +86,50 @@ b2access.externallogin.clientSecret= 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 +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= -openaire.login.redirect_uri= -openaire.login.user_info_url= +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.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:8080/login/external/zenodo + #############CONTACT EMAIL CONFIGURATIONS######### contact_email.mail= +logging.config=classpath:logging/logback-${spring.profiles.active}.xml +language.path=i18n/ -language.path=i18n/ \ No newline at end of file +##########################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 296798080..000000000 --- a/dmp-backend/web/src/main/resources/config/application-production.properties +++ /dev/null @@ -1,101 +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 - -####################PDF OVERRIDES CONFIGURATIONS########## -pdf.converter.url=http://docsbox-web/ - -####################CONFIGURATION FILES OVERRIDES CONFIGURATIONS########## -configuration.externalUrls=externalUrls/ExternalUrls.xml -configuration.rda=RDACommonStandards.txt -configuration.h2020template=documents/h2020.docx -configuration.h2020datasettemplate=documents/h2020_dataset.docx -configuration.configurable_login_providers=ConfigurableLoginProviders.json -configuration.doi_funder=DOI_Funder.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/application.properties b/dmp-backend/web/src/main/resources/config/application.properties index 67c57b4dd..d8b13c486 100644 --- a/dmp-backend/web/src/main/resources/config/application.properties +++ b/dmp-backend/web/src/main/resources/config/application.properties @@ -51,7 +51,7 @@ configuration.externalUrls=externalUrls/ExternalUrls.xml configuration.rda=RDACommonStandards.txt configuration.h2020template=documents/h2020.docx configuration.h2020datasettemplate=documents/h2020_dataset.docx -configuration.configurable_login_providers=ConfigurableLoginProviders.json +configuration.configurable_login_providers=configurableLoginProviders.json configuration.doi_funder=DOI_Funder.json ####################EMAIL FILE TEMPLATES OVERRIDES CONFIGURATIONS########## diff --git a/dmp-backend/web/src/main/resources/logging/logback-staging.xml b/dmp-backend/web/src/main/resources/logging/logback-docker.xml similarity index 100% rename from dmp-backend/web/src/main/resources/logging/logback-staging.xml rename to dmp-backend/web/src/main/resources/logging/logback-docker.xml diff --git a/dmp-backend/web/src/main/resources/logging/logback-production.xml b/dmp-backend/web/src/main/resources/logging/logback-production.xml deleted file mode 100644 index cdac3ab14..000000000 --- a/dmp-backend/web/src/main/resources/logging/logback-production.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - ${CONSOLE_LOG_PATTERN} - - - - - logs/openDMP.log - - logs/openDMP-%d{yyyy-MM-dd}.%i.log - - 100MB - - 30 - 3GB - - - ${FILE_LOG_PATTERN} - - - - - - - - - - - - - \ No newline at end of file diff --git a/dmp-frontend/Dockerfile b/dmp-frontend/Dockerfile index 5bff47629..a84918a73 100644 --- a/dmp-frontend/Dockerfile +++ b/dmp-frontend/Dockerfile @@ -1,32 +1,29 @@ # stage1 as builder FROM node:12-alpine AS BUILDER -WORKDIR /page +WORKDIR /app -# copy the package.json to install dependencies -COPY package.json /page +# copy to install dependencies +COPY . . # Install the dependencies and make the folder -RUN npm install - -COPY . /page - -# Build the project and copy the files -RUN npm run ng build -- --prod +RUN npm install && npm run ng build -- --prod FROM nginx:alpine #!/bin/sh +WORKDIR /usr/share/nginx/html + COPY nginx.conf /etc/nginx COPY mime.types /etc/nginx ## Remove default nginx index page -RUN rm -rf /usr/share/nginx/html/* +RUN rm -rf ./* # Copy from the stahg 1 -COPY --from=BUILDER /page/dist /usr/share/nginx/html +COPY --from=BUILDER /app/dist . EXPOSE 4200 -ENTRYPOINT ["nginx", "-g", "daemon off;", "-p", "/usr/share/nginx"] +ENTRYPOINT ["nginx", "-g", "daemon off;"] diff --git a/dmp-frontend/mime.types b/dmp-frontend/mime.types index 62bd4b668..e04788495 100644 --- a/dmp-frontend/mime.types +++ b/dmp-frontend/mime.types @@ -9,6 +9,7 @@ types { text/x-component htc; text/mathml mml; image/png png; + image/svg+xml svg svgz; image/x-icon ico; image/x-jng jng; image/vnd.wap.wbmp wbmp; diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml deleted file mode 100644 index 7dc4ed087..000000000 --- a/docker-compose.dev.yml +++ /dev/null @@ -1,168 +0,0 @@ ---- -version: '3' -services: -##########################ELASTIC###################################################################### - elasticsearch-dmp: - image: docker.elastic.co/elasticsearch/elasticsearch:${TAG} - container_name: elasticsearch-dmp - volumes: - - ./elastic-config/elasticsearch-custom.yml:/usr/share/elasticsearch/config/elasticsearch.yml - environment: ['http.host=0.0.0.0','transport.host=0.0.0.0','discovery.type=single-node'] - ports: ['0.0.0.0:9201:9200','0.0.0.0:9301:9300'] - networks: ['elasticsearch-dmp'] - volumes: - - esdata-dmp:/usr/share/elasticsearch/data - -##########################ELK-STACK###################################################################### - - elasticsearch: - image: docker.elastic.co/elasticsearch/elasticsearch:${TAG} - container_name: elasticsearch - environment: ['http.host=0.0.0.0', 'transport.host=127.0.0.1', 'ELASTIC_PASSWORD=${ELASTIC_PASSWORD}','discovery.type=single-node'] - ports: ['0.0.0.0:9200:9200'] - networks: ['stack'] - volumes: - - esdata:/usr/share/elasticsearch/data - - kibana: - image: docker.elastic.co/kibana/kibana:${TAG} - container_name: kibana - ports: ['0.0.0.0:5601:5601'] - networks: ['stack'] - depends_on: ['elasticsearch'] - - logstash: - image: docker.elastic.co/logstash/logstash:${TAG} - container_name: logstash - volumes: - - ./ELK.Docker/config/logstash.conf:/usr/share/logstash/pipeline/logstash.conf - ports: ['0.0.0.0:31311:31311'] - - networks: ['stack'] - depends_on: ['elasticsearch', 'setup_logstash'] - - #filebeat: - # image: docker.elastic.co/beats/filebeat:${TAG} - # container_name: filebeat - # command: -e -E 'output.elasticsearch.password=${ELASTIC_PASSWORD}' - # networks: ['stack'] - # depends_on: ['elasticsearch', 'setup_filebeat'] - - #heartbeat: - # image: docker.elastic.co/beats/heartbeat:${TAG} - # container_name: heartbeat - # command: -e -E 'output.elasticsearch.password=${ELASTIC_PASSWORD}' - # networks: ['stack'] - # depends_on: ['elasticsearch', 'setup_heartbeat'] - - # Run a short-lived container to set up Logstash. - setup_logstash: - image: centos:7 - container_name: setup_logstash - volumes: ['./ELK.Docker/scripts/setup-logstash.sh:/usr/local/bin/setup-logstash.sh:ro'] - command: ['/bin/bash', '-c', 'cat /usr/local/bin/setup-logstash.sh | tr -d "\r" | bash'] - environment: ['ELASTIC_PASSWORD=${ELASTIC_PASSWORD}'] - networks: ['stack'] - depends_on: ['elasticsearch'] - - setup_kibana: - image: centos:7 - container_name: setup_kibana - volumes: ['./ELK.Docker/scripts/setup-kibana.sh:/usr/local/bin/setup-kibana.sh:ro'] - command: ['/bin/bash', '-c', 'cat /usr/local/bin/setup-kibana.sh | tr -d "\r" | bash'] - environment: ['ELASTIC_PASSWORD=${ELASTIC_PASSWORD}'] - networks: ['stack'] - depends_on: ['elasticsearch'] - - #setup_filebeat: - # image: docker.elastic.co/beats/filebeat:${TAG} - # container_name: setup_filebeat - # volumes: ['./ELK.Docker/scripts/setup-beat.sh:/usr/local/bin/setup-beat.sh:ro'] - # command: ['/bin/bash', '-c', 'cat /usr/local/bin/setup-beat.sh | tr -d "\r" | bash -s filebeat'] - # environment: ['ELASTIC_PASSWORD=${ELASTIC_PASSWORD}'] - # networks: ['stack'] - # depends_on: ['kibana'] - - #setup_heartbeat: - # image: docker.elastic.co/beats/heartbeat:${TAG} - # container_name: setup_heartbeat - # volumes: ['./ELK.Docker/scripts/setup-beat.sh:/usr/local/bin/setup-beat.sh:ro'] - # command: ['/bin/bash', '-c', 'cat /usr/local/bin/setup-beat.sh | tr -d "\r" | bash -s heartbeat'] - # environment: ['ELASTIC_PASSWORD=${ELASTIC_PASSWORD}'] - # networks: ['stack'] - # depends_on: ['kibana'] - -##########################DOCSBOX###################################################################### - # web: - # restart: always - # build: ./docsbox-master/docsbox - # expose: - # - "8000" - # links: - # - redis:redis - # volumes: - # - docsbox:/home/docsbox - # - media:/home/docsbox/media - # command: gunicorn -b :8000 docsbox:app - # networks: ['stack'] - - # rqworker: - # restart: always - # build: ./docsbox-master/docsbox - # links: - # - redis:redis - # volumes: - # - web - # command: rq worker -c docsbox.settings - # networks: ['stack'] - - # rqscheduler: - # restart: always - # build: ./docsbox-master/docsbox - # links: - # - redis:redis - # volumes: - # - web - # command: rqscheduler -H redis -p 6379 -d 0 - # networks: ['stack'] - - # nginx: - # restart: always - # build: ./docsbox-master/nginx/ - # ports: - # - "81:80" - # volumes: - # - web - # links: - # - web:web - # networks: ['stack'] - - # redis: - # restart: always - # image: redis:latest - # expose: - # - "6379" - # volumes: - # - redisdata:/data - # networks: ['stack'] - - -##########################SETTINGS###################################################################### - -volumes: - esdata: - driver: local - esdata-dmp: - driver: local - #redisdata: - # driver: local - # docsbox: - # driver: local - # media: - # driver: local -networks: - stack: {} - elasticsearch-dmp: {} - - - diff --git a/docker-compose.override.yml b/docker-compose.override.yml new file mode 100644 index 000000000..f8bfbc584 --- /dev/null +++ b/docker-compose.override.yml @@ -0,0 +1,90 @@ +version: "3.8" + +services: + elasticsearch: + user: 1002:1002 #develuser + restart: unless-stopped + mem_limit: 2048m + environment: + - cluster.name=open-dmp-cluster + - bootstrap.memory_lock=true + - "ES_JAVA_OPTS=-Xmx1024m -Xms1024m" + - xpack.license.self_generated.type=basic + - xpack.monitoring.collection.enabled=true + - xpack.security.enabled=true + ulimits: + nproc: 65535 + memlock: + soft: -1 + hard: -1 + volumes: + - ./ELK.Docker/shared/config-elk/elasticsearch/config/log4j2.properties:/usr/share/elasticsearch/config/log4j2.properties:ro + - ./ELK.Docker/shared/config-elk/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:ro + - ./ELK.Docker/shared/data-elk/elasticsearch-01-data:/usr/share/elasticsearch/data + - ./ELK.Docker/shared/data-elk/elasticsearch-01-log:/usr/share/elasticsearch/logs + #ports: + # - 51056:9200 + # - 51057:9300 + ports: + - "9201:9200" + expose: + - "9200" + hostname: opendmp-elastic + networks: + open-dmp-elk-network: + aliases: + - opendmp-elastic + + logstash: + # user: 1002:1002 #develuser + volumes: + - ./ELK.Docker/shared/config-elk/logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml:ro + - ./ELK.Docker/shared/config-elk/logstash/config/pipelines.yml:/usr/share/logstash/config/pipelines.yml:ro + - ./ELK.Docker/shared/config-elk/logstash/config/log4j2.properties:/usr/share/logstash/config/log4j2.properties:ro + - ./ELK.Docker/shared/config-elk/logstash/pipeline:/usr/share/logstash/pipeline:ro + - ./ELK.Docker/shared/config-elk/logstash/logstash/templates:/usr/share/logstash/templates + - ./ELK.Docker/shared/data-elk/logstash-log:/usr/share/logstash/logs + - ./ELK.Docker/shared/data-elk/logstash-queue:/usr/share/logstash/queue + - ./ELK.Docker/shared/data-elk/logstash-dead_letter_queue:/usr/share/logstash/dead_letter_queue + expose: + - "31311" + - "31312" + restart: on-failure + mem_limit: 2048m + environment: + - LS_JAVA_OPTS=-Xmx1024m -Xms1024m + - xpack.license.self_generated.type=basic + - xpack.security.enabled=true + networks: + open-dmp-elk-network: + + kibana: + # user: 1002:1002 #develuser + mem_limit: 512m + environment: + - xpack.license.self_generated.type=basic + - xpack.security.enabled=true + + volumes: + - ./ELK.Docker/shared/config-elk/kibana/config:/usr/share/kibana/config:ro + #- ./ELK.Docker/shared/config-elk/kibana/certificates:/usr/share/kibana/certificates + restart: unless-stopped + ports: + - "51058:5601" + networks: + - open-dmp-elk-network + + filebeat: + restart: unless-stopped + mem_limit: 256m + #command: [ "-e=false" ] # to overwrite the -e that disables logging to file! + volumes: + - ./ELK.Docker/shared/config-elk/filebeat/config/filebeat.yml:/usr/share/filebeat/filebeat.yml:ro + - ./openDMP/logs:/usr/share/filebeat/log_data/dmp/ + - ./ELK.Docker/shared/data-elk/filebeat-log:/usr/share/filebeat/logs + - ./ELK.Docker/shared/data-elk/filebeat-data:/usr/share/filebeat/data #For windows if we mount the data directory we get "Writing of registry returned error: sync /usr/share/filebeat/data/registry/filebeat: invalid argument." + networks: + - open-dmp-elk-network + +networks: + open-dmp-elk-network: diff --git a/docker-compose.yml b/docker-compose.yml index 18412a920..fea9b49bf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,4 @@ -version: "2.4" +version: "3.8" services: dmp-db: @@ -18,6 +18,20 @@ services: networks: - opendmp-backend-network + dmp-pdf-converter: + image: gotenberg/gotenberg:7.4.0 + container_name: opendmp-pdf-converter + restart: unless-stopped + ports: + - "3001:3000" + expose: + - "3000" + hostname: opendmp-pdf + networks: + opendmp-pdf-network: + aliases: + - opendmp-pdf + dmp-backend: build: context: ./dmp-backend @@ -27,18 +41,22 @@ services: mem_limit: 2048m ports: - "8081:8081" + expose: + - "8080" networks: - opendmp-backend-network + - opendmp-pdf-network + - open-dmp-elk-network volumes: - - ./openDMP/dmp-backend/config:/app/config - - ./openDMP/dmp-backend/user-guide:/app/user-guide - - ./openDMP/dmp-backend/i18n:/app/i18n - - ./openDMP/dmp-backend/externalUrls:/app/externalUrls - - ./openDMP/dmp-backend/templates:/app/templates + - ./dmp-backend/web/main/resources/config:/app/config + - ./user-guide:/app/user-guide + - ./dmp-frontend/src/assets/i18n:/app/i18n + - ./dmp-backend/web/main/resources/externalUrls:/app/externalUrls + - ./dmp-backend/web/main/resources/templates:/app/templates - ./openDMP/dmp-backend/opendmp-logs:/app/logs - ./openDMP/dmp-backend/tmp:/app/tmp - - ./openDMP/dmp-backend/logging:/app/logging - - ./openDMP/dmp-backend/documents:/app/documents + - ./dmp-backend/web/main/resources/logging:/app/logging + - ./dmp-backend/web/main/resources/documents:/app/documents dmp-frontend: build: @@ -50,13 +68,55 @@ services: - "8080:4200" volumes: - ./openDMP/dmp-frontend/static-files:/usr/share/nginx/static - - ./openDMP/dmp-frontend/webapp/config:/usr/share/nginx/html/assets/config + - ./dmp-frontend/src/assets/config:/usr/share/nginx/html/assets/config networks: - opendmp-frontend-network + elasticsearch: + image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} + container_name: elasticsearch + build: + context: ./ELK.Docker/elasticsearch/ + args: + ELK_VERSION: $ELK_VERSION + healthcheck: + # test: curl --cacert /usr/share/elasticsearch/config/certificates/ca/ca.crt -s https://localhost:9200 >/dev/null; if [[ $$? == 52 ]]; then echo 0; else echo 1; fi + interval: 30s + timeout: 10s + retries: 5 + + logstash: + image: docker.elastic.co/logstash/logstash:${STACK_VERSION} + container_name: logstash + build: + context: ./ELK.Docker/logstash/ + args: + ELK_VERSION: $ELK_VERSION + depends_on: + - elasticsearch + + kibana: + image: docker.elastic.co/kibana/kibana:${STACK_VERSION} + build: + context: ./ELK.Docker/kibana/ + args: + ELK_VERSION: $ELK_VERSION + depends_on: + - elasticsearch + filebeat: + image: docker.elastic.co/filebeat/filebeat:${STACK_VERSION} + build: + context: ./ELK.Docker/filebeat/ + args: + ELK_VERSION: $ELK_VERSION + depends_on: + - logstash + networks: opendmp-frontend-network: opendmp-backend-network: + opendmp-pdf-network: + open-dmp-elk-network: volumes: dmpdata: external: true From 4cab6ca1607fd4e663dd068b67b3779906936887 Mon Sep 17 00:00:00 2001 From: "konstantina.galouni" Date: Fri, 16 Sep 2022 10:32:29 +0300 Subject: [PATCH 11/13] dmp-editor.component.ts: [Bug fix - #8073] Set value of "status" field of formGroup to DmpStatus.Draft, after reset() is called. --- dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts index e14bf2cfd..007dfa991 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts @@ -1065,6 +1065,7 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements } } else { this.formGroup.reset(); + this.formGroup.get("status").setValue(DmpStatus.Draft); this.formGroup.get('extraProperties').get('visible').setValue(false); this.formGroup.get('extraProperties').get('contact').setValue(this.authService.current().id); this.formGroup.get('associatedUsers').setValue([]); From ef327a0a576d236c0e2252485e8ba46bcaccf6a6 Mon Sep 17 00:00:00 2001 From: Aldo Mihasi Date: Tue, 4 Oct 2022 13:06:49 +0300 Subject: [PATCH 12/13] expose public api --- dmp-backend/pom.xml | 2 +- dmp-backend/web/pom.xml | 10 + .../configurations/SwaggerConfiguration.java | 39 +++ ...ublicDatasetsDescriptionDocumentation.java | 252 +++++++++++++++ .../controllers/PublicDmpsDocumentation.java | 277 +++++++++++++++++ .../dataset/DatasetPublicCriteria.java | 93 ++++++ .../dmp/DataManagementPlanPublicCriteria.java | 83 +++++ .../mapper/DmpPublicCriteriaMapper.java | 55 ++++ .../DataManagementPlanPublicManager.java | 80 +++++ .../managers/DatasetPublicManager.java | 179 +++++++++++ .../AssociatedProfilePublicModel.java | 57 ++++ .../DatasetProfilePublicModel.java | 45 +++ .../DataRepositoryPublicModel.java | 136 ++++++++ .../ExternalDatasetPublicListingModel.java | 153 +++++++++ .../datasetwizard/RegistryPublicModel.java | 112 +++++++ .../datasetwizard/ServicePublicModel.java | 113 +++++++ .../funder/FunderPublicOverviewModel.java | 42 +++ .../grant/GrantPublicOverviewModel.java | 100 ++++++ .../DataManagementPlanPublicListingModel.java | 161 ++++++++++ .../DatasetPublicListingModel.java | 174 +++++++++++ .../organisation/OrganizationPublicModel.java | 124 ++++++++ .../DataManagementPlanPublicModel.java | 239 ++++++++++++++ .../overviewmodels/DatasetPublicModel.java | 293 ++++++++++++++++++ .../researcher/ResearcherPublicModel.java | 151 +++++++++ .../models/user/UserInfoPublicModel.java | 68 ++++ .../dataset/DatasetPublicTableRequest.java | 65 ++++ .../DataManagmentPlanPublicTableRequest.java | 59 ++++ 27 files changed, 3161 insertions(+), 1 deletion(-) create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/configurations/SwaggerConfiguration.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/controllers/PublicDatasetsDescriptionDocumentation.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/controllers/PublicDmpsDocumentation.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/criteria/dataset/DatasetPublicCriteria.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/criteria/dmp/DataManagementPlanPublicCriteria.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/criteria/mapper/DmpPublicCriteriaMapper.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/managers/DataManagementPlanPublicManager.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/managers/DatasetPublicManager.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/models/associatedprofile/AssociatedProfilePublicModel.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/models/datasetprofile/DatasetProfilePublicModel.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/models/datasetwizard/DataRepositoryPublicModel.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/models/datasetwizard/ExternalDatasetPublicListingModel.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/models/datasetwizard/RegistryPublicModel.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/models/datasetwizard/ServicePublicModel.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/models/funder/FunderPublicOverviewModel.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/models/grant/GrantPublicOverviewModel.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/models/listingmodels/DataManagementPlanPublicListingModel.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/models/listingmodels/DatasetPublicListingModel.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/models/organisation/OrganizationPublicModel.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/models/overviewmodels/DataManagementPlanPublicModel.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/models/overviewmodels/DatasetPublicModel.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/models/researcher/ResearcherPublicModel.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/models/user/UserInfoPublicModel.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/request/dataset/DatasetPublicTableRequest.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/publicapi/request/dmp/DataManagmentPlanPublicTableRequest.java diff --git a/dmp-backend/pom.xml b/dmp-backend/pom.xml index 4c03539aa..daf645f04 100644 --- a/dmp-backend/pom.xml +++ b/dmp-backend/pom.xml @@ -42,7 +42,7 @@ 4.11 1.2.17 2.15.0 - 1.7.12 + 1.7.15 1.2.3 diff --git a/dmp-backend/web/pom.xml b/dmp-backend/web/pom.xml index 906d08f1a..6d05bdeb8 100644 --- a/dmp-backend/web/pom.xml +++ b/dmp-backend/web/pom.xml @@ -95,6 +95,16 @@ springfox-swagger-ui 3.0.0 + + io.springfox + springfox-swagger2 + 3.0.0 + + + io.springfox + springfox-boot-starter + 3.0.0 + diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/configurations/SwaggerConfiguration.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/configurations/SwaggerConfiguration.java new file mode 100644 index 000000000..3708b7b9f --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/configurations/SwaggerConfiguration.java @@ -0,0 +1,39 @@ +package eu.eudat.publicapi.configurations; + +import eu.eudat.models.data.security.Principal; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.service.Contact; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; + +import java.util.Collections; + +@Configuration +public class SwaggerConfiguration { + + // private static final TypeResolver resolver = new TypeResolver(); + + @Bean + public Docket api() { + return new Docket(DocumentationType.SWAGGER_2) + .select() + .apis(RequestHandlerSelectors.basePackage("eu.eudat.publicapi.controllers")) + .paths(PathSelectors.regex("/api/public/(dmps|datasets)/?.*")) + .build().apiInfo(apiInfo())//.ignoredParameterTypes(Principal.class) + .useDefaultResponseMessages(false); + } + + private ApiInfo apiInfo() { + return new ApiInfo( + "OpenDMP public API", + "Argos public API.", + "1.0", + "https://argos.openaire.eu/terms-and-conditions", + new Contact("Argos", "https://argos.openaire.eu/", "argos@openaire.eu "), + null, null, Collections.emptyList()); + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/controllers/PublicDatasetsDescriptionDocumentation.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/controllers/PublicDatasetsDescriptionDocumentation.java new file mode 100644 index 000000000..c30c9b860 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/controllers/PublicDatasetsDescriptionDocumentation.java @@ -0,0 +1,252 @@ +package eu.eudat.publicapi.controllers; + +import eu.eudat.controllers.BaseController; +import eu.eudat.logic.security.claims.ClaimedAuthorities; +import eu.eudat.logic.services.ApiContext; +import eu.eudat.models.data.helpers.common.DataTableData; +import eu.eudat.models.data.helpers.responses.ResponseItem; +import eu.eudat.models.data.security.Principal; +import eu.eudat.publicapi.managers.DatasetPublicManager; +import eu.eudat.publicapi.models.listingmodels.DatasetPublicListingModel; +import eu.eudat.publicapi.models.overviewmodels.DatasetPublicModel; +import eu.eudat.publicapi.request.dataset.DatasetPublicTableRequest; +import eu.eudat.types.ApiMessageCode; +import eu.eudat.types.Authorities; +import io.swagger.annotations.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + +@Api(tags = "Datasets Description", description = "Provides Dataset description public API's.") +@RestController +@CrossOrigin +@RequestMapping(value = {"/api/public/datasets/"}) +public class PublicDatasetsDescriptionDocumentation extends BaseController { + + private static final Logger logger = LoggerFactory.getLogger(PublicDatasetsDescriptionDocumentation.class); + + private DatasetPublicManager datasetManager; + + public static final String getPagedNotes = "The json response is of type **ResponseItem>** containing the following properties:\n" + + " 1. **message**: string, message indicating error, null if everything went well\n" + + " 2. **statusCode**: integer, status code indicating if something unexpected happened, otherwise 0\n" + + " 3. **responseType**: integer, 0 for json, 1 for file\n" + + " 4. **payload**: DataTableData, containing the number of values of actual data returned and the data of type **DatasetPublicListingModel**\n" + + "4.1. id: string, id of dataset returned\n" + + "4.2. label: string, label of dataset\n" + + "4.3. grant: string, grant of dataset\n" + + "4.4. dmp: string, dmp description\n" + + "4.5. dmpId: string, dmp's id\n" + + "4.6. profile: DatasetProfilePublicModel, dataset's profile\n" + + "4.8. createdAt: date, creation date\n" + + "4.9. modifiedAt: date, modification date\n" + + "4.10. description: string, dataset's description\n" + + "4.11. finalizedAt: date, finalization date\n" + + "4.12. dmpPublishedAt: date, dmp's publication date\n" + + "4.13. version: integer, dataset's version\n" + + "4.14. users: list of UserInfoPublicModel, user who collaborated on the dataset\n"; + public static final String getPagedResponseExample = "{\n" + + " \"statusCode\": 0,\n" + + " \"responseType\": 0,\n" + + " \"message\": null,\n" + + " \"payload\": {\n" + + " \"totalCount\": 2,\n" + + " \"data\": [\n" + + " {\n" + + " \"id\": \"aefc0f61-f2a7-410d-80c6-d3737afc0cd4\",\n" + + " \"label\": \"Copied 27: Agrion forcipula .\",\n" + + " \"grant\": \"Advanced Nitrogen Recovery from Sludge and other Organic Waste Materials (NITRO)\",\n" + + " \"dmp\": \"DMP_Advanced_Nitrogen_Recovery_from_Sludge_and_other_Organic_Waste_Materials_(NITRO)_0.xml\",\n" + + " \"dmpId\": \"8a8368a5-59e9-4d53-aaab-723da2df2d3b\",\n" + + " \"profile\": {\n" + + " \"id\": \"0b5b52f3-266a-45cf-8066-d1e5a70d65e1\",\n" + + " \"label\": \"Horizon 2020 (Devel Clone)\",\n" + + " \"hint\": null\n" + + " },\n" + + " \"createdAt\": 1652274681000,\n" + + " \"modifiedAt\": 1652275258000,\n" + + " \"description\": null,\n" + + " \"finalizedAt\": 1652275257000,\n" + + " \"dmpPublishedAt\": 1652276406000,\n" + + " \"version\": 0,\n" + + " \"users\": [\n" + + " {\n" + + " \"id\": \"4cb5671a-0575-4a50-878a-d1bdf59648a0\",\n" + + " \"name\": \"George Kalampokis\",\n" + + " \"role\": 0,\n" + + " \"email\": \"gkfortests@gmail.com\",\n" + + " \"hint\": \"UserInfoListingModel\"\n" + + " }\n" + + " ],\n" + + " \"hint\": \"datasetListingModel\"\n" + + " },\n" + + " {\n" + + " \"id\": \"f3b241fc-c692-4bb6-b10e-b2a4e2829f9e\",\n" + + " \"label\": \"manually 23\",\n" + + " \"grant\": \"Advanced Nitrogen Recovery from Sludge and other Organic Waste Materials (NITRO)\",\n" + + " \"dmp\": \"DMP_Advanced_Nitrogen_Recovery_from_Sludge_and_other_Organic_Waste_Materials_(NITRO)_0.xml\",\n" + + " \"dmpId\": \"8a8368a5-59e9-4d53-aaab-723da2df2d3b\",\n" + + " \"profile\": {\n" + + " \"id\": \"0b5b52f3-266a-45cf-8066-d1e5a70d65e1\",\n" + + " \"label\": \"Horizon 2020 (Devel Clone)\",\n" + + " \"hint\": null\n" + + " },\n" + + " \"createdAt\": 1652274735000,\n" + + " \"modifiedAt\": 1652275259000,\n" + + " \"description\": null,\n" + + " \"finalizedAt\": 1652275258000,\n" + + " \"dmpPublishedAt\": 1652276406000,\n" + + " \"version\": 0,\n" + + " \"users\": [\n" + + " {\n" + + " \"id\": \"4cb5671a-0575-4a50-878a-d1bdf59648a0\",\n" + + " \"name\": \"George Kalampokis\",\n" + + " \"role\": 0,\n" + + " \"email\": \"gkfortests@gmail.com\",\n" + + " \"hint\": \"UserInfoListingModel\"\n" + + " }\n" + + " ],\n" + + " \"hint\": \"datasetListingModel\"\n" + + " }\n" + + " ]\n" + + " }\n" + + "}"; + public static final String getPagedRequestBodyDescription = "The datasetTableRequest is a DatasetPublicTableRequest object with the following fields:\n" + + "• **length**: how many datasets should be fetched *(required)*\n" + "• **offset**: offset of the returned datasets, first time should be 0, then offset += length\n" + + "• **orderings**: array of strings specifying the order, format:= +string or -string or asc or desc. " + + "**+** means ascending order. **-** means descending order.\n    Available strings are: 1) status, 2) label, 3) created.\n" + + "    **asc** equivalent to +label.\n    **desc** equivalent to -label.\n" + + "**criteria**: this is DatasetPublicCriteria object which applies filters for the datasets returned. More specifically:\n" + + " 1. periodStart: date, datasets created date greater than periodStart\n" + + " 2. periodEnd: date, datasets created date less than periodEnd\n" + + " 3. grants: list of uuids, dmps(datasets) with the corresponding grants\n" + + " 4. collaborators: list of uuids, user who collaborated on the creation/modification of datasets\n" + + " 5. datasetTemplates: list of uuids, dataset templates uuids to be included\n" + + " 6. dmpOrganisations: list of strings, datasets involved in dmps which belong to these organisations\n" + + " 7. tags: list of Tag objects, tags involved in datasets\n" + + " 8. dmpIds: list of uuids, dmps with the specific ids\n" + + " 9. groupIds: list of uuids, in which groups the datasets are\n" + + "10. allVersions: boolean, if datasets should be fetched with all their versions\n" + + "11. like: string, datasets fetched have this string matched in their label or description\n"; + + public static final String getOverviewSinglePublicNotes = "The json response is of type **ResponseItem< DatasetPublicModel >** containing the following properties:\n" + + " 1. **message**: string, message indicating error, null if everything went well\n" + + " 2. **statusCode**: integer, status code indicating if something unexpected happened, otherwise 0\n" + + " 3. **responseType**: integer, 0 for json, 1 for file\n" + + " 4. **payload**: DatasetPublicModel, dmp returned\n" + + "4.1. id: uuid, id of dataset returned\n" + + "4.2. label: string, label of dataset\n" + + "4.3. reference: string, reference of dataset\n" + + "4.4. uri: string, uri of dataset\n" + + "4.5. description: string, dataset's description\n" + + "4.6. status: string, dataset's status\n" + + "4.7. createdAt: date, creation time of dataset\n" + + "4.8. dmp: DataManagementPlanPublicListingModel, dmp to which dataset belongs\n" + + "4.9. datasetProfileDefinition: PagedDatasetProfile, dataset's paged description\n" + + "4.10. registries: list of RegistryPublicModel, dataset's registries\n" + + "4.11. services: list of ServicePublicModel, dataset's services\n" + + "4.12. dataRepositories: list of DataRepositoryPublicModel, dataset's data repositories\n" + + "4.13. tags: list of Tag, dataset's tags\n" + + "4.14. externalDatasets: list of ExternalDatasetPublicListingModel, dataset's external datasets\n" + + "4.15. profile: DatasetProfilePublicModel, dataset's profile\n" + + "4.16. modifiedAt: date, modification time of dataset\n"; + public static final String getOverviewSinglePublicResponseExample = "{\n" + + " \"statusCode\": 0,\n" + + " \"responseType\": 0,\n" + + " \"message\": null,\n" + + " \"payload\": {\n" + + " \"id\": \"aefc0f61-f2a7-410d-80c6-d3737afc0cd4\",\n" + + " \"label\": \"Copied 27: Agrion forcipula .\",\n" + + " \"reference\": null,\n" + + " \"uri\": null,\n" + + " \"description\": null,\n" + + " \"status\": 1,\n" + + " \"createdAt\": 1652274681000,\n" + + " \"dmp\": {\n" + + " \"id\": \"8a8368a5-59e9-4d53-aaab-723da2df2d3b\",\n" + + " \"label\": \"DMP_Advanced_Nitrogen_Recovery_from_Sludge_and_other_Organic_Waste_Materials_(NITRO)_0.xml\",\n" + + " \"grant\": \"Advanced Nitrogen Recovery from Sludge and other Organic Waste Materials (NITRO)\",\n" + + " \"createdAt\": 1652274679000,\n" + + " \"modifiedAt\": 1652276406000,\n" + + " \"version\": 0,\n" + + " \"groupId\": \"5c3f8569-e3f2-4701-a5f0-8d8b2c07cc49\",\n" + + " \"users\": [\n" + + " {\n" + + " \"id\": \"4cb5671a-0575-4a50-878a-d1bdf59648a0\",\n" + + " \"name\": \"George Kalampokis\",\n" + + " \"role\": 0,\n" + + " \"email\": \"gkfortests@gmail.com\",\n" + + " \"hint\": \"UserInfoListingModel\"\n" + + " }\n" + + " ],\n" + + " \"finalizedAt\": 1652276406000,\n" + + " \"publishedAt\": 1652276406000,\n" + + " \"hint\": \"dataManagementPlanListingModel\"\n" + + " },\n" + + " \"datasetProfileDefinition\": {\n" + + " \"pages\": [...],\n" + + " \"rules\": [...],\n" + + " \"status\": 0\n" + + " },\n" + + " \"registries\": [],\n" + + " \"services\": [],\n" + + " \"dataRepositories\": [],\n" + + " \"tags\": null,\n" + + " \"externalDatasets\": [],\n" + + " \"profile\": {\n" + + " \"id\": \"0b5b52f3-266a-45cf-8066-d1e5a70d65e1\",\n" + + " \"label\": \"Horizon 2020 (Devel Clone)\",\n" + + " \"hint\": null\n" + + " },\n" + + " \"modifiedAt\": 1652275258000,\n" + + " \"hint\": \"datasetOverviewModel\"\n" + + " }\n" + + "}"; + + @Autowired + public PublicDatasetsDescriptionDocumentation(ApiContext apiContext, DatasetPublicManager datasetManager) { + super(apiContext); + this.datasetManager = datasetManager; + } + + @ApiOperation(value = "This method is used to get a listing of public datasets.", notes = getPagedNotes) + @ApiResponses(value = {@ApiResponse( + code = 200, + message = "The following example is generated using body: *{\"criteria\": {},\"length\": 2,\"offset\": 0,\"orderings\": {\"fields\": []} }*", + examples = @Example({@ExampleProperty( + value = getPagedResponseExample, + mediaType = APPLICATION_JSON_VALUE + )}) + )}) + @RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json") + public @ResponseBody + ResponseEntity>> getPaged(@RequestBody @ApiParam(value = getPagedRequestBodyDescription) DatasetPublicTableRequest datasetTableRequest) throws Exception { + DataTableData dataTable = this.datasetManager.getPublicPaged(datasetTableRequest); + return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem>().status(ApiMessageCode.NO_MESSAGE).payload(dataTable)); + } + + @ApiOperation(value = "This method is used to get the overview of a public dataset.", notes = getOverviewSinglePublicNotes) + @ApiResponses(value = {@ApiResponse( + code = 200, + message = "The following example is generated using id: *aefc0f61-f2a7-410d-80c6-d3737afc0cd4*", + examples = @Example({@ExampleProperty( + value = getOverviewSinglePublicResponseExample, + mediaType = APPLICATION_JSON_VALUE + )}) + )}) + @RequestMapping(method = RequestMethod.GET, value = {"/{id}"}, produces = "application/json") + public @ResponseBody + ResponseEntity> getOverviewSinglePublic(@PathVariable @ApiParam(value = "fetch the dataset with the given id", example = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx") String id) throws Exception { +// try { + DatasetPublicModel dataset = this.datasetManager.getOverviewSinglePublic(id); + return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE).payload(dataset)); +// } catch (Exception ex) { +// return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE).message(ex.getMessage())); +// } + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/controllers/PublicDmpsDocumentation.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/controllers/PublicDmpsDocumentation.java new file mode 100644 index 000000000..e121145e7 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/controllers/PublicDmpsDocumentation.java @@ -0,0 +1,277 @@ +package eu.eudat.publicapi.controllers; + +import eu.eudat.controllers.BaseController; +import eu.eudat.logic.security.claims.ClaimedAuthorities; +import eu.eudat.logic.services.ApiContext; +import eu.eudat.models.data.helpers.common.DataTableData; +import eu.eudat.models.data.helpers.responses.ResponseItem; +import eu.eudat.models.data.security.Principal; +import eu.eudat.publicapi.managers.DataManagementPlanPublicManager; +import eu.eudat.publicapi.models.listingmodels.DataManagementPlanPublicListingModel; +import eu.eudat.publicapi.models.overviewmodels.DataManagementPlanPublicModel; +import eu.eudat.publicapi.request.dmp.DataManagmentPlanPublicTableRequest; +import eu.eudat.types.ApiMessageCode; +import eu.eudat.types.Authorities; +import io.swagger.annotations.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + +@Api(tags = "DMPs", description = "Provides DMP public API's.") +@RestController +@CrossOrigin +@RequestMapping(value = {"/api/public/dmps"}) +public class PublicDmpsDocumentation extends BaseController { + + private static final Logger logger = LoggerFactory.getLogger(PublicDmpsDocumentation.class); + + private DataManagementPlanPublicManager dataManagementPlanManager; + + private static final String getPagedNotes = "The json response is of type **ResponseItem>** containing the following properties:\n" + + " 1. **message**: string, message indicating error, null if everything went well\n" + + " 2. **statusCode**: integer, status code indicating if something unexpected happened, otherwise 0\n" + + " 3. **responseType**: integer, 0 for json, 1 for file\n" + + " 4. **payload**: DataTableData, containing the number of values of actual data returned and the data of type **DataManagementPlanPublicListingModel**\n" + + "4.1. id: string, id of dmp returned\n" + + "4.2. label: string, label of dmp\n" + + "4.3. grant: string, grant of dmp\n" + + "4.4. createdAt: date, creation time of dmp\n" + + "4.5. modifiedAt: date, modification time of dmp\n" + + "4.6. version: integer, version of dmp\n" + + "4.7. groupId: uuid, group id in which dmp belongs\n" + + "4.8. users: list of UserInfoPublicModel, user who collaborated on the dmp\n" + + "4.9. finalizedAt: date, finalization date\n" + + "4.10. publishedAt: date, publication date\n"; + private static final String getPagedResponseExample = "{\n" + + " \"statusCode\": 0,\n" + + " \"responseType\": 0,\n" + + " \"message\": null,\n" + + " \"payload\": {\n" + + " \"totalCount\": 2,\n" + + " \"data\": [\n" + + " {\n" + + " \"id\": \"912d87de-fce9-48e0-84a7-d5499d10682d\",\n" + + " \"label\": \"Dmp For Project : 0/ANDRE\",\n" + + " \"grant\": \"0/ANDRE\",\n" + + " \"createdAt\": 1554128271000,\n" + + " \"modifiedAt\": 1554128271000,\n" + + " \"version\": 0,\n" + + " \"groupId\": \"764ec97d-2475-4a75-843f-d620cffbdc3f\",\n" + + " \"users\": [],\n" + + " \"finalizedAt\": 1554128271000,\n" + + " \"publishedAt\": 1554128271000,\n" + + " \"hint\": \"dataManagementPlanListingModel\"\n" + + " },\n" + + " {\n" + + " \"id\": \"43809706-0176-4d5c-b47c-c240ac5d874e\",\n" + + " \"label\": \"Dmp new version clone\",\n" + + " \"grant\": \"SMAD\",\n" + + " \"createdAt\": 1539593145000,\n" + + " \"modifiedAt\": 1539593145000,\n" + + " \"version\": 2,\n" + + " \"groupId\": \"536d9779-166e-4b55-ad3e-f93c06338598\",\n" + + " \"users\": [],\n" + + " \"finalizedAt\": 1539593145000,\n" + + " \"publishedAt\": 1539593145000,\n" + + " \"hint\": \"dataManagementPlanListingModel\"\n" + + " }\n" + + " ]\n" + + " }\n" + + "}"; + private static final String getPagedRequestBodyDescription = "The dmpTableRequest is a DataManagementPlanPublicTableRequest object with the following fields:\n" + + "• **length**: how many dmps should be fetched *(required)*\n" + "• **offset**: offset of the returned dmps, first time should be 0, then offset += length\n" + + "• **orderings**: array of strings specifying the order, format:= +string or -string or asc or desc. " + + "**+** means ascending order. **-** means descending order.\n    Available strings are: 1) status, 2) label, 3) publishedAt, 4) created.\n" + + "    **asc** equivalent to +label.\n    **desc** equivalent to -label.\n" + + "**criteria**: this is DataManagementPlanPublicCriteria object which applies filters for the dmp returned. More specifically:\n" + + " 1. periodStart: date, dmps created date greater than periodStart\n" + + " 2. periodEnd: date, dmps created date less than periodEnd\n" + + " 3. grants: list of uuids, dmps with the corresponding grants\n" + + " 4. funders: list of uuids, dmps with the corresponding funders\n" + + " 5. datasetTemplates: list of uuids, dataset templates which are described in the dmps\n" + + " 6. dmpOrganisations: list of strings, dmps belonging to these organisations\n" + + " 7. collaborators: list of uuids, user who collaborated on the creation/modification of dmps\n" + + " 8. allVersions: boolean, if dmps should be fetched with all their versions\n" + + " 9. groupIds: list of uuids, in which groups the dmps are\n" + + "10. like: string, dmps fetched have this string matched in their label or description\n"; + private static final String getPagedRequestParamDescription = "The fieldsGroup is a string which indicates if the returned objects would have all their properties\n" + + "There are two available values: 1) listing and 2) autocomplete\n" + + "**listing**: returns objects with all their properties completed\n" + + "**autocomplete**: returns objects with only id, label, groupId and creationTime assigned"; + + private static final String getOverviewSinglePublicNotes = "The json response is of type **ResponseItem< DataManagementPlanPublicModel >** containing the following properties:\n" + + " 1. **message**: string, message indicating error, null if everything went well\n" + + " 2. **statusCode**: integer, status code indicating if something unexpected happened, otherwise 0\n" + + " 3. **responseType**: integer, 0 for json, 1 for file\n" + + " 4. **payload**: DataManagementPlanPublicModel, dmp returned\n" + + "4.1. id: string, id of dmp returned\n" + + "4.2. label: string, label of dmp\n" + + "4.3. profile: string, profile of dmp\n" + + "4.4. grant: GrantPublicOverviewModel, grant of dmp\n" + + "4.5. createdAt: date, creation time of dmp\n" + + "4.6. modifiedAt: date, modification time of dmp\n" + + "4.7. finalizedAt: date, finalization date of dmp\n" + + "4.8. organisations: list of OrganizationPublicModel, organizations in which dmp belongs\n" + + "4.9. version: integer, version of dmp\n" + + "4.10. groupId: uuid, group id in which dmp belongs\n" + + "4.11. datasets: list of DatasetPublicModel, contained datasets\n" + + "4.12. associatedProfiles: list of AssociatedProfilePublicModel, associated profiles of dmp\n" + + "4.13. researchers: list of ResearcherPublicModel, researchers involved in dmp\n" + + "4.14. users: list of UserInfoPublicModel, user who collaborated on the dmp\n" + + "4.15. description: string, description of dmp\n" + + "4.16. publishedAt: date, publication date\n" + + "4.17. doi: string, if dmp has been published to zenodo so it has doi\n"; + private static final String getOverviewSinglePublicResponseExample = "{\n" + + " \"statusCode\": 0,\n" + + " \"responseType\": 0,\n" + + " \"message\": null,\n" + + " \"payload\": {\n" + + " \"id\": \"912d87de-fce9-48e0-84a7-d5499d10682d\",\n" + + " \"label\": \"Dmp For Project : 0/ANDRE\",\n" + + " \"profile\": null,\n" + + " \"grant\": {\n" + + " \"id\": \"79d35744-3bf4-4178-8bb0-bbc7110788d5\",\n" + + " \"label\": \"0/ANDRE\",\n" + + " \"abbreviation\": null,\n" + + " \"description\": null,\n" + + " \"startDate\": null,\n" + + " \"endDate\": null,\n" + + " \"uri\": null,\n" + + " \"funder\": {\n" + + " \"id\": \"baa92ce2-5ed8-4af0-8b9d-8eeabb8c3dbc\",\n" + + " \"label\": \"0/ANDRE\",\n" + + " \"hint\": null\n" + + " },\n" + + " \"hint\": null\n" + + " },\n" + + " \"createdAt\": 1554128271000,\n" + + " \"modifiedAt\": 1554128271000,\n" + + " \"finalizedAt\": 1554128271000,\n" + + " \"organisations\": [],\n" + + " \"version\": 0,\n" + + " \"groupId\": \"764ec97d-2475-4a75-843f-d620cffbdc3f\",\n" + + " \"datasets\": [\n" + + " {\n" + + " \"id\": \"ac0bf9b2-5804-456c-a5eb-6f797f888a28\",\n" + + " \"label\": \"Dataset : Checks export order For Dmp : Dmp For Project : 0/ANDRE\",\n" + + " \"reference\": null,\n" + + " \"uri\": null,\n" + + " \"description\": null,\n" + + " \"status\": 1,\n" + + " \"createdAt\": 1554127718000,\n" + + " \"dmp\": {\n" + + " \"id\": \"912d87de-fce9-48e0-84a7-d5499d10682d\",\n" + + " \"label\": \"Dmp For Project : 0/ANDRE\",\n" + + " \"grant\": \"0/ANDRE\",\n" + + " \"createdAt\": 1554128271000,\n" + + " \"modifiedAt\": 1554128271000,\n" + + " \"version\": 0,\n" + + " \"groupId\": \"764ec97d-2475-4a75-843f-d620cffbdc3f\",\n" + + " \"users\": [\n" + + " {\n" + + " \"id\": \"e602dad2-2814-401b-b03f-ba05ba799bdc\",\n" + + " \"name\": \"Georgios Kolokythas\",\n" + + " \"role\": 0,\n" + + " \"email\": \"iamgeorgioskolokythas@gmail.com\",\n" + + " \"hint\": \"UserInfoListingModel\"\n" + + " }\n" + + " ],\n" + + " \"finalizedAt\": 1554128271000,\n" + + " \"publishedAt\": 1554128271000,\n" + + " \"hint\": \"dataManagementPlanListingModel\"\n" + + " },\n" + + " \"datasetProfileDefinition\": {\n" + + " \"pages\": [...],\n" + + " \"rules\": [...],\n" + + " \"status\": 0\n" + + " },\n" + + " \"registries\": [],\n" + + " \"services\": [],\n" + + " \"dataRepositories\": [],\n" + + " \"tags\": null,\n" + + " \"externalDatasets\": [],\n" + + " \"profile\": {\n" + + " \"id\": \"01a85982-7cec-41c5-b1f1-74a646e0368b\",\n" + + " \"label\": \"Checks export order\",\n" + + " \"hint\": null\n" + + " },\n" + + " \"modifiedAt\": 1554128182000,\n" + + " \"hint\": \"datasetOverviewModel\"\n" + + " }\n" + + " ],\n" + + " \"associatedProfiles\": [\n" + + " {\n" + + " \"id\": \"01a85982-7cec-41c5-b1f1-74a646e0368b\",\n" + + " \"label\": \"Checks export order\"\n" + + " }\n" + + " ],\n" + + " \"researchers\": [],\n" + + " \"users\": [\n" + + " {\n" + + " \"id\": \"e602dad2-2814-401b-b03f-ba05ba799bdc\",\n" + + " \"name\": \"Georgios Kolokythas\",\n" + + " \"role\": 0,\n" + + " \"email\": \"iamgeorgioskolokythas@gmail.com\",\n" + + " \"hint\": \"UserInfoListingModel\"\n" + + " }\n" + + " ],\n" + + " \"description\": \"Hello\",\n" + + " \"publishedAt\": 1554128271000,\n" + + " \"doi\": null,\n" + + " \"hint\": \"dataManagementPlanOverviewModel\"\n" + + " }\n" + + "}"; + + @Autowired + public PublicDmpsDocumentation(ApiContext apiContext, DataManagementPlanPublicManager dataManagementPlanManager) { + super(apiContext); + this.dataManagementPlanManager = dataManagementPlanManager; + } + + @ApiOperation(value = "This method is used to get a listing of public dmps.", notes = getPagedNotes) + @ApiResponses(value = {@ApiResponse( + code = 200, + message = "The following example is generated using:\n" + + "a) body: *{\"criteria\": {},\"length\": 2,\"offset\": 0,\"orderings\": {\"fields\": []} }*\n" + + "b) fieldsGroup: listing", + examples = @Example({@ExampleProperty( + value = getPagedResponseExample, + mediaType = APPLICATION_JSON_VALUE + )}) + )}) + @RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json") + public @ResponseBody + ResponseEntity>> getPaged(@Valid @RequestBody @ApiParam(value = getPagedRequestBodyDescription) DataManagmentPlanPublicTableRequest dmpTableRequest, + @RequestParam @ApiParam(value = getPagedRequestParamDescription, example = "listing") String fieldsGroup) throws Exception { + DataTableData dataTable = this.dataManagementPlanManager.getPublicPaged(dmpTableRequest, fieldsGroup); + return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem>().status(ApiMessageCode.NO_MESSAGE).payload(dataTable)); + } + + @ApiOperation(value = "This method is used to get the overview of a public dmp.", notes = getOverviewSinglePublicNotes) + @ApiResponses(value = {@ApiResponse( + code = 200, + message = "The following example is generated using id: *912d87de-fce9-48e0-84a7-d5499d10682d*", + examples = @Example({@ExampleProperty( + value = getOverviewSinglePublicResponseExample, + mediaType = APPLICATION_JSON_VALUE + )}) + )}) + @RequestMapping(method = RequestMethod.GET, value = {"/{id}"}, produces = "application/json") + public @ResponseBody + ResponseEntity> getOverviewSinglePublic(@PathVariable @ApiParam(value = "fetch the dmp with the given id", example = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx") String id) throws Exception { +// try { + DataManagementPlanPublicModel dataManagementPlan = this.dataManagementPlanManager.getOverviewSinglePublic(id); + return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE).payload(dataManagementPlan)); +// } catch (Exception ex) { +// return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem().status(ApiMessageCode.NO_MESSAGE).message(ex.getMessage())); +// } + } + +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/criteria/dataset/DatasetPublicCriteria.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/criteria/dataset/DatasetPublicCriteria.java new file mode 100644 index 000000000..f332c7db3 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/criteria/dataset/DatasetPublicCriteria.java @@ -0,0 +1,93 @@ +package eu.eudat.publicapi.criteria.dataset; + +import eu.eudat.data.dao.criteria.Criteria; +import eu.eudat.data.entities.Dataset; +import eu.eudat.elastic.entities.Tag; + +import java.util.Date; +import java.util.List; +import java.util.UUID; + + +public class DatasetPublicCriteria extends Criteria { + private Date periodStart; + private Date periodEnd; + private List grants; + private List collaborators; + private List datasetTemplates; + private List dmpOrganisations; + private List tags; + private List dmpIds; + private List groupIds; + private boolean allVersions; + + public Date getPeriodStart() { + return periodStart; + } + public void setPeriodStart(Date periodStart) { + this.periodStart = periodStart; + } + + public Date getPeriodEnd() { + return periodEnd; + } + public void setPeriodEnd(Date periodEnd) { + this.periodEnd = periodEnd; + } + + public List getGrants() { + return grants; + } + public void setGrants(List grants) { + this.grants = grants; + } + + public List getCollaborators() { + return collaborators; + } + public void setCollaborators(List collaborators) { + this.collaborators = collaborators; + } + + public List getDatasetTemplates() { + return datasetTemplates; + } + public void setDatasetTemplates(List datasetTemplates) { + this.datasetTemplates = datasetTemplates; + } + + public List getDmpOrganisations() { + return dmpOrganisations; + } + public void setDmpOrganisations(List dmpOrganisations) { + this.dmpOrganisations = dmpOrganisations; + } + + public List getTags() { + return tags; + } + public void setTags(List tags) { + this.tags = tags; + } + + public List getDmpIds() { + return dmpIds; + } + public void setDmpIds(List dmpIds) { + this.dmpIds = dmpIds; + } + + public List getGroupIds() { + return groupIds; + } + public void setGroupIds(List groupIds) { + this.groupIds = groupIds; + } + + public boolean getAllVersions() { + return allVersions; + } + public void setAllVersions(boolean allVersions) { + this.allVersions = allVersions; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/criteria/dmp/DataManagementPlanPublicCriteria.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/criteria/dmp/DataManagementPlanPublicCriteria.java new file mode 100644 index 000000000..879a9f996 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/criteria/dmp/DataManagementPlanPublicCriteria.java @@ -0,0 +1,83 @@ +package eu.eudat.publicapi.criteria.dmp; + +import eu.eudat.data.dao.criteria.Criteria; +import eu.eudat.data.entities.DMP; + +import java.util.Date; +import java.util.List; +import java.util.UUID; + +public class DataManagementPlanPublicCriteria extends Criteria { + private Date periodStart; + private Date periodEnd; + private List grants; + private List funders; + private List datasetTemplates; + private List dmpOrganisations; + private List collaborators; + private boolean allVersions; + private List groupIds; + + public Date getPeriodStart() { + return periodStart; + } + public void setPeriodStart(Date periodStart) { + this.periodStart = periodStart; + } + + public Date getPeriodEnd() { + return periodEnd; + } + public void setPeriodEnd(Date periodEnd) { + this.periodEnd = periodEnd; + } + + public List getGrants() { + return grants; + } + public void setGrants(List grants) { + this.grants = grants; + } + + public List getFunders() { + return funders; + } + public void setFunders(List funders) { + this.funders = funders; + } + + public List getDatasetTemplates() { + return datasetTemplates; + } + public void setDatasetTemplates(List datasetTemplates) { + this.datasetTemplates = datasetTemplates; + } + + public List getDmpOrganisations() { + return dmpOrganisations; + } + public void setDmpOrganisations(List dmpOrganisations) { + this.dmpOrganisations = dmpOrganisations; + } + + public List getCollaborators() { + return collaborators; + } + public void setCollaborators(List collaborators) { + this.collaborators = collaborators; + } + + public boolean getAllVersions() { + return allVersions; + } + public void setAllVersions(boolean allVersions) { + this.allVersions = allVersions; + } + + public List getGroupIds() { + return groupIds; + } + public void setGroupIds(List groupIds) { + this.groupIds = groupIds; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/criteria/mapper/DmpPublicCriteriaMapper.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/criteria/mapper/DmpPublicCriteriaMapper.java new file mode 100644 index 000000000..b347dc7e2 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/criteria/mapper/DmpPublicCriteriaMapper.java @@ -0,0 +1,55 @@ +package eu.eudat.publicapi.criteria.mapper; + +import eu.eudat.data.query.definition.helpers.ColumnOrderings; +import eu.eudat.data.query.definition.helpers.Ordering; +import eu.eudat.elastic.criteria.DmpCriteria; +import eu.eudat.elastic.criteria.SortCriteria; +import eu.eudat.publicapi.criteria.dmp.DataManagementPlanPublicCriteria; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +public class DmpPublicCriteriaMapper { + + public static DmpCriteria toElasticCriteria(DataManagementPlanPublicCriteria criteria) { + DmpCriteria elastic = new DmpCriteria(); + + elastic.setPublic(true); + elastic.setLike(criteria.getLike()); + elastic.setAllowAllVersions(criteria.getAllVersions()); + if(criteria.getDatasetTemplates() != null) { + elastic.setTemplates(criteria.getDatasetTemplates()); + } + if (criteria.getGrants() != null) { + elastic.setGrants(criteria.getGrants()); + } + if (criteria.getCollaborators() != null) { + elastic.setCollaborators(criteria.getCollaborators()); + } + if (criteria.getDmpOrganisations() != null) { + elastic.setOrganizations(criteria.getDmpOrganisations().stream().map(UUID::fromString).collect(Collectors.toList())); + } + if(criteria.getGroupIds() != null) { + elastic.setGroupIds(criteria.getGroupIds()); + } + + return elastic; + } + + public static List toElasticSorting(ColumnOrderings columnOrderings) { + List sortCriteria = new ArrayList<>(); + if (columnOrderings.getFieldOrderings() != null && !columnOrderings.getFieldOrderings().isEmpty()) { + for (Ordering ordering: columnOrderings.getFieldOrderings()) { + SortCriteria sortCriteria1 = new SortCriteria(); + sortCriteria1.setFieldName(ordering.getFieldName() + (ordering.getFieldName().contains("label") ?".keyword" : "")); + sortCriteria1.setColumnType(ordering.getColumnType() != null ? SortCriteria.ColumnType.valueOf(ordering.getColumnType().name()): SortCriteria.ColumnType.COLUMN); + sortCriteria1.setOrderByType(SortCriteria.OrderByType.valueOf(ordering.getOrderByType().name())); + sortCriteria.add(sortCriteria1); + } + } + return sortCriteria; + } + +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/managers/DataManagementPlanPublicManager.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/managers/DataManagementPlanPublicManager.java new file mode 100644 index 000000000..5c8b67824 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/managers/DataManagementPlanPublicManager.java @@ -0,0 +1,80 @@ +package eu.eudat.publicapi.managers; + +import eu.eudat.data.entities.DMP; +import eu.eudat.exceptions.security.ForbiddenException; +import eu.eudat.logic.managers.PaginationManager; +import eu.eudat.logic.services.ApiContext; +import eu.eudat.logic.services.operations.DatabaseRepository; +import eu.eudat.models.HintedModelFactory; +import eu.eudat.models.data.helpers.common.DataTableData; +import eu.eudat.publicapi.models.listingmodels.DataManagementPlanPublicListingModel; +import eu.eudat.publicapi.models.overviewmodels.DataManagementPlanPublicModel; +import eu.eudat.publicapi.request.dmp.DataManagmentPlanPublicTableRequest; +import eu.eudat.queryable.QueryableList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.UUID; +import java.util.concurrent.CompletableFuture; + +@Component +public class DataManagementPlanPublicManager { + private static final Logger logger = LoggerFactory.getLogger(DataManagementPlanPublicManager.class); + + private DatabaseRepository databaseRepository; + + @Autowired + public DataManagementPlanPublicManager(ApiContext apiContext) { + this.databaseRepository = apiContext.getOperationsContext().getDatabaseRepository(); + } + + public DataTableData getPublicPaged(DataManagmentPlanPublicTableRequest dmpTableRequest, String fieldsGroup) throws Exception { + dmpTableRequest.setQuery(databaseRepository.getDmpDao().asQueryable().withHint(HintedModelFactory.getHint(DataManagementPlanPublicListingModel.class))); + QueryableList items = dmpTableRequest.applyCriteria(); + QueryableList pagedItems = PaginationManager.applyPaging(items, dmpTableRequest); + + DataTableData dataTable = new DataTableData<>(); + + CompletableFuture itemsFuture; + if (fieldsGroup.equals("listing")) { + itemsFuture = pagedItems.withHint(HintedModelFactory.getHint(DataManagementPlanPublicListingModel.class)) + .selectAsync(item -> { +// item.setDataset( +// item.getDataset().stream() +// .filter(dataset -> dataset.getStatus().equals(Dataset.Status.FINALISED.getValue())).collect(Collectors.toSet())); + return new DataManagementPlanPublicListingModel().fromDataModelNoDatasets(item); + }) + .whenComplete((resultList, throwable) -> dataTable.setData(resultList)); + } else { + itemsFuture = pagedItems + .selectAsync(item -> new DataManagementPlanPublicListingModel().fromDataModel(item)) + .whenComplete((resultList, throwable) -> dataTable.setData(resultList)); + } + + CompletableFuture countFuture = pagedItems.countAsync().whenComplete((count, throwable) -> { + dataTable.setTotalCount(count); + }); + CompletableFuture.allOf(itemsFuture, countFuture).join(); + if(dataTable.getTotalCount() > dmpTableRequest.getLength()) + dataTable.setTotalCount((long)dmpTableRequest.getLength()); + + return dataTable; + } + + public DataManagementPlanPublicModel getOverviewSinglePublic(String id) throws Exception { + DMP dataManagementPlanEntity = databaseRepository.getDmpDao().find(UUID.fromString(id)); + if (dataManagementPlanEntity.getStatus() == DMP.DMPStatus.DELETED.getValue()) { + throw new Exception("DMP is deleted."); + } + if (!dataManagementPlanEntity.isPublic()) { + throw new ForbiddenException("Selected DMP is not public"); + } + DataManagementPlanPublicModel datamanagementPlan = new DataManagementPlanPublicModel(); + datamanagementPlan.fromDataModelDatasets(dataManagementPlanEntity); + datamanagementPlan.setDatasets(datamanagementPlan.getDatasets()); + + return datamanagementPlan; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/managers/DatasetPublicManager.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/managers/DatasetPublicManager.java new file mode 100644 index 000000000..216c8814e --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/managers/DatasetPublicManager.java @@ -0,0 +1,179 @@ +package eu.eudat.publicapi.managers; + +import eu.eudat.data.entities.Dataset; +import eu.eudat.data.query.definition.helpers.ColumnOrderings; +import eu.eudat.elastic.criteria.DatasetCriteria; +import eu.eudat.elastic.repository.DatasetRepository; +import eu.eudat.exceptions.security.ForbiddenException; +import eu.eudat.logic.managers.PaginationManager; +import eu.eudat.logic.services.ApiContext; +import eu.eudat.logic.services.operations.DatabaseRepository; +import eu.eudat.logic.utilities.builders.XmlBuilder; +import eu.eudat.models.HintedModelFactory; +import eu.eudat.models.data.helpers.common.DataTableData; +import eu.eudat.models.data.user.composite.PagedDatasetProfile; +import eu.eudat.publicapi.criteria.mapper.DmpPublicCriteriaMapper; +import eu.eudat.publicapi.models.listingmodels.DatasetPublicListingModel; +import eu.eudat.publicapi.models.overviewmodels.DatasetPublicModel; +import eu.eudat.queryable.QueryableList; +import eu.eudat.types.grant.GrantStateType; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import javax.transaction.Transactional; +import java.util.*; +import java.util.stream.Collectors; + +@Component +public class DatasetPublicManager { + private static final Logger logger = LoggerFactory.getLogger(DatasetPublicManager.class); + + private DatabaseRepository databaseRepository; + private DatasetRepository datasetRepository; + + @Autowired + public DatasetPublicManager(ApiContext apiContext){ + this.databaseRepository = apiContext.getOperationsContext().getDatabaseRepository(); + this.datasetRepository = apiContext.getOperationsContext().getElasticRepository().getDatasetRepository(); + } + + public DataTableData getPublicPaged(eu.eudat.publicapi.request.dataset.DatasetPublicTableRequest datasetTableRequest) throws Exception { + Long count = 0L; + DatasetCriteria datasetCriteria = new DatasetCriteria(); + datasetCriteria.setPublic(true); + datasetCriteria.setLike(datasetTableRequest.getCriteria().getLike()); + datasetCriteria.setDatasetTemplates(datasetTableRequest.getCriteria().getDatasetTemplates()); + datasetCriteria.setDmps(datasetTableRequest.getCriteria().getDmpIds()); + datasetCriteria.setGrants(datasetTableRequest.getCriteria().getGrants()); + datasetCriteria.setCollaborators(datasetTableRequest.getCriteria().getCollaborators()); + datasetCriteria.setAllowAllVersions(datasetTableRequest.getCriteria().getAllVersions()); + datasetCriteria.setOrganiztions(datasetTableRequest.getCriteria().getDmpOrganisations()); + if(datasetTableRequest.getCriteria().getTags() != null && !datasetTableRequest.getCriteria().getTags().isEmpty()){ + datasetCriteria.setHasTags(true); + datasetCriteria.setTags(datasetTableRequest.getCriteria().getTags()); + } + datasetCriteria.setGroupIds(datasetTableRequest.getCriteria().getGroupIds()); + datasetCriteria.setGrantStatus(GrantStateType.ONGOING.getValue().shortValue()); // grant status ongoing + datasetCriteria.setStatus(Dataset.Status.FINALISED.getValue()); // dataset status finalized + if (datasetTableRequest.getOrderings() != null) { + datasetCriteria.setSortCriteria(DmpPublicCriteriaMapper.toElasticSorting(datasetTableRequest.getOrderings())); + } + datasetCriteria.setOffset(datasetTableRequest.getOffset()); + datasetCriteria.setSize(datasetTableRequest.getLength()); + List datasets; + try { + datasets = datasetRepository.exists() ? + datasetRepository.queryIds(datasetCriteria) : new LinkedList<>(); + if(datasetTableRequest.getCriteria().getPeriodStart() != null) + datasets = datasets.stream().filter(dataset -> dataset.getCreated().after(datasetTableRequest.getCriteria().getPeriodStart())).collect(Collectors.toList()); + if(datasetTableRequest.getCriteria().getPeriodEnd() != null) + datasets = datasets.stream().filter(dataset -> dataset.getCreated().before(datasetTableRequest.getCriteria().getPeriodEnd())).collect(Collectors.toList()); + count = (long) datasets.size(); + } catch (Exception ex) { + logger.warn(ex.getMessage()); + datasets = null; + } + /*datasetTableRequest.setQuery(databaseRepository.getDatasetDao().asQueryable().withHint(HintedModelFactory.getHint(DatasetPublicListingModel.class))); + QueryableList items = datasetTableRequest.applyCriteria();*/ + datasetTableRequest.setQuery(databaseRepository.getDatasetDao().asQueryable().withHint(HintedModelFactory.getHint(DatasetPublicListingModel.class))); + QueryableList items; + if (datasets != null) { + if (!datasets.isEmpty()) { + items = databaseRepository.getDatasetDao().asQueryable().withHint(HintedModelFactory.getHint(DatasetPublicListingModel.class)); + List finalDatasets = datasets; + items.where((builder, root) -> root.get("id").in(finalDatasets.stream().map(x -> UUID.fromString(x.getId())).collect(Collectors.toList()))); + } else + items = datasetTableRequest.applyCriteria(); + //items.where((builder, root) -> root.get("id").in(new UUID[]{UUID.randomUUID()})); + } else { + items = datasetTableRequest.applyCriteria(); + } + + List strings = new ArrayList<>(); + strings.add("-dmp:publishedAt|join|"); + if(datasetTableRequest.getOrderings() != null) { + datasetTableRequest.getOrderings().setFields(strings); + } + else{ + datasetTableRequest.setOrderings(new ColumnOrderings()); + datasetTableRequest.getOrderings().setFields(strings); + } + if (count == 0L) { + count = items.count(); + } + QueryableList pagedItems = PaginationManager.applyPaging(items, datasetTableRequest); + DataTableData dataTable = new DataTableData<>(); + + List datasetLists = pagedItems. + select(this::mapPublicModel); + + dataTable.setData(datasetLists.stream().filter(Objects::nonNull).collect(Collectors.toList())); + if(count <= datasetTableRequest.getLength()) + dataTable.setTotalCount(count); + else + dataTable.setTotalCount((long)datasetTableRequest.getLength()); + //CompletableFuture.allOf(countFuture).join(); + return dataTable; + } + + public DatasetPublicModel getOverviewSinglePublic(String id) throws Exception { + Dataset datasetEntity = databaseRepository.getDatasetDao().find(UUID.fromString(id)); + if (datasetEntity.getStatus() == Dataset.Status.DELETED.getValue()) { + throw new Exception("Dataset is deleted."); + } + if (!datasetEntity.getDmp().isPublic()) { + throw new ForbiddenException("Selected Dataset is not public"); + } + DatasetPublicModel dataset = new DatasetPublicModel(); + dataset.setDatasetProfileDefinition(this.getPagedProfile(dataset.getStatus(), datasetEntity)); + dataset.fromDataModel(datasetEntity); + + return dataset; + } + + @Transactional + private DatasetPublicListingModel mapPublicModel(Dataset item) { + /*if (item.getProfile() == null) + return null;*/ + DatasetPublicListingModel listingPublicModel = new DatasetPublicListingModel().fromDataModel(item); + /*DatasetProfileCriteria criteria = new DatasetProfileCriteria(); + criteria.setGroupIds(Collections.singletonList(item.getProfile().getGroupId())); + List profiles = apiContext.getOperationsContext().getDatabaseRepository().getDatasetProfileDao().getWithCriteria(criteria).toList(); + boolean islast = false; + if (!profiles.isEmpty()) { + profiles = profiles.stream().sorted(Comparator.comparing(DatasetProfile::getVersion)).collect(Collectors.toList()); + islast = profiles.get(0).getId().equals(item.getProfile().getId()); + } + listingModel.setProfileLatestVersion(islast);*/ + return listingPublicModel; + } + + private PagedDatasetProfile getPagedProfile(int status, Dataset datasetEntity){ + eu.eudat.models.data.user.composite.DatasetProfile datasetprofile = this.generateDatasetProfileModel(datasetEntity.getProfile()); + datasetprofile.setStatus(status); + if (datasetEntity.getProperties() != null) { + JSONObject jObject = new JSONObject(datasetEntity.getProperties()); + Map properties = jObject.toMap(); + datasetprofile.fromJsonObject(properties); + } + PagedDatasetProfile pagedDatasetProfile = new PagedDatasetProfile(); + pagedDatasetProfile.buildPagedDatasetProfile(datasetprofile); + return pagedDatasetProfile; + } + + private eu.eudat.models.data.user.composite.DatasetProfile generateDatasetProfileModel(eu.eudat.data.entities.DatasetProfile profile) { + Document viewStyleDoc = XmlBuilder.fromXml(profile.getDefinition()); + Element root = (Element) viewStyleDoc.getDocumentElement(); + eu.eudat.models.data.entities.xmlmodels.datasetprofiledefinition.ViewStyleModel viewstyle = new eu.eudat.models.data.entities.xmlmodels.datasetprofiledefinition.ViewStyleModel().fromXml(root); + + eu.eudat.models.data.user.composite.DatasetProfile datasetprofile = new eu.eudat.models.data.user.composite.DatasetProfile(); + datasetprofile.buildProfile(viewstyle); + + return datasetprofile; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/associatedprofile/AssociatedProfilePublicModel.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/associatedprofile/AssociatedProfilePublicModel.java new file mode 100644 index 000000000..10edac3ca --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/associatedprofile/AssociatedProfilePublicModel.java @@ -0,0 +1,57 @@ +package eu.eudat.publicapi.models.associatedprofile; + +import eu.eudat.data.entities.DatasetProfile; +import eu.eudat.logic.utilities.interfaces.XmlSerializable; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.util.UUID; + +public class AssociatedProfilePublicModel implements XmlSerializable { + private UUID id; + private String label; + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + @Override + public Element toXml(Document doc) { + Element profile = doc.createElement("profile"); + profile.setAttribute("profileId", this.id.toString()); + profile.setAttribute("label", this.label); + return profile; + } + + @Override + public AssociatedProfilePublicModel fromXml(Element item) { + this.id = UUID.fromString(item.getAttribute("profileId")); + this.label = item.getAttribute("label"); + return this; + } + + public DatasetProfile toData() { + DatasetProfile profile = new DatasetProfile(); + profile.setId(this.id); + profile.setLabel(this.label); + return profile; + } + + public AssociatedProfilePublicModel fromData(DatasetProfile entity) { + this.id = entity.getId(); + this.label = entity.getLabel(); + return this; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/datasetprofile/DatasetProfilePublicModel.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/datasetprofile/DatasetProfilePublicModel.java new file mode 100644 index 000000000..317e1a8fb --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/datasetprofile/DatasetProfilePublicModel.java @@ -0,0 +1,45 @@ +package eu.eudat.publicapi.models.datasetprofile; + +import eu.eudat.data.entities.DatasetProfile; +import eu.eudat.models.DataModel; + +import java.util.UUID; + +public class DatasetProfilePublicModel implements DataModel { + private UUID id; + private String label; + + public UUID getId() { + return id; + } + public void setId(UUID id) { + this.id = id; + } + + public String getLabel() { + return label; + } + public void setLabel(String label) { + this.label = label; + } + + @Override + public DatasetProfilePublicModel fromDataModel(DatasetProfile entity) { + this.id = entity.getId(); + this.label = entity.getLabel(); + return this; + } + + @Override + public DatasetProfile toDataModel() { + DatasetProfile entity = new DatasetProfile(); + entity.setId(this.getId()); + entity.setLabel(this.getLabel()); + return entity; + } + + @Override + public String getHint() { + return null; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/datasetwizard/DataRepositoryPublicModel.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/datasetwizard/DataRepositoryPublicModel.java new file mode 100644 index 000000000..a99af2a20 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/datasetwizard/DataRepositoryPublicModel.java @@ -0,0 +1,136 @@ +package eu.eudat.publicapi.models.datasetwizard; + +import eu.eudat.data.entities.DataRepository; +import eu.eudat.logic.utilities.helpers.LabelGenerator; +import eu.eudat.models.DataModel; + +import java.util.Date; +import java.util.UUID; + +public class DataRepositoryPublicModel implements DataModel, LabelGenerator { + private String id; + private String pid; + private String name; + private String uri; + private String info; + private String reference; + private String abbreviation; + private String tag; + private String source; + + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + + public String getPid() { + return pid; + } + public void setPid(String pid) { + this.pid = pid; + } + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + public String getUri() { + return uri; + } + public void setUri(String uri) { + this.uri = uri; + } + + public String getInfo() { + return info; + } + public void setInfo(String info) { + this.info = info; + } + + public String getReference() { + return reference; + } + public void setReference(String reference) { + this.reference = reference; + } + + public String getAbbreviation() { + return abbreviation; + } + public void setAbbreviation(String abbreviation) { + this.abbreviation = abbreviation; + } + + public String getTag() { + return tag; + } + public void setTag(String tag) { + this.tag = tag; + } + + public String getSource() { + return source; + } + public void setSource(String source) { + this.source = source; + } + + public DataRepositoryPublicModel fromDataModel(DataRepository entity) { + this.id = entity.getId().toString(); + this.pid = entity.getReference(); + this.name = entity.getLabel(); + this.uri = entity.getUri(); + this.abbreviation = entity.getAbbreviation(); + this.reference = entity.getReference(); + String source1 = entity.getReference().substring(0, entity.getReference().indexOf(":")); + if (source1.equals("dmp")) { + this.source = "Internal"; + } else { + this.source = source1; + } + return this; + } + + public DataRepository toDataModel() { + DataRepository entity = new DataRepository(); + if (this.id != null) { + entity.setId(UUID.fromString(this.id)); + } + entity.setReference(this.pid); + entity.setLabel(this.name); + entity.setUri(this.uri); + entity.setCreated(new Date()); + entity.setModified(new Date()); + entity.setStatus((short) 0); + if (this.source != null && this.source.equals("Internal")) this.source = "dmp"; + if (this.reference != null && !this.reference.trim().isEmpty() + && this.source != null && !this.source.trim().isEmpty()) { + if (this.source.equals(this.reference.substring(0, this.source.length()))) { + entity.setReference(this.reference); + } else { + entity.setReference(this.source.toLowerCase() + ":" + this.reference); + } + } + + if (this.abbreviation != null) + entity.setAbbreviation(this.abbreviation); + + return entity; + } + + @Override + public String generateLabel() { + return this.getName(); + } + + @Override + public String getHint() { + return null; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/datasetwizard/ExternalDatasetPublicListingModel.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/datasetwizard/ExternalDatasetPublicListingModel.java new file mode 100644 index 000000000..e625eff85 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/datasetwizard/ExternalDatasetPublicListingModel.java @@ -0,0 +1,153 @@ +package eu.eudat.publicapi.models.datasetwizard; + +import eu.eudat.data.entities.ExternalDataset; +import eu.eudat.models.DataModel; +import eu.eudat.types.externalsourcetype.ExternalDatasetType; + +import java.util.Date; +import java.util.UUID; + +public class ExternalDatasetPublicListingModel implements DataModel { + private UUID id; + private String name; + private String abbreviation; + private String reference; + private Date created; + private Date modified; + private String info; + private ExternalDatasetType type; + private String pid; + private String uri; + private String tag; // Api fetching the data + private String source; // Actual harvested source + + public UUID getId() { + return id; + } + public void setId(UUID id) { + this.id = id; + } + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + public String getAbbreviation() { + return abbreviation; + } + public void setAbbreviation(String abbreviation) { + this.abbreviation = abbreviation; + } + + public String getReference() { + return reference; + } + public void setReference(String reference) { + this.reference = reference; + } + + public Date getCreated() { + return created; + } + public void setCreated(Date created) { + this.created = created; + } + + public Date getModified() { + return modified; + } + public void setModified(Date modified) { + this.modified = modified; + } + + public Integer getType() { + return type != null ? type.getValue() : null; + } + public void setType(Integer type) { + this.type = ExternalDatasetType.fromInteger(type); + } + + public String getInfo() { + return info; + } + public void setInfo(String info) { + this.info = info; + } + + public String getPid() { + return pid; + } + public void setPid(String pid) { + this.pid = pid; + } + + public String getUri() { + return uri; + } + public void setUri(String uri) { + this.uri = uri; + } + + public String getTag() { + return tag; + } + public void setTag(String tag) { + this.tag = tag; + } + + public String getSource() { + return source; + } + public void setSource(String source) { + this.source = source; + } + + @Override + public ExternalDatasetPublicListingModel fromDataModel(ExternalDataset entity) { + this.id = entity.getId(); + this.abbreviation = entity.getAbbreviation(); + this.name = entity.getLabel(); + this.modified = entity.getModified(); + this.created = entity.getCreated(); + this.reference = entity.getReference(); + String source1 = entity.getReference().substring(0, entity.getReference().indexOf(":")); + if (source1.equals("dmp")) { + this.source = "Internal"; + } else { + this.source = source1; + } + return this; + } + + @Override + public ExternalDataset toDataModel() throws Exception { + ExternalDataset externalDataset = new ExternalDataset(); + externalDataset.setAbbreviation(this.abbreviation); + externalDataset.setCreated(this.created != null ? this.created : new Date()); + externalDataset.setLabel(this.name); + externalDataset.setId(this.id); + externalDataset.setModified(this.modified); + if (this.source != null && this.source.equals("Internal")) this.source = "dmp"; + if (this.reference != null && !this.reference.trim().isEmpty() + && this.source != null && !this.source.trim().isEmpty()) { + if (this.source.equals(this.reference.substring(0, this.source.length()))) { + externalDataset.setReference(this.reference); + } else { + externalDataset.setReference(this.source.toLowerCase() + ":" + this.reference); + } + } + if (externalDataset.getReference() == null) { + externalDataset.setReference(this.pid); + } + externalDataset.setModified(new Date()); + return externalDataset; + } + + @Override + public String getHint() { + return null; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/datasetwizard/RegistryPublicModel.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/datasetwizard/RegistryPublicModel.java new file mode 100644 index 000000000..8fbfa8329 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/datasetwizard/RegistryPublicModel.java @@ -0,0 +1,112 @@ +package eu.eudat.publicapi.models.datasetwizard; + +import eu.eudat.data.entities.Registry; +import eu.eudat.logic.utilities.helpers.LabelGenerator; +import eu.eudat.models.DataModel; + +import java.util.Date; +import java.util.UUID; + +public class RegistryPublicModel implements DataModel, LabelGenerator { + private UUID id; + private String label; + private String abbreviation; + private String reference; + private String uri; + private String definition; + private String source; + + public UUID getId() { + return id; + } + public void setId(UUID id) { + this.id = id; + } + + public String getLabel() { + return label; + } + public void setLabel(String label) { + this.label = label; + } + + public String getAbbreviation() { + return abbreviation; + } + @Override + public String generateLabel() { + return getLabel(); + } + public void setAbbreviation(String abbreviation) { + this.abbreviation = abbreviation; + } + + public String getReference() { + return reference; + } + public void setReference(String reference) { + this.reference = reference; + } + + public String getUri() { + return uri; + } + public void setUri(String uri) { + this.uri = uri; + } + + public String getDefinition() { + return definition; + } + public void setDefinition(String definition) { + this.definition = definition; + } + + public String getSource() { + return source; + } + public void setSource(String source) { + this.source = source; + } + + public RegistryPublicModel fromDataModel(Registry entity) { + this.id = entity.getId(); + this.label = entity.getLabel(); + this.abbreviation = entity.getAbbreviation(); + this.reference = entity.getReference(); + this.uri = entity.getUri(); + this.definition = entity.getDefinition(); + String source1 = entity.getReference().substring(0, entity.getReference().indexOf(":")); + if (source1.equals("dmp")) { + this.source = "Internal"; + } else { + this.source = source1; + } + return this; + } + + public Registry toDataModel() { + Registry entity = new Registry(); + entity.setId(this.id != null ? this.id : UUID.randomUUID()); + entity.setLabel(this.label); + entity.setAbbreviation(this.abbreviation); + if (this.source != null && this.source.equals("Internal")) this.source = "dmp"; + if (this.reference != null && !this.reference.trim().isEmpty() + && this.source != null && !this.source.trim().isEmpty()) { + if (this.source.equals(this.reference.substring(0, this.source.length()))) { + entity.setReference(this.reference); + } else { + entity.setReference(this.source.toLowerCase() + ":" + this.reference); + } + } + entity.setUri(this.uri); + entity.setModified(new Date()); + entity.setStatus((short)0); + return entity; + } + + @Override + public String getHint() { + return null; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/datasetwizard/ServicePublicModel.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/datasetwizard/ServicePublicModel.java new file mode 100644 index 000000000..8ff8184f2 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/datasetwizard/ServicePublicModel.java @@ -0,0 +1,113 @@ +package eu.eudat.publicapi.models.datasetwizard; + +import eu.eudat.data.entities.Service; +import eu.eudat.logic.utilities.helpers.LabelGenerator; +import eu.eudat.models.DataModel; + +import java.util.Date; +import java.util.UUID; + +public class ServicePublicModel implements DataModel, LabelGenerator { + private UUID id; + private String label; + private String abbreviation; + private String reference; + private String uri; + private String definition; + private String source; + + public UUID getId() { + return id; + } + public void setId(UUID id) { + this.id = id; + } + + public String getLabel() { + return label; + } + public void setLabel(String label) { + this.label = label; + } + + public String getAbbreviation() { + return abbreviation; + } + public void setAbbreviation(String abbreviation) { + this.abbreviation = abbreviation; + } + + public String getReference() { + return reference; + } + public void setReference(String reference) { + this.reference = reference; + } + + public String getUri() { + return uri; + } + public void setUri(String uri) { + this.uri = uri; + } + + public String getDefinition() { + return definition; + } + public void setDefinition(String definition) { + this.definition = definition; + } + + public String getSource() { + return source; + } + public void setSource(String source) { + this.source = source; + } + + public ServicePublicModel fromDataModel(Service entity) { + this.id = entity.getId(); + this.label = entity.getLabel(); + this.abbreviation = entity.getAbbreviation(); + this.reference = entity.getReference(); + this.uri = entity.getUri(); + this.definition = entity.getDefinition(); + String source1 = entity.getReference().substring(0, entity.getReference().indexOf(":")); + if (source1.equals("dmp")) { + this.source = "Internal"; + } else { + this.source = source1; + } + return this; + } + + public Service toDataModel() { + Service entity = new Service(); + entity.setId(this.id != null ? this.id : UUID.randomUUID()); + entity.setLabel(this.label); + entity.setAbbreviation(this.abbreviation); + if (this.source != null && this.source.equals("Internal")) this.source = "dmp"; + if (this.reference != null && !this.reference.trim().isEmpty() + && this.source != null && !this.source.trim().isEmpty()) { + if (this.source.equals(this.reference.substring(0, this.source.length()))) { + entity.setReference(this.reference); + } else { + entity.setReference(this.source.toLowerCase() + ":" + this.reference); + } + } + entity.setUri(this.uri); + entity.setModified(new Date()); + entity.setStatus((short)0); + return entity; + } + + @Override + public String generateLabel() { + return this.label; + } + + @Override + public String getHint() { + return null; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/funder/FunderPublicOverviewModel.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/funder/FunderPublicOverviewModel.java new file mode 100644 index 000000000..86accf613 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/funder/FunderPublicOverviewModel.java @@ -0,0 +1,42 @@ +package eu.eudat.publicapi.models.funder; + +import eu.eudat.data.entities.Funder; +import eu.eudat.models.DataModel; + +import java.util.UUID; + +public class FunderPublicOverviewModel implements DataModel { + private UUID id; + private String label; + + public UUID getId() { + return id; + } + public void setId(UUID id) { + this.id = id; + } + + public String getLabel() { + return label; + } + public void setLabel(String label) { + this.label = label; + } + + @Override + public FunderPublicOverviewModel fromDataModel(Funder entity) { + this.id = entity.getId(); + this.label = entity.getLabel(); + return this; + } + + @Override + public Funder toDataModel() throws Exception { + return null; + } + + @Override + public String getHint() { + return null; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/grant/GrantPublicOverviewModel.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/grant/GrantPublicOverviewModel.java new file mode 100644 index 000000000..75f17c937 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/grant/GrantPublicOverviewModel.java @@ -0,0 +1,100 @@ +package eu.eudat.publicapi.models.grant; + +import eu.eudat.data.entities.Grant; +import eu.eudat.models.DataModel; +import eu.eudat.publicapi.models.funder.FunderPublicOverviewModel; + +import java.util.Date; +import java.util.UUID; + +public class GrantPublicOverviewModel implements DataModel { + private UUID id; + private String label; + private String abbreviation; + private String description; + private Date startDate; + private Date endDate; + private String uri; + private FunderPublicOverviewModel funder; + + public UUID getId() { + return id; + } + public void setId(UUID id) { + this.id = id; + } + + public String getLabel() { + return label; + } + public void setLabel(String label) { + this.label = label; + } + + public String getAbbreviation() { + return abbreviation; + } + public void setAbbreviation(String abbreviation) { + this.abbreviation = abbreviation; + } + + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + + public Date getStartDate() { + return startDate; + } + public void setStartDate(Date startDate) { + this.startDate = startDate; + } + + public Date getEndDate() { + return endDate; + } + public void setEndDate(Date endDate) { + this.endDate = endDate; + } + + public String getUri() { + return uri; + } + public void setUri(String uri) { + this.uri = uri; + } + + public FunderPublicOverviewModel getFunder() { + return funder; + } + public void setFunder(FunderPublicOverviewModel funder) { + this.funder = funder; + } + + @Override + public GrantPublicOverviewModel fromDataModel(Grant entity) { + this.id = entity.getId(); + this.label = entity.getLabel(); + this.abbreviation = entity.getAbbreviation(); + this.description = entity.getDescription(); + this.startDate = entity.getStartdate(); + this.endDate = entity.getEnddate(); + this.uri = entity.getUri(); + this.funder = new FunderPublicOverviewModel(); + if (entity.getFunder() != null) + this.funder.fromDataModel(entity.getFunder()); + return this; + } + + @Override + public Grant toDataModel() throws Exception { + return null; + } + + @Override + public String getHint() { + return null; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/listingmodels/DataManagementPlanPublicListingModel.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/listingmodels/DataManagementPlanPublicListingModel.java new file mode 100644 index 000000000..2c0b65c69 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/listingmodels/DataManagementPlanPublicListingModel.java @@ -0,0 +1,161 @@ +package eu.eudat.publicapi.models.listingmodels; + +import eu.eudat.data.entities.DMP; +import eu.eudat.data.entities.Grant; +import eu.eudat.models.DataModel; +import eu.eudat.publicapi.models.user.UserInfoPublicModel; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +public class DataManagementPlanPublicListingModel implements DataModel { + private String id; + private String label; + private String grant; + private Date createdAt; + private Date modifiedAt; + private int version; + private UUID groupId; + private List users; + private Date finalizedAt; + private Date publishedAt; + + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + + public String getLabel() { + return label; + } + public void setLabel(String label) { + this.label = label; + } + + public String getGrant() { + return grant; + } + public void setGrant(String grant) { + this.grant = grant; + } + + public Date getCreatedAt() { + return createdAt; + } + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public Date getModifiedAt() { + return modifiedAt; + } + public void setModifiedAt(Date modifiedAt) { + this.modifiedAt = modifiedAt; + } + + public int getVersion() { + return version; + } + public void setVersion(int version) { + this.version = version; + } + + public UUID getGroupId() { + return groupId; + } + public void setGroupId(UUID groupId) { + this.groupId = groupId; + } + + public List getUsers() { + return users; + } + public void setUsers(List users) { + this.users = users; + } + + public Date getFinalizedAt() { + return finalizedAt; + } + public void setFinalizedAt(Date finalizedAt) { + this.finalizedAt = finalizedAt; + } + + public Date getPublishedAt() { + return publishedAt; + } + public void setPublishedAt(Date publishedAt) { + this.publishedAt = publishedAt; + } + + @Override + public DataManagementPlanPublicListingModel fromDataModel(DMP entity) { + this.id = entity.getId().toString(); + this.label = entity.getLabel(); + this.groupId = entity.getGroupId(); + return this; + } + + public DataManagementPlanPublicListingModel fromDataModelAssociatedProfiles(DMP entity) { + this.id = entity.getId().toString(); + this.label = entity.getLabel(); + this.groupId = entity.getGroupId(); + this.createdAt = entity.getCreated(); + return this; + } + + public DataManagementPlanPublicListingModel fromDataModelAutoComplete(DMP entity) { + this.id = entity.getId().toString(); + this.label = entity.getLabel(); + this.groupId = entity.getGroupId(); + this.createdAt = entity.getCreated(); + return this; + } + + public DataManagementPlanPublicListingModel fromDataModelNoDatasets(DMP entity) { + this.fromDataModel(entity); + this.version = entity.getVersion(); + this.grant = entity.getGrant().getLabel(); + this.createdAt = entity.getCreated(); + this.modifiedAt = entity.getModified(); + try { + this.users = entity.getUsers() != null ? entity.getUsers().stream().map(x -> new UserInfoPublicModel().fromDataModel(x)).collect(Collectors.toList()) : new ArrayList<>(); + } + catch(Exception ex){ + this.users = new ArrayList<>(); + } + this.finalizedAt = entity.getFinalizedAt(); + this.publishedAt = entity.getPublishedAt(); + + return this; + } + + @Override + public DMP toDataModel() { + DMP entity = new DMP(); + entity.setId(UUID.fromString(this.getId())); + entity.setLabel(this.getLabel()); + entity.setGroupId(this.getGroupId()); + entity.setCreated(this.getCreatedAt()); + entity.setFinalizedAt(this.getFinalizedAt()); + entity.setModified(this.getModifiedAt()); + entity.setPublishedAt(this.getPublishedAt()); + entity.setVersion(this.getVersion()); + + Grant grant = new Grant(); + grant.setLabel(this.getGrant()); + entity.setGrant(grant); + entity.setUsers(this.getUsers().stream().map(UserInfoPublicModel::toDataModel).collect(Collectors.toSet())); + return entity; + } + + @Override + public String getHint() { + return "dataManagementPlanListingModel"; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/listingmodels/DatasetPublicListingModel.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/listingmodels/DatasetPublicListingModel.java new file mode 100644 index 000000000..8f5c4e6c3 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/listingmodels/DatasetPublicListingModel.java @@ -0,0 +1,174 @@ +package eu.eudat.publicapi.models.listingmodels; + +import eu.eudat.data.entities.DMP; +import eu.eudat.data.entities.Dataset; +import eu.eudat.data.entities.Grant; +import eu.eudat.models.DataModel; +import eu.eudat.publicapi.models.datasetprofile.DatasetProfilePublicModel; +import eu.eudat.publicapi.models.user.UserInfoPublicModel; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +public class DatasetPublicListingModel implements DataModel { + private String id; + private String label; + private String grant; + private String dmp; + private String dmpId; + private DatasetProfilePublicModel profile; + private Date createdAt; + private Date modifiedAt; + private String description; + private Date finalizedAt; + private Date dmpPublishedAt; + private int version; + private List users; + + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + + public String getLabel() { + return label; + } + public void setLabel(String label) { + this.label = label; + } + + public String getGrant() { + return grant; + } + public void setGrant(String grant) { + this.grant = grant; + } + + public String getDmp() { + return dmp; + } + public void setDmp(String dmp) { + this.dmp = dmp; + } + + public String getDmpId() { + return dmpId; + } + public void setDmpId(String dmpId) { + this.dmpId = dmpId; + } + + public DatasetProfilePublicModel getProfile() { + return profile; + } + public void setProfile(DatasetProfilePublicModel profile) { + this.profile = profile; + } + + public Date getCreatedAt() { + return createdAt; + } + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public Date getModifiedAt() { + return modifiedAt; + } + public void setModifiedAt(Date modifiedAt) { + this.modifiedAt = modifiedAt; + } + + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + + public Date getFinalizedAt() { + return finalizedAt; + } + public void setFinalizedAt(Date finalizedAt) { + this.finalizedAt = finalizedAt; + } + + public Date getDmpPublishedAt() { + return dmpPublishedAt; + } + public void setDmpPublishedAt(Date dmpPublishedAt) { + this.dmpPublishedAt = dmpPublishedAt; + } + + public int getVersion() { + return version; + } + public void setVersion(int version) { + this.version = version; + } + + public List getUsers() { + return users; + } + + public void setUsers(List users) { + this.users = users; + } + + @Override + public DatasetPublicListingModel fromDataModel(Dataset entity) { + this.id = entity.getId() != null ? entity.getId().toString() : ""; + this.label = entity.getLabel(); + this.createdAt = entity.getCreated(); + this.modifiedAt = entity.getModified(); + this.grant = entity.getDmp() != null ? entity.getDmp().getGrant().getLabel() : ""; + this.dmp = entity.getDmp() != null ? entity.getDmp().getLabel() : ""; + this.dmpId = entity.getDmp() != null ? entity.getDmp().getId().toString() : ""; + this.profile = entity.getProfile() != null ? new DatasetProfilePublicModel().fromDataModel(entity.getProfile()) : null; + this.description = entity.getDescription(); + if (entity.getFinalizedAt() == null && entity.getStatus() == Dataset.Status.FINALISED.getValue()) { + this.finalizedAt = entity.getDmp().getFinalizedAt(); + } else { + this.finalizedAt = entity.getFinalizedAt(); + } + this.dmpPublishedAt = entity.getDmp().getPublishedAt(); + this.version = entity.getDmp().getVersion(); + this.users = entity.getDmp() != null ? entity.getDmp().getUsers().stream().map(x -> new UserInfoPublicModel().fromDataModel(x)).collect(Collectors.toList()) : new ArrayList<>(); + return this; + } + + @Override + public Dataset toDataModel() { + Dataset entity = new Dataset(); + entity.setId(UUID.fromString(this.getId())); + entity.setLabel(this.getLabel()); + entity.setCreated(this.getCreatedAt()); + entity.setModified(this.getModifiedAt()); + entity.setDescription(this.getDescription()); + entity.setFinalizedAt(this.getFinalizedAt()); + entity.setStatus(Dataset.Status.FINALISED.getValue()); + DMP dmp = new DMP(); + Grant grant = new Grant(); + grant.setLabel(this.getGrant()); + dmp.setGrant(grant); + dmp.setLabel(this.getDmp()); + dmp.setId(UUID.fromString(this.getDmpId())); + dmp.setPublishedAt(this.getDmpPublishedAt()); + dmp.setVersion(this.getVersion()); + dmp.setUsers(this.getUsers().stream().map(UserInfoPublicModel::toDataModel).collect(Collectors.toSet())); + dmp.setFinalizedAt(this.getFinalizedAt()); + entity.setDmp(dmp); + entity.setProfile(this.getProfile() != null ? this.getProfile().toDataModel() : null); + return entity; + } + + @Override + public String getHint() { + return "datasetListingModel"; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/organisation/OrganizationPublicModel.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/organisation/OrganizationPublicModel.java new file mode 100644 index 000000000..05042d65e --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/organisation/OrganizationPublicModel.java @@ -0,0 +1,124 @@ +package eu.eudat.publicapi.models.organisation; + +import eu.eudat.data.entities.Organisation; +import eu.eudat.logic.utilities.helpers.LabelGenerator; +import eu.eudat.models.DataModel; + +import java.util.Date; +import java.util.HashMap; +import java.util.UUID; + +public class OrganizationPublicModel implements DataModel, LabelGenerator { + private String label; + private String name; + private String id; + private String reference; + private int status; + private String tag; // how the external source is displayed. ex: "Cristin". + private String key; // the external source. ex: "cristin". + + public String getLabel() { + return label; + } + public void setLabel(String label) { + this.label = label; + } + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + + public String getReference() { + return reference; + } + public void setReference(String reference) { + this.reference = reference; + } + + public int getStatus() { + return status; + } + public void setStatus(int status) { + this.status = status; + } + + public String getTag() { + return tag; + } + public void setTag(String tag) { + this.tag = tag; + } + + public String getKey() { + return key; + } + public void setKey(String key) { + this.key = key; + } + + @Override + public OrganizationPublicModel fromDataModel(Organisation entity) { + this.id = entity.getId().toString(); + this.name = entity.getLabel(); + this.label = entity.getUri(); + if (entity.getReference() != null) { + this.reference = entity.getReference(); + this.key = entity.getReference().substring(0, entity.getReference().indexOf(":")); + } + return this; + } + + @Override + public Organisation toDataModel() { + Organisation organisationEntity = new Organisation(); + if (this.key != null && this.reference != null) { + if (this.reference.startsWith(this.key + ":")) { + organisationEntity.setReference(this.reference); + } else { + organisationEntity.setReference(this.key + ":" + this.reference); + } + } + if (this.id != null) { + organisationEntity.setId(UUID.fromString(this.id)); + } + organisationEntity.setLabel(this.name); + organisationEntity.setUri(this.label); + organisationEntity.setCreated(new Date()); + organisationEntity.setStatus((short) this.status); + return organisationEntity; + } + + public static OrganizationPublicModel fromMap(HashMap map) { + OrganizationPublicModel model = new OrganizationPublicModel(); + if (map != null) { + model.id = (String) map.get("id"); + model.key = (String) map.get("key"); + model.label = (String) map.get("label"); + model.name = (String) map.get("name"); + model.reference = (String) map.get("reference"); + model.status = (int) map.get("status"); + model.tag = (String) map.get("tag"); + } + return model; + } + + @Override + public String generateLabel() { + return this.getName(); + } + + @Override + public String getHint() { + return null; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/overviewmodels/DataManagementPlanPublicModel.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/overviewmodels/DataManagementPlanPublicModel.java new file mode 100644 index 000000000..6b5040371 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/overviewmodels/DataManagementPlanPublicModel.java @@ -0,0 +1,239 @@ +package eu.eudat.publicapi.models.overviewmodels; + +import eu.eudat.data.entities.DMP; +import eu.eudat.data.entities.Dataset; +import eu.eudat.data.entities.DatasetProfile; +import eu.eudat.logic.utilities.builders.XmlBuilder; +import eu.eudat.models.DataModel; +import eu.eudat.models.data.user.composite.PagedDatasetProfile; +import eu.eudat.publicapi.models.associatedprofile.AssociatedProfilePublicModel; +import eu.eudat.publicapi.models.grant.GrantPublicOverviewModel; +import eu.eudat.publicapi.models.organisation.OrganizationPublicModel; +import eu.eudat.publicapi.models.researcher.ResearcherPublicModel; +import eu.eudat.publicapi.models.user.UserInfoPublicModel; +import org.json.JSONObject; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.util.*; +import java.util.stream.Collectors; + +public class DataManagementPlanPublicModel implements DataModel { + private String id; + private String label; + private String profile; + private GrantPublicOverviewModel grant; + private Date createdAt; + private Date modifiedAt; + private Date finalizedAt; + private List organisations; + private int version; + private UUID groupId; + private List datasets; + private List associatedProfiles; + private List researchers; + private List users; + private String description; + private Date publishedAt; + private String doi; + + + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + + public String getLabel() { + return label; + } + public void setLabel(String label) { + this.label = label; + } + + public String getProfile() { + return profile; + } + public void setProfile(String profile) { + this.profile = profile; + } + + public GrantPublicOverviewModel getGrant() { + return grant; + } + public void setGrant(GrantPublicOverviewModel grant) { + this.grant = grant; + } + + public Date getCreatedAt() { + return createdAt; + } + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public Date getModifiedAt() { + return modifiedAt; + } + public void setModifiedAt(Date modifiedAt) { + this.modifiedAt = modifiedAt; + } + + public Date getFinalizedAt() { + return finalizedAt; + } + public void setFinalizedAt(Date finalizedAt) { + this.finalizedAt = finalizedAt; + } + + public List getOrganisations() { + return organisations; + } + public void setOrganisations(List organizations) { + this.organisations = organizations; + } + + public int getVersion() { + return version; + } + public void setVersion(int version) { + this.version = version; + } + + public UUID getGroupId() { + return groupId; + } + public void setGroupId(UUID groupId) { + this.groupId = groupId; + } + + public List getDatasets() { + return datasets; + } + public void setDatasets(List datasets) { + this.datasets = datasets; + } + + public List getAssociatedProfiles() { + return associatedProfiles; + } + public void setAssociatedProfiles(List associatedProfiles) { + this.associatedProfiles = associatedProfiles; + } + + public List getUsers() { + return users; + } + public void setUsers(List users) { + this.users = users; + } + + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + + public List getResearchers() { + return researchers; + } + public void setResearchers(List researchers) { + this.researchers = researchers; + } + + public Date getPublishedAt() { + return publishedAt; + } + public void setPublishedAt(Date publishedAt) { + this.publishedAt = publishedAt; + } + + public String getDoi() { + return doi; + } + public void setDoi(String doi) { + this.doi = doi; + } + + @Override + public DataManagementPlanPublicModel fromDataModel(DMP entity) { + this.id = entity.getId().toString(); + this.label = entity.getLabel(); + this.groupId = entity.getGroupId(); + if (entity.getResearchers() != null) { + this.researchers = entity.getResearchers().stream().map(item -> new ResearcherPublicModel().fromDataModel(item)).collect(Collectors.toList()); + } + return this; + } + + public DataManagementPlanPublicModel fromDataModelDatasets(DMP entity) { + this.fromDataModel(entity); + this.version = entity.getVersion(); + this.grant = new GrantPublicOverviewModel().fromDataModel(entity.getGrant()); + if (entity.getProfile() != null) this.profile = entity.getProfile().getLabel(); + this.createdAt = entity.getCreated(); + this.modifiedAt = entity.getModified(); + this.finalizedAt = entity.getFinalizedAt(); + this.organisations = entity.getOrganisations().stream().map(item -> new OrganizationPublicModel().fromDataModel(item)).collect(Collectors.toList()); + this.datasets = entity.getDataset().stream().filter(dataset -> !dataset.getStatus().equals(Dataset.Status.DELETED.getValue()) && !dataset.getStatus().equals(Dataset.Status.CANCELED.getValue())) + .map(datasetEntity-> { + DatasetPublicModel dataset = new DatasetPublicModel(); + dataset.setDatasetProfileDefinition(this.getPagedProfile(dataset.getStatus(), datasetEntity)); + dataset.fromDataModel(datasetEntity); + return dataset; + }).collect(Collectors.toList()); + this.users = entity.getUsers().stream().map(x -> new UserInfoPublicModel().fromDataModel(x)).collect(Collectors.toList()); + this.description = entity.getDescription(); + if (entity.getResearchers() != null) { + this.researchers = entity.getResearchers().stream().map(item -> new ResearcherPublicModel().fromDataModel(item)).collect(Collectors.toList()); + } + + if (entity.getAssociatedDmps() != null && !entity.getAssociatedDmps().isEmpty()) { + this.associatedProfiles = new LinkedList<>(); + for (DatasetProfile datasetProfile : entity.getAssociatedDmps()) { + AssociatedProfilePublicModel associatedProfile = new AssociatedProfilePublicModel().fromData(datasetProfile); + this.associatedProfiles.add(associatedProfile); + } + } + this.publishedAt = entity.getPublishedAt(); + this.doi = entity.getDoi(); + + return this; + } + + private PagedDatasetProfile getPagedProfile(int status, Dataset datasetEntity){ + eu.eudat.models.data.user.composite.DatasetProfile datasetprofile = this.generateDatasetProfileModel(datasetEntity.getProfile()); + datasetprofile.setStatus(status); + if (datasetEntity.getProperties() != null) { + JSONObject jObject = new JSONObject(datasetEntity.getProperties()); + Map properties = jObject.toMap(); + datasetprofile.fromJsonObject(properties); + } + PagedDatasetProfile pagedDatasetProfile = new PagedDatasetProfile(); + pagedDatasetProfile.buildPagedDatasetProfile(datasetprofile); + return pagedDatasetProfile; + } + + private eu.eudat.models.data.user.composite.DatasetProfile generateDatasetProfileModel(eu.eudat.data.entities.DatasetProfile profile) { + Document viewStyleDoc = XmlBuilder.fromXml(profile.getDefinition()); + Element root = (Element) viewStyleDoc.getDocumentElement(); + eu.eudat.models.data.entities.xmlmodels.datasetprofiledefinition.ViewStyleModel viewstyle = new eu.eudat.models.data.entities.xmlmodels.datasetprofiledefinition.ViewStyleModel().fromXml(root); + + eu.eudat.models.data.user.composite.DatasetProfile datasetprofile = new eu.eudat.models.data.user.composite.DatasetProfile(); + datasetprofile.buildProfile(viewstyle); + + return datasetprofile; + } + + @Override + public DMP toDataModel() { + return null; + } + + @Override + public String getHint() { + return "dataManagementPlanOverviewModel"; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/overviewmodels/DatasetPublicModel.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/overviewmodels/DatasetPublicModel.java new file mode 100644 index 000000000..b81dbdcb3 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/overviewmodels/DatasetPublicModel.java @@ -0,0 +1,293 @@ +package eu.eudat.publicapi.models.overviewmodels; + +import eu.eudat.data.entities.*; +import eu.eudat.elastic.entities.Tag; +import eu.eudat.models.DataModel; +import eu.eudat.models.data.user.composite.PagedDatasetProfile; +import eu.eudat.publicapi.models.datasetprofile.DatasetProfilePublicModel; +import eu.eudat.publicapi.models.datasetwizard.DataRepositoryPublicModel; +import eu.eudat.publicapi.models.datasetwizard.ExternalDatasetPublicListingModel; +import eu.eudat.publicapi.models.datasetwizard.RegistryPublicModel; +import eu.eudat.publicapi.models.datasetwizard.ServicePublicModel; +import eu.eudat.publicapi.models.listingmodels.DataManagementPlanPublicListingModel; +import net.minidev.json.JSONValue; + +import java.util.*; +import java.util.stream.Collectors; + +public class DatasetPublicModel implements DataModel { + private UUID id; + private String label; + private String reference; + private String uri; + private String description; + private short status; + private Date createdAt; + private DataManagementPlanPublicListingModel dmp; + private PagedDatasetProfile datasetProfileDefinition; + private List registries; + private List services; + private List dataRepositories; + private List tags; + private List externalDatasets; + private DatasetProfilePublicModel profile; + private Date modifiedAt; + + public UUID getId() { + return id; + } + public void setId(UUID id) { + this.id = id; + } + + public String getLabel() { + return label; + } + public void setLabel(String label) { + this.label = label; + } + + public String getReference() { + return reference; + } + public void setReference(String reference) { + this.reference = reference; + } + + public String getUri() { + return uri; + } + public void setUri(String uri) { + this.uri = uri; + } + + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + + public short getStatus() { + return status; + } + public void setStatus(short status) { + this.status = status; + } + + public Date getCreatedAt() { + return createdAt; + } + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public DataManagementPlanPublicListingModel getDmp() { + return dmp; + } + public void setDmp(DataManagementPlanPublicListingModel dmp) { + this.dmp = dmp; + } + + public PagedDatasetProfile getDatasetProfileDefinition() { + return datasetProfileDefinition; + } + public void setDatasetProfileDefinition(PagedDatasetProfile datasetProfileDefinition) { + this.datasetProfileDefinition = datasetProfileDefinition; + } + + public List getRegistries() { + return registries; + } + public void setRegistries(List registries) { + this.registries = registries; + } + + public List getServices() { + return services; + } + public void setServices(List services) { + this.services = services; + } + + public List getDataRepositories() { + return dataRepositories; + } + public void setDataRepositories(List dataRepositories) { + this.dataRepositories = dataRepositories; + } + + public DatasetProfilePublicModel getProfile() { + return profile; + } + public void setProfile(DatasetProfilePublicModel profile) { + this.profile = profile; + } + + public List getExternalDatasets() { + return externalDatasets; + } + public void setExternalDatasets(List externalDatasets) { + this.externalDatasets = externalDatasets; + } + + public List getTags() { + return tags; + } + public void setTags(List tags) { + this.tags = tags; + } + + public Date getModifiedAt() { + return modifiedAt; + } + public void setModifiedAt(Date modifiedAt) { + this.modifiedAt = modifiedAt; + } + + @Override + public DatasetPublicModel fromDataModel(Dataset entity) { + this.id = entity.getId(); + this.label = entity.getLabel(); + this.reference = entity.getReference(); + this.description = entity.getDescription(); + this.status = entity.getStatus(); + this.profile = new DatasetProfilePublicModel(); + this.profile = this.profile.fromDataModel(entity.getProfile()); + this.uri = entity.getUri(); + this.registries = entity.getRegistries() != null ? entity.getRegistries().stream().map(item -> new RegistryPublicModel().fromDataModel(item)).collect(Collectors.toList()) : new ArrayList<>(); + this.dataRepositories = entity.getDatasetDataRepositories() != null ? entity.getDatasetDataRepositories().stream().map(item -> { + DataRepositoryPublicModel dataRepository = new DataRepositoryPublicModel().fromDataModel(item.getDataRepository()); + if (item.getData() != null) { + Map> data = (Map>) JSONValue.parse(item.getData()); + Map values = data.get("data"); + dataRepository.setInfo(values.get("info")); + } + return dataRepository; + }).collect(Collectors.toList()) : new ArrayList<>(); + this.services = entity.getServices() != null ? entity.getServices().stream().map(item -> new ServicePublicModel().fromDataModel(item.getService())).collect(Collectors.toList()) : new ArrayList<>(); + this.createdAt = entity.getCreated(); + this.dmp = new DataManagementPlanPublicListingModel().fromDataModelNoDatasets(entity.getDmp()); + this.externalDatasets = entity.getDatasetExternalDatasets() != null ? entity.getDatasetExternalDatasets().stream().map(item -> { + ExternalDatasetPublicListingModel externalDatasetListingModel = new ExternalDatasetPublicListingModel().fromDataModel(item.getExternalDataset()); + if (item.getData() != null) { + Map> data = (Map>) JSONValue.parse(item.getData()); + Map values = data.get("data"); + externalDatasetListingModel.setInfo(values.get("info")); + externalDatasetListingModel.setType(Integer.parseInt(values.get("type"))); + } + return externalDatasetListingModel; + }).collect(Collectors.toList()) : new ArrayList<>(); + this.modifiedAt = entity.getModified(); + return this; + } + + public DatasetPublicModel fromDataModelNoDmp(Dataset entity) { + this.id = entity.getId(); + this.label = entity.getLabel(); + this.reference = entity.getReference(); + this.description = entity.getDescription(); + this.status = entity.getStatus(); + this.profile = new DatasetProfilePublicModel(); + this.profile = this.profile.fromDataModel(entity.getProfile()); + this.uri = entity.getUri(); + this.registries = entity.getRegistries() != null ? entity.getRegistries().stream().map(item -> new RegistryPublicModel().fromDataModel(item)).collect(Collectors.toList()) : new ArrayList<>(); + this.dataRepositories = entity.getDatasetDataRepositories() != null ? entity.getDatasetDataRepositories().stream().map(item -> { + DataRepositoryPublicModel dataRepository = new DataRepositoryPublicModel().fromDataModel(item.getDataRepository()); + if (item.getData() != null) { + Map> data = (Map>) JSONValue.parse(item.getData()); + Map values = data.get("data"); + dataRepository.setInfo(values.get("info")); + } + return dataRepository; + }).collect(Collectors.toList()) : new ArrayList<>(); + this.services = entity.getServices() != null ? entity.getServices().stream().map(item -> new ServicePublicModel().fromDataModel(item.getService())).collect(Collectors.toList()) : new ArrayList<>(); + this.createdAt = entity.getCreated(); + this.externalDatasets = entity.getDatasetExternalDatasets() != null ? entity.getDatasetExternalDatasets().stream().map(item -> { + ExternalDatasetPublicListingModel externalDatasetListingModel = new ExternalDatasetPublicListingModel().fromDataModel(item.getExternalDataset()); + if (item.getData() != null) { + Map> data = (Map>) JSONValue.parse(item.getData()); + Map values = data.get("data"); + externalDatasetListingModel.setInfo(values.get("info")); + externalDatasetListingModel.setType(Integer.parseInt(values.get("type"))); + } + return externalDatasetListingModel; + }).collect(Collectors.toList()) : new ArrayList<>(); + this.modifiedAt = entity.getModified(); + return this; + } + + @Override + public Dataset toDataModel() throws Exception { + Dataset entity = new Dataset(); + entity.setId(this.id); + entity.setLabel(this.label); + entity.setStatus(this.status); + entity.setReference(this.reference); + entity.setUri(this.uri); + entity.setFinalizedAt(new Date()); + DMP dmp = new DMP(); + dmp.setId(UUID.fromString(this.dmp.getId())); + entity.setDmp(dmp); + entity.setDescription(this.description); + entity.setCreated(this.createdAt != null ? this.createdAt : new Date()); + entity.setModified(new Date()); + DatasetProfile profile = new DatasetProfile(); + profile.setId(this.profile.getId()); + entity.setProfile(profile); + if (this.registries != null && !this.registries.isEmpty()) { + entity.setRegistries(new HashSet<>()); + for (RegistryPublicModel registry : this.registries) { + entity.getRegistries().add(registry.toDataModel()); + } + } + + if (this.dataRepositories != null && !this.dataRepositories.isEmpty()) { + entity.setDatasetDataRepositories(new HashSet<>()); + for (DataRepositoryPublicModel dataRepositoryModel : this.dataRepositories) { + DataRepository dataRepository = dataRepositoryModel.toDataModel(); + DatasetDataRepository datasetDataRepository = new DatasetDataRepository(); + datasetDataRepository.setDataRepository(dataRepository); + Map> data = new HashMap<>(); + Map values = new HashMap<>(); + values.put("info", dataRepositoryModel.getInfo()); + data.put("data", values); + datasetDataRepository.setData(JSONValue.toJSONString(data)); + entity.getDatasetDataRepositories().add(datasetDataRepository); + } + } + + if (this.services != null && !this.services.isEmpty()) { + entity.setServices(new HashSet<>()); + for (ServicePublicModel serviceModel : this.services) { + Service service = serviceModel.toDataModel(); + DatasetService datasetService = new DatasetService(); + datasetService.setService(service); + entity.getServices().add(datasetService); + } + } + + if (this.externalDatasets != null && !this.externalDatasets.isEmpty()) { + entity.setDatasetExternalDatasets(new HashSet<>()); + for (ExternalDatasetPublicListingModel externalDataset : this.externalDatasets) { + ExternalDataset externalDatasetEntity = externalDataset.toDataModel(); + DatasetExternalDataset datasetExternalDataset = new DatasetExternalDataset(); + datasetExternalDataset.setExternalDataset(externalDatasetEntity); + Map> data = new HashMap<>(); + Map values = new HashMap<>(); + values.put("info",externalDataset.getInfo()); + values.put("type",externalDataset.getType().toString()); + data.put("data",values); + datasetExternalDataset.setData(JSONValue.toJSONString(data)); + entity.getDatasetExternalDatasets().add(datasetExternalDataset); + } + } + return entity; + } + + + @Override + public String getHint() { + return "datasetOverviewModel"; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/researcher/ResearcherPublicModel.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/researcher/ResearcherPublicModel.java new file mode 100644 index 000000000..0630ffd12 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/researcher/ResearcherPublicModel.java @@ -0,0 +1,151 @@ +package eu.eudat.publicapi.models.researcher; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import eu.eudat.data.entities.Researcher; +import eu.eudat.logic.utilities.helpers.LabelGenerator; +import eu.eudat.models.DataModel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; +import java.util.UUID; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class ResearcherPublicModel implements DataModel, LabelGenerator { + private static final Logger logger = LoggerFactory.getLogger(eu.eudat.models.data.dmp.Researcher.class); + private String label; + private String name; + private String id; + private String reference; + private int status; + private String tag; + private String key; + + public String getLabel() { + return label; + } + public void setLabel(String label) { + this.label = label; + } + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + + public String getReference() { + return reference; + } + public void setReference(String reference) { + this.reference = reference; + } + + public int getStatus() { + return status; + } + public void setStatus(int status) { + this.status = status; + } + + public String getTag() { + return tag; + } + public void setTag(String tag) { + this.tag = tag; + } + + public String getKey() { + return key; + } + public void setKey(String key) { + this.key = key; + } + + @Override + public ResearcherPublicModel fromDataModel(Researcher entity) { + this.id = entity.getId().toString(); + this.label = entity.getUri(); + this.name = entity.getLabel(); + this.status = entity.getStatus(); + this.reference = entity.getReference(); + String refParts[] = entity.getReference().split(":"); + String source = refParts[0]; + if (source.equals("dmp")) + this.key = "Internal"; + else + this.key = source; + return this; + } + + @Override + public Researcher toDataModel() { + Researcher researcher = new Researcher(); + if (this.id == null) { + this.id = UUID.randomUUID().toString(); + } + researcher.setId(UUID.fromString(this.id)); + if (this.key != null) { + if (this.key.toLowerCase().equals("internal")) { + if (this.reference != null && !this.reference.startsWith("dmp:")) { + researcher.setReference("dmp:" + this.reference); + } else if (this.reference == null) { + researcher.setReference("dmp:" + this.id); + } else { + researcher.setReference(this.reference); + } + } else { + if ((this.key + ":").equals(this.reference.substring(0, this.key.length() + 1))) { + researcher.setReference(this.reference); + } else { + researcher.setReference(this.key + ":" + this.reference); + } + } + } else { + try { + throw new Exception("Researcher has no key value"); + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + } + + researcher.setLabel(this.name); + researcher.setUri(this.label); + researcher.setCreated(new Date()); + researcher.setStatus((short) this.status); + return researcher; + } + + @Override + public String generateLabel() { + return this.getName(); + } + + @Override + public String getHint() { + return null; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ResearcherPublicModel that = (ResearcherPublicModel) o; + + return id.equals(that.id); + } + + @Override + public int hashCode() { + return reference.hashCode(); + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/user/UserInfoPublicModel.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/user/UserInfoPublicModel.java new file mode 100644 index 000000000..8e08fab36 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/models/user/UserInfoPublicModel.java @@ -0,0 +1,68 @@ +package eu.eudat.publicapi.models.user; + +import eu.eudat.data.entities.UserDMP; +import eu.eudat.data.entities.UserInfo; +import eu.eudat.models.DataModel; + +import java.util.UUID; + +public class UserInfoPublicModel implements DataModel { + private UUID id; + private String name; + private int role; + private String email; + + public UUID getId() { + return id; + } + public void setId(UUID id) { + this.id = id; + } + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + public int getRole() { + return role; + } + public void setRole(int role) { + this.role = role; + } + + public String getEmail() { + return email; + } + public void setEmail(String email) { + this.email = email; + } + + @Override + public UserInfoPublicModel fromDataModel(UserDMP entity) { + this.id = entity.getUser().getId(); + this.name = entity.getUser().getName(); + this.role = entity.getRole(); + this.email = entity.getUser().getEmail(); + return this; + } + + @Override + public UserDMP toDataModel() { + UserDMP entity = new UserDMP(); + entity.setId(this.getId()); + entity.setRole(this.getRole()); + UserInfo userInfo = new UserInfo(); + userInfo.setName(this.getName()); + userInfo.setEmail(this.getEmail()); + entity.setUser(userInfo); + return entity; + } + + @Override + public String getHint() { + return "UserInfoListingModel"; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/request/dataset/DatasetPublicTableRequest.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/request/dataset/DatasetPublicTableRequest.java new file mode 100644 index 000000000..44f096e89 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/request/dataset/DatasetPublicTableRequest.java @@ -0,0 +1,65 @@ +package eu.eudat.publicapi.request.dataset; + +import eu.eudat.data.entities.Dataset; +import eu.eudat.data.query.definition.TableQuery; +import eu.eudat.publicapi.criteria.dataset.DatasetPublicCriteria; +import eu.eudat.queryable.QueryableList; +import eu.eudat.queryable.types.FieldSelectionType; +import eu.eudat.queryable.types.SelectionField; + +import java.util.Arrays; +import java.util.Date; +import java.util.UUID; + + +public class DatasetPublicTableRequest extends TableQuery { + @Override + public QueryableList applyCriteria() { + QueryableList query = this.getQuery(); + query.where((builder, root) -> builder.equal(root.get("dmp").get("isPublic"), true)); + query.where((builder, root) -> builder.equal(root.get("status"), Dataset.Status.FINALISED.getValue())); +// query.initSubQuery(String.class).where((builder, root) -> builder.equal(root.get("dmp").get("version"), +// query.subQueryMax((builder1, externalRoot, nestedRoot) -> builder1.equal(externalRoot.get("dmp").get("groupId"), nestedRoot.get("dmp").get("groupId")), +// Arrays.asList(new SelectionField(FieldSelectionType.COMPOSITE_FIELD, "dmp:version")), String.class))); + if (this.getCriteria().getLike() != null && !this.getCriteria().getLike().isEmpty()) + query.where((builder, root) -> builder.or( + builder.like(builder.upper(root.get("label")), "%" + this.getCriteria().getLike().toUpperCase() + "%"), + builder.like(builder.upper(root.get("description")), "%" + this.getCriteria().getLike().toUpperCase() + "%"))); + if (this.getCriteria().getPeriodStart() != null) + query.where((builder, root) -> builder.greaterThan(root.get("created"), this.getCriteria().getPeriodStart())); + if (this.getCriteria().getPeriodEnd() != null) + query.where((builder, root) -> builder.lessThan(root.get("created"), this.getCriteria().getPeriodEnd())); + if (this.getCriteria().getGrants() != null && !this.getCriteria().getGrants().isEmpty()) + query.where(((builder, root) -> root.get("dmp").get("grant").get("id").in(this.getCriteria().getGrants()))); + if (this.getCriteria().getCollaborators() != null && !this.getCriteria().getCollaborators().isEmpty()) + query.where(((builder, root) -> root.join("dmp").join("researchers").get("id").in(this.getCriteria().getCollaborators()))); + if (this.getCriteria().getDatasetTemplates() != null && !this.getCriteria().getDatasetTemplates().isEmpty()) + query.where((builder, root) -> root.get("id").in(this.getCriteria().getDatasetTemplates())); + if (this.getCriteria().getDmpOrganisations() != null && !this.getCriteria().getDmpOrganisations().isEmpty()) + query.where(((builder, root) -> root.join("dmp").join("organisations").get("reference").in(this.getCriteria().getDmpOrganisations()))); + if (this.getCriteria().getDmpIds() != null && !this.getCriteria().getDmpIds().isEmpty()) { + query.where(((builder, root) -> root.get("dmp").get("id").in(this.getCriteria().getDmpIds()))); + } + if (this.getCriteria().getGroupIds() != null && !this.getCriteria().getGroupIds().isEmpty()) { + query.where((builder, root) -> root.get("dmp").get("groupId").in(this.getCriteria().getGroupIds())); + } + + //query.where((builder, root) -> builder.lessThan(root.get("dmp").get("grant").get("enddate"), new Date())); // GrantStateType.FINISHED + query.where((builder, root) -> + builder.or(builder.greaterThan(root.get("dmp").get("grant").get("enddate"), new Date()) + , builder.isNull(root.get("dmp").get("grant").get("enddate")))); // GrantStateType.ONGOING + + if (!this.getCriteria().getAllVersions()) { + query.initSubQuery(String.class).where((builder, root) -> builder.equal(root.get("profile").get("version"), + query.subQueryMax((builder1, externalRoot, nestedRoot) -> builder1.and(builder1.equal(externalRoot.get("profile").get("groupId"), + nestedRoot.get("profile").get("groupId")), builder1.equal(nestedRoot.get("dmp").get("isPublic"), true)), Arrays.asList(new SelectionField(FieldSelectionType.COMPOSITE_FIELD, "profile:version")), String.class))); + } + query.where((builder, root) -> builder.notEqual(root.get("status"), Dataset.Status.DELETED.getValue())); + return query; + } + + @Override + public QueryableList applyPaging(QueryableList items) { + return null; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/publicapi/request/dmp/DataManagmentPlanPublicTableRequest.java b/dmp-backend/web/src/main/java/eu/eudat/publicapi/request/dmp/DataManagmentPlanPublicTableRequest.java new file mode 100644 index 000000000..9c37ff4ac --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/publicapi/request/dmp/DataManagmentPlanPublicTableRequest.java @@ -0,0 +1,59 @@ +package eu.eudat.publicapi.request.dmp; + +import eu.eudat.data.entities.DMP; +import eu.eudat.data.query.PaginationService; +import eu.eudat.data.query.definition.TableQuery; +import eu.eudat.publicapi.criteria.dmp.DataManagementPlanPublicCriteria; +import eu.eudat.queryable.QueryableList; +import eu.eudat.queryable.types.FieldSelectionType; +import eu.eudat.queryable.types.SelectionField; + +import java.util.Arrays; +import java.util.Date; +import java.util.UUID; + +public class DataManagmentPlanPublicTableRequest extends TableQuery { + + public QueryableList applyCriteria() { + QueryableList query = this.getQuery(); + query.where((builder, root) -> builder.equal(root.get("isPublic"), true)); + if (this.getCriteria().getLike() != null && !this.getCriteria().getLike().isEmpty()) + query.where((builder, root) -> builder.or( + builder.like(builder.upper(root.get("label")), "%" + this.getCriteria().getLike().toUpperCase() + "%"), + builder.like(builder.upper(root.get("description")), "%" + this.getCriteria().getLike().toUpperCase() + "%"))); + if (this.getCriteria().getPeriodStart() != null) + query.where((builder, root) -> builder.greaterThan(root.get("created"), this.getCriteria().getPeriodStart())); + if (this.getCriteria().getPeriodEnd() != null) + query.where((builder, root) -> builder.lessThan(root.get("created"), this.getCriteria().getPeriodEnd())); + if (this.getCriteria().getGrants() != null && !this.getCriteria().getGrants().isEmpty()) + query.where(((builder, root) -> root.get("grant").get("id").in(this.getCriteria().getGrants()))); + if (this.getCriteria().getFunders() != null && !this.getCriteria().getFunders().isEmpty()) + query.where(((builder, root) -> root.get("grant").get("funder").get("id").in(this.getCriteria().getFunders()))); + + //query.where((builder, root) -> builder.lessThan(root.get("grant").get("enddate"), new Date())); // GrantStateType.FINISHED + query.where((builder, root) -> + builder.or(builder.greaterThan(root.get("grant").get("enddate"), new Date()) + , builder.isNull(root.get("grant").get("enddate")))); // GrantStateType.ONGOING + + if (this.getCriteria().getDatasetTemplates() != null && !this.getCriteria().getDatasetTemplates().isEmpty()) + query.where((builder, root) -> root.join("dataset").get("id").in(this.getCriteria().getDatasetTemplates())); + if (this.getCriteria().getDmpOrganisations() != null && !this.getCriteria().getDmpOrganisations().isEmpty()) + query.where(((builder, root) -> root.join("organisations").get("reference").in(this.getCriteria().getDmpOrganisations()))); + if (this.getCriteria().getCollaborators() != null && !this.getCriteria().getCollaborators().isEmpty()) + query.where(((builder, root) -> root.join("researchers").get("id").in(this.getCriteria().getCollaborators()))); + if (!this.getCriteria().getAllVersions()) { + query.initSubQuery(String.class).where((builder, root) -> builder.equal(root.get("version"), + query.subQueryMax((builder1, externalRoot, nestedRoot) -> builder1.and(builder1.equal(externalRoot.get("groupId"), + nestedRoot.get("groupId")), builder1.equal(nestedRoot.get("isPublic"), true)), Arrays.asList(new SelectionField(FieldSelectionType.FIELD, "version")), String.class))); + } + if (this.getCriteria().getGroupIds() != null && !this.getCriteria().getGroupIds().isEmpty()) { + query.where((builder, root) -> root.get("groupId").in(this.getCriteria().getGroupIds())); + } + return query; + } + + @Override + public QueryableList applyPaging(QueryableList items) { + return PaginationService.applyPaging(items, this); + } +} From fd2ec314a017d7b7a7fb4a4b220b867f017b2b0e Mon Sep 17 00:00:00 2001 From: "k.triantafyllou" Date: Wed, 5 Oct 2022 16:22:47 +0300 Subject: [PATCH 13/13] Add next-previous buttons in dataset editot in order to navigate through chapters --- .../dataset-wizard.component.html | 14 +++-- .../dataset-wizard.component.ts | 58 ++++++++++++------- .../table-of-contents-internal.ts | 12 ++-- .../table-of-contents.ts | 30 +++++----- 4 files changed, 70 insertions(+), 44 deletions(-) diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.html b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.html index 157843b2b..a8d55b93f 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.html +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.html @@ -68,11 +68,16 @@
{{'DMP-EDITOR.STEPPER.USER-GUIDE' | translate}}
-
0. {{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (2)
-
0. {{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (done)
-
+
0. {{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (2)
+
0. {{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (done)
+
- +
@@ -81,6 +86,7 @@ chevron_left
{{'DMP-EDITOR.STEPPER.PREVIOUS' | translate}}
+
{{'DMP-EDITOR.STEPPER.NEXT' | translate}}
chevron_right diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts index 970b65d80..3cda07f3b 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts @@ -1,4 +1,4 @@ -import {Component, ElementRef, OnInit, ViewChild} from '@angular/core'; +import {Component, OnInit, ViewChild} from '@angular/core'; import {AbstractControl, FormArray, FormControl, FormGroup} from '@angular/forms'; import {MatDialog} from '@angular/material/dialog'; import {MatSnackBar} from '@angular/material/snack-bar'; @@ -14,14 +14,18 @@ import {DmpCriteria} from '@app/core/query/dmp/dmp-criteria'; import {RequestItem} from '@app/core/query/request-item'; import {DatasetWizardService} from '@app/core/services/dataset-wizard/dataset-wizard.service'; import {DmpService} from '@app/core/services/dmp/dmp.service'; -import {ExternalSourcesConfigurationService} from '@app/core/services/external-sources/external-sources-configuration.service'; +import { + ExternalSourcesConfigurationService +} from '@app/core/services/external-sources/external-sources-configuration.service'; import {ExternalSourcesService} from '@app/core/services/external-sources/external-sources.service'; import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; import {SingleAutoCompleteConfiguration} from '@app/library/auto-complete/single/single-auto-complete-configuration'; -import {DatasetCopyDialogueComponent} from '@app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component'; +import { + DatasetCopyDialogueComponent +} from '@app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component'; import {DatasetWizardEditorModel} from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; import {BreadcrumbItem} from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; import {IBreadCrumbComponent} from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; @@ -32,7 +36,9 @@ import { TableOfContents } from '@app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents'; import {FormService} from '@common/forms/form-service'; -import {FormValidationErrorsDialogComponent} from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component'; +import { + FormValidationErrorsDialogComponent +} from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component'; import {ValidationErrorModel} from '@common/forms/validation/error-model/validation-error-model'; import {ConfirmationDialogComponent} from '@common/modules/confirmation-dialog/confirmation-dialog.component'; import {TranslateService} from '@ngx-translate/core'; @@ -54,6 +60,7 @@ import {VisibilityRulesService} from '@app/ui/misc/dataset-description-form/visi import {PopupNotificationDialogComponent} from '@app/library/notification/popup/popup-notification.component'; import {CheckDeactivateBaseComponent} from '@app/library/deactivate/deactivate.component'; import {PrefillDatasetComponent} from "@app/ui/dataset/dataset-wizard/prefill-dataset/prefill-dataset.component"; +import {ToCEntry} from "@app/ui/misc/dataset-description-form/dataset-description.component"; @Component({ selector: 'app-dataset-wizard-component', @@ -94,7 +101,6 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme step: number = 0; stepOffset: number = 1; - maxStep: number; saveAnd = SaveType; datasetSavedLinks: any = null; @@ -260,7 +266,6 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme this.formGroup = this.datasetWizardModel.buildForm(); this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); this.formGroup.get('dmp').disable(); - this.maxStep = 1; this.loadDatasetProfiles(); this.registerFormListeners(); } @@ -437,8 +442,6 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme }]); } - !this.isNew ? this.maxStep = 1 : this.maxStep = 0; - // this.route.params // .pipe(takeUntil(this._destroyed)) // .subscribe((params: Params) => { @@ -528,7 +531,7 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme if (profiledId && profiledId.length > 0) { this.formGroup.removeControl('datasetProfileDefinition'); this.getDefinition(profiledId); - this.maxStep = 1; + console.log(this.table0fContents.tocentries.length + 1); } } @@ -1151,31 +1154,46 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme }); } - public changeStep(index: number, dataset?: FormControl) { - if (this.step != index) { //view is changing - this.resetScroll(); + checkSelectedParent(entry: ToCEntry, selected: ToCEntry = null) { + if(!selected) { + selected = this.table0fContents.tocentrySelected; } - this.step = index; + if(entry.numbering === selected.numbering) { + return true; + } else { + return !!entry.subEntries.find(subEntry => this.checkSelectedParent(subEntry, selected)) + } + } + + public changeStep(selected: ToCEntry = null) { + if(selected) { + let index = this.table0fContents.tocentries.findIndex(entry => this.checkSelectedParent(entry, selected)); + console.log(index); + this.step = index + 1; + } else { + this.table0fContents.onToCentrySelected(null); + this.step = 0; + } + } + + get maxStep() { + return this.table0fContents?this.table0fContents.tocentries.length:0; } public nextStep() { if (this.step < this.maxStep) {//view is changing - if (this.step === 0 && this.table0fContents) { - this.table0fContents.seekToFirstElement(); - } this.step++; + this.table0fContents.internalTable.selected = this.table0fContents.tocentries[this.step - 1]; this.resetScroll(); } - // this.step = this.step < this.maxStep ? this.step + 1 : this.step; } public previousStep() { if (this.step > 0) { - this.resetScroll(); this.step--; + this.table0fContents.internalTable.selected = this.step > 0?this.table0fContents.tocentries[this.step - 1]:null; + this.resetScroll(); } - - // this.step = this.step !== 0 ? this.step - 1 : this.step; } private resetScroll() { diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents-internal/table-of-contents-internal.ts b/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents-internal/table-of-contents-internal.ts index 9724daff3..ba4d879d2 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents-internal/table-of-contents-internal.ts +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents-internal/table-of-contents-internal.ts @@ -37,7 +37,7 @@ export class TableOfContentsInternal implements OnInit { } break; } - } + } } } } @@ -51,7 +51,7 @@ export class TableOfContentsInternal implements OnInit { } break; } - } + } } // if (!this.isActive && this.links && this.links.length > 0) { // this.links.forEach(link => { @@ -68,12 +68,12 @@ export class TableOfContentsInternal implements OnInit { navigateToFieldSet(entry:ToCEntry, event){ if(entry.type === ToCEntryType.FieldSet){ - + const fieldSetId = entry.id; const element = document.getElementById(this.TOCENTRY_ID_PREFIX+fieldSetId); if(element){ element.click();//open mat expansion panel - + //scroll asyn in 200 ms so the expansion panel is expanded and the element coordinates are updated setTimeout(() => { const element = document.getElementById(this.TOCENTRY_ID_PREFIX+fieldSetId); @@ -121,7 +121,7 @@ export class TableOfContentsInternal implements OnInit { if(tocEntryFound){ return tocEntryFound; - } + } for(let entry of tocentries){ const result = this._findTocEntryById(id, entry.subEntries); @@ -130,7 +130,7 @@ export class TableOfContentsInternal implements OnInit { break; } } - + return tocEntryFound? tocEntryFound: null; } public invalidChildsVisible(entry: ToCEntry):boolean { diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.ts b/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.ts index 573e97eeb..e9ebda2ab 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.ts +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.ts @@ -43,6 +43,7 @@ export class TableOfContents extends BaseComponent implements OnInit, OnChanges headerSelectors = '.toc-page-header, .toc-section-header, .toc-compositeField-header'; @Output() stepFound = new EventEmitter(); @Output() currentLinks = new EventEmitter(); + @Output() entrySelected = new EventEmitter(); subscription: Subscription; linksSubject: Subject = new Subject(); @@ -100,7 +101,7 @@ export class TableOfContents extends BaseComponent implements OnInit, OnChanges } }else{ - + //emit value every 500ms const source = interval(500); this.subscription = source.subscribe(val => { @@ -198,20 +199,20 @@ export class TableOfContents extends BaseComponent implements OnInit, OnChanges private _visibilityRulesSubscription:Subscription; ngOnChanges(changes: SimpleChanges) { - + if(this.selectedFieldsetId){ this.tocentrySelected = this._findTocEntryById(this.selectedFieldsetId,this.tocentries); this._actOnObservation = false; setTimeout(() => { this._actOnObservation = true; }, 1000); - + } if(changes['hasFocus'] && changes.hasFocus.currentValue){ this._resetObserver(); - + } if('visibilityRulesService'){ @@ -219,7 +220,7 @@ export class TableOfContents extends BaseComponent implements OnInit, OnChanges this._visibilityRulesSubscription.unsubscribe(); this._visibilityRulesSubscription = null; } - + if(!this.visibilityRulesService) return; this._visibilityRulesSubscription = this.visibilityRulesService.visibilityChange @@ -247,13 +248,13 @@ export class TableOfContents extends BaseComponent implements OnInit, OnChanges this._intersectionObserver.disconnect(); this._intersectionObserver = null; } - + const options = { root: null, rootMargin: '-38% 0px -60% 0px', threshold: 0 } - + this._intersectionObserver = new IntersectionObserver((entries,observer)=>{ if(!this._actOnObservation){ return; @@ -273,7 +274,7 @@ export class TableOfContents extends BaseComponent implements OnInit, OnChanges }) }, options); - const fieldsetsEtries = this._getAllFieldSets(this.tocentries); + const fieldsetsEtries = this._getAllFieldSets(this.tocentries); fieldsetsEtries.forEach(e=>{ if(e.type === ToCEntryType.FieldSet){ @@ -338,7 +339,7 @@ export class TableOfContents extends BaseComponent implements OnInit, OnChanges const tempResult:ToCEntry[] = []; - + if(sections &§ions.length){ sections.controls.forEach(section=>{ tempResult.push(this._buildRecursively(section as FormGroup, ToCEntryType.Section)); @@ -374,9 +375,9 @@ export class TableOfContents extends BaseComponent implements OnInit, OnChanges } private _sortByOrdinal(tocentries: ToCEntry[]){ - + if(!tocentries || !tocentries.length) return; - + tocentries.sort(this._customCompare); tocentries.forEach(entry=>{ this._sortByOrdinal(entry.subEntries); @@ -401,7 +402,7 @@ export class TableOfContents extends BaseComponent implements OnInit, OnChanges }); } - + getTocEntries(form): ToCEntry[] { if (form == null) { return []; } const result: ToCEntry[] = []; @@ -442,6 +443,7 @@ export class TableOfContents extends BaseComponent implements OnInit, OnChanges onToCentrySelected(entry: ToCEntry){ this.tocentrySelected = entry; + this.entrySelected.emit(entry); } @@ -460,7 +462,7 @@ export class TableOfContents extends BaseComponent implements OnInit, OnChanges if(tocEntryFound){ return tocEntryFound; - } + } for(let entry of tocentries){ const result = this._findTocEntryById(id, entry.subEntries); @@ -469,7 +471,7 @@ export class TableOfContents extends BaseComponent implements OnInit, OnChanges break; } } - + return tocEntryFound? tocEntryFound: null; } /**