add semantics controller

This commit is contained in:
amentis 2024-02-20 14:58:16 +02:00
parent b009829d6f
commit c55f160d9b
18 changed files with 213 additions and 90 deletions

View File

@ -66,7 +66,6 @@ public class AuditableAction {
public static final EventId DescriptionTemplate_PersistNewVersion = new EventId(8005, "DescriptionTemplate_PersistNewVersion");
public static final EventId DescriptionTemplate_GetXml = new EventId(8006, "DescriptionTemplate_GetXml");
public static final EventId DescriptionTemplate_Import = new EventId(8007, "DescriptionTemplate_Import");
public static final EventId DescriptionTemplate_GetSemantics = new EventId(8007, "DescriptionTemplate_GetSemantics");
public static final EventId SupportiveMaterial_Query = new EventId(9000, "SupportiveMaterial_Query");
public static final EventId SupportiveMaterial_Lookup = new EventId(9001, "SupportiveMaterial_Lookup");
@ -144,5 +143,7 @@ public class AuditableAction {
public static final EventId Principal_Lookup = new EventId(240000, "Principal_Lookup");
public static final EventId GetSemantics = new EventId(250000, "GetSemantics");
}

View File

@ -1,6 +1,6 @@
package eu.eudat.query.lookup;
public class DescriptionTemplateSemanticsLookup {
public class SemanticsLookup {
private String like;

View File

@ -17,7 +17,6 @@ import javax.management.InvalidApplicationException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
public interface DescriptionTemplateService {
@ -29,7 +28,4 @@ public interface DescriptionTemplateService {
DescriptionTemplate importXml(byte[] bytes, UUID id, String label, FieldSet fields) throws MyForbiddenException, MyNotFoundException, JAXBException, ParserConfigurationException, TransformerException, InvalidApplicationException, IOException, InstantiationException, IllegalAccessException, SAXException;
ResponseEntity<byte[]> exportXml(UUID id) throws MyForbiddenException, MyNotFoundException, JAXBException, ParserConfigurationException, IOException, InstantiationException, IllegalAccessException, SAXException, TransformerException, InvalidApplicationException;
List<String> getSemantics(String query) throws IOException;
List<Semantic> getSemantics() throws IOException;
}

View File

@ -82,8 +82,6 @@ import java.util.stream.Collectors;
@Service
public class DescriptionTemplateServiceImpl implements DescriptionTemplateService {
private List<Semantic> semantics = null;
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(DescriptionTemplateServiceImpl.class));
private final EntityManager entityManager;
@ -901,42 +899,5 @@ public class DescriptionTemplateServiceImpl implements DescriptionTemplateServic
}
//endregion
//region
@Override
public List<String> getSemantics(String like) throws IOException {
List<Semantic> semantics = this.getSemantics();
List<String> filteredSemantics = semantics.stream().map(Semantic::getName).collect(Collectors.toList());
if (like != null && !like.isEmpty()) {
filteredSemantics = semantics.stream().filter(x -> x.getCategory().contains(like.replaceAll("%", "")) || x.getName().contains(like.replaceAll("%", ""))).map(Semantic::getName).collect(Collectors.toList());
}
return filteredSemantics;
}
@Override
public List<Semantic> getSemantics() throws IOException {
this.authorizationService.authorizeForce(Permission.BrowseDescriptionTemplate);
if (semantics == null) {
semantics = new ArrayList<>();
this.loadSemantics();
}
return semantics;
}
private void loadSemantics() throws IOException {
byte[] bytes = this.storageFileService.getSemanticsFile();
if (bytes != null) {
try {
String json = new String(bytes, StandardCharsets.UTF_8);
semantics = List.of(jsonHandlingService.fromJson(Semantic[].class, json));
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
}
//endregion
}

View File

@ -1,4 +1,4 @@
package eu.eudat.service.descriptiontemplate;
package eu.eudat.service.semantic;
import com.fasterxml.jackson.annotation.JsonProperty;

View File

@ -0,0 +1,13 @@
package eu.eudat.service.semantic;
import eu.eudat.query.lookup.SemanticsLookup;
import java.io.IOException;
import java.util.List;
public interface SemanticsService {
List<String> getSemantics(SemanticsLookup lookup) throws IOException;
List<Semantic> getSemantics() throws IOException;
}

View File

@ -0,0 +1,81 @@
package eu.eudat.service.semantic;
import eu.eudat.authorization.Permission;
import eu.eudat.commons.JsonHandlingService;
import eu.eudat.query.lookup.SemanticsLookup;
import eu.eudat.service.storage.StorageFileService;
import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.tools.logging.LoggerService;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class SemanticsServiceImpl implements SemanticsService {
private List<Semantic> semantics = null;
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(SemanticsServiceImpl.class));
private final AuthorizationService authorizationService;
private final StorageFileService storageFileService;
private final JsonHandlingService jsonHandlingService;
@Autowired
public SemanticsServiceImpl(
AuthorizationService authorizationService,
StorageFileService storageFileService,
JsonHandlingService jsonHandlingService) {
this.authorizationService = authorizationService;
this.storageFileService = storageFileService;
this.jsonHandlingService = jsonHandlingService;
}
@Override
public List<String> getSemantics(SemanticsLookup lookup) throws IOException {
List<Semantic> semantics = this.getSemantics();
List<String> filteredSemantics = semantics.stream().map(Semantic::getName).collect(Collectors.toList());
String like = lookup.getLike();
if (like != null && !like.isEmpty()) {
filteredSemantics = semantics.stream().filter(x -> x.getCategory().contains(like.replaceAll("%", "")) || x.getName().contains(like.replaceAll("%", ""))).map(Semantic::getName).collect(Collectors.toList());
}
return filteredSemantics;
}
@Override
public List<Semantic> getSemantics() throws IOException {
this.authorizationService.authorizeForce(Permission.BrowseDescriptionTemplate);
if (semantics == null) {
semantics = new ArrayList<>();
this.loadSemantics();
}
return semantics;
}
private void loadSemantics() throws IOException {
byte[] bytes = this.storageFileService.getSemanticsFile();
if (bytes != null) {
try {
String json = new String(bytes, StandardCharsets.UTF_8);
semantics = List.of(jsonHandlingService.fromJson(Semantic[].class, json));
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
}
}

View File

@ -3,7 +3,6 @@ package eu.eudat.controllers;
import com.fasterxml.jackson.core.JsonProcessingException;
import eu.eudat.audit.AuditableAction;
import eu.eudat.authorization.AuthorizationFlags;
import eu.eudat.query.lookup.DescriptionTemplateSemanticsLookup;
import gr.cite.tools.fieldset.BaseFieldSet;
import gr.cite.tools.validation.ValidationFilterAnnotation;
import eu.eudat.data.DescriptionTemplateEntity;
@ -203,16 +202,4 @@ public class DescriptionTemplateController {
return model;
}
@RequestMapping(method = RequestMethod.POST, value = {"get-semantics"})
public List<String> getSemantics(@RequestBody DescriptionTemplateSemanticsLookup lookup) throws IOException {
logger.debug(new MapLogEntry("retrieving {}" + DescriptionTemplate.class.getSimpleName()).And("like", lookup.getLike()));
List<String> semantics = this.descriptionTemplateTypeService.getSemantics(lookup.getLike());
this.auditService.track(AuditableAction.DescriptionTemplate_GetSemantics, Map.ofEntries(
new AbstractMap.SimpleEntry<String, Object>("lookup", lookup)
));
return semantics;
}
}

View File

@ -0,0 +1,56 @@
package eu.eudat.controllers;
import eu.eudat.audit.AuditableAction;
import eu.eudat.query.lookup.SemanticsLookup;
import eu.eudat.service.semantic.SemanticsService;
import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.tools.auditing.AuditService;
import gr.cite.tools.logging.LoggerService;
import gr.cite.tools.logging.MapLogEntry;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.util.AbstractMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping(path = {"api/semantics"})
public class SemanticsController {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(SemanticsController.class));
private final AuditService auditService;
private final MessageSource messageSource;
private final AuthorizationService authService;
private final SemanticsService semanticsService;
@Autowired
public SemanticsController(AuditService auditService,
MessageSource messageSource, AuthorizationService authService, SemanticsService semanticsService) {
this.auditService = auditService;
this.messageSource = messageSource;
this.authService = authService;
this.semanticsService = semanticsService;
}
@PostMapping()
public List<String> getSemantics(@RequestBody SemanticsLookup lookup) throws IOException {
logger.debug(new MapLogEntry("retrieving semantics "));
List<String> semantics = this.semanticsService.getSemantics(lookup);
this.auditService.track(AuditableAction.GetSemantics, Map.ofEntries(
new AbstractMap.SimpleEntry<String, Object>("lookup", lookup)
));
return semantics;
}
}

View File

@ -46,6 +46,7 @@ import { QueryParamsService } from './services/utilities/query-params.service';
import { FileTransformerHttpService } from './services/file-transformer/file-transformer.http.service';
import { InAppNotificationService } from './services/inapp-notification/inapp-notification.service';
import { NotificationService } from './services/notification/notification-service';
import { SemanticsService } from './services/semantic/semantics.service';
//
//
// This is shared module that provides all the services. Its imported only once on the AppModule.
@ -110,7 +111,8 @@ export class CoreServiceModule {
FileTransformerService,
FileTransformerHttpService,
InAppNotificationService,
NotificationService
NotificationService,
SemanticsService
],
};
}

View File

@ -1,7 +0,0 @@
export class DescriptionTemplateSemanticsLookup {
like: string;
constructor() {
}
}

View File

@ -0,0 +1,7 @@
export class SemanticsLookup {
like: string;
constructor() {
}
}

View File

@ -18,7 +18,6 @@ import { ConfigurationService } from '../configuration/configuration.service';
import { BaseHttpV2Service } from '../http/base-http-v2.service';
import { DescriptionTemplateVersionStatus } from '@app/core/common/enum/description-template-version-status';
import { DescriptionTemplateStatus } from '@app/core/common/enum/description-template-status';
import { DescriptionTemplateSemanticsLookup } from '@app/core/query/description-template-semantics.lookup';
@Injectable()
export class DescriptionTemplateService {
@ -99,11 +98,6 @@ export class DescriptionTemplateService {
return this.http.post(url, formData, { params: params });
}
searchSemantics(q: DescriptionTemplateSemanticsLookup ): Observable<String[]> {
const url = `${this.apiBase}/get-semantics`;
return this.http.post<String[]>(url, q).pipe(catchError((error: any) => throwError(error)));
}
//
// Autocomplete Commons
//
@ -199,17 +193,4 @@ export class DescriptionTemplateService {
return lookup;
}
// Semantics Autocomplete
semanticsAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = {
initialItems: (data?: any) => this.searchSemantics(this.buildSemanticsAutocompleteLookup()).pipe(map(x => x)),
filterFn: (searchQuery: string, data?: any) => this.searchSemantics(this.buildSemanticsAutocompleteLookup(searchQuery)).pipe(map(x => x)),
displayFn: (item) => item,
titleFn: (item) => item,
}
private buildSemanticsAutocompleteLookup(like?: string ): DescriptionTemplateSemanticsLookup {
const lookup: DescriptionTemplateSemanticsLookup = new DescriptionTemplateSemanticsLookup();
if (like) { lookup.like = this.filterService.transformLike(like); }
return lookup;
}
}

View File

@ -0,0 +1,41 @@
import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
import { FilterService } from '@common/modules/text-filter/filter-service';
import { Observable, throwError } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { ConfigurationService } from '../configuration/configuration.service';
import { BaseHttpV2Service } from '../http/base-http-v2.service';
import { SemanticsLookup } from '@app/core/query/semantic.lookup';
@Injectable()
export class SemanticsService {
private headers = new HttpHeaders();
constructor(private http: BaseHttpV2Service, private httpClient: HttpClient, private configurationService: ConfigurationService, private filterService: FilterService) {
}
private get apiBase(): string { return `${this.configurationService.server}semantics`; }
searchSemantics(q: SemanticsLookup ): Observable<String[]> {
const url = `${this.apiBase}`;
return this.http.post<String[]>(url, q).pipe(catchError((error: any) => throwError(error)));
}
// Autocomplete
multipleAutocompleteConfiguration: MultipleAutoCompleteConfiguration = {
initialItems: (data?: any) => this.searchSemantics(this.buildSemanticsAutocompleteLookup()).pipe(map(x => x)),
filterFn: (searchQuery: string, data?: any) => this.searchSemantics(this.buildSemanticsAutocompleteLookup(searchQuery)).pipe(map(x => x)),
displayFn: (item) => item,
titleFn: (item) => item,
}
private buildSemanticsAutocompleteLookup(like?: string ): SemanticsLookup {
const lookup: SemanticsLookup = new SemanticsLookup();
if (like) { lookup.like = this.filterService.transformLike(like); }
return lookup;
}
}

View File

@ -136,7 +136,7 @@
<mat-form-field class="col-6">
<mat-label>{{'DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.SEMANTICS' | translate}}</mat-label>
<app-multiple-auto-complete placeholder="{{'DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.SEMANTICS' | translate}}" [hidePlaceholder]="true" required='false' [separatorKeysCodes]="separatorKeysCodes" [formControl]="this.form.get('schematics')" [configuration]="descriptionTemplateService.semanticsAutoCompleteConfiguration">
<app-multiple-auto-complete placeholder="{{'DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.SEMANTICS' | translate}}" [hidePlaceholder]="true" required='false' [separatorKeysCodes]="separatorKeysCodes" [formControl]="this.form.get('schematics')" [configuration]="semanticsService.multipleAutocompleteConfiguration">
</app-multiple-auto-complete>
<mat-error *ngIf="form.get('schematics').hasError('backendError')">{{form.get('schematics').getError('backendError').message}}</mat-error>
</mat-form-field>

View File

@ -26,6 +26,7 @@ import { map } from 'rxjs/operators';
import { DescriptionTemplateFieldEditorModel, DescriptionTemplateRuleEditorModel } from '../../description-template-editor.model';
import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model';
import { FilterService } from '@common/modules/text-filter/filter-service';
import { SemanticsService } from '@app/core/services/semantic/semantics.service';
@Component({
selector: 'app-description-template-editor-field-component',
@ -55,7 +56,8 @@ export class DescriptionTemplateEditorFieldComponent extends BaseComponent imple
public descriptionTemplateService: DescriptionTemplateService,
private dialog: MatDialog,
private configurationService: ConfigurationService,
private filterService: FilterService
private filterService: FilterService,
public semanticsService: SemanticsService
) {
super();

View File

@ -163,7 +163,7 @@
<div class="col" *ngIf="field.get('category').value != null">
<mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.SEMANTICS' | translate}}</mat-label>
<app-multiple-auto-complete placeholder="{{'DMP-BLUEPRINT-EDITOR.FIELDS.SEMANTICS' | translate}}" [hidePlaceholder]="true" required='false' [separatorKeysCodes]="separatorKeysCodes" [formControl]="field.get('semantics')" [configuration]="descriptionTemplateService.semanticsAutoCompleteConfiguration">
<app-multiple-auto-complete placeholder="{{'DMP-BLUEPRINT-EDITOR.FIELDS.SEMANTICS' | translate}}" [hidePlaceholder]="true" required='false' [separatorKeysCodes]="separatorKeysCodes" [formControl]="field.get('semantics')" [configuration]="semanticsService.multipleAutocompleteConfiguration">
</app-multiple-auto-complete>
<mat-error *ngIf="field.get('semantics').hasError('backendError')">{{field.get('semantics').getError('backendError').message}}</mat-error>
<mat-error *ngIf="field.get('semantics').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>

View File

@ -41,6 +41,7 @@ import { DmpBlueprintEditorModel } from './dmp-blueprint-editor.model';
import { DmpBlueprintEditorResolver } from './dmp-blueprint-editor.resolver';
import { DmpBlueprintEditorService } from './dmp-blueprint-editor.service';
import { ReferenceTypeService } from '@app/core/services/reference-type/reference-type.service';
import { SemanticsService } from '@app/core/services/semantic/semantics.service';
@Component({
@ -122,7 +123,8 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
private fileUtils: FileUtils,
private matomoService: MatomoService,
public descriptionTemplateService: DescriptionTemplateService,
public referenceTypeService: ReferenceTypeService
public referenceTypeService: ReferenceTypeService,
public semanticsService: SemanticsService
) {
super(dialog, language, formService, router, uiNotificationService, httpErrorHandlingService, filterService, datePipe, route, queryParamsService);
}