diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPProfileController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPProfileController.java index 2d83fc918..a53653305 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPProfileController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPProfileController.java @@ -1,10 +1,13 @@ package eu.eudat.controllers; +import eu.eudat.data.dao.criteria.RequestItem; import eu.eudat.data.entities.DMPProfile; import eu.eudat.data.query.items.table.dmpprofile.DataManagementPlanProfileTableRequest; import eu.eudat.logic.managers.DataManagementProfileManager; import eu.eudat.logic.security.claims.ClaimedAuthorities; import eu.eudat.logic.services.ApiContext; +import eu.eudat.models.data.helpermodels.Tuple; +import eu.eudat.models.data.helpers.common.AutoCompleteLookupItem; import eu.eudat.models.data.helpers.common.DataTableData; import eu.eudat.models.data.helpers.responses.ResponseItem; import eu.eudat.models.data.listingmodels.DataManagementPlanProfileListingModel; @@ -18,6 +21,7 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.validation.Valid; +import javax.xml.xpath.XPathExpressionException; import java.io.IOException; import java.util.List; @@ -82,4 +86,9 @@ public class DMPProfileController extends BaseController { .status(ApiMessageCode.SUCCESS_MESSAGE).message("")); } + @RequestMapping(method = RequestMethod.POST, value = {"/search/autocomplete"}) + public ResponseEntity getExternalAutocomplete(@RequestBody RequestItem lookupItem) throws XPathExpressionException { + List> items = this.dataManagementProfileManager.getExternalAutocomplete(lookupItem); + return ResponseEntity.status(HttpStatus.OK).body(items); + } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementProfileManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementProfileManager.java index 854bc73b8..1355b9884 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementProfileManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementProfileManager.java @@ -1,13 +1,21 @@ package eu.eudat.logic.managers; +import com.jayway.jsonpath.DocumentContext; +import com.jayway.jsonpath.JsonPath; +import eu.eudat.data.dao.criteria.RequestItem; import eu.eudat.data.dao.entities.DMPProfileDao; import eu.eudat.data.entities.DMPProfile; import eu.eudat.data.query.items.item.dmpprofile.DataManagementPlanProfileCriteriaRequest; import eu.eudat.data.query.items.table.dmpprofile.DataManagementPlanProfileTableRequest; import eu.eudat.logic.services.operations.DatabaseRepository; +import eu.eudat.logic.utilities.builders.XmlBuilder; import eu.eudat.logic.utilities.documents.helpers.FileEnvelope; import eu.eudat.logic.utilities.documents.xml.dmpXml.ExportXmlBuilderDmpProfile; import eu.eudat.logic.utilities.documents.xml.dmpXml.ImportXmlBuilderDmpProfile; +import eu.eudat.models.data.entities.xmlmodels.dmpprofiledefinition.DmpProfileExternalAutoComplete; +import eu.eudat.models.data.entities.xmlmodels.dmpprofiledefinition.Field; +import eu.eudat.models.data.helpermodels.Tuple; +import eu.eudat.models.data.helpers.common.AutoCompleteLookupItem; import eu.eudat.models.data.helpers.common.DataTableData; import eu.eudat.models.data.listingmodels.DataManagementPlanProfileListingModel; import eu.eudat.models.data.security.Principal; @@ -18,14 +26,17 @@ import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import javax.activation.MimetypesFileTypeMap; +import javax.xml.xpath.*; import java.io.*; import java.nio.file.Files; -import java.util.List; -import java.util.UUID; +import java.util.*; import java.util.concurrent.CompletableFuture; import org.springframework.http.*; +import org.springframework.web.client.RestTemplate; import org.springframework.web.multipart.MultipartFile; +import org.w3c.dom.Document; +import org.w3c.dom.Element; /** * Created by ikalyvas on 3/21/2018. @@ -79,11 +90,7 @@ public class DataManagementProfileManager { apiContext.getOperationsContext().getDatabaseRepository().getDmpProfileDao().createOrUpdate(dmpProfile); } - - public ResponseEntity getDocument(DataManagementPlanProfileListingModel dmpProfile, String label) throws IllegalAccessException, IOException, InstantiationException { - - FileEnvelope envelope = getXmlDocument(dmpProfile, label); InputStream resource = new FileInputStream(envelope.getFile()); System.out.println("Mime Type of " + envelope.getFilename() + " is " + @@ -131,4 +138,37 @@ public class DataManagementProfileManager { return convFile; } + public List> getExternalAutocomplete(RequestItem lookupItem) throws XPathExpressionException { + DMPProfile dmpProfile = this.apiContext.getOperationsContext().getDatabaseRepository().getDmpProfileDao().find(UUID.fromString(lookupItem.getCriteria().getProfileID())); + Field field = this.queryForField(dmpProfile.getDefinition(), lookupItem.getCriteria().getFieldID()); + DmpProfileExternalAutoComplete data = field.getExternalAutocomplete(); + return this.externalAutocompleteRequest(data, lookupItem.getCriteria().getLike()); + } + + private Field queryForField(String xml, String fieldId) throws XPathExpressionException { + Field field = new Field(); + Document document = XmlBuilder.fromXml(xml); + XPathFactory xpathFactory = XPathFactory.newInstance(); + XPath xpath = xpathFactory.newXPath(); + XPathExpression expr = xpath.compile("//field[@id='" + fieldId + "']"); + Element name = (Element) expr.evaluate(document, XPathConstants.NODE); + field.fromXml(name); + return field; + } + + private List> externalAutocompleteRequest(DmpProfileExternalAutoComplete data, String like) { + List> result = new LinkedList<>(); + RestTemplate restTemplate = new RestTemplate(); + HttpHeaders headers = new HttpHeaders(); + headers.setAccept(Collections.singletonList(MediaType.valueOf("application/vnd.api+json; charset=utf-8"))); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity entity = new HttpEntity<>("parameters", headers); + + ResponseEntity response = restTemplate.exchange(data.getUrl() + "?search=" + like, HttpMethod.GET, entity, Object.class); + DocumentContext jsonContext = JsonPath.parse(response.getBody()); + + List> jsonItems = jsonContext.read(data.getOptionsRoot() + "['" + data.getLabel() + "','" + data.getValue() + "']"); + jsonItems.forEach(item -> result.add(new Tuple<>(item.get(data.getValue()), item.get(data.getLabel())))); + return result; + } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/entities/xmlmodels/dmpprofiledefinition/DmpProfileExternalAutoComplete.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/entities/xmlmodels/dmpprofiledefinition/DmpProfileExternalAutoComplete.java new file mode 100644 index 000000000..43beb8c9b --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/entities/xmlmodels/dmpprofiledefinition/DmpProfileExternalAutoComplete.java @@ -0,0 +1,68 @@ +package eu.eudat.models.data.entities.xmlmodels.dmpprofiledefinition; + +import eu.eudat.logic.utilities.interfaces.XmlSerializable; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +public class DmpProfileExternalAutoComplete implements XmlSerializable { + private String url; + private String optionsRoot; + private Boolean multiAutoComplete; + private String label; + private String value; + + public String getUrl() { + return url; + } + public void setUrl(String url) { + this.url = url; + } + + public String getOptionsRoot() { + return optionsRoot; + } + public void setOptionsRoot(String optionsRoot) { + this.optionsRoot = optionsRoot; + } + + public Boolean getMultiAutoComplete() { return multiAutoComplete; } + public void setMultiAutoComplete(Boolean multiAutoComplete) { this.multiAutoComplete = multiAutoComplete; } + + public String getLabel() { + return label; + } + public void setLabel(String label) { + this.label = label; + } + + public String getValue() { + return value; + } + public void setValue(String value) { + this.value = value; + } + + @Override + public Element toXml(Document doc) { + Element root = doc.createElement("externalAutocomplete"); + root.setAttribute("url", this.url); + root.setAttribute("optionsRoot", this.optionsRoot); + if (this.multiAutoComplete == null) this.multiAutoComplete = false; + root.setAttribute("multiAutoComplete", this.multiAutoComplete.toString()); + root.setAttribute("label", this.label); + root.setAttribute("value", this.value); + + return root; + } + + @Override + public DmpProfileExternalAutoComplete fromXml(Element item) { + this.url = item.getAttribute("url"); + this.optionsRoot = item.getAttribute("optionsRoot"); + this.multiAutoComplete = Boolean.valueOf(item.getAttribute("multiAutoComplete")); + this.label = item.getAttribute("label"); + this.value = item.getAttribute("value"); + + return this; + } +} diff --git a/dmp-frontend/src/app/core/services/dmp/dmp-profile.service.ts b/dmp-frontend/src/app/core/services/dmp/dmp-profile.service.ts index 167b3f2dd..cbb28a893 100644 --- a/dmp-frontend/src/app/core/services/dmp/dmp-profile.service.ts +++ b/dmp-frontend/src/app/core/services/dmp/dmp-profile.service.ts @@ -12,6 +12,7 @@ import { DmpProfileCriteria } from '../../query/dmp/dmp-profile-criteria'; import { DatasetListingModel } from '../../model/dataset/dataset-listing'; import { BaseHttpParams } from '../../../common/http/base-http-params'; import { InterceptorType } from '../../../common/http/interceptors/interceptor-type'; +import { DmpProfileExternalAutocompleteCriteria } from '../../query/dmp/dmp-profile-external-autocomplete-criteria'; @Injectable() export class DmpProfileService { @@ -49,4 +50,8 @@ export class DmpProfileService { formData.append('file', file[0], labelSent); return this.http.post(this.actionUrl + "upload", formData, { params: params }); } + + externalAutocomplete(lookUpItem: RequestItem): Observable { + return this.httpClient.post(this.actionUrl + 'search/autocomplete', lookUpItem); + } } diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.component.html b/dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.component.html index 9cd10d47a..395527ab7 100644 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.component.html +++ b/dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.component.html @@ -5,10 +5,6 @@ {{'DMP-PROFILE-EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE.MULTIPLE-AUTOCOMPLETE' | translate}} - - - diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.component.scss b/dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.component.scss index 864574853..fdb51b6d5 100644 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.component.scss +++ b/dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.component.scss @@ -1,4 +1,6 @@ .external-autocomplete { + margin-bottom: 10px; + .centered-row-item { align-items: center; display: flex; diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.model.ts b/dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.model.ts index 0048e0595..64a9ee437 100644 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.model.ts +++ b/dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.model.ts @@ -3,7 +3,6 @@ import { DmpProfileExternalAutoCompleteField } from "../../../../../core/model/d export class DmpProfileExternalAutoCompleteFieldDataEditorModel { - public placeholder: string; public url: string; public optionsRoot: string; public multiAutoComplete: boolean = false; @@ -12,7 +11,6 @@ export class DmpProfileExternalAutoCompleteFieldDataEditorModel { buildForm(disabled: boolean = false, skipDisable: Array = []): FormGroup { const formGroup = new FormBuilder().group({ - placeholder: [{ value: this.placeholder, disabled: (disabled && !skipDisable.includes('DmpProfileExternalAutoCompleteFieldDataEditorModel.placeholder')) }], url: [{ value: this.url, disabled: (disabled && !skipDisable.includes('DmpProfileExternalAutoCompleteFieldDataEditorModel.url')) }], optionsRoot: [{ value: this.optionsRoot, disabled: (disabled && !skipDisable.includes('DmpProfileExternalAutoCompleteFieldDataEditorModel.optionsRoot')) }], multiAutoComplete: [{ value: this.multiAutoComplete, disabled: (disabled && !skipDisable.includes('DmpProfileExternalAutoCompleteFieldDataEditorModel.multiAutoComplete')) }], @@ -24,7 +22,6 @@ export class DmpProfileExternalAutoCompleteFieldDataEditorModel { } fromModel(item: DmpProfileExternalAutoCompleteField): DmpProfileExternalAutoCompleteFieldDataEditorModel { - this.placeholder = item.placeholder; this.url = item.url; this.optionsRoot = item.optionsRoot; this.multiAutoComplete = item.multiAutoComplete; diff --git a/dmp-frontend/src/app/ui/dmp/editor/dynamic-field-resolver/dynamic-dmp-field-resolver.component.html b/dmp-frontend/src/app/ui/dmp/editor/dynamic-field-resolver/dynamic-dmp-field-resolver.component.html index 2598a4a88..04ce615da 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/dynamic-field-resolver/dynamic-dmp-field-resolver.component.html +++ b/dmp-frontend/src/app/ui/dmp/editor/dynamic-field-resolver/dynamic-dmp-field-resolver.component.html @@ -24,6 +24,29 @@ {{'GENERAL.VALIDATION.REQUIRED' | translate}} - +
+
+ + + + +
+
+ + + + +
+ +
diff --git a/dmp-frontend/src/app/ui/dmp/editor/dynamic-field-resolver/dynamic-dmp-field-resolver.component.ts b/dmp-frontend/src/app/ui/dmp/editor/dynamic-field-resolver/dynamic-dmp-field-resolver.component.ts index 30a198abc..d95540f87 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/dynamic-field-resolver/dynamic-dmp-field-resolver.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/dynamic-field-resolver/dynamic-dmp-field-resolver.component.ts @@ -1,8 +1,14 @@ import { Component, Input, OnDestroy, OnInit, SimpleChanges } from '@angular/core'; -import { FormArray, FormBuilder, FormGroup } from '@angular/forms'; +import { FormArray, FormBuilder, FormGroup, FormControl } from '@angular/forms'; import { DmpProfileFieldDataType } from '../../../../core/common/enum/dmp-profile-field-type'; import { DmpProfileType } from '../../../../core/common/enum/dmp-profile-type'; import { DmpProfileDefinition } from '../../../../core/model/dmp-profile/dmp-profile'; +import { SingleAutoCompleteConfiguration } from '../../../../library/auto-complete/single/single-auto-complete-configuration'; +import { MultipleAutoCompleteConfiguration } from '../../../../library/auto-complete/multiple/multiple-auto-complete-configuration'; +import { DmpProfileService } from '../../../../core/services/dmp/dmp-profile.service'; +import { DmpProfileExternalAutocompleteCriteria } from '../../../../core/query/dmp/dmp-profile-external-autocomplete-criteria'; +import { RequestItem } from '../../../../core/query/request-item'; +import { DmpProfileField } from '../../../../core/model/dmp-profile/dmp-profile-field'; @Component({ selector: 'app-dynamic-dmp-field-resolver', @@ -14,13 +20,47 @@ export class DynamicDmpFieldResolverComponent implements OnInit, OnDestroy { dmpProfileFieldDataType = DmpProfileFieldDataType; dmpProfileTypeEnum = DmpProfileType; + singleAutocompleteMap: { [id: string]: SingleAutoCompleteConfiguration; } = {}; + multiAutocompleteMap: { [id: string]: MultipleAutoCompleteConfiguration; } = {}; + @Input() dmpProfileId: string; @Input() dmpProfileDefinition: DmpProfileDefinition; @Input() formGroup: FormGroup; + constructor( + private dmpProfileService: DmpProfileService + ) { } + ngOnInit(): void { this.createControleFields(); + + if (this.dmpProfileDefinition) { + this.dmpProfileDefinition.fields.forEach( + field => { + if (field.externalAutocomplete) { + if (field.externalAutocomplete.multiAutoComplete) { + const multiConf: MultipleAutoCompleteConfiguration = { + filterFn: this.externalAutocomplete.bind(this, field), + initialItems: (extraData) => this.externalAutocomplete('', field.id), + displayFn: (item) => item['label'], + titleFn: (item) => item['label'] + } + this.multiAutocompleteMap[field.id] = multiConf; + } else { + const singleConf: SingleAutoCompleteConfiguration = { + filterFn: this.externalAutocomplete.bind(this, field), + initialItems: (extraData) => this.externalAutocomplete('', field.id), + displayFn: (item) => item['label'], + titleFn: (item) => item['label'] + } + this.singleAutocompleteMap[field.id] = singleConf; + } + } + } + ); + } } + ngOnChanges(changes: SimpleChanges) { if (changes['dmpProfileDefinition'] && !changes['dmpProfileDefinition'].isFirstChange()) { this.createControleFields(); @@ -39,7 +79,7 @@ export class DynamicDmpFieldResolverComponent implements OnInit, OnDestroy { })); }); } - if(this.dmpProfileDefinition==null){ + if (this.dmpProfileDefinition == null) { this.formGroup.removeControl('properties'); } } @@ -47,4 +87,21 @@ export class DynamicDmpFieldResolverComponent implements OnInit, OnDestroy { ngOnDestroy(): void { this.formGroup.removeControl('properties'); } + + externalAutocomplete(query: any, extFieldID: any) { + const autocompleteRequestItem: RequestItem = new RequestItem(); + autocompleteRequestItem.criteria = new DmpProfileExternalAutocompleteCriteria(); + + if (typeof extFieldID == "string" && typeof query == "string") { + autocompleteRequestItem.criteria.like = query; + autocompleteRequestItem.criteria.profileID = this.dmpProfileId; + autocompleteRequestItem.criteria.fieldID = extFieldID; + } else { + autocompleteRequestItem.criteria.like = extFieldID; + autocompleteRequestItem.criteria.profileID = this.dmpProfileId; + autocompleteRequestItem.criteria.fieldID = query.id; + } + + return this.dmpProfileService.externalAutocomplete(autocompleteRequestItem); + } } diff --git a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.html b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.html index 274b330b6..c3adfec5f 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.html +++ b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.html @@ -63,8 +63,8 @@ {{formGroup.get('researchers').getError('backendError').message}} - {{'GENERAL.VALIDATION.REQUIRED' | - translate}} + + {{'GENERAL.VALIDATION.REQUIRED' | translate}}