diff --git a/backend/core/src/main/java/org/opencdmp/audit/AuditableAction.java b/backend/core/src/main/java/org/opencdmp/audit/AuditableAction.java index 84cfbdc9b..085dedac1 100644 --- a/backend/core/src/main/java/org/opencdmp/audit/AuditableAction.java +++ b/backend/core/src/main/java/org/opencdmp/audit/AuditableAction.java @@ -45,6 +45,8 @@ public class AuditableAction { public static final EventId Dmp_Finalize = new EventId(5013, "Dmp_Finalize"); public static final EventId Dmp_Undo_Finalize = new EventId(5014, "Dmp_Undo_Finalize"); public static final EventId Dmp_Validate = new EventId(5015, "Dmp_Validate"); + public static final EventId Dmp_GetXml = new EventId(5016, "Dmp_GetXml"); + public static final EventId Dmp_Import = new EventId(5017, "Dmp_Import"); public static final EventId Description_Query = new EventId(6000, "Description_Query"); diff --git a/backend/core/src/main/java/org/opencdmp/service/dmp/DmpService.java b/backend/core/src/main/java/org/opencdmp/service/dmp/DmpService.java index 673a625c4..9a2c4bc71 100644 --- a/backend/core/src/main/java/org/opencdmp/service/dmp/DmpService.java +++ b/backend/core/src/main/java/org/opencdmp/service/dmp/DmpService.java @@ -55,4 +55,7 @@ public interface DmpService { DmpImportExport exportXmlEntity(UUID id, boolean ignoreAuthorize) throws MyForbiddenException, MyNotFoundException, JAXBException, ParserConfigurationException, IOException, InstantiationException, IllegalAccessException, SAXException, InvalidApplicationException; ResponseEntity exportXml(UUID id) throws MyForbiddenException, MyNotFoundException, JAXBException, ParserConfigurationException, IOException, InstantiationException, IllegalAccessException, SAXException, InvalidApplicationException; + + Dmp importXml(byte[] bytes, String label, FieldSet fields) throws MyForbiddenException, MyNotFoundException, JAXBException, ParserConfigurationException, TransformerException, InvalidApplicationException, IOException, InstantiationException, IllegalAccessException, SAXException; + } diff --git a/backend/core/src/main/java/org/opencdmp/service/dmp/DmpServiceImpl.java b/backend/core/src/main/java/org/opencdmp/service/dmp/DmpServiceImpl.java index 3bee75ac3..cb6a00058 100644 --- a/backend/core/src/main/java/org/opencdmp/service/dmp/DmpServiceImpl.java +++ b/backend/core/src/main/java/org/opencdmp/service/dmp/DmpServiceImpl.java @@ -36,6 +36,8 @@ import org.opencdmp.commons.types.dmp.DmpPropertiesEntity; import org.opencdmp.commons.types.dmp.importexport.*; import org.opencdmp.commons.types.dmpblueprint.ReferenceTypeFieldEntity; import org.opencdmp.commons.types.dmpblueprint.SectionEntity; +import org.opencdmp.commons.types.dmpblueprint.importexport.BlueprintReferenceTypeFieldImportExport; +import org.opencdmp.commons.types.dmpblueprint.importexport.BlueprintSectionImportExport; import org.opencdmp.commons.types.dmpreference.DmpReferenceDataEntity; import org.opencdmp.commons.types.notification.*; import org.opencdmp.commons.types.reference.DefinitionEntity; @@ -92,7 +94,9 @@ import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.management.InvalidApplicationException; import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -1620,4 +1624,192 @@ public class DmpServiceImpl implements DmpService { //endregion + + //region Import + + public Dmp importXml(byte[] bytes, String label, FieldSet fields) throws MyForbiddenException, MyNotFoundException, JAXBException, ParserConfigurationException, TransformerException, InvalidApplicationException, IOException, InstantiationException, IllegalAccessException, SAXException { + logger.debug(new MapLogEntry("import data").And("bytes", bytes).And("label", label).And("fields", fields)); + +// this.authorizationService.authorizeForce(Permission.ImportDmpBlueprint); + + DmpPersist persist = new DmpPersist(); + + persist.setLabel(label); + persist.setStatus(DmpStatus.Draft); + + DmpImportExport dmpXml = this.xmlHandlingService.fromXml(DmpImportExport.class, new String(bytes, StandardCharsets.UTF_8)); + + persist.setDescription(dmpXml.getDescription()); + persist.setAccessType(dmpXml.getAccess()); + persist.setLanguage(dmpXml.getLanguage()); + + persist.setProperties(this.xmlToDmpPropertiesPersist(dmpXml)); + + if (!this.conventionService.isListNullOrEmpty(dmpXml.getUsers())) { + List users = this.queryFactory.query(UserQuery.class).disableTracking().ids(dmpXml.getUsers().stream().map(DmpUserImportExport::getId).filter(Objects::nonNull).distinct().toList()).isActive(IsActive.Active).collect(); + List userIds = users == null ? new ArrayList<>() : users.stream().map(x -> x.getId()).collect(Collectors.toList()); + + List dmpUsers = new ArrayList<>(); + for (DmpUserImportExport user : dmpXml.getUsers()) { + dmpUsers.add(this.xmlDmpUserToPersist(user, userIds)); + } + persist.setUsers(dmpUsers); + } + + if (dmpXml.getBlueprint() != null) persist.setBlueprint(dmpXml.getBlueprint().getId()); + + if (!this.conventionService.isListNullOrEmpty(dmpXml.getDescriptionTemplates())) { + List descriptionTemplates = new ArrayList<>(); + for (DmpDescriptionTemplateImportExport descriptionTemplate : dmpXml.getDescriptionTemplates()) { + descriptionTemplates.add(this.xmlDmpDescriptionTemplateToPersist(descriptionTemplate)); + } + persist.setDescriptionTemplates(descriptionTemplates); + } + + this.validatorFactory.validator(DmpPersist.DmpPersistValidator.class).validateForce(persist); + + return this.persist(persist, fields); + } + + private DmpPropertiesPersist xmlToDmpPropertiesPersist(DmpImportExport importXml) { + if (importXml == null) + return null; + + DmpPropertiesPersist persist = new DmpPropertiesPersist(); + + List contacts = new ArrayList<>(); + if (!this.conventionService.isListNullOrEmpty(importXml.getContacts())) { + List users = this.queryFactory.query(UserQuery.class).disableTracking().ids(importXml.getContacts().stream().map(DmpContactImportExport::getUserId).filter(Objects::nonNull).distinct().toList()).isActive(IsActive.Active).collect(); + List usersIds = users == null ? new ArrayList<>() : users.stream().map(x -> x.getId()).collect(Collectors.toList()); + for (DmpContactImportExport contact : importXml.getContacts()) { + contacts.add(this.xmlDmpContactToPersist(contact, usersIds)); + } + } + + Map dmpBlueprintValues = new HashMap<>(); + + // reference + if (!this.conventionService.isListNullOrEmpty(importXml.getBlueprint().getDmpBlueprintDefinition().getSections())) { + List sections = importXml.getBlueprint().getDmpBlueprintDefinition().getSections(); + if (!this.conventionService.isListNullOrEmpty(sections)){ + for (BlueprintSectionImportExport section : importXml.getBlueprint().getDmpBlueprintDefinition().getSections()) { + if (!this.conventionService.isListNullOrEmpty(section.getReferenceFields()) && !this.conventionService.isListNullOrEmpty(importXml.getReferences())){ + for (BlueprintReferenceTypeFieldImportExport blueprintReferenceTypeField : section.getReferenceFields()) { + List dmpReferencesByField = importXml.getReferences().stream().filter(x -> x.getFieldId().equals(blueprintReferenceTypeField.getId())).collect(Collectors.toList()); + if (!this.conventionService.isListNullOrEmpty(dmpReferencesByField)){ + dmpBlueprintValues.put(blueprintReferenceTypeField.getId(), this.xmlReferenceFieldToDmpBlueprintValuePersist(blueprintReferenceTypeField, dmpReferencesByField)); + } + } + } + } + } + + } + + + // custom fields + if (!this.conventionService.isListNullOrEmpty(importXml.getBlueprintValues())){ + for (DmpBlueprintValueImportExport value : importXml.getBlueprintValues()) { + if (value.getFieldId() != null) dmpBlueprintValues.put(value.getFieldId(), this.xmlDmpBlueprintValueToPersist(value)); + } + } + + persist.setContacts(contacts); + persist.setDmpBlueprintValues(dmpBlueprintValues); + + return persist; + } + + private DmpBlueprintValuePersist xmlReferenceFieldToDmpBlueprintValuePersist(BlueprintReferenceTypeFieldImportExport blueprintReferenceTypeFieldImportXml, List dmpReferencesImportXml) { + if (blueprintReferenceTypeFieldImportXml == null || this.conventionService.isListNullOrEmpty(dmpReferencesImportXml)) + return null; + + DmpBlueprintValuePersist persist = new DmpBlueprintValuePersist(); + + persist.setFieldId(blueprintReferenceTypeFieldImportXml.getId()); + if (blueprintReferenceTypeFieldImportXml.getMultipleSelect()){ + List references = new ArrayList<>(); + for (DmpReferenceImportExport dmpReference : dmpReferencesImportXml) { + references.add(this.xmlDmpReferenceToReferencePersist(dmpReference)); + } + persist.setReferences(references); + } else { + persist.setReference(this.xmlDmpReferenceToReferencePersist(dmpReferencesImportXml.stream().findFirst().orElse(null))); + } + + return persist; + } + + private ReferencePersist xmlDmpReferenceToReferencePersist(DmpReferenceImportExport importXml) { + if (importXml == null) + return null; + + ReferencePersist persist = new ReferencePersist(); + + persist.setId(importXml.getId()); + persist.setLabel(importXml.getLabel()); + persist.setReference(importXml.getReference()); + + return persist; + } + + private DmpBlueprintValuePersist xmlDmpBlueprintValueToPersist(DmpBlueprintValueImportExport importXml) { + if (importXml == null) + return null; + + DmpBlueprintValuePersist persist = new DmpBlueprintValuePersist(); + + persist.setFieldId(importXml.getFieldId()); + persist.setFieldValue(importXml.getValue()); + + return persist; + } + + private DmpDescriptionTemplatePersist xmlDmpDescriptionTemplateToPersist(DmpDescriptionTemplateImportExport importXml) { + if (importXml == null) + return null; + + DmpDescriptionTemplatePersist persist = new DmpDescriptionTemplatePersist(); + + persist.setDescriptionTemplateGroupId(importXml.getDescriptionTemplateGroupId()); + persist.setSectionId(importXml.getSectionId()); + + return persist; + } + + private DmpUserPersist xmlDmpUserToPersist(DmpUserImportExport importXml, List userIds) { + if (importXml == null) + return null; + + if (importXml.getId() != null && !userIds.isEmpty() && userIds.contains(importXml.getId())) { + DmpUserPersist persist = new DmpUserPersist(); + + persist.setUser(importXml.getId()); + persist.setRole(importXml.getRole()); + persist.setSectionId(importXml.getSectionId()); + + return persist; + } + return null; + } + + private DmpContactPersist xmlDmpContactToPersist(DmpContactImportExport importXml, List userIds) { + if (importXml == null) + return null; + + DmpContactPersist persist = new DmpContactPersist(); + + if (importXml.getUserId() != null && !userIds.isEmpty() && userIds.contains(importXml.getUserId())){ + persist.setUserId(importXml.getUserId()); + } else { + persist.setEmail(importXml.getEmail()); + persist.setFirstName(importXml.getEmail()); + persist.setLastName(importXml.getLastName()); + } + + return persist; + } + + //endregion + } diff --git a/backend/web/src/main/java/org/opencdmp/controllers/DmpController.java b/backend/web/src/main/java/org/opencdmp/controllers/DmpController.java index 0dcd0e1e3..0a9244486 100644 --- a/backend/web/src/main/java/org/opencdmp/controllers/DmpController.java +++ b/backend/web/src/main/java/org/opencdmp/controllers/DmpController.java @@ -39,6 +39,7 @@ import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import org.xml.sax.SAXException; import javax.crypto.BadPaddingException; @@ -343,10 +344,24 @@ public class DmpController { ResponseEntity response = this.dmpService.exportXml(id); - this.auditService.track(AuditableAction.DmpBlueprint_GetXml, Map.ofEntries( + this.auditService.track(AuditableAction.Dmp_GetXml, Map.ofEntries( new AbstractMap.SimpleEntry("id", id) )); return response; } + @RequestMapping(method = RequestMethod.POST, value = "/xml/import") + @Transactional + public Dmp importXml(@RequestParam("file") MultipartFile file, @RequestParam("label") String label, FieldSet fields) throws JAXBException, ParserConfigurationException, IOException, InstantiationException, IllegalAccessException, SAXException, InvalidApplicationException, TransformerException { + logger.debug(new MapLogEntry("import xml" + Dmp.class.getSimpleName()).And("file", file).And("label", label)); + + Dmp model = this.dmpService.importXml(file.getBytes(), label, fields); + + this.auditService.track(AuditableAction.Dmp_Import, Map.ofEntries( + new AbstractMap.SimpleEntry("file", file), + new AbstractMap.SimpleEntry("fields", fields) + )); + return model; + } + } diff --git a/dmp-frontend/src/app/core/services/dmp/dmp.service.ts b/dmp-frontend/src/app/core/services/dmp/dmp.service.ts index f0cc30820..730ec4052 100644 --- a/dmp-frontend/src/app/core/services/dmp/dmp.service.ts +++ b/dmp-frontend/src/app/core/services/dmp/dmp.service.ts @@ -188,15 +188,17 @@ export class DmpService { return this.httpClient.get(url, { params: params, responseType: 'blob', observe: 'response', headers: headerXml }); } - uploadFile(file: FileList, labelSent: string, reqFields: string[] = []): Observable { + uploadXml(file: File, label: string, reqFields: string[] = []): Observable { const url = `${this.apiBase}/xml/import`; const params = new BaseHttpParams(); params.interceptorContext = { excludedInterceptors: [InterceptorType.JSONContentType] }; const formData = new FormData(); - formData.append('file', file[0], labelSent); - return this.http.post(url, formData, { params: params }); + formData.append('file', file); + formData.append('label', label); + return this.http.post(url, formData, { params: params }).pipe( + catchError((error: any) => throwError(error)));; } // diff --git a/dmp-frontend/src/app/ui/dmp/new/start-new-dmp-dialogue/start-new-dmp-dialog.component.ts b/dmp-frontend/src/app/ui/dmp/new/start-new-dmp-dialogue/start-new-dmp-dialog.component.ts index 43fc15a15..64e1d3064 100644 --- a/dmp-frontend/src/app/ui/dmp/new/start-new-dmp-dialogue/start-new-dmp-dialog.component.ts +++ b/dmp-frontend/src/app/ui/dmp/new/start-new-dmp-dialogue/start-new-dmp-dialog.component.ts @@ -66,16 +66,15 @@ export class StartNewDmpDialogComponent extends BaseComponent { }); dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { if (result && result.success) { - //TODO refactor - // this.dmpService.uploadXml(result.fileList[0], result.dmpTitle, result.dmpBlueprints) - // .pipe(takeUntil(this._destroyed)) - // .subscribe( - // (complete) => { - // this.onCallbackImportComplete(); - // this.dialog.closeAll(); - // }, - // (error) => this.onCallbackImportFail(error.error) - // ); + this.dmpService.uploadXml(result.fileList[0], result.dmpTitle) + .pipe(takeUntil(this._destroyed)) + .subscribe( + (complete) => { + this.onCallbackImportComplete(); + this.dialog.closeAll(); + }, + (error) => this.onCallbackImportFail(error.error) + ); } }); } @@ -87,7 +86,7 @@ export class StartNewDmpDialogComponent extends BaseComponent { } private onCallbackImportFail(error: any) { - this.uiNotificationService.snackBarNotification(this.language.instant(error.message), SnackBarNotificationLevel.Error); + this.uiNotificationService.snackBarNotification(this.language.instant(error.error), SnackBarNotificationLevel.Error); } }