diff --git a/RDF_Back/.gitattributes b/Backend/.gitattributes similarity index 100% rename from RDF_Back/.gitattributes rename to Backend/.gitattributes diff --git a/RDF_Back/.gitignore b/Backend/.gitignore similarity index 100% rename from RDF_Back/.gitignore rename to Backend/.gitignore diff --git a/RDF_Back/.mvn/wrapper/maven-wrapper.properties b/Backend/.mvn/wrapper/maven-wrapper.properties similarity index 100% rename from RDF_Back/.mvn/wrapper/maven-wrapper.properties rename to Backend/.mvn/wrapper/maven-wrapper.properties diff --git a/RDF_Back/data/model.ttl b/Backend/data/model.ttl similarity index 100% rename from RDF_Back/data/model.ttl rename to Backend/data/model.ttl diff --git a/RDF_Back/data/tropy/export.ttl b/Backend/data/tropy/export.ttl similarity index 100% rename from RDF_Back/data/tropy/export.ttl rename to Backend/data/tropy/export.ttl diff --git a/RDF_Back/data/tropy/model.ttl b/Backend/data/tropy/model.ttl similarity index 100% rename from RDF_Back/data/tropy/model.ttl rename to Backend/data/tropy/model.ttl diff --git a/RDF_Back/data/tropy/tropy.ttl b/Backend/data/tropy/tropy.ttl similarity index 100% rename from RDF_Back/data/tropy/tropy.ttl rename to Backend/data/tropy/tropy.ttl diff --git a/RDF_Back/data/tropy/tropy1.ttl b/Backend/data/tropy/tropy1.ttl similarity index 100% rename from RDF_Back/data/tropy/tropy1.ttl rename to Backend/data/tropy/tropy1.ttl diff --git a/RDF_Back/data/tropyV1/export.ttl b/Backend/data/tropyV1/export.ttl similarity index 100% rename from RDF_Back/data/tropyV1/export.ttl rename to Backend/data/tropyV1/export.ttl diff --git a/RDF_Back/metadata/testproject/metadata.ttl b/Backend/metadata/testproject/metadata.ttl similarity index 100% rename from RDF_Back/metadata/testproject/metadata.ttl rename to Backend/metadata/testproject/metadata.ttl diff --git a/RDF_Back/mvnw b/Backend/mvnw similarity index 100% rename from RDF_Back/mvnw rename to Backend/mvnw diff --git a/RDF_Back/mvnw.cmd b/Backend/mvnw.cmd similarity index 100% rename from RDF_Back/mvnw.cmd rename to Backend/mvnw.cmd diff --git a/RDF_Back/pom.xml b/Backend/pom.xml similarity index 93% rename from RDF_Back/pom.xml rename to Backend/pom.xml index 88d3bb13..14234754 100644 --- a/RDF_Back/pom.xml +++ b/Backend/pom.xml @@ -9,9 +9,9 @@ com.uspn - RDF_Back + Backend 0.0.1-SNAPSHOT - RDF_Back + Backend RDF_Back @@ -28,6 +28,8 @@ 17 + UTF-8 + UTF-8 diff --git a/Backend/projects/archive_2026/store/contexts.dat b/Backend/projects/archive_2026/store/contexts.dat new file mode 100644 index 00000000..b560a934 Binary files /dev/null and b/Backend/projects/archive_2026/store/contexts.dat differ diff --git a/RDF_Back/projects/archive/store/namespaces.dat b/Backend/projects/archive_2026/store/namespaces.dat similarity index 100% rename from RDF_Back/projects/archive/store/namespaces.dat rename to Backend/projects/archive_2026/store/namespaces.dat diff --git a/RDF_Back/projects/Test_Mehrez/store/nativerdf.ver b/Backend/projects/archive_2026/store/nativerdf.ver similarity index 100% rename from RDF_Back/projects/Test_Mehrez/store/nativerdf.ver rename to Backend/projects/archive_2026/store/nativerdf.ver diff --git a/Backend/projects/archive_2026/store/triples-posc.alloc b/Backend/projects/archive_2026/store/triples-posc.alloc new file mode 100644 index 00000000..2a7d0176 Binary files /dev/null and b/Backend/projects/archive_2026/store/triples-posc.alloc differ diff --git a/Backend/projects/archive_2026/store/triples-posc.dat b/Backend/projects/archive_2026/store/triples-posc.dat new file mode 100644 index 00000000..0f9fa12f Binary files /dev/null and b/Backend/projects/archive_2026/store/triples-posc.dat differ diff --git a/RDF_Back/projects/archive_khaoula/store/triples-spoc.alloc b/Backend/projects/archive_2026/store/triples-spoc.alloc similarity index 100% rename from RDF_Back/projects/archive_khaoula/store/triples-spoc.alloc rename to Backend/projects/archive_2026/store/triples-spoc.alloc diff --git a/Backend/projects/archive_2026/store/triples-spoc.dat b/Backend/projects/archive_2026/store/triples-spoc.dat new file mode 100644 index 00000000..a572c796 Binary files /dev/null and b/Backend/projects/archive_2026/store/triples-spoc.dat differ diff --git a/RDF_Back/projects/Test_Mehrez/store/triples.prop b/Backend/projects/archive_2026/store/triples.prop similarity index 71% rename from RDF_Back/projects/Test_Mehrez/store/triples.prop rename to Backend/projects/archive_2026/store/triples.prop index caa81a7b..b7cec6bc 100644 --- a/RDF_Back/projects/Test_Mehrez/store/triples.prop +++ b/Backend/projects/archive_2026/store/triples.prop @@ -1,4 +1,4 @@ #triple indexes meta-data, DO NOT EDIT! -#Sun Mar 29 12:59:07 CEST 2026 +#Wed Jul 15 12:25:02 CEST 2026 triple-indexes=spoc,posc version=10 diff --git a/RDF_Back/projects/Test_Mehrez/store/txn-status b/Backend/projects/archive_2026/store/txn-status similarity index 100% rename from RDF_Back/projects/Test_Mehrez/store/txn-status rename to Backend/projects/archive_2026/store/txn-status diff --git a/RDF_Back/projects/Test_Mehrez/store/txncache.alloc b/Backend/projects/archive_2026/store/txncache.alloc similarity index 100% rename from RDF_Back/projects/Test_Mehrez/store/txncache.alloc rename to Backend/projects/archive_2026/store/txncache.alloc diff --git a/RDF_Back/projects/Test_Mehrez/store/txncache.dat b/Backend/projects/archive_2026/store/txncache.dat similarity index 100% rename from RDF_Back/projects/Test_Mehrez/store/txncache.dat rename to Backend/projects/archive_2026/store/txncache.dat diff --git a/Backend/projects/archive_2026/store/values.dat b/Backend/projects/archive_2026/store/values.dat new file mode 100644 index 00000000..4d15073b Binary files /dev/null and b/Backend/projects/archive_2026/store/values.dat differ diff --git a/Backend/projects/archive_2026/store/values.hash b/Backend/projects/archive_2026/store/values.hash new file mode 100644 index 00000000..89516c2a Binary files /dev/null and b/Backend/projects/archive_2026/store/values.hash differ diff --git a/Backend/projects/archive_2026/store/values.id b/Backend/projects/archive_2026/store/values.id new file mode 100644 index 00000000..e25d68a3 Binary files /dev/null and b/Backend/projects/archive_2026/store/values.id differ diff --git a/Backend/projects/okok/store/contexts.dat b/Backend/projects/okok/store/contexts.dat new file mode 100644 index 00000000..2d91cabd Binary files /dev/null and b/Backend/projects/okok/store/contexts.dat differ diff --git a/RDF_Back/projects/archive_khaouala/store/namespaces.dat b/Backend/projects/okok/store/namespaces.dat similarity index 100% rename from RDF_Back/projects/archive_khaouala/store/namespaces.dat rename to Backend/projects/okok/store/namespaces.dat diff --git a/RDF_Back/projects/archive/store/nativerdf.ver b/Backend/projects/okok/store/nativerdf.ver similarity index 100% rename from RDF_Back/projects/archive/store/nativerdf.ver rename to Backend/projects/okok/store/nativerdf.ver diff --git a/RDF_Back/projects/archive/store/triples-posc.alloc b/Backend/projects/okok/store/triples-posc.alloc similarity index 100% rename from RDF_Back/projects/archive/store/triples-posc.alloc rename to Backend/projects/okok/store/triples-posc.alloc diff --git a/Backend/projects/okok/store/triples-posc.dat b/Backend/projects/okok/store/triples-posc.dat new file mode 100644 index 00000000..d8a6d801 Binary files /dev/null and b/Backend/projects/okok/store/triples-posc.dat differ diff --git a/Backend/projects/okok/store/triples-spoc.alloc b/Backend/projects/okok/store/triples-spoc.alloc new file mode 100644 index 00000000..bfcdf6ec Binary files /dev/null and b/Backend/projects/okok/store/triples-spoc.alloc differ diff --git a/Backend/projects/okok/store/triples-spoc.dat b/Backend/projects/okok/store/triples-spoc.dat new file mode 100644 index 00000000..5c199206 Binary files /dev/null and b/Backend/projects/okok/store/triples-spoc.dat differ diff --git a/RDF_Back/projects/archive/store/triples.prop b/Backend/projects/okok/store/triples.prop similarity index 71% rename from RDF_Back/projects/archive/store/triples.prop rename to Backend/projects/okok/store/triples.prop index 4eb8a8a1..b2bdde22 100644 --- a/RDF_Back/projects/archive/store/triples.prop +++ b/Backend/projects/okok/store/triples.prop @@ -1,4 +1,4 @@ #triple indexes meta-data, DO NOT EDIT! -#Thu Mar 19 11:22:37 CET 2026 +#Wed Jul 15 12:40:46 CEST 2026 triple-indexes=spoc,posc version=10 diff --git a/RDF_Back/projects/archive/store/txn-status b/Backend/projects/okok/store/txn-status similarity index 100% rename from RDF_Back/projects/archive/store/txn-status rename to Backend/projects/okok/store/txn-status diff --git a/RDF_Back/projects/archive_khaouala/store/txncache.alloc b/Backend/projects/okok/store/txncache.alloc similarity index 100% rename from RDF_Back/projects/archive_khaouala/store/txncache.alloc rename to Backend/projects/okok/store/txncache.alloc diff --git a/RDF_Back/projects/archive_khaouala/store/txncache.dat b/Backend/projects/okok/store/txncache.dat similarity index 100% rename from RDF_Back/projects/archive_khaouala/store/txncache.dat rename to Backend/projects/okok/store/txncache.dat diff --git a/Backend/projects/okok/store/values.dat b/Backend/projects/okok/store/values.dat new file mode 100644 index 00000000..e3562e90 Binary files /dev/null and b/Backend/projects/okok/store/values.dat differ diff --git a/Backend/projects/okok/store/values.hash b/Backend/projects/okok/store/values.hash new file mode 100644 index 00000000..9e738a73 Binary files /dev/null and b/Backend/projects/okok/store/values.hash differ diff --git a/Backend/projects/okok/store/values.id b/Backend/projects/okok/store/values.id new file mode 100644 index 00000000..f4c9dfc8 Binary files /dev/null and b/Backend/projects/okok/store/values.id differ diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/RdfBackApplication.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/RdfBackApplication.java similarity index 83% rename from RDF_Back/src/main/java/com/uspn/rdf_back/RdfBackApplication.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/RdfBackApplication.java index b9861a40..6a17869b 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/RdfBackApplication.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/RdfBackApplication.java @@ -1,6 +1,6 @@ -package com.uspn.rdf_back; +package fr.cnrs.lacito.fieldarchive; -import com.uspn.rdf_back.example.Example; +import fr.cnrs.lacito.fieldarchive.example.Example; import org.eclipse.rdf4j.spring.RDF4JConfig; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/config/Rdf4jConfig.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/config/Rdf4jConfig.java similarity index 95% rename from RDF_Back/src/main/java/com/uspn/rdf_back/config/Rdf4jConfig.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/config/Rdf4jConfig.java index 7a523499..2925498e 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/config/Rdf4jConfig.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/config/Rdf4jConfig.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back.config; +package fr.cnrs.lacito.fieldarchive.config; import org.eclipse.rdf4j.repository.Repository; import org.eclipse.rdf4j.repository.sail.SailRepository; diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/config/WebConfig.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/config/WebConfig.java similarity index 93% rename from RDF_Back/src/main/java/com/uspn/rdf_back/config/WebConfig.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/config/WebConfig.java index 4c6c3da8..9ae158d7 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/config/WebConfig.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/config/WebConfig.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back.config; +package fr.cnrs.lacito.fieldarchive.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/controllers/DataSourceController.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/controllers/DataSourceController.java similarity index 84% rename from RDF_Back/src/main/java/com/uspn/rdf_back/controllers/DataSourceController.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/controllers/DataSourceController.java index d7f21f79..f25b173c 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/controllers/DataSourceController.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/controllers/DataSourceController.java @@ -1,10 +1,10 @@ -package com.uspn.rdf_back.controllers; +package fr.cnrs.lacito.fieldarchive.controllers; -import com.uspn.rdf_back.dtos.CreateInternalDataSourceRequest; -import com.uspn.rdf_back.dtos.CreateExternalDataSourceRequest; -import com.uspn.rdf_back.dtos.DataSourceDto; -import com.uspn.rdf_back.dtos.UpdateDataSourceRequest; -import com.uspn.rdf_back.services.DataSourceService; +import fr.cnrs.lacito.fieldarchive.dtos.CreateInternalDataSourceRequest; +import fr.cnrs.lacito.fieldarchive.dtos.CreateExternalDataSourceRequest; +import fr.cnrs.lacito.fieldarchive.dtos.DataSourceDto; +import fr.cnrs.lacito.fieldarchive.dtos.UpdateDataSourceRequest; +import fr.cnrs.lacito.fieldarchive.services.DataSourceService; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/controllers/OntologyController.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/controllers/OntologyController.java similarity index 89% rename from RDF_Back/src/main/java/com/uspn/rdf_back/controllers/OntologyController.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/controllers/OntologyController.java index ce7a1c0f..feb3b1c1 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/controllers/OntologyController.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/controllers/OntologyController.java @@ -1,13 +1,13 @@ -package com.uspn.rdf_back.controllers; +package fr.cnrs.lacito.fieldarchive.controllers; -import com.uspn.rdf_back.dtos.OntologyLabelDto; -import com.uspn.rdf_back.dtos.SaveOntologyLabelRequest; -import com.uspn.rdf_back.services.OntologyService; +import fr.cnrs.lacito.fieldarchive.dtos.OntologyLabelDto; +import fr.cnrs.lacito.fieldarchive.dtos.SaveOntologyLabelRequest; +import fr.cnrs.lacito.fieldarchive.services.OntologyService; import org.springframework.web.bind.annotation.*; import java.util.List; -import com.uspn.rdf_back.dtos.OntologyClassDto; -import com.uspn.rdf_back.services.BuiltinOntologyService; +import fr.cnrs.lacito.fieldarchive.dtos.OntologyClassDto; +import fr.cnrs.lacito.fieldarchive.services.BuiltinOntologyService; @RestController @RequestMapping("/ontology") diff --git a/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/controllers/ProjectController.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/controllers/ProjectController.java new file mode 100644 index 00000000..8d43ecc4 --- /dev/null +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/controllers/ProjectController.java @@ -0,0 +1,186 @@ +package fr.cnrs.lacito.fieldarchive.controllers; + +import fr.cnrs.lacito.fieldarchive.dtos.*; +import fr.cnrs.lacito.fieldarchive.dtos.*; +import fr.cnrs.lacito.fieldarchive.exceptions.ImportException; +import fr.cnrs.lacito.fieldarchive.services.FileExportService; +import fr.cnrs.lacito.fieldarchive.services.FileImportService; +import fr.cnrs.lacito.fieldarchive.services.ProjectService; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.*; +import java.util.Map; + +@RestController +@RequestMapping("/projects") +public class ProjectController { + + private final ProjectService projectService; + private final FileImportService fileImportService; + private final FileExportService fileExportService; + + public ProjectController(ProjectService projectService, FileImportService fileImportService, FileExportService fileExportService) { + this.projectService = projectService; + this.fileImportService = fileImportService; + this.fileExportService = fileExportService; + } + + @PostMapping(value = "/import-backup", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public ResponseEntity> importBackup(@RequestParam("file") MultipartFile file) { + try (InputStream is = file.getInputStream()) { + ImportResult result = fileImportService.importBackup(is); + Map body = new HashMap<>(); + body.put("status", "ok"); + body.put("message", "Project is successfully restored !"); + body.put("project", result.message); + return ResponseEntity.ok(body); + + } catch (ImportException e) { + return ResponseEntity.badRequest().body(Map.of("status", "error", "message", e.getMessage())); + } catch (IllegalArgumentException e) { + return ResponseEntity.badRequest().body(Map.of("status", "error", "message", e.getMessage())); + } catch (IOException e) { + return ResponseEntity.internalServerError().body(Map.of("status", "error", "message", "Error while reading file.")); + } + } + + @GetMapping(value = "/export/backup", produces = "application/zip") + public void exportBackup(HttpServletResponse response) throws IOException { + response.setContentType("application/zip"); + response.setHeader("Content-Disposition", "attachment; filename=\"project-backup.zip\""); + fileExportService.exportBackup(response.getOutputStream()); + } + + @GetMapping(value = "/export/internal", produces = "text/turtle") + public void exportInternal(HttpServletResponse response) throws IOException { + response.setContentType("text/turtle"); + response.setHeader("Content-Disposition", "attachment; filename=\"internal-data.ttl\""); + fileExportService.exportInternalDataSource(response.getOutputStream()); + } + + @PostMapping(value = "/import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public ResponseEntity> importExternalTurtle( + @RequestParam("file") MultipartFile file) { + + try (InputStream is = file.getInputStream()) { + String baseURI = projectService.readCurrentProject().prefix; + ImportResult result = fileImportService.importTurtle(is, baseURI); + Map body = new HashMap<>(); + body.put("status", "ok"); + body.put("message", "Internal DataSource was successfully updated !"); + body.put("project", result.message); + return ResponseEntity.ok(body); + } catch (ImportException e) { + return ResponseEntity.badRequest().body(Map.of("status", "error", "message", e.getMessage())); + } catch (IOException e) { + return ResponseEntity.internalServerError().build(); + } + } + + @PostMapping("/open") + public Map open(@RequestBody CreateProjectRequest req) { + ProjectDto dto = projectService.openProject(req.getName(), req.isPersistent(), req.getDescription(), req.getPrefix()); + return Map.of( + "status", "ok", + "project", dto.name + ); + } + + @PostMapping("/create") + public Map create(@RequestBody CreateProjectRequest req) { + ProjectDto dto = projectService.createProject(req.getName(), req.isPersistent(), req.getDescription(), req.getPrefix()); + return Map.of( + "status", "ok", + "project", dto.name + ); + } + + @GetMapping("/current") + public ProjectDto current() { + return projectService.readCurrentProject(); + } + + @DeleteMapping("/{projectName}") + public ResponseEntity deleteProject(@PathVariable String projectName) { + try { + projectService.deleteProject(projectName); + return ResponseEntity.ok("Project deleted successfully"); + + } catch (IllegalArgumentException e) { + return ResponseEntity + .badRequest() + .body(e.getMessage()); + + } catch (FileNotFoundException e) { + return ResponseEntity + .status(HttpStatus.NOT_FOUND) + .body(e.getMessage()); + + } catch (IOException e) { + return ResponseEntity + .status(HttpStatus.INTERNAL_SERVER_ERROR) + .body("Error deleting project"); + } + } + + @PostMapping("/close") + public Map close() { + projectService.closeProject(); + return Map.of("status", "ok"); + } + + @PutMapping("/{oldProjectName}") + public ResponseEntity updateProject( + @PathVariable String oldProjectName, + @RequestBody UpdateProjectObject newProject) { + + try { + + System.out.println("New Description is "+ newProject.description); + projectService.updateProject( + oldProjectName, + newProject.name, + newProject.description + ); + + return ResponseEntity.ok( + new ApiResponse<>(true, "Project updated successfully", null) + ); + + } catch (IllegalArgumentException e) { + return ResponseEntity + .badRequest() + .body(new ApiError(e.getMessage(), "VALIDATION_ERROR")); + + } catch (IOException e) { + return ResponseEntity + .status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(new ApiError("Internal error while updating project", "IO_ERROR")); + + } catch (Exception e) { + return ResponseEntity + .status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(new ApiError("Unexpected error", "UNKNOWN_ERROR")); + } + } + // Liste simple +// @GetMapping("/list") +// public List listProjects() { +// return projectService.listProjects(); +// } + + // Liste détaillée + @GetMapping("/list/details") + public List> listProjectsDetailed() { + return projectService.listProjectsDetailed(); + } + +} diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/controllers/RdfEntityController.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/controllers/RdfEntityController.java similarity index 83% rename from RDF_Back/src/main/java/com/uspn/rdf_back/controllers/RdfEntityController.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/controllers/RdfEntityController.java index 288ce7c5..3efc9557 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/controllers/RdfEntityController.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/controllers/RdfEntityController.java @@ -1,7 +1,11 @@ -package com.uspn.rdf_back.controllers; +package fr.cnrs.lacito.fieldarchive.controllers; -import com.uspn.rdf_back.dtos.*; -import com.uspn.rdf_back.services.RdfEntityService; +import fr.cnrs.lacito.fieldarchive.dtos.*; +import fr.cnrs.lacito.fieldarchive.dtos.CreateRdfEntityRequest; +import fr.cnrs.lacito.fieldarchive.dtos.RdfEntityDto; +import fr.cnrs.lacito.fieldarchive.dtos.RdfEntitySummaryDto; +import fr.cnrs.lacito.fieldarchive.dtos.UpdateRdfEntityRequest; +import fr.cnrs.lacito.fieldarchive.services.RdfEntityService; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/controllers/SparqlController.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/controllers/SparqlController.java similarity index 69% rename from RDF_Back/src/main/java/com/uspn/rdf_back/controllers/SparqlController.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/controllers/SparqlController.java index 79a20dd6..6087b0cb 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/controllers/SparqlController.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/controllers/SparqlController.java @@ -1,6 +1,6 @@ -package com.uspn.rdf_back.controllers; +package fr.cnrs.lacito.fieldarchive.controllers; -import com.uspn.rdf_back.services.SparqlService; +import fr.cnrs.lacito.fieldarchive.services.SparqlService; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -18,7 +18,9 @@ public SparqlController(SparqlService service) { @PostMapping("/select") public List> select(@RequestBody Map body) { - return service.select(body.get("query")); + String query = body.get("query"); +// System.out.println("SPARQL QUERY:\n" + query); + return service.select(query); } @PostMapping("/update") diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/core/ProjectContext.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/core/ProjectContext.java similarity index 94% rename from RDF_Back/src/main/java/com/uspn/rdf_back/core/ProjectContext.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/core/ProjectContext.java index d27f6021..471519af 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/core/ProjectContext.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/core/ProjectContext.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back.core; +package fr.cnrs.lacito.fieldarchive.core; import org.eclipse.rdf4j.repository.Repository; diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/core/RdfContexts.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/core/RdfContexts.java similarity index 52% rename from RDF_Back/src/main/java/com/uspn/rdf_back/core/RdfContexts.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/core/RdfContexts.java index 0246427b..f645014c 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/core/RdfContexts.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/core/RdfContexts.java @@ -1,14 +1,10 @@ -package com.uspn.rdf_back.core; +package fr.cnrs.lacito.fieldarchive.core; //un contexte = un graphe nommé public final class RdfContexts { private RdfContexts() {} // Contexte où on stocke les METADONNEES des sources (en RDF) // graphe nommé pour les métadonnées (projet, sources de données, etc.) - public static final String CTX_META = RdfNamespaces.APP + "context/metadata"; - - // Contexte éditable interne (source interne) - public static final String CTX_INTERNAL = RdfNamespaces.APP + "context/internal"; - - public static final String CTX_ONTO_RICO = RdfNamespaces.APP + "context/ontology/rico"; + public static final String CTX_META = RdfNamespaces.APP + "/context/metadata"; + public static final String CTX_ONTO_RICO = RdfNamespaces.APP + "/context/ontology/rico"; } diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/core/RdfNamespaces.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/core/RdfNamespaces.java similarity index 57% rename from RDF_Back/src/main/java/com/uspn/rdf_back/core/RdfNamespaces.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/core/RdfNamespaces.java index ad2b3b99..dad215ca 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/core/RdfNamespaces.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/core/RdfNamespaces.java @@ -1,11 +1,10 @@ -package com.uspn.rdf_back.core; +package fr.cnrs.lacito.fieldarchive.core; public final class RdfNamespaces { private RdfNamespaces() {} // Namespace interne de l'application - public static final String APP = "http://uspn.fr/app#"; - //public static final String APP = "http://example.org/app#"; + public static final String APP = "http://cnrs.lacito/app#"; // RIC-O public static final String RICO = "https://www.ica.org/standards/RiC/ontology#"; diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/ApiError.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/ApiError.java similarity index 65% rename from RDF_Back/src/main/java/com/uspn/rdf_back/dtos/ApiError.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/ApiError.java index 01e5f5a5..525b1fa3 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/ApiError.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/ApiError.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back.dtos; +package fr.cnrs.lacito.fieldarchive.dtos; public record ApiError( String message, diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/ApiResponse.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/ApiResponse.java similarity index 70% rename from RDF_Back/src/main/java/com/uspn/rdf_back/dtos/ApiResponse.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/ApiResponse.java index dda24aa7..46510d94 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/ApiResponse.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/ApiResponse.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back.dtos; +package fr.cnrs.lacito.fieldarchive.dtos; public record ApiResponse( boolean success, diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/CreateDataSourceRequest.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/CreateDataSourceRequest.java similarity index 86% rename from RDF_Back/src/main/java/com/uspn/rdf_back/dtos/CreateDataSourceRequest.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/CreateDataSourceRequest.java index 6d2b2108..85a1614a 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/CreateDataSourceRequest.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/CreateDataSourceRequest.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back.dtos; +package fr.cnrs.lacito.fieldarchive.dtos; import lombok.Getter; diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/CreateExternalDataSourceRequest.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/CreateExternalDataSourceRequest.java similarity index 89% rename from RDF_Back/src/main/java/com/uspn/rdf_back/dtos/CreateExternalDataSourceRequest.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/CreateExternalDataSourceRequest.java index 943406ea..fc313312 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/CreateExternalDataSourceRequest.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/CreateExternalDataSourceRequest.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back.dtos; +package fr.cnrs.lacito.fieldarchive.dtos; import lombok.Getter; import lombok.Setter; diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/CreateInternalDataSourceRequest.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/CreateInternalDataSourceRequest.java similarity index 74% rename from RDF_Back/src/main/java/com/uspn/rdf_back/dtos/CreateInternalDataSourceRequest.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/CreateInternalDataSourceRequest.java index 7e6ee066..4a5ad052 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/CreateInternalDataSourceRequest.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/CreateInternalDataSourceRequest.java @@ -1,10 +1,12 @@ -package com.uspn.rdf_back.dtos; +package fr.cnrs.lacito.fieldarchive.dtos; +import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; @Getter @Setter +@AllArgsConstructor public class CreateInternalDataSourceRequest { private String shortName; // ex: "internal" diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/CreateProjectRequest.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/CreateProjectRequest.java similarity index 73% rename from RDF_Back/src/main/java/com/uspn/rdf_back/dtos/CreateProjectRequest.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/CreateProjectRequest.java index 008bb6e0..bd68a985 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/CreateProjectRequest.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/CreateProjectRequest.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back.dtos; +package fr.cnrs.lacito.fieldarchive.dtos; public class CreateProjectRequest { public String name; // ex: "archive_2025" @@ -6,6 +6,8 @@ public class CreateProjectRequest { private String description; + private String prefix; + public String getName() { return name; } public void setName(String name) { this.name = name; } @@ -15,6 +17,12 @@ public class CreateProjectRequest { public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } + public String getPrefix() { + return prefix; + } + public void setPrefix(String prefix) { + this.prefix = prefix; + } } diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/CreateRdfEntityRequest.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/CreateRdfEntityRequest.java similarity index 83% rename from RDF_Back/src/main/java/com/uspn/rdf_back/dtos/CreateRdfEntityRequest.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/CreateRdfEntityRequest.java index fdd58922..ea213576 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/CreateRdfEntityRequest.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/CreateRdfEntityRequest.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back.dtos; +package fr.cnrs.lacito.fieldarchive.dtos; import java.util.ArrayList; import java.util.List; diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/DataSourceDto.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/DataSourceDto.java similarity index 91% rename from RDF_Back/src/main/java/com/uspn/rdf_back/dtos/DataSourceDto.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/DataSourceDto.java index 76330330..8d43c700 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/DataSourceDto.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/DataSourceDto.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back.dtos; +package fr.cnrs.lacito.fieldarchive.dtos; diff --git a/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/ImportResult.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/ImportResult.java new file mode 100644 index 00000000..c2a26714 --- /dev/null +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/ImportResult.java @@ -0,0 +1,20 @@ +package fr.cnrs.lacito.fieldarchive.dtos; + +import java.time.OffsetDateTime; + +public class ImportResult { + public boolean success; + public String sourceName; + public long tripleCount; + public OffsetDateTime importedAt; + public String message; + + public static ImportResult success(String sourceName, long tripleCount) { + ImportResult r = new ImportResult(); + r.success = true; + r.sourceName = sourceName; + r.tripleCount = tripleCount; + r.importedAt = OffsetDateTime.now(); + return r; + } +} diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/OntologyClassDto.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/OntologyClassDto.java similarity index 88% rename from RDF_Back/src/main/java/com/uspn/rdf_back/dtos/OntologyClassDto.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/OntologyClassDto.java index b117f2ab..c732be95 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/OntologyClassDto.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/OntologyClassDto.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back.dtos; +package fr.cnrs.lacito.fieldarchive.dtos; public class OntologyClassDto { public String iri; diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/OntologyLabelDto.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/OntologyLabelDto.java similarity index 92% rename from RDF_Back/src/main/java/com/uspn/rdf_back/dtos/OntologyLabelDto.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/OntologyLabelDto.java index 92cdfda4..aeb48524 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/OntologyLabelDto.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/OntologyLabelDto.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back.dtos; +package fr.cnrs.lacito.fieldarchive.dtos; public class OntologyLabelDto { public String url; diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/ProjectDto.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/ProjectDto.java similarity index 76% rename from RDF_Back/src/main/java/com/uspn/rdf_back/dtos/ProjectDto.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/ProjectDto.java index 4d9fa567..0357ef7d 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/ProjectDto.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/ProjectDto.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back.dtos; +package fr.cnrs.lacito.fieldarchive.dtos; public class ProjectDto { public String name; @@ -6,4 +6,5 @@ public class ProjectDto { public String created; // ISO date or datetime as string public String modified; // ISO datetime as string public boolean open; + public String prefix; } \ No newline at end of file diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/RdfEntityDto.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/RdfEntityDto.java similarity index 92% rename from RDF_Back/src/main/java/com/uspn/rdf_back/dtos/RdfEntityDto.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/RdfEntityDto.java index 698369ce..2008c6c0 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/RdfEntityDto.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/RdfEntityDto.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back.dtos; +package fr.cnrs.lacito.fieldarchive.dtos; import java.util.ArrayList; import java.util.List; diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/RdfEntitySummaryDto.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/RdfEntitySummaryDto.java similarity index 82% rename from RDF_Back/src/main/java/com/uspn/rdf_back/dtos/RdfEntitySummaryDto.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/RdfEntitySummaryDto.java index 300a4d35..24fdfccc 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/RdfEntitySummaryDto.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/RdfEntitySummaryDto.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back.dtos; +package fr.cnrs.lacito.fieldarchive.dtos; public class RdfEntitySummaryDto { public String entityKey; diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/RdfPropertyDto.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/RdfPropertyDto.java similarity index 73% rename from RDF_Back/src/main/java/com/uspn/rdf_back/dtos/RdfPropertyDto.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/RdfPropertyDto.java index 1c1a08b1..39de65ca 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/RdfPropertyDto.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/RdfPropertyDto.java @@ -1,9 +1,10 @@ -package com.uspn.rdf_back.dtos; +package fr.cnrs.lacito.fieldarchive.dtos; public class RdfPropertyDto { public String predicate; // ex: "ric:hasName" ou IRI complet public String kind; // "literal" | "iri" public String value; // valeur littérale ou IRI/curie + public String name ; // when the entity is of type IRI, return its name also. public String datatype; // ex: "xsd:string" (optionnel pour literal) public String lang; // ex: "fr" (optionnel pour literal) } \ No newline at end of file diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/SaveOntologyLabelRequest.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/SaveOntologyLabelRequest.java similarity index 89% rename from RDF_Back/src/main/java/com/uspn/rdf_back/dtos/SaveOntologyLabelRequest.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/SaveOntologyLabelRequest.java index df1baa62..71e98f02 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/SaveOntologyLabelRequest.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/SaveOntologyLabelRequest.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back.dtos; +package fr.cnrs.lacito.fieldarchive.dtos; public class SaveOntologyLabelRequest { diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/UpdateDataSourceRequest.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/UpdateDataSourceRequest.java similarity index 79% rename from RDF_Back/src/main/java/com/uspn/rdf_back/dtos/UpdateDataSourceRequest.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/UpdateDataSourceRequest.java index 501249ce..36cc54b5 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/UpdateDataSourceRequest.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/UpdateDataSourceRequest.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back.dtos; +package fr.cnrs.lacito.fieldarchive.dtos; import lombok.Getter; import lombok.Setter; diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/UpdateProjectObject.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/UpdateProjectObject.java similarity index 68% rename from RDF_Back/src/main/java/com/uspn/rdf_back/dtos/UpdateProjectObject.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/UpdateProjectObject.java index a87a33dc..d505ff89 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/UpdateProjectObject.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/UpdateProjectObject.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back.dtos; +package fr.cnrs.lacito.fieldarchive.dtos; public class UpdateProjectObject { public String name; diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/UpdateRdfEntityRequest.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/UpdateRdfEntityRequest.java similarity index 84% rename from RDF_Back/src/main/java/com/uspn/rdf_back/dtos/UpdateRdfEntityRequest.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/UpdateRdfEntityRequest.java index f5dbc2d2..61e9a609 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/dtos/UpdateRdfEntityRequest.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/dtos/UpdateRdfEntityRequest.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back.dtos; +package fr.cnrs.lacito.fieldarchive.dtos; import java.util.ArrayList; import java.util.List; diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/example/Example.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/example/Example.java similarity index 93% rename from RDF_Back/src/main/java/com/uspn/rdf_back/example/Example.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/example/Example.java index 1a27fb5f..94ba822f 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/example/Example.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/example/Example.java @@ -1,6 +1,5 @@ -package com.uspn.rdf_back.example; +package fr.cnrs.lacito.fieldarchive.example; -import com.uspn.rdf_back.RdfBackApplication; import org.eclipse.rdf4j.model.*; import org.eclipse.rdf4j.model.impl.DynamicModelFactory; import org.eclipse.rdf4j.model.impl.SimpleValueFactory; @@ -9,7 +8,6 @@ import org.eclipse.rdf4j.model.vocabulary.RDF; import org.eclipse.rdf4j.rio.RDFFormat; import org.eclipse.rdf4j.rio.Rio; -import org.springframework.boot.SpringApplication; import java.io.*; diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/exception/ApiExceptionHandler.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/exception/ApiExceptionHandler.java similarity index 93% rename from RDF_Back/src/main/java/com/uspn/rdf_back/exception/ApiExceptionHandler.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/exception/ApiExceptionHandler.java index b9c87123..64d77047 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/exception/ApiExceptionHandler.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/exception/ApiExceptionHandler.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back.exception; +package fr.cnrs.lacito.fieldarchive.exception; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/exception/BadRequestException.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/exception/BadRequestException.java similarity index 72% rename from RDF_Back/src/main/java/com/uspn/rdf_back/exception/BadRequestException.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/exception/BadRequestException.java index 7b46fa2d..bab40536 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/exception/BadRequestException.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/exception/BadRequestException.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back.exception; +package fr.cnrs.lacito.fieldarchive.exception; public class BadRequestException extends RuntimeException { public BadRequestException(String msg) { super(msg); } diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/exception/ConflictException.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/exception/ConflictException.java similarity index 86% rename from RDF_Back/src/main/java/com/uspn/rdf_back/exception/ConflictException.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/exception/ConflictException.java index 0dade035..3bfd6e91 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/exception/ConflictException.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/exception/ConflictException.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back.exception; +package fr.cnrs.lacito.fieldarchive.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/exception/NotFoundException.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/exception/NotFoundException.java similarity index 71% rename from RDF_Back/src/main/java/com/uspn/rdf_back/exception/NotFoundException.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/exception/NotFoundException.java index 004d1cbf..b840bc54 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/exception/NotFoundException.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/exception/NotFoundException.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back.exception; +package fr.cnrs.lacito.fieldarchive.exception; public class NotFoundException extends RuntimeException { public NotFoundException(String msg) { super(msg); } diff --git a/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/exceptions/ImportException.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/exceptions/ImportException.java new file mode 100644 index 00000000..9dece7df --- /dev/null +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/exceptions/ImportException.java @@ -0,0 +1,21 @@ +package fr.cnrs.lacito.fieldarchive.exceptions; + +public class ImportException extends RuntimeException{ + private final Long lineNumber; + private final Long columnNumber; + + public ImportException(String message) { + super(message); + this.lineNumber = null; + this.columnNumber = null; + } + + public ImportException(long lineNumber, long columnNumber, String message) { + super(message); + this.lineNumber = lineNumber; + this.columnNumber = columnNumber; + } + + public Long getLineNumber() { return lineNumber; } + public Long getColumnNumber() { return columnNumber; } +} diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/services/BuiltinOntologyService.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/services/BuiltinOntologyService.java similarity index 95% rename from RDF_Back/src/main/java/com/uspn/rdf_back/services/BuiltinOntologyService.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/services/BuiltinOntologyService.java index c45f772b..3b6a98c3 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/services/BuiltinOntologyService.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/services/BuiltinOntologyService.java @@ -1,12 +1,12 @@ -package com.uspn.rdf_back.services; - -import com.uspn.rdf_back.core.ProjectContext; -import com.uspn.rdf_back.core.RdfContexts; -import com.uspn.rdf_back.core.RdfNamespaces; -import com.uspn.rdf_back.dtos.OntologyClassDto; -import com.uspn.rdf_back.dtos.OntologyLabelDto; -import com.uspn.rdf_back.exception.BadRequestException; -import com.uspn.rdf_back.exception.NotFoundException; +package fr.cnrs.lacito.fieldarchive.services; + +import fr.cnrs.lacito.fieldarchive.core.ProjectContext; +import fr.cnrs.lacito.fieldarchive.core.RdfContexts; +import fr.cnrs.lacito.fieldarchive.core.RdfNamespaces; +import fr.cnrs.lacito.fieldarchive.dtos.OntologyClassDto; +import fr.cnrs.lacito.fieldarchive.dtos.OntologyLabelDto; +import fr.cnrs.lacito.fieldarchive.exception.BadRequestException; +import fr.cnrs.lacito.fieldarchive.exception.NotFoundException; import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.Statement; import org.eclipse.rdf4j.model.Value; diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/services/DataSourceService.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/services/DataSourceService.java similarity index 93% rename from RDF_Back/src/main/java/com/uspn/rdf_back/services/DataSourceService.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/services/DataSourceService.java index fc7299b4..b57868a1 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/services/DataSourceService.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/services/DataSourceService.java @@ -1,15 +1,14 @@ -package com.uspn.rdf_back.services; - -import com.uspn.rdf_back.core.ProjectContext; -import com.uspn.rdf_back.core.RdfContexts; -import com.uspn.rdf_back.core.RdfNamespaces; -import com.uspn.rdf_back.dtos.CreateInternalDataSourceRequest; -import com.uspn.rdf_back.dtos.CreateExternalDataSourceRequest; -import com.uspn.rdf_back.dtos.DataSourceDto; -import com.uspn.rdf_back.dtos.UpdateDataSourceRequest; -import com.uspn.rdf_back.exception.BadRequestException; -import com.uspn.rdf_back.exception.ConflictException; -import com.uspn.rdf_back.exception.NotFoundException; +package fr.cnrs.lacito.fieldarchive.services; + +import fr.cnrs.lacito.fieldarchive.core.ProjectContext; +import fr.cnrs.lacito.fieldarchive.core.RdfContexts; +import fr.cnrs.lacito.fieldarchive.core.RdfNamespaces; +import fr.cnrs.lacito.fieldarchive.dtos.CreateInternalDataSourceRequest; +import fr.cnrs.lacito.fieldarchive.dtos.CreateExternalDataSourceRequest; +import fr.cnrs.lacito.fieldarchive.dtos.DataSourceDto; +import fr.cnrs.lacito.fieldarchive.dtos.UpdateDataSourceRequest; +import fr.cnrs.lacito.fieldarchive.exception.BadRequestException; +import fr.cnrs.lacito.fieldarchive.exception.NotFoundException; import org.eclipse.rdf4j.model.*; import org.eclipse.rdf4j.model.impl.SimpleValueFactory; import org.eclipse.rdf4j.model.vocabulary.DCTERMS; @@ -20,12 +19,10 @@ import org.springframework.stereotype.Service; import java.time.OffsetDateTime; -import java.time.LocalDate; import java.util.ArrayList; import java.util.List; import org.eclipse.rdf4j.rio.RDFFormat; -import org.eclipse.rdf4j.rio.Rio; import org.springframework.web.server.ResponseStatusException; import java.io.InputStream; @@ -44,7 +41,7 @@ private IRI metaCtx() { } private IRI dsIri(String shortName) { - return vf.createIRI(RdfNamespaces.APP + "datasource/" + shortName); + return vf.createIRI(RdfNamespaces.APP + "/datasource/" + shortName); } /** Graphe nommé (contexte) où seront stockés les triplets "contenu" de la source */ @@ -508,4 +505,19 @@ public void synchronizeExternalDataSource(String shortName) { } } + public IRI getGraphIri(String shortName) { + requireProjectOpen(); + validateShortName(shortName); + + IRI ctxMeta = metaCtx(); + IRI ds = dsIri(shortName); + + try (RepositoryConnection conn = ProjectContext.getRepository().getConnection()) { + String graphIri = getIri(conn, ds, pGraph(), ctxMeta); + if (graphIri == null) { + throw new NotFoundException("No graph found for source : " + shortName); + } + return vf.createIRI(graphIri); + } + } } \ No newline at end of file diff --git a/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/services/FileExportService.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/services/FileExportService.java new file mode 100644 index 00000000..3532fb3f --- /dev/null +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/services/FileExportService.java @@ -0,0 +1,109 @@ +package fr.cnrs.lacito.fieldarchive.services; + +import fr.cnrs.lacito.fieldarchive.core.ProjectContext; +import fr.cnrs.lacito.fieldarchive.core.RdfContexts; +import fr.cnrs.lacito.fieldarchive.exceptions.ImportException; +import org.eclipse.rdf4j.model.IRI; +import org.eclipse.rdf4j.model.Statement; +import org.eclipse.rdf4j.model.ValueFactory; +import org.eclipse.rdf4j.model.impl.SimpleValueFactory; +import org.eclipse.rdf4j.repository.Repository; +import org.eclipse.rdf4j.repository.RepositoryConnection; +import org.eclipse.rdf4j.repository.RepositoryResult; +import org.eclipse.rdf4j.rio.RDFFormat; +import org.eclipse.rdf4j.rio.RDFWriter; +import org.eclipse.rdf4j.rio.Rio; +import org.springframework.stereotype.Service; + +import java.io.OutputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +@Service +public class FileExportService { + private static final ValueFactory vf = SimpleValueFactory.getInstance(); + private final ProjectService projectService; + private final DataSourceService dsService; + + public FileExportService(ProjectService projectService,DataSourceService dsService) { + this.projectService = projectService; + this.dsService = dsService; + } + + /** + * Exports only the InternalDataSource named graph (the data the user + * actually created/imported in the app) as plain Turtle triples. + * The named graph itself is NOT part of the output — Turtle has no + * notion of context, so the statements come out as bare triples, + * ready to be fed into any other RDF-consuming application. + */ + public void exportInternalDataSource(OutputStream out) { + Repository repo = ProjectContext.getRepository(); + if (repo == null) { + throw new ImportException("No project opened"); + } + + String projectName = projectService.readCurrentProject().name; + IRI ctxInternal = dsService.getGraphIri(projectName + "_internal"); // ✅ idem + + try (RepositoryConnection conn = repo.getConnection()) { + RDFWriter writer = Rio.createWriter(RDFFormat.TURTLE, out); + + conn.begin(); + writer.startRDF(); + + try (RepositoryResult statements = + conn.getStatements(null, null, null, false, ctxInternal)) { + for (Statement st : statements) { + // Re-emit as a context-free statement so the writer never + // even sees the graph — belt and braces alongside Turtle's + // own lack of context support. + writer.handleStatement( + vf.createStatement(st.getSubject(), st.getPredicate(), st.getObject())); + } + } + + writer.endRDF(); + conn.commit(); + } catch (Exception e) { + throw new ImportException("Export failed: " + e.getMessage()); + } + } + + public void exportBackup(OutputStream zipOut) { + Repository repo = ProjectContext.getRepository(); + if (repo == null) { + throw new ImportException("No project opened"); + } + + String projectName = projectService.readCurrentProject().name; + IRI ctxInternal = dsService.getGraphIri(projectName + "_internal"); // ✅ + IRI ctxMeta = vf.createIRI(RdfContexts.CTX_META); + IRI ctxProjectMeta = projectService.getMetadataContext(projectName, vf); // ✅ ajouté + + try (RepositoryConnection conn = repo.getConnection()) { + ZipOutputStream zip = new ZipOutputStream(zipOut); + zip.putNextEntry(new ZipEntry(projectName+"/project-backup.trig")); + + RDFWriter writer = Rio.createWriter(RDFFormat.TRIG, zip); + + conn.begin(); + writer.startRDF(); + + try (RepositoryResult statements = + conn.getStatements(null, null, null, false, ctxInternal, ctxMeta,ctxProjectMeta)) { + for (Statement st : statements) { + writer.handleStatement(st); // keep context — this is a quad export + } + } + + writer.endRDF(); + conn.commit(); + + zip.closeEntry(); + zip.finish(); + } catch (Exception e) { + throw new ImportException("Backup export failed: " + e.getMessage()); + } + } +} diff --git a/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/services/FileImportService.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/services/FileImportService.java new file mode 100644 index 00000000..06f6c0f7 --- /dev/null +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/services/FileImportService.java @@ -0,0 +1,144 @@ +package fr.cnrs.lacito.fieldarchive.services; + +import fr.cnrs.lacito.fieldarchive.core.ProjectContext; +import fr.cnrs.lacito.fieldarchive.dtos.ImportResult; +import fr.cnrs.lacito.fieldarchive.exceptions.ImportException; +import org.eclipse.rdf4j.model.IRI; +import org.eclipse.rdf4j.model.ValueFactory; +import org.eclipse.rdf4j.model.impl.SimpleValueFactory; +import org.eclipse.rdf4j.repository.Repository; +import org.eclipse.rdf4j.repository.RepositoryConnection; +import org.eclipse.rdf4j.repository.util.RDFInserter; +import org.eclipse.rdf4j.rio.RDFFormat; +import org.eclipse.rdf4j.rio.RDFParseException; +import org.eclipse.rdf4j.rio.RDFParser; +import org.eclipse.rdf4j.rio.Rio; +import org.eclipse.rdf4j.rio.helpers.BasicParserSettings; +import org.springframework.stereotype.Service; + +import java.io.InputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; + +@Service +public class FileImportService { + + private static final ValueFactory vf = SimpleValueFactory.getInstance(); + private final ProjectService projectService; + private final DataSourceService dsService; + private final BuiltinOntologyService builtinOntologyService; // ✅ pour recharger RICO après restauration + + public FileImportService(ProjectService projectService, + DataSourceService dsService, + BuiltinOntologyService builtinOntologyService + ) { + this.projectService = projectService; + this.dsService = dsService; + this.builtinOntologyService = builtinOntologyService; + } + + public ImportResult importTurtle(InputStream ttlStream, String baseURI) { + Repository repo = ProjectContext.getRepository(); + if (repo == null) { + throw new ImportException("No project opened"); + } +// IRI CTX_INTERNAL = SimpleValueFactory.getInstance() +// .createIRI("http://fieldarchive.local/source/" + sourceName); +// IRI CTX_INTERNAL = vf.createIRI("urn:datasource:"+this.projectService.readCurrentProject().prefix+"_internal"); + String projectName = projectService.readCurrentProject().name; + IRI CTX_INTERNAL = dsService.getGraphIri(projectName + "_internal"); // ✅ lu depuis les métadonnées + + try (RepositoryConnection conn = repo.getConnection()) { + conn.begin(); + + // Re-import semantics: wipe the named graph before reloading +// conn.clear(CTX_INTERNAL); + + RDFInserter inserter = new RDFInserter(conn); + inserter.enforceContext(CTX_INTERNAL); // force every triple into this named graph + + RDFParser parser = Rio.createParser(RDFFormat.TURTLE); + parser.setRDFHandler(inserter); + parser.getParserConfig() + .set(BasicParserSettings.VERIFY_RELATIVE_URIS, false); + + parser.parse(ttlStream, baseURI); + + conn.commit(); + return ImportResult.success(CTX_INTERNAL.stringValue(), conn.size(CTX_INTERNAL)); + } catch (RDFParseException e) { + // line/column info is on the exception — surface it to the frontend + throw new ImportException(e.getLineNumber(), e.getColumnNumber(), e.getMessage()); + } catch (Exception e) { + throw new ImportException("Import failed: " + e.getMessage()); + } + } + + /* Restaure un projet depuis un backup (.zip contenant un .trig avec + * les graphes InternalDataSource + métadonnées projet/datasource). + * Le nom du projet est déduit du chemin interne du zip + * (dossier parent de project-backup.trig), pas du nom de fichier uploadé. + */ + public ImportResult importBackup(InputStream zipStream) { + byte[] trigContent = null; + String projectName = null; + + try (ZipInputStream zip = new ZipInputStream(zipStream)) { + ZipEntry entry; + while ((entry = zip.getNextEntry()) != null) { + if (entry.getName().endsWith("project-backup.trig")) { + // ex: "archive2025/project-backup.trig" → "archive2025" + String entryPath = entry.getName(); + int slash = entryPath.lastIndexOf('/'); + if (slash <= 0) { + throw new ImportException("Invalid Backup Project : Can't find project's name."); + } + projectName = entryPath.substring(0, slash); + + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + zip.transferTo(buffer); + trigContent = buffer.toByteArray(); + break; + } + } + } catch (Exception e) { + throw new ImportException("Cannot read the archive : " + e.getMessage()); + } + + if (trigContent == null || projectName == null) { + throw new ImportException("No file project-backup.trig found."); + } + + // 1) Create a new empty repo (fails if already exists) + projectService.initEmptyProjectRepository(projectName, true); + + Repository repo = ProjectContext.getRepository(); + + try (RepositoryConnection conn = repo.getConnection()) { + conn.begin(); + + try (InputStream trigStream = new ByteArrayInputStream(trigContent)) { + RDFParser parser = Rio.createParser(RDFFormat.TRIG); + parser.getParserConfig().set(BasicParserSettings.VERIFY_URI_SYNTAX, false); // ✅ tolère les IRIs non strictement conformes (double '#') + parser.getParserConfig().set(BasicParserSettings.VERIFY_RELATIVE_URIS, false); + + RDFInserter inserter = new RDFInserter(conn); // pas de enforceContext() : conserve les graphes tels qu'écrits dans le .trig + parser.setRDFHandler(inserter); + parser.parse(trigStream, ""); + } + + conn.commit(); + } catch (Exception e) { + throw new ImportException("Failed to extract backup project's content: " + e.getMessage()); + } + + // 3) Recharger l'ontologie RICO — absente du backup, l'app en a besoin. + // ensureRicoLoaded() est idempotent : il ne réécrit rien si déjà présent. + builtinOntologyService.ensureRicoLoaded(); + + return ImportResult.success(projectName, repo.getConnection().size()); + } + +} diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/services/OntologyService.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/services/OntologyService.java similarity index 95% rename from RDF_Back/src/main/java/com/uspn/rdf_back/services/OntologyService.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/services/OntologyService.java index 66b18faf..98577bd2 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/services/OntologyService.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/services/OntologyService.java @@ -1,12 +1,12 @@ -package com.uspn.rdf_back.services; - -import com.uspn.rdf_back.core.ProjectContext; -import com.uspn.rdf_back.core.RdfContexts; -import com.uspn.rdf_back.core.RdfNamespaces; -import com.uspn.rdf_back.dtos.OntologyLabelDto; -import com.uspn.rdf_back.dtos.SaveOntologyLabelRequest; -import com.uspn.rdf_back.exception.BadRequestException; -import com.uspn.rdf_back.exception.NotFoundException; +package fr.cnrs.lacito.fieldarchive.services; + +import fr.cnrs.lacito.fieldarchive.core.ProjectContext; +import fr.cnrs.lacito.fieldarchive.core.RdfContexts; +import fr.cnrs.lacito.fieldarchive.core.RdfNamespaces; +import fr.cnrs.lacito.fieldarchive.dtos.OntologyLabelDto; +import fr.cnrs.lacito.fieldarchive.dtos.SaveOntologyLabelRequest; +import fr.cnrs.lacito.fieldarchive.exception.BadRequestException; +import fr.cnrs.lacito.fieldarchive.exception.NotFoundException; import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.Statement; import org.eclipse.rdf4j.model.Value; diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/services/ProjectService.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/services/ProjectService.java similarity index 77% rename from RDF_Back/src/main/java/com/uspn/rdf_back/services/ProjectService.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/services/ProjectService.java index 223e446a..8a2d100a 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/services/ProjectService.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/services/ProjectService.java @@ -1,10 +1,10 @@ -package com.uspn.rdf_back.services; +package fr.cnrs.lacito.fieldarchive.services; -import com.uspn.rdf_back.core.ProjectContext; -import com.uspn.rdf_back.core.RdfContexts; -import com.uspn.rdf_back.core.RdfNamespaces; -import com.uspn.rdf_back.dtos.ProjectDto; -import com.uspn.rdf_back.dtos.UpdateProjectObject; +import fr.cnrs.lacito.fieldarchive.core.ProjectContext; +import fr.cnrs.lacito.fieldarchive.core.RdfContexts; +import fr.cnrs.lacito.fieldarchive.core.RdfNamespaces; +import fr.cnrs.lacito.fieldarchive.dtos.CreateInternalDataSourceRequest; +import fr.cnrs.lacito.fieldarchive.dtos.ProjectDto; import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.ValueFactory; import org.eclipse.rdf4j.model.vocabulary.DCTERMS; @@ -31,26 +31,90 @@ @Service public class ProjectService { + private final DataSourceService dsService ; + private static final IRI TYPE_PROJECT = org.eclipse.rdf4j.model.impl.SimpleValueFactory.getInstance() .createIRI(RdfNamespaces.APP, "Project"); - public ProjectService(BuiltinOntologyService builtinOntologyService) { + private static final IRI PROP_PREFIX = org.eclipse.rdf4j.model.impl.SimpleValueFactory.getInstance() + .createIRI(RdfNamespaces.APP, "prefix"); + + public ProjectService(BuiltinOntologyService builtinOntologyService, DataSourceService dsService ) { this.builtinOntologyService = builtinOntologyService; + this.dsService = dsService; + } + + private IRI projectIri(String projectName, ValueFactory vf) { + return vf.createIRI(RdfNamespaces.APP + "/projects#" + projectName); } - private IRI projectIri(ValueFactory vf, String projectName) { - return vf.createIRI(RdfNamespaces.APP + "project/" + projectName); + private IRI metadataCtx(String projectName, ValueFactory vf) { + return vf.createIRI(RdfNamespaces.APP + "/projects#" +projectName+"/metadata"); } - private IRI metadataCtx(ValueFactory vf) { - return vf.createIRI(RdfContexts.CTX_META); + public IRI getMetadataContext(String projectName, ValueFactory vf) { + return metadataCtx(projectName, vf); } private final BuiltinOntologyService builtinOntologyService; + + public void initEmptyProjectRepository(String name, boolean persistent) { + if (name == null || name.isBlank()) { + throw new IllegalArgumentException("Project's name should not be empty !"); + } + + Path path = Paths.get("projects", name); + if (Files.exists(path)) { + throw new IllegalArgumentException("A project with name \"" + name + "\" already exists."); + } + + ProjectContext.close(); + + Repository repo = createRepository(name, persistent); + repo.init(); + ProjectContext.set(repo, name); + } + + + public ProjectDto createProject(String name, boolean persistent, String description, String prefix) { + + if (name == null || name.isBlank()) { + throw new IllegalArgumentException("Project's name should not be empty !"); + } + + // 1) Fermer un projet déjà ouvert + ProjectContext.close(); + + // 2) Créer / ouvrir le store + Repository repo = createRepository(name, persistent); + repo.init(); + ProjectContext.set(repo, name); + + try { + // 3) Écrire (ou mettre à jour) les métadonnées RDF du projet + upsertProjectMetadata(name, description, prefix); + + // 4) Charger automatiquement RiC-O dans le projet + builtinOntologyService.ensureRicoLoaded(); + + CreateInternalDataSourceRequest dataSourceCreationRequest = new CreateInternalDataSourceRequest(name+"_internal",name+" internal DataSource ",""); + this.dsService.createInternalDataSource(dataSourceCreationRequest); + + // 5) Retour DTO + return readCurrentProject(); + } + + catch (RuntimeException e) { + ProjectContext.close(); + throw e; + } + + } + /** * Ouvre (ou crée) le repository RDF4J du projet et écrit les métadonnées du projet en RDF. */ - public ProjectDto openProject(String name, boolean persistent, String description) { + public ProjectDto openProject(String name, boolean persistent, String description, String prefix) { if (name == null || name.isBlank()) { throw new IllegalArgumentException("Project's name should not be empty !"); } @@ -65,7 +129,7 @@ public ProjectDto openProject(String name, boolean persistent, String descriptio try { // 3) Écrire (ou mettre à jour) les métadonnées RDF du projet - upsertProjectMetadata(name, description); + upsertProjectMetadata(name, description, prefix ); // 4) Charger automatiquement RiC-O dans le projet builtinOntologyService.ensureRicoLoaded(); @@ -90,6 +154,9 @@ public void deleteProject(String projectName) throws IOException { if (projectName == null || projectName.isBlank()) { throw new IllegalArgumentException("Project name must not be empty"); } + if (projectName.equals(ProjectContext.getProjectName())) { + ProjectContext.close(); + } Path path = Paths.get("projects", projectName); @@ -115,12 +182,12 @@ public void deleteProject(String projectName) throws IOException { } } - private void upsertProjectMetadata(String projectName, String description) { + private void upsertProjectMetadata(String projectName, String description, String prefix) { Repository repo = ProjectContext.getRepository(); try (RepositoryConnection conn = repo.getConnection()) { ValueFactory vf = conn.getValueFactory(); - IRI project = projectIri(vf, projectName); - IRI ctx = metadataCtx(vf); + IRI project = projectIri(projectName,vf); + IRI ctx = metadataCtx(projectName,vf); String now = OffsetDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); String today = LocalDate.now().toString(); @@ -148,6 +215,11 @@ private void upsertProjectMetadata(String projectName, String description) { conn.add(project, DCTERMS.DESCRIPTION, vf.createLiteral(description), ctx); } + if (prefix != null) { + conn.remove(project, PROP_PREFIX, null, ctx); + conn.add(project, PROP_PREFIX, vf.createLiteral(prefix), ctx); + } + conn.commit(); } } @@ -203,9 +275,9 @@ public void updateProject(String oldName, String newName, String newDescription) try (RepositoryConnection conn = repo.getConnection()) { ValueFactory vf = conn.getValueFactory(); - IRI oldProject = projectIri(vf, oldName); - IRI newProject = projectIri(vf, newName); - IRI ctx = metadataCtx(vf); + IRI oldProject = projectIri(oldName,vf); + IRI newProject = projectIri(newName,vf); + IRI ctx = metadataCtx(newName,vf); conn.begin(); @@ -255,8 +327,8 @@ public ProjectDto readCurrentProject() { try (RepositoryConnection conn = ProjectContext.getRepository().getConnection()) { ValueFactory vf = conn.getValueFactory(); - IRI project = projectIri(vf, name); - IRI ctx = metadataCtx(vf); + IRI project = projectIri(name,vf); + IRI ctx = metadataCtx(name,vf); // read description var descSt = conn.getStatements(project, DCTERMS.DESCRIPTION, null, ctx).stream().findFirst().orElse(null); @@ -267,6 +339,11 @@ public ProjectDto readCurrentProject() { var modifiedSt = conn.getStatements(project, DCTERMS.MODIFIED, null, ctx).stream().findFirst().orElse(null); dto.modified = (modifiedSt != null) ? modifiedSt.getObject().stringValue() : null; + + var prefix = conn.getStatements(project, PROP_PREFIX, null, ctx).stream().findFirst().orElse(null); + dto.prefix = (prefix != null) ? prefix.getObject().stringValue() : null; + + } return dto; @@ -338,6 +415,8 @@ public List> listProjectsDetailed() { info.put("description", null); info.put("created", null); info.put("lastModified", new java.util.Date(dir.lastModified())); + info.put("prefix", "NOT_FOUND"); + } finally { tempRepo.shutDown(); } @@ -354,12 +433,14 @@ public List> listProjectsDetailed() { private void readMetadataFromRepo(Repository repo, String projectName, Map info) { try (RepositoryConnection conn = repo.getConnection()) { ValueFactory vf = conn.getValueFactory(); - IRI project = projectIri(vf, projectName); // même helper que upsertProjectMetadata - IRI ctx = metadataCtx(vf); // même helper que upsertProjectMetadata + IRI project = projectIri(projectName,vf); // même helper que upsertProjectMetadata + IRI ctx = metadataCtx(projectName,vf); // même helper que upsertProjectMetadata info.put("description", getStringValue(conn, project, DCTERMS.DESCRIPTION, ctx)); info.put("created", getStringValue(conn, project, DCTERMS.CREATED, ctx)); info.put("lastModified", getStringValue(conn, project, DCTERMS.MODIFIED, ctx)); + info.put("prefix", getStringValue(conn, project, PROP_PREFIX, ctx)); + } } diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/services/RdfEntityService.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/services/RdfEntityService.java similarity index 72% rename from RDF_Back/src/main/java/com/uspn/rdf_back/services/RdfEntityService.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/services/RdfEntityService.java index f6a276d1..238990b5 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/services/RdfEntityService.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/services/RdfEntityService.java @@ -1,10 +1,12 @@ -package com.uspn.rdf_back.services; - -import com.uspn.rdf_back.core.ProjectContext; -import com.uspn.rdf_back.core.RdfNamespaces; -import com.uspn.rdf_back.dtos.*; -import com.uspn.rdf_back.exception.BadRequestException; -import com.uspn.rdf_back.exception.NotFoundException; +package fr.cnrs.lacito.fieldarchive.services; + +import fr.cnrs.lacito.fieldarchive.core.ProjectContext; +import fr.cnrs.lacito.fieldarchive.core.RdfContexts; +import fr.cnrs.lacito.fieldarchive.core.RdfNamespaces; +import fr.cnrs.lacito.fieldarchive.dtos.*; +import fr.cnrs.lacito.fieldarchive.dtos.*; +import fr.cnrs.lacito.fieldarchive.exception.BadRequestException; +import fr.cnrs.lacito.fieldarchive.exception.NotFoundException; import org.eclipse.rdf4j.model.*; import org.eclipse.rdf4j.model.impl.SimpleValueFactory; import org.eclipse.rdf4j.model.vocabulary.RDF; @@ -17,24 +19,46 @@ @Service public class RdfEntityService { - private static final String ENTITY_NS = RdfNamespaces.APP + "entity/"; - private IRI iriFromKey(String key) { - return vf.createIRI(ENTITY_NS + key); + private static final ValueFactory vf = SimpleValueFactory.getInstance(); + + private final ProjectService projectService; + private final DataSourceService dsService; + + public RdfEntityService(ProjectService projectService, DataSourceService dsService) { + this.projectService = projectService; + this.dsService = dsService; + } + private IRI internalCtx() { + String projectName = projectService.readCurrentProject().name; + return dsService.getGraphIri(projectName + "_internal"); + } + + private IRI iriFromKey(String entityIri, String key) { + String entityTypeName = entityIri.replace(RdfNamespaces.RICO,""); + ProjectDto currentProject = this.projectService.readCurrentProject(); + return vf.createIRI(currentProject.prefix + '/' + entityTypeName +'/' + key); } private String keyFromIri(IRI iri) { String s = iri.stringValue(); - if (!s.startsWith(ENTITY_NS)) { - throw new IllegalArgumentException("IRI invalide: " + s); + String entityNs = projectService.readCurrentProject().prefix; + +// || !s.startsWith(entityNs) + if (entityNs == null ) { + throw new IllegalArgumentException("invalid IRI: " + s); + } + + int lastSlash = s.lastIndexOf('/'); + + if (lastSlash == -1 || lastSlash == s.length() - 1) { + throw new IllegalArgumentException("IRI mal formée (pas de clé): " + s); } - return s.substring(ENTITY_NS.length()); + + return s.substring(lastSlash + 1); } - private static final ValueFactory vf = SimpleValueFactory.getInstance(); - // Graphe interne éditable (aligné avec ton implémentation actuelle) - private static final IRI CTX_INTERNAL = vf.createIRI("urn:datasource:internal"); // Prefixes acceptés par l’API (CURIE -> IRI) private static final Map PREFIX = Map.of( @@ -71,6 +95,8 @@ private String expand(String iriOrCurie) { private boolean isInternalEntity(RepositoryConnection conn, IRI subject) { // Si l'entité a au moins un triplet dans le graphe interne, on la considère interne/éditable + IRI CTX_INTERNAL = internalCtx(); + try (var stmts = conn.getStatements(subject, null, null, CTX_INTERNAL)) { return stmts.hasNext(); } @@ -123,17 +149,18 @@ public List listTypes() { // ========================= public RdfEntityDto create(CreateRdfEntityRequest req) { requireProjectOpen(); - if (req == null) throw new BadRequestException("Body manquant."); + if (req == null) throw new BadRequestException("Body is missing."); if (req.types == null || req.types.isEmpty()) { - throw new BadRequestException("types obligatoire (au moins 1 rdf:type)."); + throw new BadRequestException("Entity type is mandatory (at least one)"); } String entityKey = UUID.randomUUID().toString(); - IRI subject = iriFromKey(entityKey); + IRI subject = iriFromKey(req.types.get(0),entityKey); try (RepositoryConnection conn = ProjectContext.getRepository().getConnection()) { conn.begin(); + IRI CTX_INTERNAL = internalCtx(); // rdf:type for (String t : req.types) { @@ -151,7 +178,7 @@ public RdfEntityDto create(CreateRdfEntityRequest req) { conn.commit(); } - return getByKey(entityKey); + return getByIri(subject); } @@ -163,7 +190,7 @@ private void addProperty(RepositoryConnection conn, IRI subject, RdfPropertyDto if (p.kind == null || p.kind.isBlank()) { throw new BadRequestException("Predicate's kind is mandatory (literal|iri)."); } - + IRI CTX_INTERNAL = internalCtx(); IRI pred = vf.createIRI(expand(p.predicate)); if ("iri".equalsIgnoreCase(p.kind)) { @@ -198,7 +225,7 @@ public List listByType(String typeCurieOrIri) { requireProjectOpen(); if (typeCurieOrIri == null || typeCurieOrIri.isBlank()) { - throw new BadRequestException("Paramètre type obligatoire."); + throw new BadRequestException("Type parameter is mandatory."); } IRI typeIri = vf.createIRI(expand(typeCurieOrIri)); @@ -235,19 +262,66 @@ public List listByType(String typeCurieOrIri) { // ========================= // READ ONE // ========================= +// public RdfEntityDto getByKey(String key) { +// requireProjectOpen(); +// if (key == null || key.isBlank()) { +// throw new BadRequestException("entityKey manquant."); +// } +// IRI subject = iriFromKey(key); +// return getByIri(subject); +// } + + public String getNameOfEntityByIri(IRI subject) { + requireProjectOpen(); + if (subject == null) { + throw new BadRequestException("IRI manquant."); + } + try (RepositoryConnection conn = ProjectContext.getRepository().getConnection()) { + boolean exists; + try (var st = conn.getStatements(subject, null, null)) { + exists = st.hasNext(); + } + if (!exists) throw new NotFoundException("Entité introuvable: " + subject.stringValue()); + IRI CTX_INTERNAL = internalCtx(); + // properties (on renvoie tout ce qu’on trouve) + // Lire toutes les propriétés + try (var stmts = conn.getStatements(subject, null, null, CTX_INTERNAL)) { + while (stmts.hasNext()) { + Statement st = stmts.next(); + IRI pred = st.getPredicate(); + Value obj = st.getObject(); + + // Ignore rdf:type (déjà traité) + String predicateString = pred.stringValue(); + if (!predicateString.equals("https://www.ica.org/standards/RiC/ontology#name") ) continue; + + + if (obj.isLiteral()) { + Literal lit = (Literal) obj; + return lit.getLabel(); + + } + + + } + } + } + return ""; + + } + public RdfEntityDto getByKey(String key) { - requireProjectOpen(); if (key == null || key.isBlank()) { - throw new BadRequestException("entityKey manquant."); + throw new BadRequestException("IRI is missing."); } - IRI subject = iriFromKey(key); - return getByIri(subject); + return getByIri(vf.createIRI(key)); } + public RdfEntityDto getByIri(IRI subject) { requireProjectOpen(); if (subject == null) { - throw new BadRequestException("IRI manquant."); + throw new BadRequestException("IRI is missing."); } try (RepositoryConnection conn = ProjectContext.getRepository().getConnection()) { @@ -273,6 +347,7 @@ public RdfEntityDto getByIri(IRI subject) { // properties (on renvoie tout ce qu’on trouve) // Lire toutes les propriétés + IRI CTX_INTERNAL = internalCtx(); try (var stmts = conn.getStatements(subject, null, null, CTX_INTERNAL)) { while (stmts.hasNext()) { Statement st = stmts.next(); @@ -288,6 +363,7 @@ public RdfEntityDto getByIri(IRI subject) { if (obj.isIRI()) { p.kind = "iri"; p.value = obj.stringValue(); + p.name = this.getNameOfEntityByIri((IRI) obj); } else if (obj.isLiteral()) { Literal lit = (Literal) obj; @@ -318,18 +394,18 @@ public RdfEntityDto getByIri(IRI subject) { // ========================= // UPDATE (interne uniquement) // ========================= - public RdfEntityDto updateByKey(String key, UpdateRdfEntityRequest req) { + public RdfEntityDto updateByKey(String entityIri, UpdateRdfEntityRequest req) { requireProjectOpen(); - if (key == null || key.isBlank()) { + if (entityIri == null || entityIri.isBlank()) { throw new BadRequestException("entityKey manquant."); } if (req == null) { throw new BadRequestException("Body manquant."); } - IRI subject = iriFromKey(key); + IRI subject = vf.createIRI(entityIri); try (RepositoryConnection conn = ProjectContext.getRepository().getConnection()) { @@ -339,7 +415,7 @@ public RdfEntityDto updateByKey(String key, UpdateRdfEntityRequest req) { exists = st.hasNext(); } if (!exists) { - throw new NotFoundException("Entité introuvable: " + key); + throw new NotFoundException("Entity not found : " + entityIri); } // 2 Vérifier éditable @@ -360,7 +436,7 @@ public RdfEntityDto updateByKey(String key, UpdateRdfEntityRequest req) { } IRI pred = vf.createIRI(expand(p.predicate)); - + IRI CTX_INTERNAL = internalCtx(); // Supprimer anciennes valeurs dans le graphe interne conn.remove(subject, pred, null, CTX_INTERNAL); @@ -377,20 +453,20 @@ public RdfEntityDto updateByKey(String key, UpdateRdfEntityRequest req) { conn.commit(); } - return getByKey(key); + return getByIri(subject); } // DELETE (interne uniquement) // ========================= - public void deleteByKey(String key) { + public void deleteByKey(String entityIri) { requireProjectOpen(); - if (key == null || key.isBlank()) { + if (entityIri == null || entityIri.isBlank()) { throw new BadRequestException("entityKey manquant."); } - IRI subject = iriFromKey(key); + IRI subject = vf.createIRI(entityIri); try (RepositoryConnection conn = ProjectContext.getRepository().getConnection()) { @@ -400,16 +476,16 @@ public void deleteByKey(String key) { exists = st.hasNext(); } if (!exists) { - throw new NotFoundException("Entité introuvable: " + key); + throw new NotFoundException("Entity not found: " + entityIri); } // 2 Vérifier éditable if (!isInternalEntity(conn, subject)) { throw new BadRequestException( - "Suppression interdite : entité provenant d'une source externe." + "Deletion of entity is not allowed : Entity is from an external DataSource" ); } - + IRI CTX_INTERNAL = internalCtx(); conn.begin(); // 3 Supprimer UNIQUEMENT dans la source interne //Supprimer tous les triplets où l'entité est SUJET @@ -428,16 +504,13 @@ public void deleteByKey(String key) { private void touchInternalDataSource(RepositoryConnection conn) { - IRI ctxMeta = vf.createIRI("urn:datasource:meta"); - IRI ds = vf.createIRI("http://uspn.fr/app#datasource/internal"); + IRI ctxMeta = vf.createIRI(RdfContexts.CTX_META); + String projectName = projectService.readCurrentProject().name; + IRI ds = vf.createIRI(RdfNamespaces.APP + "/datasource/" + projectName + "_internal"); String now = OffsetDateTime.now().toString(); - conn.remove(ds, vf.createIRI("http://purl.org/dc/terms/modified"), null, ctxMeta); - conn.add(ds, - vf.createIRI("http://purl.org/dc/terms/modified"), - vf.createLiteral(now), - ctxMeta); + conn.add(ds, vf.createIRI("http://purl.org/dc/terms/modified"), vf.createLiteral(now), ctxMeta); } } \ No newline at end of file diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/services/SparqlService.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/services/SparqlService.java similarity index 94% rename from RDF_Back/src/main/java/com/uspn/rdf_back/services/SparqlService.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/services/SparqlService.java index 0b0b211f..31f15a8c 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/services/SparqlService.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/services/SparqlService.java @@ -1,7 +1,7 @@ -package com.uspn.rdf_back.services; +package fr.cnrs.lacito.fieldarchive.services; -import com.uspn.rdf_back.core.ProjectContext; -import com.uspn.rdf_back.exception.BadRequestException; +import fr.cnrs.lacito.fieldarchive.core.ProjectContext; +import fr.cnrs.lacito.fieldarchive.exception.BadRequestException; import org.eclipse.rdf4j.query.QueryLanguage; import org.eclipse.rdf4j.query.TupleQueryResult; import org.eclipse.rdf4j.query.Update; diff --git a/RDF_Back/src/main/java/com/uspn/rdf_back/utils/CsvFileHandler.java b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/utils/CsvFileHandler.java similarity index 95% rename from RDF_Back/src/main/java/com/uspn/rdf_back/utils/CsvFileHandler.java rename to Backend/src/main/java/fr/cnrs/lacito/fieldarchive/utils/CsvFileHandler.java index e9b08343..e08e2547 100644 --- a/RDF_Back/src/main/java/com/uspn/rdf_back/utils/CsvFileHandler.java +++ b/Backend/src/main/java/fr/cnrs/lacito/fieldarchive/utils/CsvFileHandler.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back.utils; +package fr.cnrs.lacito.fieldarchive.utils; import org.springframework.stereotype.Service; diff --git a/RDF_Back/src/main/resources/application.properties b/Backend/src/main/resources/application.properties similarity index 100% rename from RDF_Back/src/main/resources/application.properties rename to Backend/src/main/resources/application.properties diff --git a/RDF_Back/src/main/resources/ontologies/rico.rdf b/Backend/src/main/resources/ontologies/rico.rdf similarity index 100% rename from RDF_Back/src/main/resources/ontologies/rico.rdf rename to Backend/src/main/resources/ontologies/rico.rdf diff --git a/RDF_Back/src/test/java/com/uspn/rdf_back/RdfBackApplicationTests.java b/Backend/src/test/java/fr/cnrs/lacito/fieldarchive/RdfBackApplicationTests.java similarity index 83% rename from RDF_Back/src/test/java/com/uspn/rdf_back/RdfBackApplicationTests.java rename to Backend/src/test/java/fr/cnrs/lacito/fieldarchive/RdfBackApplicationTests.java index c5393b19..b83affd2 100644 --- a/RDF_Back/src/test/java/com/uspn/rdf_back/RdfBackApplicationTests.java +++ b/Backend/src/test/java/fr/cnrs/lacito/fieldarchive/RdfBackApplicationTests.java @@ -1,4 +1,4 @@ -package com.uspn.rdf_back; +package fr.cnrs.lacito.fieldarchive; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; diff --git a/Frontend/src/app/components/create-ressource/create-ressource.component.html b/Frontend/src/app/components/create-ressource/create-ressource.component.html index b6cb55b8..aee1c9f4 100644 --- a/Frontend/src/app/components/create-ressource/create-ressource.component.html +++ b/Frontend/src/app/components/create-ressource/create-ressource.component.html @@ -3,109 +3,141 @@
-
- -
+
+ +
-
- - -
+ @if(dialogData === null && inputData === undefined) { +
+ + +
- -
- - -

Types are fetched from the RDF graph base.

-
+ +
+ + +

Types are fetched from the RDF graph base.

+
- -
+ +
- -
- -
- - + +
+ +
+ + +
-
- -
- -
- - / - + +
+ +
+ + / + +
+

+ Resolved URI: {{ resolvedTypeUri }} +

+
+ + +
+ + +

Enter the complete, fully qualified URI for this type.

-

- Resolved URI: {{ resolvedTypeUri }} -

-
- -
- - -

Enter the complete, fully qualified URI for this type.

-
+
+ Entity type is required. +
+ } + @else if (dialogData || inputData ){ +
+ + +

+ {{ availableTypes }} +

+
-
- Entity type is required. -
+ }
@@ -142,7 +174,7 @@ - Ajouter une association + Add property
@@ -151,10 +183,10 @@
- +
- -
-
@@ -282,16 +280,32 @@
- + +
+ + + +
+
+ +
diff --git a/Frontend/src/app/components/create-ressource/create-ressource.component.scss b/Frontend/src/app/components/create-ressource/create-ressource.component.scss index e69de29b..4fd2d47c 100644 --- a/Frontend/src/app/components/create-ressource/create-ressource.component.scss +++ b/Frontend/src/app/components/create-ressource/create-ressource.component.scss @@ -0,0 +1,3 @@ +button { + cursor : pointer ; +} \ No newline at end of file diff --git a/Frontend/src/app/components/create-ressource/create-ressource.component.ts b/Frontend/src/app/components/create-ressource/create-ressource.component.ts index 53074cc4..a65e6bfd 100644 --- a/Frontend/src/app/components/create-ressource/create-ressource.component.ts +++ b/Frontend/src/app/components/create-ressource/create-ressource.component.ts @@ -1,15 +1,18 @@ -import { Component, OnInit, Inject } from '@angular/core'; +import { Component, OnInit, Inject, Input, Output, EventEmitter, Optional, ChangeDetectorRef, inject } from '@angular/core'; import { FormsModule, ReactiveFormsModule, FormBuilder, FormGroup, FormArray, Validators } from '@angular/forms'; import { CommonModule } from '@angular/common'; import { Entity } from '../../models/ressource'; + import { EntityDetailsComponent } from '../entity-details/entity-details.component'; import { GestionRessourcesService } from '../../services/gestion-ressources.service'; +import { RicoPropertiesComponent } from '../rico-properties/rico-properties.component'; + import { debounceTime } from 'rxjs'; import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar'; import { FileViewerComponent } from '../file-viewer/file-viewer.component'; +import { MatDialog } from '@angular/material/dialog'; -import {MAT_DIALOG_DATA} from '@angular/material/dialog'; -import { ChangeDetectorRef } from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; export type OntologyLabels = Record; @@ -30,7 +33,8 @@ export let ONTOLOGY_LABELS: OntologyLabels = { CommonModule, EntityDetailsComponent, MatSnackBarModule, - FileViewerComponent + FileViewerComponent, + RicoPropertiesComponent ], templateUrl: './create-ressource.component.html', @@ -44,11 +48,8 @@ export class CreateRessourceComponent implements OnInit { properties: { key: string; value: string; kind: 'literal' | 'iri'; predicate: string }[] = []; - // entityPropertiesDict : any[] = []; - // When Entity is a media file // - isEntityMediaFile(): boolean { return this.newAssociation?.predicate?.p === 'https://www.ica.org/standards/RiC/ontology#identifier' ; } @@ -57,12 +58,12 @@ export class CreateRessourceComponent implements OnInit { this.newAssociation!.value = path; } - // + createSubEntity : boolean = false; allPredicatesByType: any[] = []; - typeMode: 'existing' | 'custom' = 'existing'; + typeMode: 'defined' |'rico' | 'custom' = 'rico'; customSource: 'url' | 'full' = 'url'; availableTypes: string[] = []; @@ -79,14 +80,26 @@ export class CreateRessourceComponent implements OnInit { ontologyList: { name: string; iri: string }[] = []; - constructor(@Inject(MAT_DIALOG_DATA) public data: any, - private fb: FormBuilder, - private ontologyService: GestionRessourcesService, - private snackBar : MatSnackBar, - private cdr: ChangeDetectorRef, - ) { - + // Used only when opened as a dialog + public dialogData: any = inject(MAT_DIALOG_DATA, { optional: true }); + private dialogRef: MatDialogRef | null = inject(MatDialogRef, { optional: true }); + + // Used only when used as a child component tag + @Input() inputData: any; + //let the parent know when created inline (no dialogRef to close) + @Output() closed = new EventEmitter(); + + // The single source of truth + public data: any; + + constructor( + private fb: FormBuilder, + private ontologyService: GestionRessourcesService, + private snackBar : MatSnackBar, + private cdr: ChangeDetectorRef, + private dialog: MatDialog + ) { this.personForm = this.fb.group({ entityType: [''], @@ -102,26 +115,62 @@ export class CreateRessourceComponent implements OnInit { this.ontologyList = this.getOntologyList(); } + onChildClosed(event: any) { + if (event === true) { + this.createSubEntity = false; + this.onPredicateChange(null); // Refresh the list of possible ranges after the child entity is created + } + } + + getFullEntityPath(entityType : string, ontologyName: string): string { + return ontologyName + ? this.ontologyService.getTypeUrlByName(ontologyName) + entityType + : ''; + } + + openRicoPropertiesDialog() { + this.newAssociation!.mode = 'existing'; + this.dialog.open(RicoPropertiesComponent, { + width: '450px', + height:'300px', + data: { + predicates: this.allPredicatesByType, + association: this.newAssociation + } + }); + } + + extractEntityTypeFromIRI(iri :string ) : string { + return iri.includes('#') + ? iri.substring(iri.lastIndexOf('#') + 1) + : iri.substring(iri.lastIndexOf('/') + 1); + } ngOnInit(): void { - // this.ontologyService.getTypes().subscribe({ - // next: (data: any[]) => { - // this.availableTypes = data; - // }, - // error: (err) => { - // console.error("Erreur lors du chargement des types d'ontology ", err); - // } - // }); - this.availableTypes = this.data?.type && this.data?.ontology - ? [this.ontologyService.getTypeUrlByName(this.data?.ontology)+this.data.type] - : []; + + + if (!this.dialogData && this.inputData === undefined) { + this.getAllRicoEntities(); + } + + // else if (this.dialogData.type && this.dialogData.ontology || this.inputData.type && this.inputData.ontology ) { + else if (this.dialogData || this.inputData) { + + this.data = this.inputData ?? this.dialogData; + + console.log("RECEIVED DATA : ", this.data); + + this.availableTypes = this.data?.type && this.data?.ontology + ? [this.ontologyService.getTypeUrlByName(this.data?.ontology)+this.data.type] + : []; + } this.personForm.get('entityType')?.valueChanges .pipe(debounceTime(300)) .subscribe(value => { if (value) { - console.log("VALUEEEEE :",this.data.type); - this.ontologyService.getPredicatesByTypeRico(this.data.type) + + this.ontologyService.getPredicatesByTypeRico(this.personForm.get('entityType')?.value) .subscribe(res => { console.log("All predicates : ",res); this.allPredicatesByType = Object.values( @@ -130,12 +179,25 @@ export class CreateRessourceComponent implements OnInit { return acc; }, {}) ); - //.map(r => r.p); } ); } }); + + if (this.data) { + // const fullType = this.ontologyService.getTypeUrlByName(this.data.ontology) + this.data.type; + this.personForm.get('entityType')?.patchValue(this.data?.type, { emitEvent: true }); + } + + // if(this.typeMode === 'rico' && !this.data?.type ) { + // this.getAllRicoEntities(); + // } + + } + + createSubEntityToggle() { + this.createSubEntity = true; } onPredicateChange(event: any) { @@ -184,13 +246,45 @@ export class CreateRessourceComponent implements OnInit { return `${selectedIri}${sep}${typeName}`; } - setTypeMode(mode: 'existing' | 'custom') { + setTypeMode(mode: 'rico' | 'custom') { this.typeMode = mode; this.personForm.get('entityType')?.reset(); this.personForm.get('customTypeUri')?.reset(); this.personForm.get('customTypeUrl')?.reset(); } + getAllRicoEntities() : void { + + this.ontologyService.getAllRicoClasses().subscribe({ + next: (data) => { + try { + // Step 1: Map to type strings + const allRicoClassesNotFormatted = this.ontologyService.getOntologyLabel( + data.map((d: any) => d.type) + ); + + // Step 2: Extract the RIC-O array + let ricOClasses = allRicoClassesNotFormatted[0]['rico']; + + // Step 3: Remove duplicates + // Assuming each element is a string; if it's an object, use a key like `type` + ricOClasses = Array.from(new Set(ricOClasses)); + + this.availableTypes = ricOClasses; + console.log("Classes RICO (no duplicates) ", this.availableTypes); + + } catch (e) { + console.error("ERROR in getOntologyLabel:", e); + } + + this.cdr.markForCheck(); + }, + error: (err) => { + console.error(err); + } + }); + } + setCustomSource(src: 'url' | 'full') { this.customSource = src; this.personForm.get('customTypeUri')?.reset(); @@ -249,13 +343,15 @@ export class CreateRessourceComponent implements OnInit { cancelNewPerson() { this.personForm.reset(); + this.dialogRef?.close(); } saveNewPerson() { let type: string = ''; - if (this.typeMode === 'existing') { - type = this.personForm.get('entityType')?.value; + if (this.typeMode === 'rico') { + type = this.getFullEntityPath(this.personForm.get('entityType')?.value, 'rico'); + } else { type = this.customSource === 'url' @@ -301,6 +397,8 @@ export class CreateRessourceComponent implements OnInit { panelClass: ['snackbar-success'] } ); + // const dataToSend = { status: 'closed', reason: 'user clicked button' }; + this.closed.emit(true); // optional UX improvements this.personForm.reset(); this.properties = []; diff --git a/Frontend/src/app/components/entity-details/entity-details.component.html b/Frontend/src/app/components/entity-details/entity-details.component.html index 334c4167..bb243983 100644 --- a/Frontend/src/app/components/entity-details/entity-details.component.html +++ b/Frontend/src/app/components/entity-details/entity-details.component.html @@ -62,15 +62,40 @@

