Initial commit for the new Dataset Template Field (identifier validator)

This commit is contained in:
George Kalampokis 2020-11-05 18:20:37 +02:00
parent 078d472859
commit da9872576e
15 changed files with 231 additions and 2 deletions

View File

@ -0,0 +1,44 @@
package eu.eudat.controllers;
import eu.eudat.data.entities.Service;
import eu.eudat.logic.managers.ServiceManager;
import eu.eudat.logic.managers.ValidationManager;
import eu.eudat.logic.proxy.config.exceptions.HugeResultSet;
import eu.eudat.logic.proxy.config.exceptions.NoURLFound;
import eu.eudat.logic.services.ApiContext;
import eu.eudat.models.data.helpers.responses.ResponseItem;
import eu.eudat.models.data.security.Principal;
import eu.eudat.models.data.services.ServiceModel;
import eu.eudat.types.ApiMessageCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@CrossOrigin
@RequestMapping(value = {"/api"})
public class Validation extends BaseController {
private ValidationManager validationManager;
@Autowired
public Validation(ApiContext apiContext, ValidationManager validationManager) {
super(apiContext);
this.validationManager = validationManager;
}
@RequestMapping(method = RequestMethod.GET, value = {"/external/validation"}, produces = "application/json")
public @ResponseBody
ResponseEntity<ResponseItem<Boolean>> validate(
@RequestParam(value = "query", required = false) String query, @RequestParam(value = "type", required = false) String type, Principal principal
) throws HugeResultSet, NoURLFound {
Boolean isValid = this.validationManager.validateIdentifier(query, type, principal);
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<Boolean>().payload(isValid).status(ApiMessageCode.NO_MESSAGE));
}
}

View File

@ -0,0 +1,31 @@
package eu.eudat.logic.managers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import eu.eudat.logic.proxy.config.ExternalUrlCriteria;
import eu.eudat.logic.proxy.config.exceptions.HugeResultSet;
import eu.eudat.logic.proxy.config.exceptions.NoURLFound;
import eu.eudat.logic.proxy.fetching.RemoteFetcher;
import eu.eudat.models.data.security.Principal;
@Component
public class ValidationManager {
private RemoteFetcher remoteFetcher;
@Autowired
public ValidationManager(RemoteFetcher remoteFetcher) {
super();
this.remoteFetcher = remoteFetcher;
}
public Boolean validateIdentifier(String identifier, String type, Principal principal) throws NoURLFound, HugeResultSet {
ExternalUrlCriteria externalUrlCriteria = new ExternalUrlCriteria(identifier);
Integer count = this.remoteFetcher.findEntries(externalUrlCriteria, type);
return principal != null && count > 0;
}
}

View File

