diff --git a/modules/restapi/src/main/resources/docspell-openapi.yml b/modules/restapi/src/main/resources/docspell-openapi.yml index 6c8f5530..f7f691f0 100644 --- a/modules/restapi/src/main/resources/docspell-openapi.yml +++ b/modules/restapi/src/main/resources/docspell-openapi.yml @@ -1880,13 +1880,44 @@ paths: application/json: schema: {} + /sec/clientSettings/{clientId}: parameters: - $ref: "#/components/parameters/clientId" get: operationId: "sec-clientsettings-get" tags: [ Client Settings ] - summary: Return the current user settings + summary: Return the client settings of current user + description: | + Returns the settings for the current user by merging the + client settings for the collective and the user's own client + settings into one json structure. + + Null, Array, Boolean, String and Number are treated as values, + and values from the users settings completely replace values + from the collective's settings. + + The `clientId` is an identifier to a client application. It + returns a JSON structure. The server doesn't care about the + actual data, since it is meant to be interpreted by clients. + security: + - authTokenHeader: [] + responses: + 422: + description: BadRequest + 200: + description: Ok + content: + application/json: + schema: {} + + /sec/clientSettings/user/{clientId}: + parameters: + - $ref: "#/components/parameters/clientId" + get: + operationId: "sec-clientsettings-user-get" + tags: [ Client Settings ] + summary: Return the user's own client settings description: | Returns the settings for the current user. The `clientId` is an identifier to a client application. It returns a JSON @@ -1903,9 +1934,9 @@ paths: application/json: schema: {} put: - operationId: "sec-clientsettings-update" + operationId: "sec-clientsettings-user-update" tags: [ Client Settings ] - summary: Update current user settings + summary: Update client settings of current user description: | Updates (replaces or creates) the current user's settings with the given data. The `clientId` is an identifier to a client @@ -1933,9 +1964,9 @@ paths: schema: $ref: "#/components/schemas/BasicResult" delete: - operationId: "sec-clientsettings-delete" + operationId: "sec-clientsettings-user-delete" tags: [ Client Settings ] - summary: Clears the current user settings + summary: Clears client settings of current user description: | Removes all stored user settings for the client identified by `clientId`. @@ -1951,6 +1982,77 @@ paths: schema: $ref: "#/components/schemas/BasicResult" + /sec/clientSettings/collective/{clientId}: + parameters: + - $ref: "#/components/parameters/clientId" + get: + operationId: "sec-clientsettings-collective-get" + tags: [ Client Settings ] + summary: Return collective client settings + description: | + Returns the settings for the current collective. The + `clientId` is an identifier to a client application. It + returns a JSON structure. The server doesn't care about the + actual data, since it is meant to be interpreted by clients. + security: + - authTokenHeader: [] + responses: + 422: + description: BadRequest + 200: + description: Ok + content: + application/json: + schema: {} + put: + operationId: "sec-clientsettings-collective-update" + tags: [ Client Settings ] + summary: Update collective client settings + description: | + Updates (replaces or creates) the current collective's + settings with the given data. The `clientId` is an identifier + to a client application. The request body is expected to be + JSON, the structure is not important to the server. + + The data is stored for the current user and given `clientId`. + + The data is only saved without being checked in any way + (besides being valid JSON). It is returned "as is" to the + client in the corresponding GET endpoint. + security: + - authTokenHeader: [] + requestBody: + content: + application/json: + schema: {} + responses: + 422: + description: BadRequest + 200: + description: Ok + content: + application/json: + schema: + $ref: "#/components/schemas/BasicResult" + delete: + operationId: "sec-clientsettings-collective-delete" + tags: [ Client Settings ] + summary: Clears collective's client settings + description: | + Removes all stored client settings of id `clientId` for + collective. + security: + - authTokenHeader: [] + responses: + 422: + description: BadRequest + 200: + description: Ok + content: + application/json: + schema: + $ref: "#/components/schemas/BasicResult" + /share/search/query: post: operationId: "share-search-query" diff --git a/modules/restserver/src/main/scala/docspell/restserver/routes/ClientSettingsRoutes.scala b/modules/restserver/src/main/scala/docspell/restserver/routes/ClientSettingsRoutes.scala index 28e1426f..79dcbd19 100644 --- a/modules/restserver/src/main/scala/docspell/restserver/routes/ClientSettingsRoutes.scala +++ b/modules/restserver/src/main/scala/docspell/restserver/routes/ClientSettingsRoutes.scala @@ -19,6 +19,7 @@ import org.http4s.HttpRoutes import org.http4s.circe.CirceEntityDecoder._ import org.http4s.circe.CirceEntityEncoder._ import org.http4s.dsl.Http4sDsl +import cats.kernel.Semigroup object ClientSettingsRoutes { @@ -27,14 +28,27 @@ object ClientSettingsRoutes { import dsl._ HttpRoutes.of { - case req @ PUT -> Root / Ident(clientId) => + case GET -> Root / Ident(clientId) => + for { + collData <- backend.clientSettings.loadCollective(clientId, user.account) + userData <- backend.clientSettings.loadUser(clientId, user.account) + + mergedData = collData.map(_.settingsData) |+| userData.map(_.settingsData) + + res <- mergedData match { + case Some(j) => Ok(j) + case None => NotFound() + } + } yield res + + case req @ PUT -> Root / "user" / Ident(clientId) => for { data <- req.as[Json] _ <- backend.clientSettings.saveUser(clientId, user.account, data) res <- Ok(BasicResult(true, "Settings stored")) } yield res - case GET -> Root / Ident(clientId) => + case GET -> Root / "user" / Ident(clientId) => for { data <- backend.clientSettings.loadUser(clientId, user.account) res <- data match { @@ -43,7 +57,7 @@ object ClientSettingsRoutes { } } yield res - case DELETE -> Root / Ident(clientId) => + case DELETE -> Root / "user" / Ident(clientId) => for { flag <- backend.clientSettings.deleteUser(clientId, user.account) res <- Ok( @@ -53,6 +67,36 @@ object ClientSettingsRoutes { ) ) } yield res + + case req @ PUT -> Root / "collective" / Ident(clientId) => + for { + data <- req.as[Json] + _ <- backend.clientSettings.saveCollective(clientId, user.account, data) + res <- Ok(BasicResult(true, "Settings stored")) + } yield res + + case GET -> Root / "collective" / Ident(clientId) => + for { + data <- backend.clientSettings.loadCollective(clientId, user.account) + res <- data match { + case Some(d) => Ok(d.settingsData) + case None => NotFound() + } + } yield res + + case DELETE -> Root / "collective" / Ident(clientId) => + for { + flag <- backend.clientSettings.deleteCollective(clientId, user.account) + res <- Ok( + BasicResult( + flag, + if (flag) "Settings deleted" else "Deleting settings failed" + ) + ) + } yield res } } + + implicit def jsonSemigroup: Semigroup[Json] = + Semigroup.instance((a1, a2) => a1.deepMerge(a2)) } diff --git a/modules/webapp/src/main/elm/Api.elm b/modules/webapp/src/main/elm/Api.elm index 1d719f5c..4c66482d 100644 --- a/modules/webapp/src/main/elm/Api.elm +++ b/modules/webapp/src/main/elm/Api.elm @@ -2261,7 +2261,7 @@ getClientSettings flags receive = Data.UiSettings.storedUiSettingsDecoder in Http2.authGet - { url = flags.config.baseUrl ++ "/api/v1/sec/clientSettings/webClient" + { url = flags.config.baseUrl ++ "/api/v1/sec/clientSettings/user/webClient" , account = getAccount flags , expect = Http.expectJson receive decoder } @@ -2277,7 +2277,7 @@ saveClientSettings flags settings receive = Data.UiSettings.storedUiSettingsEncode storedSettings in Http2.authPut - { url = flags.config.baseUrl ++ "/api/v1/sec/clientSettings/webClient" + { url = flags.config.baseUrl ++ "/api/v1/sec/clientSettings/user/webClient" , account = getAccount flags , body = Http.jsonBody encode , expect = Http.expectJson receive Api.Model.BasicResult.decoder