{{ selectedEntity?.titre }}

-
New Project RDF placeholder="ex: archive_2025" class="w-full px-3 py-2.5 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent text-sm transition-all" [class.border-red-300]="projectForm.get('name')?.invalid && projectForm.get('name')?.touched"> -

Lettres, chiffres, tirets et underscores uniquement

+

Must contain only letters, numbers, dashes, and underscores.

@if (projectForm.get('name')?.invalid && projectForm.get('name')?.touched) {
- Nom requis — lettres, chiffres, tirets et underscores uniquement + Name is required and must contain only letters, numbers, dashes, and underscores. +
+ } +
+ + +
+ + + + @if (projectForm.get('prefix')?.invalid && projectForm.get('prefix')?.touched) { +
+ A URL is required for the project prefix.
}
@@ -397,8 +452,9 @@

New Project RDF

+ -
+
@@ -523,6 +579,22 @@

{{ selectedProject.name

+
+ +
+ + +
+
+
@@ -575,6 +647,7 @@

{{ selectedProject.name Update Project + @if (selectedProject?.name === originalProject!.name) { + } + + @if (activeProject?.name === originalProject!.name ) { - @if (activeProject?.name === originalProject!.name) { - @if (activeProject?.name === originalProject!.name) { - } + + + + - - - - - - - - + - + +

+ +
-
-
- - + + {{ getKey(ontology_type) }} - - {{ getValuesOfKey(ontology_type)?.length }} + + {{ getValuesOfKey(ontology_type).length }} - -
-
- -
-
+ + + @if(accordionItem.expanded && index === 1) { + + } + @if (index !== 1 && accordionItem.expanded) { + + } + + + } + +
+ @@ -244,10 +281,10 @@

-