@ -25,6 +25,7 @@ public class ExternalUrls implements Serializable {
/*TagUrls tags;*/
FunderUrls funders;
LicenseUrls licenses;
ValidationUrls validations;
public RegistryUrls getRegistries() {
@ -143,6 +144,15 @@ public class ExternalUrls implements Serializable {
public void setLicenses(LicenseUrls licenses) {
this.licenses = licenses;
}
public ValidationUrls getValidations() {
return validations;
}
@XmlElement(name = "validators")
public void setValidations(ValidationUrls validations) {
this.validations = validations;
}
}

View File

@ -0,0 +1,36 @@
package eu.eudat.logic.proxy.config.entities;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import eu.eudat.logic.proxy.config.FetchStrategy;
import eu.eudat.logic.proxy.config.UrlConfiguration;
public class ValidationUrls {
List<UrlConfiguration> urls;
FetchStrategy fetchMode;
public List<UrlConfiguration> getUrls() {
return urls;
}
@XmlElementWrapper
@XmlElement(name = "urlConfig")
public void setUrls(List<UrlConfiguration> urls) {
this.urls = urls;
}
public FetchStrategy getFetchMode() {
return fetchMode;
}
@XmlElement(name = "fetchMode")
public void setFetchMode(FetchStrategy fetchMode) {
this.fetchMode = fetchMode;
}
}

View File

@ -141,6 +141,15 @@ public class RemoteFetcher {
FetchStrategy fetchStrategy = configLoader.getExternalUrls().getLicenses().getFetchMode();
return getAll(urlConfigs, fetchStrategy, externalUrlCriteria);
}
public Integer findEntries(ExternalUrlCriteria externalUrlCriteria, String key) throws NoURLFound, HugeResultSet {
List<UrlConfiguration> urlConfigs =
key != null && !key.isEmpty() ? configLoader.getExternalUrls().getValidations().getUrls().stream().filter(item -> item.getKey().equals(key)).collect(Collectors.toList())
: configLoader.getExternalUrls().getLicenses().getUrls();
FetchStrategy fetchStrategy = configLoader.getExternalUrls().getLicenses().getFetchMode();
List<Map<String, String>> data = this.getAll(urlConfigs, fetchStrategy, externalUrlCriteria);
return data.size();
}
private List<Map<String, String>> getAll(List<UrlConfiguration> urlConfigs, FetchStrategy fetchStrategy, ExternalUrlCriteria externalUrlCriteria) throws NoURLFound, HugeResultSet {

View File

@ -959,6 +959,28 @@
</urls>
<fetchMode>FIRST</fetchMode>
</licenses>
<validators>
<urls>
<urlConfig>
<key>zenodo</key>
<label>Zenodo</label>
<ordinal>1</ordinal>
<type>External</type>
<url>https://sandbox.zenodo.org/api/records/?page={page}&amp;size={pageSize}&amp;q={like}</url>
<firstPage>1</firstPage>
<contenttype>application/vnd.zenodo.v1+json; charset=utf-8</contenttype>
<data>
<path>$['hits']['hits'][*]</path>
<fields>
<id>'conceptrecid'</id>
</fields>
</data>
<paginationpath>$['hits']['total']</paginationpath>
</urlConfig>
</urls>
<fetchMode>FIRST</fetchMode>
</validators>
</externalUrls>

View File

@ -15,5 +15,6 @@ export enum DatasetProfileFieldViewStyle {
Researchers = "researchers",
Organizations = "organizations",
DatasetIdentifier = "datasetIdentifier",
Currency = "currency"
Currency = "currency",
Validation = 'validation'
}

View File

@ -76,4 +76,8 @@ export class ExternalSourcesService {
return this.http.get<ExternalSourceItemModel[]>(this.actionUrl + 'datasetprofiles/get' + '?query=' + like, { headers: this.headers });
}
public validateIdentifier(like: string, type: string): Observable<boolean> {
return this.http.get<boolean>(this.actionUrl + 'validation?query=' + like, '&type=' + type);
}
}

View File

@ -37,6 +37,7 @@ import { DatasetProfileEditorResearchersFieldComponent } from './editor/componen
import { DatasetProfileEditorOrganizationsFieldComponent } from './editor/components/field-type/organizations/dataset-profile-editor-organizations-field.component';
import { DatasetProfileEditorDatasetIdentifierFieldComponent } from './editor/components/field-type/dataset-identifier/dataset-profile-editor-dataset-identifier-field.component';
import { DatasetProfileEditorCurrencyFieldComponent } from './editor/components/field-type/currency/dataset-profile-editor-currency-field.component';
import { DatasetProfileEditorValidatorFieldComponent } from './editor/components/field-type/validator/dataset-profile-editor-validator-field.component';
@NgModule({
imports: [
@ -79,7 +80,8 @@ import { DatasetProfileEditorCurrencyFieldComponent } from './editor/components/
DatasetProfileEditorResearchersFieldComponent,
DatasetProfileEditorOrganizationsFieldComponent,
DatasetProfileEditorDatasetIdentifierFieldComponent,
DatasetProfileEditorCurrencyFieldComponent
DatasetProfileEditorCurrencyFieldComponent,
DatasetProfileEditorValidatorFieldComponent
],
entryComponents: [
DialodConfirmationUploadDatasetProfiles

View File

@ -0,0 +1,9 @@
<div class="row" *ngIf="form.get('data')">
<h5 style="font-weight: bold" class="col-12">{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-DATE-PICKER-TITLE'
| translate}}</h5>
<mat-form-field class="col-12">
<input matInput type="string"
placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-CHECKBOX-PLACEHOLDER' | translate}}"
[formControl]="form.get('data').get('label')">
</mat-form-field>
</div>

View File

@ -0,0 +1,18 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { DataRepositoriesDataEditorModel } from '@app/ui/admin/dataset-profile/admin/field-data/data-repositories-data-editor-models';
@Component({
selector: 'app-dataset-profile-editor-validator-field-component',
styleUrls: ['./dataset-profile-editor-validator-field.component.scss'],
templateUrl: './dataset-profile-editor-validator-field.component.html'
})
export class DatasetProfileEditorValidatorFieldComponent implements OnInit {
@Input() form: FormGroup;
private data: DataRepositoriesDataEditorModel = new DataRepositoriesDataEditorModel();
ngOnInit() {
if (!this.form.get('data')) { this.form.addControl('data', this.data.buildForm()); }
}
}

View File

@ -82,6 +82,7 @@
<app-dataset-profile-editor-organizations-field-component *ngSwitchCase="viewStyleEnum.Organizations" class="col-12" [form]="form"></app-dataset-profile-editor-organizations-field-component>
<app-dataset-profile-editor-dataset-identifier-field-component *ngSwitchCase="viewStyleEnum.DatasetIdentifier" class="col-12" [form]="form"></app-dataset-profile-editor-dataset-identifier-field-component>
<app-dataset-profile-editor-currency-field-component *ngSwitchCase="viewStyleEnum.Currency" class="col-12" [form]="form"></app-dataset-profile-editor-currency-field-component>
<app-dataset-profile-editor-validator-field-component *ngSwitchCase="viewStyleEnum.Validation" class="col-12" [form]="form"></app-dataset-profile-editor-validator-field-component>
</div>
<div class="row">
<h4 class="col-12" style="font-weight: bold">{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.RULES-TITLE' | translate}}

View File

@ -247,4 +247,28 @@
</mat-form-field>
</div>
</div>
<div *ngSwitchCase="datasetProfileFieldViewStyleEnum.Validation" class="col-12">
<div class="row">
<mat-form-field class="col-md-4">
<input matInput class="col-md-12" [formControl]="getDatasetIdControl('identifier')" placeholder="{{form.get('data').value.label}}" [required]="form.get('validationRequired').value">
<mat-error *ngIf="form.get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
</mat-error>
</mat-form-field>
<mat-form-field class="col-md-4">
<mat-select class="col-md-12" [formControl]="getDatasetIdControl('type')">
<mat-option *ngFor="let type of validationTypes" [value]="type.value">
{{ type.name }}
</mat-option>
</mat-select>
<mat-error *ngIf="form.get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
</mat-error>
</mat-form-field>
<mat-form-field class="col-md-4">
<button type="button" mat-button class="lightblue-btn" (click)="validateId()">Validate</button>
<mat-error *ngIf="form.get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
</mat-error>
</mat-form-field>
</div>
</div>
</div>

View File

@ -78,6 +78,11 @@ export class FormFieldComponent extends BaseComponent implements OnInit {
{ name: 'Other', value: 'other' }
];
readonly validationTypes: any[] = [
{ name: 'Zenodo', value: 'zenodo' }
];
constructor(
public visibilityRulesService: VisibilityRulesService,
private datasetExternalAutocompleteService: DatasetExternalAutocompleteService,
@ -420,4 +425,14 @@ export class FormFieldComponent extends BaseComponent implements OnInit {
searchCurrency(query: string): Observable<LocalFetchModel[]> {
return this.currencyService.get(query);
}
validateId() {
const identifier = this.getDatasetIdControl('identifier').value;
const type = this.getDatasetIdControl('type').value;
this.externalSourcesService.validateIdentifier(identifier, type).pipe(takeUntil(this._destroyed)).subscribe(result => {
console.log(result);
});
}
}