mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-22 02:18:26 +00:00
Use collective settings for shares
This commit is contained in:
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
package docspell.backend.ops
|
package docspell.backend.ops
|
||||||
|
|
||||||
|
import cats.Semigroup
|
||||||
import cats.data.OptionT
|
import cats.data.OptionT
|
||||||
import cats.effect.{Async, Resource}
|
import cats.effect.{Async, Resource}
|
||||||
import cats.implicits._
|
import cats.implicits._
|
||||||
@ -32,6 +33,7 @@ trait OClientSettings[F[_]] {
|
|||||||
account: AccountId
|
account: AccountId
|
||||||
): F[Option[RClientSettingsCollective]]
|
): F[Option[RClientSettingsCollective]]
|
||||||
|
|
||||||
|
def loadMerged(clientId: Ident, account: AccountId): F[Option[Json]]
|
||||||
}
|
}
|
||||||
|
|
||||||
object OClientSettings {
|
object OClientSettings {
|
||||||
@ -108,5 +110,14 @@ object OClientSettings {
|
|||||||
data <- OptionT(store.transact(RClientSettingsUser.find(clientId, userId)))
|
data <- OptionT(store.transact(RClientSettingsUser.find(clientId, userId)))
|
||||||
} yield data).value
|
} yield data).value
|
||||||
|
|
||||||
|
def loadMerged(clientId: Ident, account: AccountId) =
|
||||||
|
for {
|
||||||
|
collData <- loadCollective(clientId, account)
|
||||||
|
userData <- loadUser(clientId, account)
|
||||||
|
mergedData = collData.map(_.settingsData) |+| userData.map(_.settingsData)
|
||||||
|
} yield mergedData
|
||||||
|
|
||||||
|
implicit def jsonSemigroup: Semigroup[Json] =
|
||||||
|
Semigroup.instance((a1, a2) => a1.deepMerge(a2))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -2356,13 +2356,7 @@ paths:
|
|||||||
summary: Return the client settings of current user
|
summary: Return the client settings of current user
|
||||||
description: |
|
description: |
|
||||||
Returns the settings for the share. This is the settings of
|
Returns the settings for the share. This is the settings of
|
||||||
the user who created the share. It is created by merging the
|
the collective that belongs to the share.
|
||||||
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
|
The `clientId` is an identifier to a client application. It
|
||||||
returns a JSON structure. The server doesn't care about the
|
returns a JSON structure. The server doesn't care about the
|
||||||
|
@ -6,10 +6,9 @@
|
|||||||
|
|
||||||
package docspell.restserver.routes
|
package docspell.restserver.routes
|
||||||
|
|
||||||
|
import cats.data.OptionT
|
||||||
import cats.effect._
|
import cats.effect._
|
||||||
import cats.implicits._
|
import cats.implicits._
|
||||||
import cats.{Monad, Semigroup}
|
|
||||||
import cats.data.OptionT
|
|
||||||
|
|
||||||
import docspell.backend.BackendApp
|
import docspell.backend.BackendApp
|
||||||
import docspell.backend.auth.{AuthToken, ShareToken}
|
import docspell.backend.auth.{AuthToken, ShareToken}
|
||||||
@ -33,16 +32,14 @@ object ClientSettingsRoutes {
|
|||||||
val dsl = new Http4sDsl[F] {}
|
val dsl = new Http4sDsl[F] {}
|
||||||
import dsl._
|
import dsl._
|
||||||
|
|
||||||
HttpRoutes.of {
|
HttpRoutes.of { case GET -> Root / Ident(clientId) =>
|
||||||
case GET -> Root / Ident(clientId) =>
|
|
||||||
(for {
|
(for {
|
||||||
_ <- OptionT.liftF(logger.debug(s"Get client settings for share ${token.id}"))
|
_ <- OptionT.liftF(logger.debug(s"Get client settings for share ${token.id}"))
|
||||||
share <- backend.share.findActiveById(token.id)
|
share <- backend.share.findActiveById(token.id)
|
||||||
merged <- OptionT.liftF(getMergedSettings(backend, share.user.accountId, clientId))
|
sett <- OptionT(
|
||||||
res <- OptionT.liftF(merged match {
|
backend.clientSettings.loadCollective(clientId, share.user.accountId)
|
||||||
case Some(j) => Ok(j)
|
)
|
||||||
case None => NotFound()
|
res <- OptionT.liftF(Ok(sett.settingsData))
|
||||||
})
|
|
||||||
} yield res)
|
} yield res)
|
||||||
.getOrElseF(Ok(Map.empty[String, String]))
|
.getOrElseF(Ok(Map.empty[String, String]))
|
||||||
}
|
}
|
||||||
@ -55,11 +52,10 @@ object ClientSettingsRoutes {
|
|||||||
HttpRoutes.of {
|
HttpRoutes.of {
|
||||||
case GET -> Root / Ident(clientId) =>
|
case GET -> Root / Ident(clientId) =>
|
||||||
for {
|
for {
|
||||||
mergedData <- getMergedSettings(backend, user.account, clientId)
|
mergedData <- backend.clientSettings.loadMerged(clientId, user.account)
|
||||||
|
|
||||||
res <- mergedData match {
|
res <- mergedData match {
|
||||||
case Some(j) => Ok(j)
|
case Some(j) => Ok(j)
|
||||||
case None => NotFound()
|
case None => Ok(Map.empty[String, String])
|
||||||
}
|
}
|
||||||
} yield res
|
} yield res
|
||||||
|
|
||||||
@ -118,17 +114,4 @@ object ClientSettingsRoutes {
|
|||||||
} yield res
|
} yield res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
|
@ -580,7 +580,6 @@ update flags sett msg model =
|
|||||||
TagsTab ->
|
TagsTab ->
|
||||||
{ sett | tagCategoryColors = Nothing }
|
{ sett | tagCategoryColors = Nothing }
|
||||||
|
|
||||||
-- no reset here
|
|
||||||
FieldsTab ->
|
FieldsTab ->
|
||||||
{ sett | formFields = Nothing }
|
{ sett | formFields = Nothing }
|
||||||
|
|
||||||
@ -658,7 +657,7 @@ settingFormTabs texts flags _ model =
|
|||||||
, onClick (ResetTab tab)
|
, onClick (ResetTab tab)
|
||||||
]
|
]
|
||||||
[ i [ class "fa fa-eraser mr-1" ] []
|
[ i [ class "fa fa-eraser mr-1" ] []
|
||||||
, text "Reset"
|
, text texts.resetLabel
|
||||||
]
|
]
|
||||||
in
|
in
|
||||||
[ { name = akkordionTabName GeneralTab
|
[ { name = akkordionTabName GeneralTab
|
||||||
|
@ -28,7 +28,9 @@ import Html.Attributes exposing (..)
|
|||||||
import Http
|
import Http
|
||||||
import Messages.Comp.UiSettingsManage exposing (Texts)
|
import Messages.Comp.UiSettingsManage exposing (Texts)
|
||||||
import Page.Search.Data exposing (Msg(..))
|
import Page.Search.Data exposing (Msg(..))
|
||||||
|
import Process
|
||||||
import Styles as S
|
import Styles as S
|
||||||
|
import Task
|
||||||
|
|
||||||
|
|
||||||
type alias Model =
|
type alias Model =
|
||||||
@ -67,6 +69,7 @@ type Msg
|
|||||||
| ReceiveServerSettings (Result Http.Error ( StoredUiSettings, StoredUiSettings ))
|
| ReceiveServerSettings (Result Http.Error ( StoredUiSettings, StoredUiSettings ))
|
||||||
| ToggleExpandCollapse
|
| ToggleExpandCollapse
|
||||||
| SwitchForm AccountScope
|
| SwitchForm AccountScope
|
||||||
|
| ResetFormState
|
||||||
|
|
||||||
|
|
||||||
init : Flags -> ( Model, Cmd Msg )
|
init : Flags -> ( Model, Cmd Msg )
|
||||||
@ -134,12 +137,6 @@ update flags settings msg model =
|
|||||||
| collSettings = Maybe.withDefault data.collSettings sett
|
| collSettings = Maybe.withDefault data.collSettings sett
|
||||||
, collModel = m_
|
, collModel = m_
|
||||||
}
|
}
|
||||||
, formResult =
|
|
||||||
if sett /= Nothing then
|
|
||||||
FormInit
|
|
||||||
|
|
||||||
else
|
|
||||||
model.formResult
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Data.AccountScope.User ->
|
Data.AccountScope.User ->
|
||||||
@ -155,12 +152,6 @@ update flags settings msg model =
|
|||||||
| userSettings = Maybe.withDefault data.userSettings sett
|
| userSettings = Maybe.withDefault data.userSettings sett
|
||||||
, userModel = m_
|
, userModel = m_
|
||||||
}
|
}
|
||||||
, formResult =
|
|
||||||
if sett /= Nothing then
|
|
||||||
FormInit
|
|
||||||
|
|
||||||
else
|
|
||||||
model.formResult
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Submit ->
|
Submit ->
|
||||||
@ -198,9 +189,13 @@ update flags settings msg model =
|
|||||||
update flags
|
update flags
|
||||||
settings
|
settings
|
||||||
(ReceiveServerSettings (Ok ( data.collSettings, data.userSettings )))
|
(ReceiveServerSettings (Ok ( data.collSettings, data.userSettings )))
|
||||||
model
|
{ model | formResult = FormSaved }
|
||||||
|
|
||||||
|
cmd =
|
||||||
|
Process.sleep 2000
|
||||||
|
|> Task.perform (\_ -> ResetFormState)
|
||||||
in
|
in
|
||||||
{ result | appEvent = AppReloadUiSettings }
|
{ result | appEvent = AppReloadUiSettings, cmd = Cmd.batch [ cmd, result.cmd ] }
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
unit { model | formResult = FormUnknownError }
|
unit { model | formResult = FormUnknownError }
|
||||||
@ -231,7 +226,13 @@ update flags settings msg model =
|
|||||||
, collSettings = coll
|
, collSettings = coll
|
||||||
, collModel = cm
|
, collModel = cm
|
||||||
}
|
}
|
||||||
, formModel = ViewUser
|
, formModel =
|
||||||
|
case model.formModel of
|
||||||
|
ViewLoading ->
|
||||||
|
ViewUser
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
model.formModel
|
||||||
}
|
}
|
||||||
|
|
||||||
cmds =
|
cmds =
|
||||||
@ -262,6 +263,14 @@ update flags settings msg model =
|
|||||||
in
|
in
|
||||||
Data.AccountScope.fold forUser forColl scope
|
Data.AccountScope.fold forUser forColl scope
|
||||||
|
|
||||||
|
ResetFormState ->
|
||||||
|
case model.formResult of
|
||||||
|
FormSaved ->
|
||||||
|
unit { model | formResult = FormInit }
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
unit model
|
||||||
|
|
||||||
|
|
||||||
isError : Model -> Bool
|
isError : Model -> Bool
|
||||||
isError model =
|
isError model =
|
||||||
@ -364,6 +373,9 @@ view2 texts flags _ classes model =
|
|||||||
[ h2 [ class S.header2 ]
|
[ h2 [ class S.header2 ]
|
||||||
[ text texts.collectiveHeader
|
[ text texts.collectiveHeader
|
||||||
]
|
]
|
||||||
|
, div [ class "py-1 opacity-80" ]
|
||||||
|
[ text texts.collectiveInfo
|
||||||
|
]
|
||||||
, Html.map (UiFormMsg scope)
|
, Html.map (UiFormMsg scope)
|
||||||
(Comp.UiSettingsForm.view2
|
(Comp.UiSettingsForm.view2
|
||||||
texts.uiSettingsForm
|
texts.uiSettingsForm
|
||||||
|
@ -56,6 +56,7 @@ type alias Texts =
|
|||||||
, fieldLabel : Field -> String
|
, fieldLabel : Field -> String
|
||||||
, templateHelpMessage : String
|
, templateHelpMessage : String
|
||||||
, pdfMode : PdfMode -> String
|
, pdfMode : PdfMode -> String
|
||||||
|
, resetLabel : String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -131,6 +132,7 @@ and if that is not present the person. If both are absent a dash `-`
|
|||||||
is rendered.
|
is rendered.
|
||||||
"""
|
"""
|
||||||
, pdfMode = Messages.Data.PdfMode.gb
|
, pdfMode = Messages.Data.PdfMode.gb
|
||||||
|
, resetLabel = "Reset"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -208,4 +210,5 @@ oder, wenn diese leer ist, die Person. Sind beide leer wird ein `-`
|
|||||||
dargestellt.
|
dargestellt.
|
||||||
"""
|
"""
|
||||||
, pdfMode = Messages.Data.PdfMode.de
|
, pdfMode = Messages.Data.PdfMode.de
|
||||||
|
, resetLabel = "Zurücksetzen"
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ type alias Texts =
|
|||||||
, userHeader : String
|
, userHeader : String
|
||||||
, userInfo : String
|
, userInfo : String
|
||||||
, collectiveHeader : String
|
, collectiveHeader : String
|
||||||
|
, collectiveInfo : String
|
||||||
, expandCollapse : String
|
, expandCollapse : String
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,8 +46,9 @@ gb =
|
|||||||
, unknownSaveError = "Unknown error while trying to save settings."
|
, unknownSaveError = "Unknown error while trying to save settings."
|
||||||
, httpError = Messages.Comp.HttpError.gb
|
, httpError = Messages.Comp.HttpError.gb
|
||||||
, userHeader = "Personal settings"
|
, userHeader = "Personal settings"
|
||||||
, userInfo = "Your personal settings override those of the collective. On reset, settings are set back to those of the collective."
|
, userInfo = "Your personal settings override those of the collective. On reset, settings are taken from the collective settings."
|
||||||
, collectiveHeader = "Collective settings"
|
, collectiveHeader = "Collective settings"
|
||||||
|
, collectiveInfo = "These settings apply to all users, unless overriden by personal ones. A reset loads the provided default values of the application."
|
||||||
, expandCollapse = "Expand/collapse all"
|
, expandCollapse = "Expand/collapse all"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +64,8 @@ de =
|
|||||||
, unknownSaveError = "Unbekannter Fehler beim Speichern der Einstellungen."
|
, unknownSaveError = "Unbekannter Fehler beim Speichern der Einstellungen."
|
||||||
, httpError = Messages.Comp.HttpError.de
|
, httpError = Messages.Comp.HttpError.de
|
||||||
, userHeader = "Persönliche Einstellungen"
|
, userHeader = "Persönliche Einstellungen"
|
||||||
, userInfo = "Die persönlichen Einstellungen überschreiben die des Kollektivs. Wenn Einstellungen zurückgesetzt werden, werden sie auf die Werte des Kollektivs gesetzt."
|
, userInfo = "Die persönlichen Einstellungen überschreiben die des Kollektivs. Wenn Einstellungen zurückgesetzt werden, gelten automatisch die Werte des Kollektivs."
|
||||||
, collectiveHeader = "Kollektiv Einstellungen"
|
, collectiveHeader = "Kollektiv Einstellungen"
|
||||||
|
, collectiveInfo = "Diese Einstellungen sind für alle Benutzer, können aber in den persönlichen Einstellungen überschrieben werden. Durch ein Zurücksetzen erhält man die bereitgestellten Standardwerte der Anwendung."
|
||||||
, expandCollapse = "Alle ein-/ausklappen"
|
, expandCollapse = "Alle ein-/ausklappen"
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user