Add route to get settings for a share

Returns the client settings of the creator.
This commit is contained in:
eikek 2022-01-29 10:11:54 +01:00
parent c29ce73dd0
commit 1ca64f09d1
4 changed files with 78 additions and 9 deletions
modules
backend/src/main/scala/docspell/backend/ops
restapi/src/main/resources
restserver/src/main/scala/docspell/restserver

@ -48,6 +48,8 @@ trait OShare[F[_]] {
// ---
def findActiveById(id: Ident): OptionT[F, ShareData]
/** Verifies the given id and password and returns a authorization token on success. */
def verify(key: ByteVector)(id: Ident, password: Option[Password]): F[VerifyResult]
@ -277,6 +279,9 @@ object OShare {
VerifyResult.invalidToken.pure[F]
}
def findActiveById(id: Ident): OptionT[F, ShareData] =
RShare.findCurrentActive(id).mapK(store.transform).map(ShareData.tupled)
def findShareQuery(id: Ident): OptionT[F, ShareQuery] =
RShare
.findCurrentActive(id)

@ -2304,7 +2304,7 @@ paths:
/share/attachment/{id}/preview:
head:
operationId: "share-attach-check-preview"
tags: [ Attachment ]
tags: [ Share ]
summary: Get the headers to a preview image of an attachment file.
description: |
Checks if an image file showing a preview of the attachment is
@ -2320,7 +2320,7 @@ paths:
description: NotFound
get:
operationId: "share-attach-get-preview"
tags: [ Attachment ]
tags: [ Share ]
summary: Get a preview image of an attachment file.
description: |
Gets a image file showing a preview of the attachment. Usually
@ -2347,6 +2347,37 @@ paths:
schema:
type: string
format: binary
/share/clientSettings/{clientId}:
parameters:
- $ref: "#/components/parameters/clientId"
get:
operationId: "share-clientsettings-get"
tags: [ Share ]
summary: Return the client settings of current user
description: |
Returns the settings for the share. This is the settings of
the user who created the share. It is created 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:
- shareTokenHeader: []
responses:
422:
description: BadRequest
200:
description: Ok
content:
application/json:
schema: {}
/admin/user/resetPassword:
post:

@ -213,7 +213,8 @@ object RestServer {
Router(
"search" -> ShareSearchRoutes(restApp.backend, cfg, token),
"attachment" -> ShareAttachmentRoutes(restApp.backend, token),
"item" -> ShareItemRoutes(restApp.backend, token)
"item" -> ShareItemRoutes(restApp.backend, token),
"clientSettings" -> ClientSettingsRoutes.share(restApp.backend, token)
)
def redirectTo[F[_]: Async](path: String): HttpRoutes[F] = {

@ -8,10 +8,11 @@ package docspell.restserver.routes
import cats.effect._
import cats.implicits._
import cats.kernel.Semigroup
import cats.{Monad, Semigroup}
import cats.data.OptionT
import docspell.backend.BackendApp
import docspell.backend.auth.AuthToken
import docspell.backend.auth.{AuthToken, ShareToken}
import docspell.common._
import docspell.restapi.model._
@ -23,6 +24,30 @@ import org.http4s.dsl.Http4sDsl
object ClientSettingsRoutes {
def share[F[_]: Async](
backend: BackendApp[F],
token: ShareToken
): HttpRoutes[F] = {
val logger = Logger.log4s[F](org.log4s.getLogger)
val dsl = new Http4sDsl[F] {}
import dsl._
HttpRoutes.of {
case GET -> Root / Ident(clientId) =>
(for {
_ <- OptionT.liftF(logger.debug(s"Get client settings for share ${token.id}"))
share <- backend.share.findActiveById(token.id)
merged <- OptionT.liftF(getMergedSettings(backend, share.user.accountId, clientId))
res <- OptionT.liftF(merged match {
case Some(j) => Ok(j)
case None => NotFound()
})
} yield res)
.getOrElseF(Ok(Map.empty[String, String]))
}
}
def apply[F[_]: Async](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = {
val dsl = new Http4sDsl[F] {}
import dsl._
@ -30,10 +55,7 @@ object ClientSettingsRoutes {
HttpRoutes.of {
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)
mergedData <- getMergedSettings(backend, user.account, clientId)
res <- mergedData match {
case Some(j) => Ok(j)
@ -97,6 +119,16 @@ object ClientSettingsRoutes {
}
}
def getMergedSettings[F[_]: Monad](backend:BackendApp[F], account: AccountId, clientId: Ident) =
for {
collData <- backend.clientSettings.loadCollective(clientId, account)
userData <- backend.clientSettings.loadUser(clientId, account)
mergedData = collData.map(_.settingsData) |+| userData.map(_.settingsData)
} yield mergedData
implicit def jsonSemigroup: Semigroup[Json] =
Semigroup.instance((a1, a2) => a1.deepMerge(a2))
}