diff --git a/mde-importer/src/main/java/de/terrestris/mde/mde_importer/importer/ImportService.java b/mde-importer/src/main/java/de/terrestris/mde/mde_importer/importer/ImportService.java index b5902cf..07e5def 100644 --- a/mde-importer/src/main/java/de/terrestris/mde/mde_importer/importer/ImportService.java +++ b/mde-importer/src/main/java/de/terrestris/mde/mde_importer/importer/ImportService.java @@ -1,12 +1,8 @@ package de.terrestris.mde.mde_importer.importer; import de.terrestris.mde.mde_backend.enumeration.MetadataProfile; -import de.terrestris.mde.mde_backend.jpa.ClientMetadataRepository; -import de.terrestris.mde.mde_backend.jpa.IsoMetadataRepository; -import de.terrestris.mde.mde_backend.jpa.TechnicalMetadataRepository; -import de.terrestris.mde.mde_backend.model.ClientMetadata; -import de.terrestris.mde.mde_backend.model.IsoMetadata; -import de.terrestris.mde.mde_backend.model.TechnicalMetadata; +import de.terrestris.mde.mde_backend.jpa.MetadataCollectionRepository; +import de.terrestris.mde.mde_backend.model.MetadataCollection; import de.terrestris.mde.mde_backend.model.json.*; import de.terrestris.mde.mde_backend.model.json.ColumnInfo.ColumnType; import de.terrestris.mde.mde_backend.model.json.ColumnInfo.FilterType; @@ -106,13 +102,7 @@ public class ImportService { } @Autowired - private IsoMetadataRepository isoMetadataRepository; - - @Autowired - private ClientMetadataRepository clientMetadataRepository; - - @Autowired - private TechnicalMetadataRepository technicalMetadataRepository; + private MetadataCollectionRepository metadataCollectionRepository; private final Map> servicesMap = new HashMap<>(); @@ -194,50 +184,49 @@ private void scanServiceFile(XMLStreamReader reader, Path file) throws XMLStream } private void parseDatasetMetadata(XMLStreamReader reader) throws XMLStreamException, ParseException { - var metadata = new IsoMetadata(); - var json = new JsonIsoMetadata(); - var client = new ClientMetadata(); - var technical = new TechnicalMetadata(); - technical.setData(new JsonTechnicalMetadata()); - client.setData(new JsonClientMetadata()); - client.getData().setLayers(new HashMap<>()); - metadata.setData(json); - json.setContacts(new ArrayList<>()); + var metadataCollection = new MetadataCollection(); + var isoMetadata = new JsonIsoMetadata(); + var technicalMetadata = new JsonTechnicalMetadata(); + var clientMetadata = new JsonClientMetadata(); + clientMetadata.setLayers(new HashMap<>()); + + metadataCollection.setTechnicalMetadata(technicalMetadata); + metadataCollection.setClientMetadata(clientMetadata); + metadataCollection.setIsoMetadata(isoMetadata); + isoMetadata.setContacts(new ArrayList<>()); skipToElement(reader, "Metadaten"); var type = reader.getAttributeValue(null, "metadatenTyp"); if (type.equals("ISO")) { - json.setMetadataProfile(MetadataProfile.ISO); + isoMetadata.setMetadataProfile(MetadataProfile.ISO); } if (type.equals("INSPIRE")) { - json.setMetadataProfile(MetadataProfile.INSPIRE_IDENTIFIED); + isoMetadata.setMetadataProfile(MetadataProfile.INSPIRE_IDENTIFIED); } skipToElement(reader, "Titel"); - json.setTitle(reader.getElementText()); + isoMetadata.setTitle(reader.getElementText()); skipToElement(reader, "fileIdentifier"); skipToElement(reader, "CharacterString"); - json.setFileIdentifier(reader.getElementText()); + isoMetadata.setFileIdentifier(reader.getElementText()); skipToElement(reader, "contact"); var contact = parseContact(reader, "contact"); - if (json.getContacts() == null) { - json.setContacts(new ArrayList<>()); + if (isoMetadata.getContacts() == null) { + isoMetadata.setContacts(new ArrayList<>()); } - json.getContacts().add(contact); + isoMetadata.getContacts().add(contact); skipToElement(reader, "dateStamp"); skipToElement(reader, "DateTime"); - json.setDateTime(Instant.parse(reader.getElementText() + "Z")); - extractCoordinateSystem(reader, json); - extractFromIso(reader, metadata, json, client, technical); - var list = servicesMap.get(metadata.getMetadataId()); + isoMetadata.setDateTime(Instant.parse(reader.getElementText() + "Z")); + extractCoordinateSystem(reader, isoMetadata); + extractFromIso(reader, metadataCollection); + var list = servicesMap.get(metadataCollection.getMetadataId()); if (list != null) { - list.forEach(file -> addService(file, json, client.getData(), technical.getData())); + list.forEach(file -> addService(file, metadataCollection)); } - if (json.getTermsOfUseId() == null) { - log.info("Terms of use could not be mapped for {}, using standard.", metadata.getMetadataId()); - json.setTermsOfUseId(BigInteger.ONE); + if (isoMetadata.getTermsOfUseId() == null) { + log.info("Terms of use could not be mapped for {}, using standard.", metadataCollection.getMetadataId()); + isoMetadata.setTermsOfUseId(BigInteger.ONE); } - isoMetadataRepository.save(metadata); - clientMetadataRepository.save(client); - technicalMetadataRepository.save(technical); + metadataCollectionRepository.save(metadataCollection); } private static void extractCoordinateSystem(XMLStreamReader reader, JsonIsoMetadata json) throws XMLStreamException { @@ -254,12 +243,11 @@ private static void extractCoordinateSystem(XMLStreamReader reader, JsonIsoMetad } } - private static void extractFromIso(XMLStreamReader reader, IsoMetadata metadata, JsonIsoMetadata json, ClientMetadata client, TechnicalMetadata technical) throws XMLStreamException, ParseException { + private static void extractFromIso(XMLStreamReader reader, MetadataCollection metadataCollection) throws XMLStreamException, ParseException { skipToElement(reader, "MD_DataIdentification"); - metadata.setMetadataId(reader.getAttributeValue(null, "uuid")); - client.setMetadataId(metadata.getMetadataId()); - technical.setMetadataId(metadata.getMetadataId()); - json.setPointsOfContact(new ArrayList<>()); + metadataCollection.setMetadataId(reader.getAttributeValue(null, "uuid")); + var isoMetadata = metadataCollection.getIsoMetadata(); + isoMetadata.setPointsOfContact(new ArrayList<>()); while (reader.hasNext() && !(reader.isEndElement() && reader.getLocalName().equals("MD_Metadata"))) { reader.next(); if (!reader.isStartElement()) { @@ -267,41 +255,41 @@ private static void extractFromIso(XMLStreamReader reader, IsoMetadata metadata, } if (reader.isStartElement() && reader.getLocalName().equals("identifier")) { skipToElement(reader, "CharacterString"); - json.setIdentifier(reader.getElementText()); + isoMetadata.setIdentifier(reader.getElementText()); } if (reader.isStartElement() && reader.getLocalName().equals("abstract")) { skipToElement(reader, "CharacterString"); - json.setDescription(reader.getElementText()); + isoMetadata.setDescription(reader.getElementText()); } if (reader.isStartElement() && reader.getLocalName().equals("pointOfContact")) { var contact = parseContact(reader, "pointOfContact"); - json.getPointsOfContact().add(contact); + isoMetadata.getPointsOfContact().add(contact); } if (reader.isStartElement() && reader.getLocalName().equals("topicCategory")) { skipToElement(reader, "MD_TopicCategoryCode"); - json.setTopicCategory(reader.getElementText()); + isoMetadata.setTopicCategory(reader.getElementText()); } if (reader.isStartElement() && reader.getLocalName().equals("graphicOverview")) { skipToElement(reader, "CharacterString"); - json.setPreview(reader.getElementText()); + isoMetadata.setPreview(reader.getElementText()); } - extractConformanceResult(reader, json); - extractKeyword(reader, json); + extractConformanceResult(reader, isoMetadata); + extractKeyword(reader, isoMetadata); if (reader.isStartElement() && reader.getLocalName().equals("resourceMaintenance")) { skipToElement(reader, "MD_MaintenanceFrequencyCode"); - json.setMaintenanceFrequency(MD_MaintenanceFrequencyCode.valueOf(reader.getAttributeValue(null, "codeListValue"))); - } - extractExtent(reader, json); - extractSpatialResolution(reader, json); - extractGraphicOverview(reader, json); - extractTransferOptions(reader, json); - extractResourceConstraints(reader, json); - extractDistributionFormat(reader, json); + isoMetadata.setMaintenanceFrequency(MD_MaintenanceFrequencyCode.valueOf(reader.getAttributeValue(null, "codeListValue"))); + } + extractExtent(reader, isoMetadata); + extractSpatialResolution(reader, isoMetadata); + extractGraphicOverview(reader, isoMetadata); + extractTransferOptions(reader, isoMetadata); + extractResourceConstraints(reader, isoMetadata); + extractDistributionFormat(reader, isoMetadata); if (reader.isStartElement() && reader.getLocalName().equals("statement")) { skipToElement(reader, "CharacterString"); - json.setLineage(reader.getElementText()); + isoMetadata.setLineage(reader.getElementText()); } - extractDate(reader, json); + extractDate(reader, isoMetadata); } } @@ -594,14 +582,17 @@ private static Contact parseContact(XMLStreamReader reader, String elementName) return contact; } - private void addService(Path file, JsonIsoMetadata json, JsonClientMetadata clientMetadata, JsonTechnicalMetadata technical) { + private void addService(Path file, MetadataCollection metadataCollection) { log.info("Adding service from {}", file.toString()); + var isoMetadata = metadataCollection.getIsoMetadata(); + var technicalMetadata = metadataCollection.getTechnicalMetadata(); + var clientMetadata = metadataCollection.getClientMetadata(); try { var service = new Service(); - if (json.getServices() == null) { - json.setServices(new ArrayList<>()); + if (isoMetadata.getServices() == null) { + isoMetadata.setServices(new ArrayList<>()); } - json.getServices().add(service); + isoMetadata.getServices().add(service); service.setServiceDescriptions(new ArrayList<>()); service.setDataBases(new ArrayList<>()); service.setPublications(new ArrayList<>()); @@ -610,7 +601,7 @@ private void addService(Path file, JsonIsoMetadata json, JsonClientMetadata clie nextElement(reader); List layers = null; while (reader.hasNext() && !reader.getLocalName().equals("IsoMetadata") && !reader.getLocalName().equals("IsoMetadataWMTS")) { - var res = extractMetadataFields(reader, service, technical); + var res = extractMetadataFields(reader, service, technicalMetadata); if (!res.isEmpty()) { layers = res; } diff --git a/mde-services/src/main/java/de/terrestris/mde/mde_backend/controller/BaseMetadataController.java b/mde-services/src/main/java/de/terrestris/mde/mde_backend/controller/BaseMetadataController.java index 04238f4..bf5a78a 100644 --- a/mde-services/src/main/java/de/terrestris/mde/mde_backend/controller/BaseMetadataController.java +++ b/mde-services/src/main/java/de/terrestris/mde/mde_backend/controller/BaseMetadataController.java @@ -1,6 +1,5 @@ package de.terrestris.mde.mde_backend.controller; -import com.github.fge.jsonpatch.mergepatch.JsonMergePatch; import de.terrestris.mde.mde_backend.model.BaseMetadata; import de.terrestris.mde.mde_backend.service.BaseMetadataService; import io.swagger.v3.oas.annotations.Operation; @@ -87,234 +86,6 @@ public Page findAll(@PageableDefault(Integer.MAX_VALUE) @ParameterObject Page } } - @GetMapping("/{id}") - @ResponseStatus(HttpStatus.OK) - @Operation(security = { @SecurityRequirement(name = "bearer-key") }) - @ApiResponses(value = { - @ApiResponse( - responseCode = "200", - description = "Ok: The entity was successfully returned" - ), - @ApiResponse( - responseCode = "401", - description = "Unauthorized: You need to provide a bearer token", - content = @Content - ), - @ApiResponse( - responseCode = "404", - description = "Not found: The provided ID does not exist (or you don't have the permission to read it)" - ), - @ApiResponse( - responseCode = "500", - description = "Internal Server Error: Something internal went wrong while getting the entity" - ) - }) - public S findOne(@PathVariable("id") BigInteger entityId) { - log.trace("Requested to return entity of type {} with ID {}", - getGenericClassName(), entityId); - - try { - Optional entity = service.findOne(entityId); - - if (entity.isPresent()) { - S persistedEntity = entity.get(); - - log.trace("Successfully got entity of type {} with ID {}", - getGenericClassName(), entityId); - - return persistedEntity; - } else { - log.error("Could not find entity of type {} with ID {}", - getGenericClassName(), entityId); - - throw new ResponseStatusException( - HttpStatus.NOT_FOUND, - messageSource.getMessage( - "BASE_CONTROLLER.NOT_FOUND", - null, - LocaleContextHolder.getLocale() - ) - ); - } - } catch (AccessDeniedException ade) { - log.warn("Access to entity of type {} with ID {} is denied", - getGenericClassName(), entityId); - log.trace("Full Stack trace:", ade); - - throw new ResponseStatusException( - HttpStatus.NOT_FOUND, - messageSource.getMessage( - "BASE_CONTROLLER.NOT_FOUND", - null, - LocaleContextHolder.getLocale() - ), - ade - ); - } catch (ResponseStatusException rse) { - throw rse; - } catch (Exception e) { - log.error("Error while requesting entity of type {} with ID {}: \n {}", - getGenericClassName(), entityId, e.getMessage()); - log.trace("Full stack trace: ", e); - - throw new ResponseStatusException( - HttpStatus.INTERNAL_SERVER_ERROR, - messageSource.getMessage( - "BASE_CONTROLLER.INTERNAL_SERVER_ERROR", - null, - LocaleContextHolder.getLocale() - ), - e - ); - } - } - - @GetMapping("/m/{id}") - @ResponseStatus(HttpStatus.OK) - @Operation(security = { @SecurityRequirement(name = "bearer-key") }) - @ApiResponses(value = { - @ApiResponse( - responseCode = "200", - description = "Ok: The entity was successfully returned" - ), - @ApiResponse( - responseCode = "401", - description = "Unauthorized: You need to provide a bearer token", - content = @Content - ), - @ApiResponse( - responseCode = "404", - description = "Not found: The provided ID does not exist (or you don't have the permission to read it)" - ), - @ApiResponse( - responseCode = "500", - description = "Internal Server Error: Something internal went wrong while getting the entity" - ) - }) - public S findOneByMetadataId(@PathVariable("id") String metadataId) { - log.trace("Requested to return entity of type {} with metadataId {}", - getGenericClassName(), metadataId); - - try { - Optional entity = service.findOneByMetadataId(metadataId); - - if (entity.isPresent()) { - S persistedEntity = entity.get(); - - log.trace("Successfully got entity of type {} with metadataId {}", - getGenericClassName(), metadataId); - - return persistedEntity; - } else { - log.error("Could not find entity of type {} with metadataId {}", - getGenericClassName(), metadataId); - - throw new ResponseStatusException( - HttpStatus.NOT_FOUND, - messageSource.getMessage( - "BASE_CONTROLLER.NOT_FOUND", - null, - LocaleContextHolder.getLocale() - ) - ); - } - } catch (AccessDeniedException ade) { - log.warn("Access to entity of type {} with metadataId {} is denied", - getGenericClassName(), metadataId); - log.trace("Full Stack trace:", ade); - - throw new ResponseStatusException( - HttpStatus.NOT_FOUND, - messageSource.getMessage( - "BASE_CONTROLLER.NOT_FOUND", - null, - LocaleContextHolder.getLocale() - ), - ade - ); - } catch (ResponseStatusException rse) { - throw rse; - } catch (Exception e) { - log.error("Error while requesting entity of type {} with metadataId {}: \n {}", - getGenericClassName(), metadataId, e.getMessage()); - log.trace("Full stack trace: ", e); - - throw new ResponseStatusException( - HttpStatus.INTERNAL_SERVER_ERROR, - messageSource.getMessage( - "BASE_CONTROLLER.INTERNAL_SERVER_ERROR", - null, - LocaleContextHolder.getLocale() - ), - e - ); - } - } - - @PostMapping - @ResponseStatus(HttpStatus.CREATED) - @Operation(security = { @SecurityRequirement(name = "bearer-key") }) - @ApiResponses(value = { - @ApiResponse( - responseCode = "200", - description = "Ok: The entity was successfully created" - ), - @ApiResponse( - responseCode = "401", - description = "Unauthorized: You need to provide a bearer token", - content = @Content - ), - @ApiResponse( - responseCode = "404", - description = "You don't have the permission to create this type of entity" - ), - @ApiResponse( - responseCode = "500", - description = "Internal Server Error: Something internal went wrong while creating the entity" - ) - }) - public S add(@RequestBody S entity) { - log.trace("Requested to create a new entity of type {} ({})", - getGenericClassName(), entity); - - try { - S persistedEntity = service.create(entity); - - log.trace("Successfully created the entity of type {} with ID {}", - getGenericClassName(), persistedEntity.getId()); - - return persistedEntity; - } catch (AccessDeniedException ade) { - log.warn("Creating entity of type {} is denied", getGenericClassName()); - log.trace("Full Stack trace:", ade); - - throw new ResponseStatusException( - HttpStatus.NOT_FOUND, - messageSource.getMessage( - "BASE_CONTROLLER.NOT_FOUND", - null, - LocaleContextHolder.getLocale() - ), - ade - ); - } catch (ResponseStatusException rse) { - throw rse; - } catch (Exception e) { - log.error("Error while creating entity {}: \n {}", entity, e.getMessage()); - log.trace("Full stack trace: ", e); - - throw new ResponseStatusException( - HttpStatus.INTERNAL_SERVER_ERROR, - messageSource.getMessage( - "BASE_CONTROLLER.INTERNAL_SERVER_ERROR", - null, - LocaleContextHolder.getLocale() - ), - e - ); - } - } - @PutMapping("/{id}") @ResponseStatus(HttpStatus.OK) @Operation(security = { @SecurityRequirement(name = "bearer-key") }) @@ -404,91 +175,6 @@ public S update(@RequestBody S entity, @PathVariable("id") BigInteger entityId) } } - @PatchMapping(value = "/{id}") - @ResponseStatus(HttpStatus.OK) - @Operation(security = { @SecurityRequirement(name = "bearer-key") }) - @ApiResponses(value = { - @ApiResponse( - responseCode = "200", - description = "Ok: The entity was successfully updated" - ), - @ApiResponse( - responseCode = "401", - description = "Unauthorized: You need to provide a bearer token", - content = @Content - ), - @ApiResponse( - responseCode = "404", - description = "You don't have the permission to update this entity" - ), - @ApiResponse( - responseCode = "500", - description = "Internal Server Error: Something internal went wrong while updating the entity" - ) - }) - public S updatePartial(@RequestBody JsonMergePatch patch, @PathVariable("id") BigInteger entityId) { - log.trace("Requested to partially update entity of type {} with ID {} ({})", getGenericClassName(), entityId, patch); - - try { - S persistedEntity = service.findOne(entityId).orElse(null); - if (persistedEntity != null) { - S updatedEntity = service.updatePartial(persistedEntity, patch); - - log.trace("Successfully updated values for entity of type {} with ID {}", - getGenericClassName(), entityId); - - return updatedEntity; - } else { - log.error("Could not find entity of type {} with ID {}", - getGenericClassName(), entityId); - - throw new ResponseStatusException( - HttpStatus.NOT_FOUND, - messageSource.getMessage( - "BASE_CONTROLLER.NOT_FOUND", - null, - LocaleContextHolder.getLocale() - ) - ); - } - } catch (AccessDeniedException ade) { - log.warn("Updating values of type {} with ID {} is denied", - getGenericClassName(), entityId); - log.trace("Stack trace:", ade); - - throw new ResponseStatusException( - HttpStatus.NOT_FOUND, - messageSource.getMessage( - "BASE_CONTROLLER.NOT_FOUND", - null, - LocaleContextHolder.getLocale() - ), - ade - ); - } catch (NumberFormatException nfe) { - log.error("Can't parse 'id' field ({}) from values ({}). It has to be an Integer.: {}", - patch, entityId, nfe.getMessage()); - log.trace("Stack trace:", nfe); - throw new ResponseStatusException(HttpStatus.BAD_REQUEST); - } catch (ResponseStatusException rse) { - throw rse; - } catch (Exception e) { - log.error("Error while updating values for entity of type {} with ID {}: \n {}", - getGenericClassName(), entityId, e.getMessage()); - log.trace("Full stack trace: ", e); - - throw new ResponseStatusException( - HttpStatus.INTERNAL_SERVER_ERROR, - messageSource.getMessage( - "BASE_CONTROLLER.INTERNAL_SERVER_ERROR", - null, - LocaleContextHolder.getLocale() - ), - e - ); - } - } - @DeleteMapping( value = "/{id}", produces = { "application/json" } @@ -584,5 +270,4 @@ protected String getGenericClassName() { return null; } } - } diff --git a/mde-services/src/main/java/de/terrestris/mde/mde_backend/controller/ClientMetadataController.java b/mde-services/src/main/java/de/terrestris/mde/mde_backend/controller/ClientMetadataController.java deleted file mode 100644 index 74e16d5..0000000 --- a/mde-services/src/main/java/de/terrestris/mde/mde_backend/controller/ClientMetadataController.java +++ /dev/null @@ -1,94 +0,0 @@ -package de.terrestris.mde.mde_backend.controller; - -import de.terrestris.mde.mde_backend.model.IsoMetadata; -import de.terrestris.mde.mde_backend.model.json.Comment; -import de.terrestris.mde.mde_backend.service.ClientMetadataService; -import de.terrestris.mde.mde_backend.service.IsoMetadataService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import io.swagger.v3.oas.annotations.security.SecurityRequirement; -import lombok.extern.log4j.Log4j2; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.i18n.LocaleContextHolder; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.server.ResponseStatusException; - -import java.util.UUID; - -import static org.springframework.http.HttpStatus.OK; - -@Log4j2 -@RestController -@RequestMapping("/metadata/client") -public class ClientMetadataController extends BaseMetadataController { - - @Autowired - private ClientMetadataService service; - - @PostMapping("/comment/{metadataId}") - @ResponseStatus(HttpStatus.OK) - @Operation(security = { @SecurityRequirement(name = "bearer-key") }) - @ApiResponses(value = { - @ApiResponse( - responseCode = "200", - description = "Ok: The Comment was successfully added" - ), - @ApiResponse( - responseCode = "500", - description = "Internal Server Error: Something internal went wrong while adding the Comment" - ) - }) - public ResponseEntity addComment( - @RequestBody String commentText, - @PathVariable("metadataId") String metadataId - ) { - try { - Comment comment = service.addComment(metadataId, commentText); - return ResponseEntity.status(OK).body(comment); - // TODO: Add more specific exception handling - } catch (Exception e) { - log.error("Error while add comment: {}", e.getMessage()); - log.trace("Full stack trace: ", e); - - throw new ResponseStatusException( - HttpStatus.INTERNAL_SERVER_ERROR, - messageSource.getMessage( - "BASE_CONTROLLER.INTERNAL_SERVER_ERROR", - null, - LocaleContextHolder.getLocale() - ), - e - ); - } - } - - @DeleteMapping("/comment/{metadataId}") - @ResponseStatus(HttpStatus.NO_CONTENT) - @Operation(security = { @SecurityRequirement(name = "bearer-key") }) - public ResponseEntity deleteComment( - @RequestBody String commentId, - @PathVariable("metadataId") String metadataId - ) { - try { - service.deleteComment(metadataId, UUID.fromString(commentId)); - return ResponseEntity.status(OK).build(); - } catch (Exception e) { - log.error("Error while deleting comment: {}", e.getMessage()); - log.trace("Full stack trace: ", e); - - throw new ResponseStatusException( - HttpStatus.INTERNAL_SERVER_ERROR, - messageSource.getMessage( - "BASE_CONTROLLER.INTERNAL_SERVER_ERROR", - null, - LocaleContextHolder.getLocale() - ), - e - ); - } - } - -} diff --git a/mde-services/src/main/java/de/terrestris/mde/mde_backend/controller/IsoMetadataController.java b/mde-services/src/main/java/de/terrestris/mde/mde_backend/controller/IsoMetadataController.java deleted file mode 100644 index defad2a..0000000 --- a/mde-services/src/main/java/de/terrestris/mde/mde_backend/controller/IsoMetadataController.java +++ /dev/null @@ -1,98 +0,0 @@ -package de.terrestris.mde.mde_backend.controller; - -import de.terrestris.mde.mde_backend.model.IsoMetadata; -import de.terrestris.mde.mde_backend.service.IsoGenerator; -import de.terrestris.mde.mde_backend.service.IsoMetadataService; -import de.terrestris.mde.mde_backend.service.PublicationService; -import de.terrestris.mde.mde_backend.service.ValidatorService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import io.swagger.v3.oas.annotations.security.SecurityRequirement; -import lombok.extern.log4j.Log4j2; -import org.hibernate.search.engine.search.query.SearchResult; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.i18n.LocaleContextHolder; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.server.ResponseStatusException; - -import javax.xml.stream.XMLStreamException; -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.List; - -import static org.springframework.http.HttpStatus.OK; - -@Log4j2 -@RestController -@RequestMapping("/metadata/iso") -public class IsoMetadataController extends BaseMetadataController { - - @Autowired - private IsoGenerator isoGenerator; - - @Autowired - private ValidatorService validator; - - @Autowired - private PublicationService publicationService; - - @GetMapping( - path = "/search", - produces = { - "application/json" - } - ) - @ResponseStatus(HttpStatus.OK) - @Operation(security = { @SecurityRequirement(name = "bearer-key") }) - @ApiResponses(value = { - @ApiResponse( - responseCode = "200", - description = "Ok: The entity was successfully updated" - ), - @ApiResponse( - responseCode = "500", - description = "Internal Server Error: Something internal went wrong while updating the entity" - ) - }) - public List search(@RequestParam String searchTerm, @RequestParam(required = false) Integer offset, @RequestParam(required = false) Integer limit) { - - log.trace("Search request for IsoMetadata with searchTerm: {}, offset: {}, limit: {}", searchTerm, offset, limit); - try { - SearchResult result = this.service.search(searchTerm, offset, limit); - return result.hits(); - } catch (Exception e) { - log.error("Error while searching for IsoMetadata with searchTerm: {}, offset: {}, limit: {}", searchTerm, offset, limit, e); - - throw new ResponseStatusException( - HttpStatus.INTERNAL_SERVER_ERROR, - messageSource.getMessage( - "BASE_CONTROLLER.INTERNAL_SERVER_ERROR", - null, - LocaleContextHolder.getLocale() - ), - e - ); - } - } - - @GetMapping(path = "/validate/{id}") - public ResponseEntity> validateIsoMetadata(@PathVariable("id") String id) throws XMLStreamException, IOException { - var list = validator.validateMetadata(id); - return new ResponseEntity<>(list, OK); - } - - @GetMapping(path = "/publish/{id}") - public ResponseEntity publishMetadata(@PathVariable("id") String id) { - try { - publicationService.publishMetadata(id); - } catch (XMLStreamException | IOException | URISyntaxException | InterruptedException e) { - log.warn("Unable to publish metadata: {}", e.getMessage()); - log.trace("Stack trace:", e); - } - return new ResponseEntity<>(OK); - } - -} diff --git a/mde-services/src/main/java/de/terrestris/mde/mde_backend/controller/MetadataCollectionController.java b/mde-services/src/main/java/de/terrestris/mde/mde_backend/controller/MetadataCollectionController.java index 724d4f3..9025a31 100644 --- a/mde-services/src/main/java/de/terrestris/mde/mde_backend/controller/MetadataCollectionController.java +++ b/mde-services/src/main/java/de/terrestris/mde/mde_backend/controller/MetadataCollectionController.java @@ -2,10 +2,11 @@ import de.terrestris.mde.mde_backend.enumeration.MetadataType; import de.terrestris.mde.mde_backend.model.BaseMetadata; -import de.terrestris.mde.mde_backend.model.dto.MetadataCollection; +import de.terrestris.mde.mde_backend.model.MetadataCollection; import de.terrestris.mde.mde_backend.model.dto.MetadataCreationData; import de.terrestris.mde.mde_backend.model.dto.MetadataCreationResponse; import de.terrestris.mde.mde_backend.model.dto.MetadataJsonPatch; +import de.terrestris.mde.mde_backend.model.json.Comment; import de.terrestris.mde.mde_backend.service.DatasetIsoGenerator; import de.terrestris.mde.mde_backend.service.MetadataCollectionService; import io.swagger.v3.oas.annotations.Operation; @@ -14,6 +15,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import lombok.extern.log4j.Log4j2; +import org.hibernate.search.engine.search.query.SearchResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; @@ -26,14 +28,15 @@ import java.util.List; import java.util.NoSuchElementException; import java.util.Optional; +import java.util.UUID; import static org.springframework.http.HttpStatus.NOT_FOUND; import static org.springframework.http.HttpStatus.OK; @Log4j2 @RestController -@RequestMapping("/metadata/collection") -public class MetadataCollectionController { +@RequestMapping("/metadata") +public class MetadataCollectionController extends BaseMetadataController { @Autowired MetadataCollectionService service; @@ -194,12 +197,12 @@ public BaseMetadata updateJsonValue(@RequestBody MetadataJsonPatch patch, @PathV @GetMapping("/{metadataId}/autokeywords") public ResponseEntity> getAutomaticKeywords(@PathVariable("metadataId") String metadataId) { - var maybeMetadata = service.findOneByMetadataId(metadataId); - if (maybeMetadata.isEmpty()) { + var metadataOptional = service.findOneByMetadataId(metadataId); + if (metadataOptional.isEmpty()) { return new ResponseEntity<>(NOT_FOUND); } - var metadata = maybeMetadata.get().getIsoMetadata(); - return new ResponseEntity<>(DatasetIsoGenerator.getAutomaticKeywords(metadata), OK); + var isoMetadata = metadataOptional.get().getIsoMetadata(); + return new ResponseEntity<>(DatasetIsoGenerator.getAutomaticKeywords(isoMetadata), OK); } @PostMapping("/{metadataId}/assignUser") @@ -224,9 +227,9 @@ public ResponseEntity assignUser(@PathVariable("metadataId") String metada } @DeleteMapping("/{metadataId}/unassignUser") - public ResponseEntity unassignUser(@PathVariable("metadataId") String metadataId) { + public ResponseEntity unassignUser(@PathVariable("metadataId") String metadataId, @RequestBody String userId) { try { - service.unassignUser(metadataId); + service.unassignUser(metadataId, userId); return new ResponseEntity(OK); } catch (Exception e) { log.error("Error while unassigning user from metadata with id {}: \n {}", metadataId, e.getMessage()); @@ -286,4 +289,106 @@ public ResponseEntity unassignRole(@PathVariable("metadataId") String meta } } + @GetMapping( + path = "/search", + produces = { + "application/json" + } + ) + @ResponseStatus(HttpStatus.OK) + @Operation(security = { @SecurityRequirement(name = "bearer-key") }) + @ApiResponses(value = { + @ApiResponse( + responseCode = "200", + description = "Ok: The entity was successfully updated" + ), + @ApiResponse( + responseCode = "500", + description = "Internal Server Error: Something internal went wrong while updating the entity" + ) + }) + public List search(@RequestParam String searchTerm, @RequestParam(required = false) Integer offset, @RequestParam(required = false) Integer limit) { + + log.trace("Search request for MetadataCollection with searchTerm: {}, offset: {}, limit: {}", searchTerm, offset, limit); + try { + SearchResult result = this.service.search(searchTerm, offset, limit); + return result.hits(); + } catch (Exception e) { + log.error("Error while searching for MetadataCollection with searchTerm: {}, offset: {}, limit: {}", searchTerm, offset, limit, e); + + throw new ResponseStatusException( + HttpStatus.INTERNAL_SERVER_ERROR, + messageSource.getMessage( + "BASE_CONTROLLER.INTERNAL_SERVER_ERROR", + null, + LocaleContextHolder.getLocale() + ), + e + ); + } + } + + @PostMapping("/{metadataId}/comment") + @ResponseStatus(HttpStatus.OK) + @Operation(security = { @SecurityRequirement(name = "bearer-key") }) + @ApiResponses(value = { + @ApiResponse( + responseCode = "200", + description = "Ok: The Comment was successfully added" + ), + @ApiResponse( + responseCode = "500", + description = "Internal Server Error: Something internal went wrong while adding the Comment" + ) + }) + public ResponseEntity addComment( + @RequestBody String commentText, + @PathVariable("metadataId") String metadataId + ) { + try { + Comment comment = service.addComment(metadataId, commentText); + return ResponseEntity.status(OK).body(comment); + // TODO: Add more specific exception handling + } catch (Exception e) { + log.error("Error while add comment: {}", e.getMessage()); + log.trace("Full stack trace: ", e); + + throw new ResponseStatusException( + HttpStatus.INTERNAL_SERVER_ERROR, + messageSource.getMessage( + "BASE_CONTROLLER.INTERNAL_SERVER_ERROR", + null, + LocaleContextHolder.getLocale() + ), + e + ); + } + } + + @DeleteMapping("/{metadataId}/comment") + @ResponseStatus(HttpStatus.NO_CONTENT) + @Operation(security = { @SecurityRequirement(name = "bearer-key") }) + public ResponseEntity deleteComment( + @RequestBody String commentId, + @PathVariable("metadataId") String metadataId + ) { + try { + service.deleteComment(metadataId, UUID.fromString(commentId)); + return ResponseEntity.status(OK).build(); + } catch (Exception e) { + log.error("Error while deleting comment: {}", e.getMessage()); + log.trace("Full stack trace: ", e); + + throw new ResponseStatusException( + HttpStatus.INTERNAL_SERVER_ERROR, + messageSource.getMessage( + "BASE_CONTROLLER.INTERNAL_SERVER_ERROR", + null, + LocaleContextHolder.getLocale() + ), + e + ); + } + } + } diff --git a/mde-services/src/main/java/de/terrestris/mde/mde_backend/controller/SearchController.java b/mde-services/src/main/java/de/terrestris/mde/mde_backend/controller/SearchController.java index 44a3c1c..b4214bb 100644 --- a/mde-services/src/main/java/de/terrestris/mde/mde_backend/controller/SearchController.java +++ b/mde-services/src/main/java/de/terrestris/mde/mde_backend/controller/SearchController.java @@ -1,7 +1,5 @@ package de.terrestris.mde.mde_backend.controller; -import de.terrestris.mde.mde_backend.model.IsoMetadata; -import de.terrestris.mde.mde_backend.service.IsoMetadataService; import de.terrestris.mde.mde_backend.service.SearchService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; @@ -9,6 +7,7 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; @@ -17,7 +16,10 @@ @Log4j2 @RestController @RequestMapping("/search") -public class SearchController extends BaseMetadataController { +public class SearchController { + + @Autowired + protected MessageSource messageSource; @Autowired private SearchService service; diff --git a/mde-services/src/main/java/de/terrestris/mde/mde_backend/jpa/ClientMetadataRepository.java b/mde-services/src/main/java/de/terrestris/mde/mde_backend/jpa/ClientMetadataRepository.java deleted file mode 100644 index 93c3a0a..0000000 --- a/mde-services/src/main/java/de/terrestris/mde/mde_backend/jpa/ClientMetadataRepository.java +++ /dev/null @@ -1,19 +0,0 @@ -package de.terrestris.mde.mde_backend.jpa; - -import de.terrestris.mde.mde_backend.model.ClientMetadata; -import jakarta.persistence.QueryHint; -import org.hibernate.jpa.AvailableHints; -import org.springframework.data.jpa.repository.JpaSpecificationExecutor; -import org.springframework.data.jpa.repository.QueryHints; -import org.springframework.data.querydsl.QuerydslPredicateExecutor; -import org.springframework.stereotype.Repository; - -import java.math.BigInteger; -import java.util.Optional; - -@Repository -public interface ClientMetadataRepository extends BaseRepository, JpaSpecificationExecutor, QuerydslPredicateExecutor { - - @QueryHints(@QueryHint(name = AvailableHints.HINT_CACHEABLE, value = "true")) - Optional findByMetadataId(String metadataId); -} diff --git a/mde-services/src/main/java/de/terrestris/mde/mde_backend/jpa/IsoMetadataRepository.java b/mde-services/src/main/java/de/terrestris/mde/mde_backend/jpa/IsoMetadataRepository.java deleted file mode 100644 index f8b0a7d..0000000 --- a/mde-services/src/main/java/de/terrestris/mde/mde_backend/jpa/IsoMetadataRepository.java +++ /dev/null @@ -1,19 +0,0 @@ -package de.terrestris.mde.mde_backend.jpa; - -import de.terrestris.mde.mde_backend.model.IsoMetadata; -import jakarta.persistence.QueryHint; -import org.hibernate.jpa.AvailableHints; -import org.springframework.data.jpa.repository.JpaSpecificationExecutor; -import org.springframework.data.jpa.repository.QueryHints; -import org.springframework.data.querydsl.QuerydslPredicateExecutor; -import org.springframework.stereotype.Repository; - -import java.math.BigInteger; -import java.util.Optional; - -@Repository -public interface IsoMetadataRepository extends BaseRepository, JpaSpecificationExecutor, QuerydslPredicateExecutor { - - @QueryHints(@QueryHint(name = AvailableHints.HINT_CACHEABLE, value = "true")) - Optional findByMetadataId(String metadataId); -} diff --git a/mde-services/src/main/java/de/terrestris/mde/mde_backend/jpa/TechnicalMetadataRepository.java b/mde-services/src/main/java/de/terrestris/mde/mde_backend/jpa/MetadataCollectionRepository.java similarity index 61% rename from mde-services/src/main/java/de/terrestris/mde/mde_backend/jpa/TechnicalMetadataRepository.java rename to mde-services/src/main/java/de/terrestris/mde/mde_backend/jpa/MetadataCollectionRepository.java index 2b8b970..a82c57b 100644 --- a/mde-services/src/main/java/de/terrestris/mde/mde_backend/jpa/TechnicalMetadataRepository.java +++ b/mde-services/src/main/java/de/terrestris/mde/mde_backend/jpa/MetadataCollectionRepository.java @@ -1,6 +1,6 @@ package de.terrestris.mde.mde_backend.jpa; -import de.terrestris.mde.mde_backend.model.TechnicalMetadata; +import de.terrestris.mde.mde_backend.model.MetadataCollection; import jakarta.persistence.QueryHint; import org.hibernate.jpa.AvailableHints; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; @@ -12,8 +12,8 @@ import java.util.Optional; @Repository -public interface TechnicalMetadataRepository extends BaseRepository, JpaSpecificationExecutor, QuerydslPredicateExecutor { +public interface MetadataCollectionRepository extends BaseRepository, JpaSpecificationExecutor, QuerydslPredicateExecutor { @QueryHints(@QueryHint(name = AvailableHints.HINT_CACHEABLE, value = "true")) - Optional findByMetadataId(String metadataId); + Optional findByMetadataId(String metadataId); } diff --git a/mde-services/src/main/java/de/terrestris/mde/mde_backend/model/BaseMetadata.java b/mde-services/src/main/java/de/terrestris/mde/mde_backend/model/BaseMetadata.java index 077555b..48efeab 100644 --- a/mde-services/src/main/java/de/terrestris/mde/mde_backend/model/BaseMetadata.java +++ b/mde-services/src/main/java/de/terrestris/mde/mde_backend/model/BaseMetadata.java @@ -2,7 +2,6 @@ import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.fasterxml.jackson.annotation.ObjectIdGenerators; -import de.terrestris.mde.mde_backend.enumeration.Role; import jakarta.persistence.*; import lombok.*; import org.hibernate.Hibernate; @@ -26,18 +25,6 @@ public abstract class BaseMetadata implements Serializable { @Id private BigInteger id; - @Column - @Setter - private String metadataId; - - @Column - @Setter - private String responsibleUserId; - - @Column - @Setter - private Role responsibleRole; - @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/mde-services/src/main/java/de/terrestris/mde/mde_backend/model/ClientMetadata.java b/mde-services/src/main/java/de/terrestris/mde/mde_backend/model/ClientMetadata.java deleted file mode 100644 index 1db627d..0000000 --- a/mde-services/src/main/java/de/terrestris/mde/mde_backend/model/ClientMetadata.java +++ /dev/null @@ -1,32 +0,0 @@ -package de.terrestris.mde.mde_backend.model; - -import de.terrestris.mde.mde_backend.model.json.JsonClientMetadata; -import io.hypersistence.utils.hibernate.type.json.JsonBinaryType; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Table; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; -import lombok.ToString; -import org.hibernate.annotations.Type; - -@EqualsAndHashCode(callSuper = true) -@NoArgsConstructor -@Entity -@Table(name = "client_metadata") -@Data -public class ClientMetadata extends BaseMetadata { - - @Column - @Type(JsonBinaryType.class) - @ToString.Exclude - private JsonClientMetadata data; - - public ClientMetadata (String metadataId) { - super(); - setMetadataId(metadataId); - setData(new JsonClientMetadata()); - } - -} diff --git a/mde-services/src/main/java/de/terrestris/mde/mde_backend/model/IsoMetadata.java b/mde-services/src/main/java/de/terrestris/mde/mde_backend/model/IsoMetadata.java deleted file mode 100644 index 4d6bd37..0000000 --- a/mde-services/src/main/java/de/terrestris/mde/mde_backend/model/IsoMetadata.java +++ /dev/null @@ -1,37 +0,0 @@ -package de.terrestris.mde.mde_backend.model; - -import de.terrestris.mde.mde_backend.model.json.JsonIsoMetadata; -import io.hypersistence.utils.hibernate.type.json.JsonBinaryType; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Table; -import lombok.*; -import org.hibernate.annotations.Formula; -import org.hibernate.annotations.Type; -import org.hibernate.search.mapper.pojo.mapping.definition.annotation.Indexed; -import org.hibernate.search.mapper.pojo.mapping.definition.annotation.IndexedEmbedded; - -@EqualsAndHashCode(callSuper = true) -@NoArgsConstructor -@Entity -@Table(name = "iso_metadata") -@Data -@Indexed -public class IsoMetadata extends BaseMetadata { - - @Formula("(data->>'title')") - private String title; - - @Column - @Type(JsonBinaryType.class) - @ToString.Exclude - @IndexedEmbedded - private JsonIsoMetadata data; - - public IsoMetadata (String metadataId) { - super(); - setMetadataId(metadataId); - setData(new JsonIsoMetadata()); - } - -} diff --git a/mde-services/src/main/java/de/terrestris/mde/mde_backend/model/MetadataCollection.java b/mde-services/src/main/java/de/terrestris/mde/mde_backend/model/MetadataCollection.java new file mode 100644 index 0000000..7d2cfcf --- /dev/null +++ b/mde-services/src/main/java/de/terrestris/mde/mde_backend/model/MetadataCollection.java @@ -0,0 +1,65 @@ +package de.terrestris.mde.mde_backend.model; + +import de.terrestris.mde.mde_backend.enumeration.Role; +import de.terrestris.mde.mde_backend.model.json.JsonClientMetadata; +import de.terrestris.mde.mde_backend.model.json.JsonIsoMetadata; +import de.terrestris.mde.mde_backend.model.json.JsonTechnicalMetadata; +import io.hypersistence.utils.hibernate.type.json.JsonBinaryType; +import jakarta.persistence.*; +import lombok.*; +import org.hibernate.annotations.Formula; +import org.hibernate.annotations.Type; +import org.hibernate.search.mapper.pojo.mapping.definition.annotation.IndexedEmbedded; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@Entity +@Table(name = "metadata_collection") +@Data +public class MetadataCollection extends BaseMetadata { + + @Column + @Setter + private String metadataId; + + @Formula("(iso_metadata->>'title')") + private String title; + + @Column + @Setter + private List responsibleUserIds; + + @Column + @Setter + private Role responsibleRole; + + @Column + @Type(JsonBinaryType.class) + @ToString.Exclude + @Setter + private JsonClientMetadata clientMetadata; + + @Column + @Type(JsonBinaryType.class) + @ToString.Exclude + @Setter + @IndexedEmbedded + private JsonIsoMetadata isoMetadata; + + @Column + @Type(JsonBinaryType.class) + @ToString.Exclude + @Setter + private JsonTechnicalMetadata technicalMetadata; + + public MetadataCollection (String metadataId) { + super(); + setMetadataId(metadataId); + setIsoMetadata(new JsonIsoMetadata()); + setClientMetadata(new JsonClientMetadata()); + setTechnicalMetadata(new JsonTechnicalMetadata()); + } + +} diff --git a/mde-services/src/main/java/de/terrestris/mde/mde_backend/model/TechnicalMetadata.java b/mde-services/src/main/java/de/terrestris/mde/mde_backend/model/TechnicalMetadata.java deleted file mode 100644 index e60fa3b..0000000 --- a/mde-services/src/main/java/de/terrestris/mde/mde_backend/model/TechnicalMetadata.java +++ /dev/null @@ -1,32 +0,0 @@ -package de.terrestris.mde.mde_backend.model; - -import de.terrestris.mde.mde_backend.model.json.JsonTechnicalMetadata; -import io.hypersistence.utils.hibernate.type.json.JsonBinaryType; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Table; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; -import lombok.ToString; -import org.hibernate.annotations.Type; - -@EqualsAndHashCode(callSuper = true) -@NoArgsConstructor -@Entity -@Table(name = "technical_metadata") -@Data -public class TechnicalMetadata extends BaseMetadata { - - @Column - @Type(JsonBinaryType.class) - @ToString.Exclude - private JsonTechnicalMetadata data; - - public TechnicalMetadata (String metadataId) { - super(); - setMetadataId(metadataId); - setData(new JsonTechnicalMetadata()); - } - -} diff --git a/mde-services/src/main/java/de/terrestris/mde/mde_backend/model/dto/MetadataCollection.java b/mde-services/src/main/java/de/terrestris/mde/mde_backend/model/dto/MetadataCollection.java deleted file mode 100644 index 5b7d259..0000000 --- a/mde-services/src/main/java/de/terrestris/mde/mde_backend/model/dto/MetadataCollection.java +++ /dev/null @@ -1,22 +0,0 @@ -package de.terrestris.mde.mde_backend.model.dto; - -import de.terrestris.mde.mde_backend.model.json.JsonClientMetadata; -import de.terrestris.mde.mde_backend.model.json.JsonIsoMetadata; -import de.terrestris.mde.mde_backend.model.json.JsonTechnicalMetadata; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Setter -@Getter -@NoArgsConstructor -@AllArgsConstructor -public class MetadataCollection { - - JsonClientMetadata clientMetadata; - - JsonTechnicalMetadata technicalMetadata; - - JsonIsoMetadata isoMetadata; -} diff --git a/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/BaseMetadataService.java b/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/BaseMetadataService.java index cb22ca8..bd65515 100644 --- a/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/BaseMetadataService.java +++ b/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/BaseMetadataService.java @@ -67,12 +67,6 @@ public Optional findOne(BigInteger id) { return repository.findById(id); } - @PostAuthorize("hasRole('ROLE_ADMIN') or hasPermission(returnObject.orElse(null), 'READ')") - @Transactional(readOnly = true) - public Optional findOneByMetadataId(String metadataId) { - return repository.findByMetadataId(metadataId); - } - @PostFilter("hasRole('ROLE_ADMIN') or hasPermission(filterObject, 'READ')") @Transactional(readOnly = true) public List findAllById(List id) { diff --git a/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/ClientMetadataService.java b/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/ClientMetadataService.java deleted file mode 100644 index a294a17..0000000 --- a/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/ClientMetadataService.java +++ /dev/null @@ -1,69 +0,0 @@ -package de.terrestris.mde.mde_backend.service; - -import de.terrestris.mde.mde_backend.jpa.ClientMetadataRepository; -import de.terrestris.mde.mde_backend.model.ClientMetadata; -import de.terrestris.mde.mde_backend.model.json.Comment; -import de.terrestris.mde.mde_backend.model.json.JsonClientMetadata; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Isolation; -import org.springframework.transaction.annotation.Transactional; - -import java.util.ArrayList; -import java.util.NoSuchElementException; -import java.util.UUID; - -@Service -public class ClientMetadataService extends BaseMetadataService { - - @Autowired - protected ClientMetadataRepository repository; - - @PreAuthorize("hasRole('ROLE_ADMIN') or hasPermission(#entity, 'CREATE')") - @Transactional(isolation = Isolation.SERIALIZABLE) - public Comment addComment(String metadataId, String text) { - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - - if (!authentication.isAuthenticated()) { - throw new IllegalStateException("User must be authenticated to add a comment"); - } - - ClientMetadata clientMetadata = repository.findByMetadataId(metadataId) - .orElseThrow(() -> new NoSuchElementException("IsoMetadata not found for metadataId: " + metadataId)); - - JsonClientMetadata data = clientMetadata.getData(); - - String userName = ((JwtAuthenticationToken) authentication).getTokenAttributes().get("preferred_username").toString(); - Comment comment = new Comment(text, authentication.getName(), userName); - - if (data.getComments() == null) { - data.setComments(new ArrayList<>()); - } - data.getComments().add(comment); - - repository.save(clientMetadata); - - return comment; - } - - @PreAuthorize("hasRole('ROLE_ADMIN') or hasPermission(#entity, 'DELETE')") - @Transactional(isolation = Isolation.SERIALIZABLE) - public void deleteComment(String metadataId, UUID commentId) { - ClientMetadata clientMetadata = repository.findByMetadataId(metadataId) - .orElseThrow(() -> new NoSuchElementException("IsoMetadata not found for metadataId: " + metadataId)); - - JsonClientMetadata data = clientMetadata.getData(); - - if (data.getComments() == null) { - return; - } - - data.getComments().removeIf(comment -> comment.getId().equals(commentId)); - - repository.save(clientMetadata); - } -} diff --git a/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/DatasetIsoGenerator.java b/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/DatasetIsoGenerator.java index 163efdd..31946b9 100644 --- a/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/DatasetIsoGenerator.java +++ b/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/DatasetIsoGenerator.java @@ -215,17 +215,17 @@ private static void writeKeyword(XMLStreamWriter writer, String keyword) throws writer.writeEndElement(); // keyword } - public static List getAutomaticKeywords(JsonIsoMetadata metadata) { + public static List getAutomaticKeywords(JsonIsoMetadata isoMetadata) { var list = new ArrayList(); - if (!metadata.getMetadataProfile().equals(ISO)) { + if (!isoMetadata.getMetadataProfile().equals(ISO)) { list.add("inspireidentifiziert"); } - if (TERMS_OF_USE_BY_ID.get(metadata.getTermsOfUseId().intValue()).isOpenData()) { + if (TERMS_OF_USE_BY_ID.get(isoMetadata.getTermsOfUseId().intValue()).isOpenData()) { list.add("open data"); list.add("opendata"); } - if (metadata.getServices() != null) { - for (var service : metadata.getServices()) { + if (isoMetadata.getServices() != null) { + for (var service : isoMetadata.getServices()) { switch (service.getServiceType()) { case WFS, ATOM -> { if (!list.contains("Sachdaten")) { diff --git a/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/IsoGenerator.java b/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/IsoGenerator.java index 056f619..1975014 100644 --- a/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/IsoGenerator.java +++ b/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/IsoGenerator.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.type.TypeFactory; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; -import de.terrestris.mde.mde_backend.jpa.IsoMetadataRepository; +import de.terrestris.mde.mde_backend.jpa.MetadataCollectionRepository; import de.terrestris.mde.mde_backend.model.json.termsofuse.TermsOfUse; import de.terrestris.mde.mde_backend.utils.MdeException; import lombok.extern.log4j.Log4j2; @@ -25,7 +25,7 @@ public class IsoGenerator { @Autowired - private IsoMetadataRepository isoMetadataRepository; + private MetadataCollectionRepository metadataCollectionRepository; @Autowired private DatasetIsoGenerator datasetIsoGenerator; @@ -69,21 +69,21 @@ public static String replaceValues(String text) { public List generateMetadata(String metadataId) throws XMLStreamException, IOException { var files = new ArrayList(); - var metadata = isoMetadataRepository.findByMetadataId(metadataId); - if (metadata.isEmpty()) { + var metadataCollection = metadataCollectionRepository.findByMetadataId(metadataId); + if (metadataCollection.isEmpty()) { log.info("Metadata with ID {} is not available.", metadataId); return null; } - var data = metadata.get().getData(); + var isoMetadata = metadataCollection.get().getIsoMetadata(); var tmp = Files.createTempDirectory(null).toFile(); var dataset = new File(tmp, String.format("dataset_%s.xml", metadataId)).toPath(); - datasetIsoGenerator.generateDatasetMetadata(data, metadataId, Files.newOutputStream(dataset)); + datasetIsoGenerator.generateDatasetMetadata(isoMetadata, metadataId, Files.newOutputStream(dataset)); files.add(dataset); - if (data.getServices() != null) { - data.getServices().forEach(service -> { + if (isoMetadata.getServices() != null) { + isoMetadata.getServices().forEach(service -> { try { var file = new File(tmp, String.format("service_%s_%s.xml", service.getServiceType().toString(), service.getServiceIdentification())).toPath(); - serviceIsoGenerator.generateServiceMetadata(data, service, Files.newOutputStream(file)); + serviceIsoGenerator.generateServiceMetadata(isoMetadata, service, Files.newOutputStream(file)); files.add(file); } catch (IOException | XMLStreamException e) { throw new MdeException("Unable to render service metadata for " + service.getServiceIdentification(), e); diff --git a/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/IsoMetadataService.java b/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/IsoMetadataService.java deleted file mode 100644 index b53adb7..0000000 --- a/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/IsoMetadataService.java +++ /dev/null @@ -1,33 +0,0 @@ -package de.terrestris.mde.mde_backend.service; - -import de.terrestris.mde.mde_backend.jpa.IsoMetadataRepository; -import de.terrestris.mde.mde_backend.model.IsoMetadata; -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; -import org.hibernate.search.engine.search.query.SearchResult; -import org.hibernate.search.mapper.orm.Search; -import org.hibernate.search.mapper.orm.session.SearchSession; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -public class IsoMetadataService extends BaseMetadataService { - - @PersistenceContext - private EntityManager entityManager; - - // TODO: add security check -// @PostAuthorize("hasRole('ROLE_ADMIN') or hasPermission(returnObject.orElse(null), 'READ')") - @Transactional(readOnly = true) - public SearchResult search(String searchTerm, Integer offset, Integer limit) { - SearchSession searchSession = Search.session(entityManager); - - return searchSession.search(IsoMetadata.class) - .where(f -> f.simpleQueryString() - .fields("data.title", "data.description") - // title is tokenized with standard analyzer so a wildcard prefix is not necessary - .matching(searchTerm + "*") - ) - .fetch(offset, limit); - } -} diff --git a/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/MetadataCollectionService.java b/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/MetadataCollectionService.java index 19a7d94..17e9a1d 100644 --- a/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/MetadataCollectionService.java +++ b/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/MetadataCollectionService.java @@ -6,60 +6,59 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.github.fge.jsonpatch.JsonPatchException; import de.terrestris.mde.mde_backend.enumeration.Role; -import de.terrestris.mde.mde_backend.jpa.ClientMetadataRepository; -import de.terrestris.mde.mde_backend.jpa.IsoMetadataRepository; -import de.terrestris.mde.mde_backend.jpa.TechnicalMetadataRepository; -import de.terrestris.mde.mde_backend.model.ClientMetadata; -import de.terrestris.mde.mde_backend.model.IsoMetadata; -import de.terrestris.mde.mde_backend.model.TechnicalMetadata; -import de.terrestris.mde.mde_backend.model.dto.MetadataCollection; +import de.terrestris.mde.mde_backend.jpa.MetadataCollectionRepository; +import de.terrestris.mde.mde_backend.model.MetadataCollection; +import de.terrestris.mde.mde_backend.model.json.Comment; import de.terrestris.mde.mde_backend.model.json.JsonClientMetadata; import de.terrestris.mde.mde_backend.model.json.JsonIsoMetadata; import de.terrestris.mde.mde_backend.model.json.JsonTechnicalMetadata; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.hibernate.search.engine.search.query.SearchResult; +import org.hibernate.search.mapper.orm.Search; +import org.hibernate.search.mapper.orm.session.SearchSession; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.security.access.prepost.PostAuthorize; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import java.io.IOException; -import java.util.NoSuchElementException; -import java.util.Optional; -import java.util.UUID; +import java.util.*; @Service -public class MetadataCollectionService { +public class MetadataCollectionService extends BaseMetadataService { - @Autowired - private ClientMetadataRepository clientMetadataRepository; - - @Autowired - private TechnicalMetadataRepository technicalMetadataRepository; - - @Autowired - private IsoMetadataRepository isoMetadataRepository; + @PersistenceContext + private EntityManager entityManager; @Autowired @Lazy ObjectMapper objectMapper; + @Transactional(readOnly = true) + public SearchResult search(String searchTerm, Integer offset, Integer limit) { + SearchSession searchSession = Search.session(entityManager); + + return searchSession.search(MetadataCollection.class) + .where(f -> f.simpleQueryString() + .fields("isoMetadata.title", "isoMetadata.description") + // title is tokenized with standard analyzer so a wildcard prefix is not necessary + .matching(searchTerm + "*") + ) + .fetch(offset, limit); + } + @PostAuthorize("hasRole('ROLE_ADMIN') or hasPermission(returnObject.orElse(null), 'READ')") @Transactional(readOnly = true) public Optional findOneByMetadataId(String metadataId) { - MetadataCollection metadataCollection = new MetadataCollection(); - - ClientMetadata clientMetadata = clientMetadataRepository.findByMetadataId(metadataId) - .orElseThrow(() -> new NoSuchElementException("ClientMetadata not found for metadataId: " + metadataId)); - TechnicalMetadata technicalMetadata = technicalMetadataRepository.findByMetadataId(metadataId) - .orElseThrow(() -> new NoSuchElementException("TechnicalMetadata not found for metadataId: " + metadataId)); - IsoMetadata isoMetadata = isoMetadataRepository.findByMetadataId(metadataId) - .orElseThrow(() -> new NoSuchElementException("IsoMetadata not found for metadataId: " + metadataId)); - - metadataCollection.setClientMetadata(clientMetadata.getData()); - metadataCollection.setTechnicalMetadata(technicalMetadata.getData()); - metadataCollection.setIsoMetadata(isoMetadata.getData()); + MetadataCollection metadataCollection = repository.findByMetadataId(metadataId) + .orElseThrow(() -> new NoSuchElementException("MetadataCollection not found for metadataId: " + metadataId)); return Optional.of(metadataCollection); } @@ -69,18 +68,15 @@ public Optional findOneByMetadataId(String metadataId) { public String create(String title) { String metadataId = UUID.randomUUID().toString(); - ClientMetadata clientMetadata = new ClientMetadata(metadataId); - TechnicalMetadata technicalMetadata = new TechnicalMetadata(metadataId); - IsoMetadata isoMetadata = new IsoMetadata(metadataId); - isoMetadata.getData().setTitle(title); - isoMetadata.getData().setIdentifier(metadataId); - isoMetadata.getData().setFileIdentifier(null); + MetadataCollection metadataCollection = new MetadataCollection(metadataId); - clientMetadataRepository.save(clientMetadata); - technicalMetadataRepository.save(technicalMetadata); - isoMetadataRepository.save(isoMetadata); + metadataCollection.getIsoMetadata().setTitle(title); + metadataCollection.getIsoMetadata().setIdentifier(metadataId); + metadataCollection.getIsoMetadata().setFileIdentifier(null); - return metadataId; + repository.save(metadataCollection); + + return metadataId; } @PreAuthorize("hasRole('ROLE_ADMIN') or hasPermission(#entity, 'CREATE')") @@ -88,174 +84,186 @@ public String create(String title) { public String create(String title, String cloneMetadataId) throws IOException { String metadataId = UUID.randomUUID().toString(); - ClientMetadata clientMetadata = new ClientMetadata(metadataId); - TechnicalMetadata technicalMetadata = new TechnicalMetadata(metadataId); - IsoMetadata isoMetadata = new IsoMetadata(metadataId); + MetadataCollection metadataCollection = new MetadataCollection(metadataId); - IsoMetadata oIso = isoMetadataRepository.findByMetadataId(cloneMetadataId) - .orElseThrow(() -> new NoSuchElementException("IsoMetadata not found for metadataId: " + cloneMetadataId)); - ClientMetadata oClient = clientMetadataRepository.findByMetadataId(cloneMetadataId) - .orElseThrow(() -> new NoSuchElementException("ClientMetadata not found for metadataId: " + cloneMetadataId)); - TechnicalMetadata oTechnical = technicalMetadataRepository.findByMetadataId(cloneMetadataId) - .orElseThrow(() -> new NoSuchElementException("TechnicalMetadata not found for metadataId: " + cloneMetadataId)); + MetadataCollection originalMetadataCollection = repository.findByMetadataId(cloneMetadataId) + .orElseThrow(() -> new NoSuchElementException("MetadataCollection not found for metadataId: " + cloneMetadataId)); JsonIsoMetadata clonedIsoData = objectMapper.readValue( - objectMapper.writeValueAsString(oIso.getData()), + objectMapper.writeValueAsString(originalMetadataCollection.getIsoMetadata()), new TypeReference() {} ); clonedIsoData.setTitle(title); JsonClientMetadata clonedClientData = objectMapper.readValue( - objectMapper.writeValueAsString(oClient.getData()), + objectMapper.writeValueAsString(originalMetadataCollection.getClientMetadata()), new TypeReference() {} ); JsonTechnicalMetadata clonedTechnicalData = objectMapper.readValue( - objectMapper.writeValueAsString(oTechnical.getData()), + objectMapper.writeValueAsString(originalMetadataCollection.getTechnicalMetadata()), new TypeReference() {} ); clonedIsoData.setIdentifier(metadataId); clonedIsoData.setFileIdentifier(null); - isoMetadata.setData(clonedIsoData); - clientMetadata.setData(clonedClientData); - technicalMetadata.setData(clonedTechnicalData); + metadataCollection.setIsoMetadata(clonedIsoData); + metadataCollection.setClientMetadata(clonedClientData); + metadataCollection.setTechnicalMetadata(clonedTechnicalData); - clientMetadataRepository.save(clientMetadata); - technicalMetadataRepository.save(technicalMetadata); - isoMetadataRepository.save(isoMetadata); + repository.save(metadataCollection); return metadataId; } @PreAuthorize("hasRole('ROLE_ADMIN') or hasPermission(#entity, 'UPDATE')") @Transactional(isolation = Isolation.SERIALIZABLE) - public IsoMetadata updateIsoJsonValue(String metadataId, String key, JsonNode value) throws IOException, IllegalArgumentException { - IsoMetadata isoMetadata = isoMetadataRepository.findByMetadataId(metadataId) - .orElseThrow(() -> new NoSuchElementException("IsoMetadata not found for metadataId: " + metadataId)); + public MetadataCollection updateIsoJsonValue(String metadataId, String key, JsonNode value) throws IOException, IllegalArgumentException { + MetadataCollection metadataCollection = repository.findByMetadataId(metadataId) + .orElseThrow(() -> new NoSuchElementException("MetadataCollection not found for metadataId: " + metadataId)); - JsonIsoMetadata data = isoMetadata.getData(); + JsonIsoMetadata data = metadataCollection.getIsoMetadata(); String jsonString = objectMapper.writeValueAsString(data); ObjectNode jsonNode = (ObjectNode) objectMapper.readTree(jsonString); jsonNode.replace(key, value); JsonIsoMetadata updatedData = objectMapper.treeToValue(jsonNode, JsonIsoMetadata.class); - isoMetadata.setData(updatedData); + metadataCollection.setIsoMetadata(updatedData); - return isoMetadataRepository.save(isoMetadata); + return repository.save(metadataCollection); } @PreAuthorize("hasRole('ROLE_ADMIN') or hasPermission(#entity, 'UPDATE')") @Transactional(isolation = Isolation.SERIALIZABLE) - public ClientMetadata updateClientJsonValue(String metadataId, String key, JsonNode value) throws IOException, JsonPatchException { - ClientMetadata clientMetadata = clientMetadataRepository.findByMetadataId(metadataId) - .orElseThrow(() -> new NoSuchElementException("ClientMetadata not found for metadataId: " + metadataId)); + public MetadataCollection updateClientJsonValue(String metadataId, String key, JsonNode value) throws IOException, JsonPatchException { + MetadataCollection metadataCollection = repository.findByMetadataId(metadataId) + .orElseThrow(() -> new NoSuchElementException("MetadataCollection not found for metadataId: " + metadataId)); - JsonClientMetadata data = clientMetadata.getData(); + JsonClientMetadata data = metadataCollection.getClientMetadata(); String jsonString = objectMapper.writeValueAsString(data); ObjectNode jsonNode = (ObjectNode) objectMapper.readTree(jsonString); jsonNode.replace(key, value); JsonClientMetadata updatedData = objectMapper.treeToValue(jsonNode, JsonClientMetadata.class); - clientMetadata.setData(updatedData); + metadataCollection.setClientMetadata(updatedData); - return clientMetadataRepository.save(clientMetadata); + return repository.save(metadataCollection); } @PreAuthorize("hasRole('ROLE_ADMIN') or hasPermission(#entity, 'UPDATE')") @Transactional(isolation = Isolation.SERIALIZABLE) - public TechnicalMetadata updateTechnicalJsonValue(String metadataId, String key, JsonNode value) throws IOException, JsonPatchException { - TechnicalMetadata technicalMetadata = technicalMetadataRepository.findByMetadataId(metadataId) - .orElseThrow(() -> new NoSuchElementException("TechnicalMetadata not found for metadataId: " + metadataId)); + public MetadataCollection updateTechnicalJsonValue(String metadataId, String key, JsonNode value) throws IOException, JsonPatchException { + MetadataCollection metadataCollection = repository.findByMetadataId(metadataId) + .orElseThrow(() -> new NoSuchElementException("MetadataCollection not found for metadataId: " + metadataId)); - JsonTechnicalMetadata data = technicalMetadata.getData(); + JsonTechnicalMetadata data = metadataCollection.getTechnicalMetadata(); String jsonString = objectMapper.writeValueAsString(data); ObjectNode jsonNode = (ObjectNode) objectMapper.readTree(jsonString); jsonNode.replace(key, value); JsonTechnicalMetadata updatedData = objectMapper.treeToValue(jsonNode, JsonTechnicalMetadata.class); - technicalMetadata.setData(updatedData); + metadataCollection.setTechnicalMetadata(updatedData); - return technicalMetadataRepository.save(technicalMetadata); + return repository.save(metadataCollection); } @PreAuthorize("hasRole('ROLE_ADMIN') or hasPermission(#entity, 'UPDATE')") @Transactional(isolation = Isolation.SERIALIZABLE) public void assignUser(String metadataId, String userId) { - IsoMetadata isoMetadata = isoMetadataRepository.findByMetadataId(metadataId) - .orElseThrow(() -> new NoSuchElementException("IsoMetadata not found for metadataId: " + metadataId)); - ClientMetadata clientMetadata = clientMetadataRepository.findByMetadataId(metadataId) - .orElseThrow(() -> new NoSuchElementException("ClientMetadata not found for metadataId: " + metadataId)); - TechnicalMetadata technicalMetadata = technicalMetadataRepository.findByMetadataId(metadataId) - .orElseThrow(() -> new NoSuchElementException("TechnicalMetadata not found for metadataId: " + metadataId)); - - isoMetadata.setResponsibleUserId(userId); - clientMetadata.setResponsibleUserId(userId); - technicalMetadata.setResponsibleUserId(userId); - - isoMetadataRepository.save(isoMetadata); - clientMetadataRepository.save(clientMetadata); - technicalMetadataRepository.save(technicalMetadata); + MetadataCollection metadataCollection = repository.findByMetadataId(metadataId) + .orElseThrow(() -> new NoSuchElementException("MetadataCollection not found for metadataId: " + metadataId)); + + List responsibleUserIds = metadataCollection.getResponsibleUserIds(); + if (responsibleUserIds == null) { + responsibleUserIds = new ArrayList<>(); + metadataCollection.setResponsibleUserIds(responsibleUserIds); + } + responsibleUserIds.add(userId); + + repository.save(metadataCollection); } @PreAuthorize("hasRole('ROLE_ADMIN') or hasPermission(#entity, 'UPDATE')") @Transactional(isolation = Isolation.SERIALIZABLE) - public void unassignUser(String metadataId) { - IsoMetadata isoMetadata = isoMetadataRepository.findByMetadataId(metadataId) - .orElseThrow(() -> new NoSuchElementException("IsoMetadata not found for metadataId: " + metadataId)); - ClientMetadata clientMetadata = clientMetadataRepository.findByMetadataId(metadataId) - .orElseThrow(() -> new NoSuchElementException("ClientMetadata not found for metadataId: " + metadataId)); - TechnicalMetadata technicalMetadata = technicalMetadataRepository.findByMetadataId(metadataId) - .orElseThrow(() -> new NoSuchElementException("TechnicalMetadata not found for metadataId: " + metadataId)); - - isoMetadata.setResponsibleUserId(null); - clientMetadata.setResponsibleUserId(null); - technicalMetadata.setResponsibleUserId(null); - - isoMetadataRepository.save(isoMetadata); - clientMetadataRepository.save(clientMetadata); - technicalMetadataRepository.save(technicalMetadata); + public void unassignUser(String metadataId, String userId) { + MetadataCollection metadataCollection = repository.findByMetadataId(metadataId) + .orElseThrow(() -> new NoSuchElementException("MetadataCollection not found for metadataId: " + metadataId)); + + List responsibleUserIds = metadataCollection.getResponsibleUserIds(); + + if (responsibleUserIds == null) { + return; + } + + metadataCollection.getResponsibleUserIds().remove(userId); + repository.save(metadataCollection); } @PreAuthorize("hasRole('ROLE_ADMIN') or hasPermission(#entity, 'UPDATE')") @Transactional(isolation = Isolation.SERIALIZABLE) public void assignRole(String metadataId, String role) { - IsoMetadata isoMetadata = isoMetadataRepository.findByMetadataId(metadataId) - .orElseThrow(() -> new NoSuchElementException("IsoMetadata not found for metadataId: " + metadataId)); - ClientMetadata clientMetadata = clientMetadataRepository.findByMetadataId(metadataId) - .orElseThrow(() -> new NoSuchElementException("ClientMetadata not found for metadataId: " + metadataId)); - TechnicalMetadata technicalMetadata = technicalMetadataRepository.findByMetadataId(metadataId) - .orElseThrow(() -> new NoSuchElementException("TechnicalMetadata not found for metadataId: " + metadataId)); - - isoMetadata.setResponsibleRole(Role.valueOf(role)); - clientMetadata.setResponsibleRole(Role.valueOf(role)); - technicalMetadata.setResponsibleRole(Role.valueOf(role)); - - isoMetadataRepository.save(isoMetadata); - clientMetadataRepository.save(clientMetadata); - technicalMetadataRepository.save(technicalMetadata); + MetadataCollection metadataCollection = repository.findByMetadataId(metadataId) + .orElseThrow(() -> new NoSuchElementException("MetadataCollection not found for metadataId: " + metadataId)); + + metadataCollection.setResponsibleRole(Role.valueOf(role)); + repository.save(metadataCollection); } @PreAuthorize("hasRole('ROLE_ADMIN') or hasPermission(#entity, 'UPDATE')") @Transactional(isolation = Isolation.SERIALIZABLE) public void unassignRole(String metadataId) { - IsoMetadata isoMetadata = isoMetadataRepository.findByMetadataId(metadataId) - .orElseThrow(() -> new NoSuchElementException("IsoMetadata not found for metadataId: " + metadataId)); - ClientMetadata clientMetadata = clientMetadataRepository.findByMetadataId(metadataId) - .orElseThrow(() -> new NoSuchElementException("ClientMetadata not found for metadataId: " + metadataId)); - TechnicalMetadata technicalMetadata = technicalMetadataRepository.findByMetadataId(metadataId) - .orElseThrow(() -> new NoSuchElementException("TechnicalMetadata not found for metadataId: " + metadataId)); - - isoMetadata.setResponsibleRole(null); - clientMetadata.setResponsibleRole(null); - technicalMetadata.setResponsibleRole(null); - - isoMetadataRepository.save(isoMetadata); - clientMetadataRepository.save(clientMetadata); - technicalMetadataRepository.save(technicalMetadata); + MetadataCollection metadataCollection = repository.findByMetadataId(metadataId) + .orElseThrow(() -> new NoSuchElementException("MetadataCollection not found for metadataId: " + metadataId)); + + metadataCollection.setResponsibleRole(null); + repository.save(metadataCollection); + } + + @PreAuthorize("hasRole('ROLE_ADMIN') or hasPermission(#entity, 'CREATE')") + @Transactional(isolation = Isolation.SERIALIZABLE) + public Comment addComment(String metadataId, String text) { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + + if (!authentication.isAuthenticated()) { + throw new IllegalStateException("User must be authenticated to add a comment"); + } + + MetadataCollection metadataCollection = repository.findByMetadataId(metadataId) + .orElseThrow(() -> new NoSuchElementException("MetadataCollection not found for metadataId: " + metadataId)); + + JsonClientMetadata data = metadataCollection.getClientMetadata(); + + String userName = ((JwtAuthenticationToken) authentication).getTokenAttributes().get("preferred_username").toString(); + Comment comment = new Comment(text, authentication.getName(), userName); + + if (data.getComments() == null) { + data.setComments(new ArrayList<>()); } + data.getComments().add(comment); + + repository.save(metadataCollection); + + return comment; + } + + @PreAuthorize("hasRole('ROLE_ADMIN') or hasPermission(#entity, 'DELETE')") + @Transactional(isolation = Isolation.SERIALIZABLE) + public void deleteComment(String metadataId, UUID commentId) { + MetadataCollection metadataCollection = repository.findByMetadataId(metadataId) + .orElseThrow(() -> new NoSuchElementException("MetadataCollection not found for metadataId: " + metadataId)); + + JsonClientMetadata data = metadataCollection.getClientMetadata(); + + if (data.getComments() == null) { + return; + } + + data.getComments().removeIf(comment -> comment.getId().equals(commentId)); + + repository.save(metadataCollection); + } } diff --git a/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/PublicationService.java b/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/PublicationService.java index 130ebb2..c356241 100644 --- a/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/PublicationService.java +++ b/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/PublicationService.java @@ -40,13 +40,13 @@ public class PublicationService { private static final String CSW = "http://www.opengis.net/cat/csw/2.0.2"; - @Value("${csw.server}") + @Value("${csw.server:}") private String cswServer; - @Value("${csw.user}") + @Value("${csw.user:}") private String cswUser; - @Value("${csw.password}") + @Value("${csw.password:}") private String cswPassword; private String publicationUrl; @@ -60,7 +60,7 @@ public class PublicationService { private ServiceIsoGenerator serviceIsoGenerator; @Autowired - private IsoMetadataService metadataService; + private MetadataCollectionService metadataCollectionService; @PostConstruct public void completeCswUrl() { @@ -186,19 +186,19 @@ private void publishRecords(List uuids) throws URISyntaxException, IOExc } public void publishMetadata(String metadataId) throws XMLStreamException, IOException, URISyntaxException, InterruptedException { - var metadata = metadataService.findOneByMetadataId(metadataId); + var metadata = metadataCollectionService.findOneByMetadataId(metadataId); if (metadata.isEmpty()) { log.info("Metadata with ID {} is not available.", metadataId); return; } var entity = metadata.get(); - var data = entity.getData(); + var isoMetadata = entity.getIsoMetadata(); var uuids = new ArrayList(); - var insert = data.getFileIdentifier() == null; + var insert = isoMetadata.getFileIdentifier() == null; if (log.isTraceEnabled()) { saveTransaction(writer -> { try { - datasetIsoGenerator.generateDatasetMetadata(data, metadataId, writer); + datasetIsoGenerator.generateDatasetMetadata(isoMetadata, metadataId, writer); } catch (IOException | XMLStreamException e) { log.warn("Unable to generate dataset metadata: {}", e.getMessage()); log.trace("Stack trace:", e); @@ -208,21 +208,21 @@ public void publishMetadata(String metadataId) throws XMLStreamException, IOExce } sendTransaction(writer -> { try { - datasetIsoGenerator.generateDatasetMetadata(data, metadataId, writer); - uuids.add(data.getFileIdentifier()); + datasetIsoGenerator.generateDatasetMetadata(isoMetadata, metadataId, writer); + uuids.add(isoMetadata.getFileIdentifier()); } catch (IOException | XMLStreamException e) { log.warn("Unable to generate dataset metadata: {}", e.getMessage()); log.trace("Stack trace:", e); } return null; - }, insert, data); - if (data.getServices() != null) { - data.getServices().forEach(service -> { + }, insert, isoMetadata); + if (isoMetadata.getServices() != null) { + isoMetadata.getServices().forEach(service -> { try { if (log.isTraceEnabled()) { saveTransaction(writer -> { try { - serviceIsoGenerator.generateServiceMetadata(data, service, writer); + serviceIsoGenerator.generateServiceMetadata(isoMetadata, service, writer); } catch (IOException | XMLStreamException e) { log.warn("Unable to generate service metadata: {}", e.getMessage()); log.trace("Stack trace:", e); @@ -232,7 +232,7 @@ public void publishMetadata(String metadataId) throws XMLStreamException, IOExce } sendTransaction(writer -> { try { - serviceIsoGenerator.generateServiceMetadata(data, service, writer); + serviceIsoGenerator.generateServiceMetadata(isoMetadata, service, writer); uuids.add(service.getFileIdentifier()); } catch (IOException | XMLStreamException e) { log.warn("Unable to generate service metadata: {}", e.getMessage()); @@ -246,7 +246,7 @@ public void publishMetadata(String metadataId) throws XMLStreamException, IOExce } }); } - metadataService.update(entity.getId(), entity); + metadataCollectionService.update(entity.getId(), entity); publishRecords(uuids); } diff --git a/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/TechnicalMetadataService.java b/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/TechnicalMetadataService.java deleted file mode 100644 index d4f165c..0000000 --- a/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/TechnicalMetadataService.java +++ /dev/null @@ -1,9 +0,0 @@ -package de.terrestris.mde.mde_backend.service; - -import de.terrestris.mde.mde_backend.jpa.TechnicalMetadataRepository; -import de.terrestris.mde.mde_backend.model.TechnicalMetadata; -import org.springframework.stereotype.Service; - -@Service -public class TechnicalMetadataService extends BaseMetadataService { -} diff --git a/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/ValidatorService.java b/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/ValidatorService.java index d410b7c..863f5d7 100644 --- a/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/ValidatorService.java +++ b/mde-services/src/main/java/de/terrestris/mde/mde_backend/service/ValidatorService.java @@ -5,7 +5,7 @@ import de.terrestris.bkgtestsuite.core.spi.TestRunner; import de.terrestris.bkgtestsuite.te.TeTestRunner; import de.terrestris.mde.mde_backend.enumeration.MetadataProfile; -import de.terrestris.mde.mde_backend.jpa.IsoMetadataRepository; +import de.terrestris.mde.mde_backend.jpa.MetadataCollectionRepository; import jakarta.annotation.PostConstruct; import lombok.extern.log4j.Log4j2; import org.apache.commons.io.FileUtils; @@ -44,7 +44,7 @@ public class ValidatorService { private List metadataResources; @Autowired - private IsoMetadataRepository isoMetadataRepository; + private MetadataCollectionRepository metadataCollectionRepository; @Autowired private IsoGenerator generator; @@ -126,13 +126,13 @@ public List validate(boolean inspire, Path file) { } public List validateMetadata(String metadataId) throws XMLStreamException, IOException { - var metadata = isoMetadataRepository.findByMetadataId(metadataId); - if (metadata.isEmpty()) { + var metadataCollection = metadataCollectionRepository.findByMetadataId(metadataId); + if (metadataCollection.isEmpty()) { log.info("Metadata with ID {} is not available.", metadataId); return null; } - var data = metadata.get().getData(); - var inspire = !data.getMetadataProfile().equals(MetadataProfile.ISO); + var isoMetadata = metadataCollection.get().getIsoMetadata(); + var inspire = !isoMetadata.getMetadataProfile().equals(MetadataProfile.ISO); var files = generator.generateMetadata(metadataId); var errors = new ArrayList(); files.forEach(f -> errors.addAll(validate(inspire, f))); diff --git a/mde-services/src/main/resources/db/migration/V2.0.0__refactor_base_models.sql b/mde-services/src/main/resources/db/migration/V2.0.0__refactor_base_models.sql new file mode 100644 index 0000000..4754eb2 --- /dev/null +++ b/mde-services/src/main/resources/db/migration/V2.0.0__refactor_base_models.sql @@ -0,0 +1,21 @@ +DROP TABLE IF EXISTS client_metadata cascade; +DROP TABLE IF EXISTS iso_metadata cascade; +DROP TABLE IF EXISTS technical_metadata cascade; +DROP TABLE IF EXISTS metadata_collection cascade; + +CREATE TABLE metadata_collection ( + id BIGSERIAL PRIMARY KEY, + metadata_id TEXT UNIQUE NOT NULL, + responsible_user_ids TEXT[], + responsible_role TEXT, + client_metadata JSONB, + iso_metadata JSONB, + technical_metadata JSONB +); + +CREATE INDEX idx_metadata_collection_metadata_id ON metadata_collection(metadata_id); +CREATE INDEX idx_metadata_collection_responsible_user_id ON metadata_collection(responsible_user_ids); +CREATE INDEX idx_metadata_collection_responsible_role ON metadata_collection(responsible_role); +CREATE INDEX idx_metadata_collection_client_metadata ON metadata_collection USING GIN (client_metadata); +CREATE INDEX idx_metadata_collection_iso_metadata ON metadata_collection USING GIN (iso_metadata); +CREATE INDEX idx_metadata_collection_technical_metadata ON metadata_collection USING GIN (technical_metadata);