From 32bf7cc991880aa113385376c8385689f30183c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Kleinb=C3=B6lting?= Date: Tue, 23 Jan 2024 15:04:16 +0100 Subject: [PATCH] feat: Add support to load knora-ontologies in the docker-compose stack (#3002) Co-authored-by: Marcin Procyk --- docker-compose.yml | 2 + .../org/knora/webapi/core/LayersTest.scala | 7 +- .../webapi/e2e/admin/StoreADME2ESpec.scala | 42 -------- .../testservices/TestClientService.scala | 22 ---- .../org/knora/webapi/core/LayersLive.scala | 7 +- .../storesmessages/StoresMessagesADM.scala | 52 --------- .../TriplestoreMessages.scala | 6 +- .../responders/admin/StoresResponderADM.scala | 101 ------------------ .../org/knora/webapi/routing/ApiRoutes.scala | 1 - .../webapi/routing/admin/StoreRouteADM.scala | 44 -------- .../slice/admin/api/AdminApiEndpoints.scala | 2 + .../slice/admin/api/AdminApiRoutes.scala | 2 + .../slice/admin/api/StoreEndpoints.scala | 46 ++++++++ .../admin/api/StoreEndpointsHandler.scala | 40 +++++++ .../api/service/ProjectsADMRestService.scala | 6 +- .../admin/api/service/StoreRestService.scala | 52 +++++++++ .../slice/common/api/DocsGenerator.scala | 2 + .../impl/TriplestoreServiceLive.scala | 2 +- 18 files changed, 165 insertions(+), 271 deletions(-) delete mode 100644 integration/src/test/scala/org/knora/webapi/e2e/admin/StoreADME2ESpec.scala delete mode 100644 webapi/src/main/scala/org/knora/webapi/messages/admin/responder/storesmessages/StoresMessagesADM.scala delete mode 100644 webapi/src/main/scala/org/knora/webapi/responders/admin/StoresResponderADM.scala delete mode 100644 webapi/src/main/scala/org/knora/webapi/routing/admin/StoreRouteADM.scala create mode 100644 webapi/src/main/scala/org/knora/webapi/slice/admin/api/StoreEndpoints.scala create mode 100644 webapi/src/main/scala/org/knora/webapi/slice/admin/api/StoreEndpointsHandler.scala create mode 100644 webapi/src/main/scala/org/knora/webapi/slice/admin/api/service/StoreRestService.scala diff --git a/docker-compose.yml b/docker-compose.yml index 3aad2cbae9..130ec77e87 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -93,6 +93,8 @@ services: - "3339:3339" volumes: - /tmp:/tmp + - ./knora-ontologies:/opt/knora-ontologies + - ./test_data:/opt/test_data networks: - knora-net environment: diff --git a/integration/src/test/scala/org/knora/webapi/core/LayersTest.scala b/integration/src/test/scala/org/knora/webapi/core/LayersTest.scala index ef3b8dafab..6c6e95e38d 100644 --- a/integration/src/test/scala/org/knora/webapi/core/LayersTest.scala +++ b/integration/src/test/scala/org/knora/webapi/core/LayersTest.scala @@ -33,6 +33,7 @@ import org.knora.webapi.slice.admin.api.service.MaintenanceRestService import org.knora.webapi.slice.admin.api.service.PermissionsRestService import org.knora.webapi.slice.admin.api.service.ProjectADMRestService import org.knora.webapi.slice.admin.api.service.ProjectsADMRestServiceLive +import org.knora.webapi.slice.admin.api.service.StoreRestService import org.knora.webapi.slice.admin.api.service.UsersRestService import org.knora.webapi.slice.admin.domain.service.* import org.knora.webapi.slice.admin.repo.service.KnoraProjectRepoLive @@ -135,7 +136,7 @@ object LayersTest { with StandoffResponderV2 with StandoffTagUtilV2 with State - with StoresResponderADM + with StoreRestService with TestClientService with TriplestoreService with UsersResponderADM @@ -200,6 +201,8 @@ object LayersTest { ProjectsEndpoints.layer, ProjectsEndpointsHandler.layer, ProjectsResponderADMLive.layer, + StoreEndpoints.layer, + StoreEndpointsHandler.layer, QueryTraverser.layer, RepositoryUpdater.layer, ResourceInfoLayers.live, @@ -213,7 +216,7 @@ object LayersTest { StandoffResponderV2Live.layer, StandoffTagUtilV2Live.layer, State.layer, - StoresResponderADMLive.layer, + StoreRestService.layer, TapirToPekkoInterpreter.layer, TestClientService.layer, TriplestoreServiceLive.layer, diff --git a/integration/src/test/scala/org/knora/webapi/e2e/admin/StoreADME2ESpec.scala b/integration/src/test/scala/org/knora/webapi/e2e/admin/StoreADME2ESpec.scala deleted file mode 100644 index ea31b7d114..0000000000 --- a/integration/src/test/scala/org/knora/webapi/e2e/admin/StoreADME2ESpec.scala +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright © 2021 - 2024 Swiss National Data and Service Center for the Humanities and/or DaSCH Service Platform contributors. - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.knora.webapi.e2e.admin - -import org.apache.pekko -import spray.json.* -import zio.Duration - -import org.knora.webapi.E2ESpec -import org.knora.webapi.messages.store.triplestoremessages.TriplestoreJsonProtocol - -import pekko.http.scaladsl.model.ContentTypes -import pekko.http.scaladsl.model.HttpEntity -import pekko.http.scaladsl.model.StatusCodes - -/** - * End-to-End (E2E) test specification for testing the 'v1/store' route. - * - * This spec tests the 'v1/store' route. - */ -class StoreADME2ESpec extends E2ESpec with TriplestoreJsonProtocol { - - "The ResetTriplestoreContent Route ('admin/store/ResetTriplestoreContent')" should { - - "succeed with resetting" in { - - /** - * This test corresponds to the following curl call: - * curl -H "Content-Type: application/json" -X POST -d '[{"path":"../knora-ontologies/knora-base.ttl","name":"http://www.knora.org/ontology/knora-base"}]' http://localhost:3333/admin/store/ResetTriplestoreContent - */ - val request = Post( - baseApiUrl + "/admin/store/ResetTriplestoreContent", - HttpEntity(ContentTypes.`application/json`, rdfDataObjects.toJson.compactPrint) - ) - val response = singleAwaitingRequest(request, Duration.fromSeconds(480)) - assert(response.status === StatusCodes.OK) - } - } -} diff --git a/integration/src/test/scala/org/knora/webapi/testservices/TestClientService.scala b/integration/src/test/scala/org/knora/webapi/testservices/TestClientService.scala index f37cdf36f5..eeb2b6c4f3 100644 --- a/integration/src/test/scala/org/knora/webapi/testservices/TestClientService.scala +++ b/integration/src/test/scala/org/knora/webapi/testservices/TestClientService.scala @@ -38,7 +38,6 @@ import org.knora.webapi.messages.store.sipimessages.SipiUploadResponse import org.knora.webapi.messages.store.sipimessages.SipiUploadResponseJsonProtocol.* import org.knora.webapi.messages.store.sipimessages.SipiUploadWithoutProcessingResponse import org.knora.webapi.messages.store.sipimessages.SipiUploadWithoutProcessingResponseJsonProtocol.* -import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject import org.knora.webapi.messages.store.triplestoremessages.TriplestoreJsonProtocol import org.knora.webapi.messages.util.rdf.JsonLDDocument import org.knora.webapi.messages.util.rdf.JsonLDUtil @@ -75,27 +74,6 @@ final case class TestClientService(config: AppConfig, httpClient: CloseableHttpC case class TestClientTimeoutException(msg: String) extends Exception - /** - * Loads test data. - */ - def loadTestData(rdfDataObjects: Seq[RdfDataObject]): Task[Unit] = { - - val loadRequest = Post( - config.knoraApi.internalKnoraApiBaseUrl + "/admin/store/ResetTriplestoreContent", - pekko.http.scaladsl.model - .HttpEntity( - pekko.http.scaladsl.model.ContentTypes.`application/json`, - rdfDataObjects.toJson.compactPrint - ) - ) - - for { - _ <- ZIO.logInfo("Loading test data started ...") - _ <- singleAwaitingRequest(loadRequest) - _ <- ZIO.logInfo("... loading test data done.") - } yield () - } - /** * Performs a http request. * diff --git a/webapi/src/main/scala/org/knora/webapi/core/LayersLive.scala b/webapi/src/main/scala/org/knora/webapi/core/LayersLive.scala index 52b502af0a..14211d0a9d 100644 --- a/webapi/src/main/scala/org/knora/webapi/core/LayersLive.scala +++ b/webapi/src/main/scala/org/knora/webapi/core/LayersLive.scala @@ -34,6 +34,7 @@ import org.knora.webapi.slice.admin.api.service.MaintenanceRestService import org.knora.webapi.slice.admin.api.service.PermissionsRestService import org.knora.webapi.slice.admin.api.service.ProjectADMRestService import org.knora.webapi.slice.admin.api.service.ProjectsADMRestServiceLive +import org.knora.webapi.slice.admin.api.service.StoreRestService import org.knora.webapi.slice.admin.api.service.UsersRestService import org.knora.webapi.slice.admin.domain.service.* import org.knora.webapi.slice.admin.repo.service.KnoraProjectRepoLive @@ -81,7 +82,7 @@ object LayersLive { ProjectExportStorageService & ProjectImportService & ProjectsResponderADM & QueryTraverser & RepositoryUpdater & ResourcesResponderV2 & ResourceUtilV2 & ResourceUtilV2 & RestCardinalityService & RestResourceInfoService & SearchApiRoutes & SearchResponderV2 & AssetPermissionsResponder & SipiService & StandoffResponderV2 & StandoffTagUtilV2 & - State & StoresResponderADM & StringFormatter & TriplestoreService & UsersResponderADM & ValuesResponderV2 + State & StoreRestService & StringFormatter & TriplestoreService & UsersResponderADM & ValuesResponderV2 /** * All effect layers needed to provide the `Environment` @@ -148,6 +149,8 @@ object LayersLive { ProjectsEndpoints.layer, ProjectsEndpointsHandler.layer, ProjectsResponderADMLive.layer, + StoreEndpoints.layer, + StoreEndpointsHandler.layer, QueryTraverser.layer, RepositoryUpdater.layer, ResourceInfoLayers.live, @@ -162,7 +165,7 @@ object LayersLive { StandoffResponderV2Live.layer, StandoffTagUtilV2Live.layer, State.layer, - StoresResponderADMLive.layer, + StoreRestService.layer, StringFormatter.live, TapirToPekkoInterpreter.layer, TriplestoreServiceLive.layer, diff --git a/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/storesmessages/StoresMessagesADM.scala b/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/storesmessages/StoresMessagesADM.scala deleted file mode 100644 index eafdbeca73..0000000000 --- a/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/storesmessages/StoresMessagesADM.scala +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright © 2021 - 2024 Swiss National Data and Service Center for the Humanities and/or DaSCH Service Platform contributors. - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.knora.webapi.messages.admin.responder.storesmessages - -import org.apache.pekko -import spray.json.* - -import org.knora.webapi.core.RelayedMessage -import org.knora.webapi.messages.ResponderRequest.KnoraRequestADM -import org.knora.webapi.messages.admin.responder.KnoraResponseADM -import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject -import org.knora.webapi.messages.store.triplestoremessages.TriplestoreJsonProtocol - -import pekko.http.scaladsl.marshallers.sprayjson.SprayJsonSupport - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Messages - -sealed trait StoreResponderRequestADM extends KnoraRequestADM with RelayedMessage - -/** - * Requests to load the triplestore with data referenced inside [[RdfDataObject]]. Any data contained inside the - * triplestore will be deleted first. - * - * @param rdfDataObjects a sequence of [[RdfDataObject]] objects containing the path to the data and the name of - * the named graph into which the data should be loaded. - * @param prependDefaults should a default set of [[RdfDataObject]]s be prepended. The default is `false`. - */ -case class ResetTriplestoreContentRequestADM( - rdfDataObjects: Seq[RdfDataObject], - prependDefaults: Boolean = false -) extends StoreResponderRequestADM - -case class ResetTriplestoreContentResponseADM(message: String) extends KnoraResponseADM with StoresADMJsonProtocol { - def toJsValue: JsValue = resetTriplestoreContentResponseADMFormat.write(this) -} - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// JSON formatting - -/** - * A spray-json protocol for generating Knora API ADM JSON for property values. - */ -trait StoresADMJsonProtocol extends SprayJsonSupport with DefaultJsonProtocol with TriplestoreJsonProtocol { - - /* Very strange construct at the end is needed, but I don't really understand why and what it means */ - implicit val resetTriplestoreContentResponseADMFormat: RootJsonFormat[ResetTriplestoreContentResponseADM] = - jsonFormat[String, ResetTriplestoreContentResponseADM](ResetTriplestoreContentResponseADM, "message") -} diff --git a/webapi/src/main/scala/org/knora/webapi/messages/store/triplestoremessages/TriplestoreMessages.scala b/webapi/src/main/scala/org/knora/webapi/messages/store/triplestoremessages/TriplestoreMessages.scala index be183cba4d..9a8abae1d8 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/store/triplestoremessages/TriplestoreMessages.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/store/triplestoremessages/TriplestoreMessages.scala @@ -8,6 +8,8 @@ package org.knora.webapi.messages.store.triplestoremessages import org.apache.pekko.http.scaladsl.marshallers.sprayjson.SprayJsonSupport import spray.json.* import zio.* +import zio.json.DeriveJsonCodec +import zio.json.JsonCodec import java.time.Instant import scala.collection.mutable @@ -157,6 +159,9 @@ case class RepositoryUpdatedResponse(message: String) * @param name of the named graph the data will be load into. */ case class RdfDataObject(path: String, name: String) +object RdfDataObject { + implicit val jsonCodec: JsonCodec[RdfDataObject] = DeriveJsonCodec.gen[RdfDataObject] +} /** * Represents the subject of a statement read from the triplestore. @@ -589,5 +594,4 @@ trait TriplestoreJsonProtocol extends SprayJsonSupport with DefaultJsonProtocol } } - implicit val rdfDataObjectFormat: RootJsonFormat[RdfDataObject] = jsonFormat2(RdfDataObject) } diff --git a/webapi/src/main/scala/org/knora/webapi/responders/admin/StoresResponderADM.scala b/webapi/src/main/scala/org/knora/webapi/responders/admin/StoresResponderADM.scala deleted file mode 100644 index 674ef83123..0000000000 --- a/webapi/src/main/scala/org/knora/webapi/responders/admin/StoresResponderADM.scala +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright © 2021 - 2024 Swiss National Data and Service Center for the Humanities and/or DaSCH Service Platform contributors. - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.knora.webapi.responders.admin - -import zio.* - -import dsp.errors.ForbiddenException -import org.knora.webapi.config.AppConfig -import org.knora.webapi.core.MessageHandler -import org.knora.webapi.core.MessageRelay -import org.knora.webapi.messages.ResponderRequest -import org.knora.webapi.messages.admin.responder.storesmessages.ResetTriplestoreContentRequestADM -import org.knora.webapi.messages.admin.responder.storesmessages.ResetTriplestoreContentResponseADM -import org.knora.webapi.messages.admin.responder.storesmessages.StoreResponderRequestADM -import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject -import org.knora.webapi.messages.util.KnoraSystemInstances -import org.knora.webapi.responders.Responder -import org.knora.webapi.slice.ontology.repo.service.OntologyCache -import org.knora.webapi.store.cache.api.CacheService -import org.knora.webapi.store.triplestore.api.TriplestoreService - -/** - * This responder is used by [[org.knora.webapi.routing.admin.StoreRouteADM]], for piping through HTTP requests to the - * 'Store Module' - */ -trait StoresResponderADM { - - /** - * Resets the triplestore with provided data, adding defaults optionally. - * - * @param rdfDataObjects the payload consisting of a list of [[RdfDataObject]] send inside the message. - * @return a [[ResetTriplestoreContentResponseADM]]. - */ - def resetTriplestoreContent( - rdfDataObjects: List[RdfDataObject], - prependDefaults: Boolean = true - ): Task[ResetTriplestoreContentResponseADM] -} - -final case class StoresResponderADMLive( - appConfig: AppConfig, - cacheService: CacheService, - messageRelay: MessageRelay, - triplestoreService: TriplestoreService, - ontologyCache: OntologyCache -) extends StoresResponderADM - with MessageHandler { - - /** - * A user representing the Knora API server, used in those cases where a user is required. - */ - private val systemUser = KnoraSystemInstances.Users.SystemUser - - override def isResponsibleFor(message: ResponderRequest): Boolean = message.isInstanceOf[StoreResponderRequestADM] - - override def handle(msg: ResponderRequest): Task[Any] = msg match { - case r: ResetTriplestoreContentRequestADM => resetTriplestoreContent(r.rdfDataObjects.toList, r.prependDefaults) - case other => Responder.handleUnexpectedMessage(other, this.getClass.getName) - } - - override def resetTriplestoreContent( - rdfDataObjects: List[RdfDataObject], - prependDefaults: Boolean = true - ): Task[ResetTriplestoreContentResponseADM] = - for { - _ <- ZIO.logDebug(s"resetTriplestoreContent - called") - _ <- ZIO - .fail( - ForbiddenException( - "The ResetTriplestoreContent operation is not allowed. Did you start the server with the right flag?" - ) - ) - .when(!appConfig.allowReloadOverHttp) - resetResponse <- triplestoreService.resetTripleStoreContent(rdfDataObjects, prependDefaults) - _ <- ZIO.logDebug(s"resetTriplestoreContent - triplestore reset done - ${resetResponse.toString}") - _ <- ontologyCache.loadOntologies(systemUser) - _ <- ZIO.logDebug(s"resetTriplestoreContent - load ontology done.") - _ <- cacheService.flushDB(systemUser) - _ <- ZIO.logDebug(s"resetTriplestoreContent - flushing cache store done.") - } yield ResetTriplestoreContentResponseADM("success") -} - -object StoresResponderADMLive { - val layer: URLayer[ - TriplestoreService & MessageRelay & CacheService & AppConfig & OntologyCache, - StoresResponderADMLive - ] = - ZLayer.fromZIO { - for { - config <- ZIO.service[AppConfig] - cs <- ZIO.service[CacheService] - mr <- ZIO.service[MessageRelay] - ts <- ZIO.service[TriplestoreService] - oc <- ZIO.service[OntologyCache] - handler <- mr.subscribe(StoresResponderADMLive(config, cs, mr, ts, oc)) - } yield handler - } -} diff --git a/webapi/src/main/scala/org/knora/webapi/routing/ApiRoutes.scala b/webapi/src/main/scala/org/knora/webapi/routing/ApiRoutes.scala index 0ff2806040..4fd2479260 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/ApiRoutes.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/ApiRoutes.scala @@ -108,7 +108,6 @@ private final case class ApiRoutesImpl( RejectingRoute(appConfig, runtime).makeRoute ~ ResourcesRouteV2(appConfig).makeRoute ~ StandoffRouteV2().makeRoute ~ - StoreRouteADM(routeData, runtime).makeRoute ~ UsersRouteADM().makeRoute ~ ValuesRouteV2().makeRoute ~ VersionRoute().makeRoute diff --git a/webapi/src/main/scala/org/knora/webapi/routing/admin/StoreRouteADM.scala b/webapi/src/main/scala/org/knora/webapi/routing/admin/StoreRouteADM.scala deleted file mode 100644 index 02bbca3c54..0000000000 --- a/webapi/src/main/scala/org/knora/webapi/routing/admin/StoreRouteADM.scala +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright © 2021 - 2024 Swiss National Data and Service Center for the Humanities and/or DaSCH Service Platform contributors. - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.knora.webapi.routing.admin - -import org.apache.pekko -import zio.Runtime - -import org.knora.webapi.core.MessageRelay -import org.knora.webapi.messages.StringFormatter -import org.knora.webapi.messages.admin.responder.storesmessages.ResetTriplestoreContentRequestADM -import org.knora.webapi.messages.admin.responder.storesmessages.StoresADMJsonProtocol -import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject -import org.knora.webapi.routing.Authenticator -import org.knora.webapi.routing.KnoraRoute -import org.knora.webapi.routing.KnoraRouteData -import org.knora.webapi.routing.RouteUtilADM.runJsonRoute - -import pekko.http.scaladsl.server.Directives.* -import pekko.http.scaladsl.server.Route - -/** - * A route used to send requests which can directly affect the data stored inside the triplestore. - */ - -final case class StoreRouteADM( - private val routeData: KnoraRouteData, - override protected implicit val runtime: Runtime[Authenticator & StringFormatter & MessageRelay] -) extends KnoraRoute(routeData, runtime) - with StoresADMJsonProtocol { - override def makeRoute: Route = Route { - path("admin" / "store" / "ResetTriplestoreContent") { - post { - entity(as[Seq[RdfDataObject]]) { apiRequest => - parameter(Symbol("prependdefaults").as[Boolean] ? true) { prependDefaults => requestContext => - runJsonRoute(ResetTriplestoreContentRequestADM(apiRequest, prependDefaults), requestContext) - } - } - } - } - } -} diff --git a/webapi/src/main/scala/org/knora/webapi/slice/admin/api/AdminApiEndpoints.scala b/webapi/src/main/scala/org/knora/webapi/slice/admin/api/AdminApiEndpoints.scala index b4dde64e0f..cb03f3504d 100644 --- a/webapi/src/main/scala/org/knora/webapi/slice/admin/api/AdminApiEndpoints.scala +++ b/webapi/src/main/scala/org/knora/webapi/slice/admin/api/AdminApiEndpoints.scala @@ -13,6 +13,7 @@ final case class AdminApiEndpoints( maintenanceEndpoints: MaintenanceEndpoints, permissionsEndpoints: PermissionsEndpoints, projectsEndpoints: ProjectsEndpoints, + storeEndpoints: StoreEndpoints, usersEndpoints: UsersEndpoints, filesEndpoints: FilesEndpoints ) { @@ -22,6 +23,7 @@ final case class AdminApiEndpoints( maintenanceEndpoints.endpoints ++ permissionsEndpoints.endpoints ++ projectsEndpoints.endpoints ++ + storeEndpoints.endpoints ++ usersEndpoints.endpoints ++ filesEndpoints.endpoints } diff --git a/webapi/src/main/scala/org/knora/webapi/slice/admin/api/AdminApiRoutes.scala b/webapi/src/main/scala/org/knora/webapi/slice/admin/api/AdminApiRoutes.scala index da6adf251c..873e7a6c41 100644 --- a/webapi/src/main/scala/org/knora/webapi/slice/admin/api/AdminApiRoutes.scala +++ b/webapi/src/main/scala/org/knora/webapi/slice/admin/api/AdminApiRoutes.scala @@ -15,6 +15,7 @@ final case class AdminApiRoutes( maintenance: MaintenanceEndpointsHandlers, permissions: PermissionsEndpointsHandlers, project: ProjectsEndpointsHandler, + storeEndpoints: StoreEndpointsHandler, filesEndpoints: FilesEndpointsHandler, users: UsersEndpointsHandler, tapirToPekko: TapirToPekkoInterpreter @@ -25,6 +26,7 @@ final case class AdminApiRoutes( groups.handlers ++ maintenance.handlers ++ permissions.allHanders ++ + storeEndpoints.allHandlers ++ project.allHanders ++ users.allHanders diff --git a/webapi/src/main/scala/org/knora/webapi/slice/admin/api/StoreEndpoints.scala b/webapi/src/main/scala/org/knora/webapi/slice/admin/api/StoreEndpoints.scala new file mode 100644 index 0000000000..d99deb91a1 --- /dev/null +++ b/webapi/src/main/scala/org/knora/webapi/slice/admin/api/StoreEndpoints.scala @@ -0,0 +1,46 @@ +/* + * Copyright © 2021 - 2024 Swiss National Data and Service Center for the Humanities and/or DaSCH Service Platform contributors. + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.knora.webapi.slice.admin.api + +import sttp.tapir.* +import sttp.tapir.generic.auto.schemaForCaseClass +import sttp.tapir.json.zio.jsonBody +import sttp.tapir.query +import zio.ZLayer +import zio.json.DeriveJsonCodec +import zio.json.JsonCodec + +import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject +import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject.jsonCodec +import org.knora.webapi.slice.common.api.BaseEndpoints + +final case class MessageResponse(message: String) +object MessageResponse { + implicit val jsonCodec: JsonCodec[MessageResponse] = DeriveJsonCodec.gen[MessageResponse] +} + +final case class StoreEndpoints(baseEndpoints: BaseEndpoints) { + + val postStoreResetTriplestoreContent = + baseEndpoints.publicEndpoint + .in("admin" / "store" / "ResetTriplestoreContent") + .in( + jsonBody[Option[List[RdfDataObject]]] + .description("RDF data objects to load into the triplestore, uses defaults if not present.") + ) + .in(query[Boolean]("prependDefaults").default(true).description("Prepend defaults to the data objects.")) + .out(jsonBody[MessageResponse]) + .description( + "Resets the content of the triplestore, only available if configuration `allowReloadOverHttp` is set to `true`." + ) + .tags(List("admin")) + + val endpoints = Seq(postStoreResetTriplestoreContent) +} + +object StoreEndpoints { + val layer = ZLayer.derive[StoreEndpoints] +} diff --git a/webapi/src/main/scala/org/knora/webapi/slice/admin/api/StoreEndpointsHandler.scala b/webapi/src/main/scala/org/knora/webapi/slice/admin/api/StoreEndpointsHandler.scala new file mode 100644 index 0000000000..1d780f1b10 --- /dev/null +++ b/webapi/src/main/scala/org/knora/webapi/slice/admin/api/StoreEndpointsHandler.scala @@ -0,0 +1,40 @@ +/* + * Copyright © 2021 - 2024 Swiss National Data and Service Center for the Humanities and/or DaSCH Service Platform contributors. + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.knora.webapi.slice.admin.api + +import zio.ZLayer + +import org.knora.webapi.config.AppConfig +import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject +import org.knora.webapi.slice.admin.api.service.StoreRestService +import org.knora.webapi.slice.common.api.EndpointAndZioHandler +import org.knora.webapi.slice.common.api.HandlerMapper + +final case class StoreEndpointsHandler( + endpoints: StoreEndpoints, + appConfig: AppConfig, + storesResponder: StoreRestService, + mapper: HandlerMapper +) { + + private val postStoreResetTriplestoreContentHandler = + EndpointAndZioHandler[Unit, (Option[List[RdfDataObject]], Boolean), MessageResponse]( + endpoints.postStoreResetTriplestoreContent, + { case (rdfObjs: Option[List[RdfDataObject]], prependDefaults: Boolean) => + storesResponder.resetTriplestoreContent(rdfObjs.getOrElse(List.empty), prependDefaults) + } + ) + + val allHandlers = { + val handlerIfConfigured = + if (appConfig.allowReloadOverHttp) Seq(postStoreResetTriplestoreContentHandler) else Seq.empty + handlerIfConfigured.map(mapper.mapEndpointAndHandler(_)) + } +} + +object StoreEndpointsHandler { + val layer = ZLayer.derive[StoreEndpointsHandler] +} diff --git a/webapi/src/main/scala/org/knora/webapi/slice/admin/api/service/ProjectsADMRestService.scala b/webapi/src/main/scala/org/knora/webapi/slice/admin/api/service/ProjectsADMRestService.scala index 3dc208f628..2f834f87ba 100644 --- a/webapi/src/main/scala/org/knora/webapi/slice/admin/api/service/ProjectsADMRestService.scala +++ b/webapi/src/main/scala/org/knora/webapi/slice/admin/api/service/ProjectsADMRestService.scala @@ -267,9 +267,9 @@ final case class ProjectsADMRestServiceLive( /** * Sets project's restricted view settings. * - * @param id the project's id represented by iri, shortcode or shortname, - * @param user requesting user, - * @param setSizeReq value to be set, + * @param id The project's id represented by iri, shortcode or shortname. + * @param user Requesting user. + * @param req Contains the values to be set. * @return [[ProjectRestrictedViewSizeResponseADM]]. */ override def updateProjectRestrictedViewSettings( diff --git a/webapi/src/main/scala/org/knora/webapi/slice/admin/api/service/StoreRestService.scala b/webapi/src/main/scala/org/knora/webapi/slice/admin/api/service/StoreRestService.scala new file mode 100644 index 0000000000..596e3766ea --- /dev/null +++ b/webapi/src/main/scala/org/knora/webapi/slice/admin/api/service/StoreRestService.scala @@ -0,0 +1,52 @@ +/* + * Copyright © 2021 - 2024 Swiss National Data and Service Center for the Humanities and/or DaSCH Service Platform contributors. + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.knora.webapi.slice.admin.api.service + +import zio.* + +import dsp.errors.ForbiddenException +import org.knora.webapi.config.AppConfig +import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject +import org.knora.webapi.messages.util.KnoraSystemInstances.Users.SystemUser +import org.knora.webapi.slice.admin.api.MessageResponse +import org.knora.webapi.slice.ontology.repo.service.OntologyCache +import org.knora.webapi.store.cache.api.CacheService +import org.knora.webapi.store.triplestore.api.TriplestoreService + +final case class StoreRestService( + appConfig: AppConfig, + cacheService: CacheService, + triplestoreService: TriplestoreService, + ontologyCache: OntologyCache +) { + + /** + * Resets the triplestore with provided data, adding defaults optionally. + * + * @param rdfDataObjects the payload consisting of a list of [[RdfDataObject]] send inside the message. + * @param prependDefaults denotes if the rdfDataObjects list should be prepended with a default set. + * @return a [[MessageResponse]]. + */ + def resetTriplestoreContent( + rdfDataObjects: List[RdfDataObject], + prependDefaults: Boolean = true + ): Task[MessageResponse] = + for { + _ <- ZIO.when(!appConfig.allowReloadOverHttp) { + val msg = + "The ResetTriplestoreContent operation is not allowed. Did you start the server with the right flag?" + ZIO.fail(ForbiddenException(msg)) + } + _ <- ZIO.logWarning(s"Resetting triplestore content with ${rdfDataObjects.map(_.name).mkString(", ")}") + _ <- triplestoreService.resetTripleStoreContent(rdfDataObjects, prependDefaults).logError + _ <- ontologyCache.loadOntologies(SystemUser).logError + _ <- cacheService.flushDB(SystemUser).logError + } yield MessageResponse("success") +} + +object StoreRestService { + val layer = ZLayer.derive[StoreRestService] +} diff --git a/webapi/src/main/scala/org/knora/webapi/slice/common/api/DocsGenerator.scala b/webapi/src/main/scala/org/knora/webapi/slice/common/api/DocsGenerator.scala index 1896b1bf6c..e2f5b939ef 100644 --- a/webapi/src/main/scala/org/knora/webapi/slice/common/api/DocsGenerator.scala +++ b/webapi/src/main/scala/org/knora/webapi/slice/common/api/DocsGenerator.scala @@ -29,6 +29,7 @@ import org.knora.webapi.slice.admin.api.GroupsEndpoints import org.knora.webapi.slice.admin.api.MaintenanceEndpoints import org.knora.webapi.slice.admin.api.PermissionsEndpoints import org.knora.webapi.slice.admin.api.ProjectsEndpoints +import org.knora.webapi.slice.admin.api.StoreEndpoints import org.knora.webapi.slice.admin.api.UsersEndpoints import org.knora.webapi.slice.admin.domain.model.Email import org.knora.webapi.slice.admin.domain.model.User @@ -79,6 +80,7 @@ object DocsGenerator extends ZIOAppDefault { ProjectsEndpoints.layer, ResourceInfoEndpoints.layer, SearchEndpoints.layer, + StoreEndpoints.layer, UsersEndpoints.layer ) diff --git a/webapi/src/main/scala/org/knora/webapi/store/triplestore/impl/TriplestoreServiceLive.scala b/webapi/src/main/scala/org/knora/webapi/store/triplestore/impl/TriplestoreServiceLive.scala index 025dc48237..db8d164787 100644 --- a/webapi/src/main/scala/org/knora/webapi/store/triplestore/impl/TriplestoreServiceLive.scala +++ b/webapi/src/main/scala/org/knora/webapi/store/triplestore/impl/TriplestoreServiceLive.scala @@ -268,7 +268,7 @@ case class TriplestoreServiceLive( // to the parent folder where the files can be found val inputFile = Paths.get("..", elem.path) if (!Files.exists(inputFile)) { - throw BadRequestException(s"File $inputFile does not exist") + throw BadRequestException(s"File ${inputFile.toAbsolutePath} does not exist") } val fileEntity = new FileEntity(inputFile.toFile, ContentType.create(mimeTypeTextTurtle, "UTF-8"))