mirror of
				https://github.com/TheAnachronism/docspell.git
				synced 2025-10-31 09:30:12 +00:00 
			
		
		
		
	Allow a collective to disable the integration endpoint
This commit is contained in:
		| @@ -14,7 +14,7 @@ trait OCollective[F[_]] { | ||||
|  | ||||
|   def find(name: Ident): F[Option[RCollective]] | ||||
|  | ||||
|   def updateLanguage(collective: Ident, lang: Language): F[AddResult] | ||||
|   def updateSettings(collective: Ident, lang: OCollective.Settings): F[AddResult] | ||||
|  | ||||
|   def listUser(collective: Ident): F[Vector[RUser]] | ||||
|  | ||||
| @@ -45,6 +45,9 @@ object OCollective { | ||||
|   type InsightData = QCollective.InsightData | ||||
|   val insightData = QCollective.InsightData | ||||
|  | ||||
|   type Settings = RCollective.Settings | ||||
|   val Settings = RCollective.Settings | ||||
|  | ||||
|   sealed trait PassChangeResult | ||||
|   object PassChangeResult { | ||||
|     case object UserNotFound     extends PassChangeResult | ||||
| @@ -85,9 +88,9 @@ object OCollective { | ||||
|       def find(name: Ident): F[Option[RCollective]] = | ||||
|         store.transact(RCollective.findById(name)) | ||||
|  | ||||
|       def updateLanguage(collective: Ident, lang: Language): F[AddResult] = | ||||
|       def updateSettings(collective: Ident, sett: Settings): F[AddResult] = | ||||
|         store | ||||
|           .transact(RCollective.updateLanguage(collective, lang)) | ||||
|           .transact(RCollective.updateSettings(collective, sett)) | ||||
|           .attempt | ||||
|           .map(AddResult.fromUpdate) | ||||
|  | ||||
|   | ||||
| @@ -88,7 +88,13 @@ object OSignup { | ||||
|           for { | ||||
|             id2 <- Ident.randomId[F] | ||||
|             now <- Timestamp.current[F] | ||||
|             c = RCollective(data.collName, CollectiveState.Active, Language.German, now) | ||||
|             c = RCollective( | ||||
|               data.collName, | ||||
|               CollectiveState.Active, | ||||
|               Language.German, | ||||
|               true, | ||||
|               now | ||||
|             ) | ||||
|             u = RUser( | ||||
|               id2, | ||||
|               data.login, | ||||
|   | ||||
| @@ -618,10 +618,9 @@ paths: | ||||
|                 $ref: "#/components/schemas/CollectiveSettings" | ||||
|     post: | ||||
|       tags: [ Collective ] | ||||
|       summary: Set document language of the collective | ||||
|       summary: Update settings for a collective | ||||
|       description: | | ||||
|         Updates settings for a collective, which currently is just the | ||||
|         document language. | ||||
|         Updates settings for a collective. | ||||
|       security: | ||||
|         - authTokenHeader: [] | ||||
|       requestBody: | ||||
| @@ -2692,10 +2691,16 @@ components: | ||||
|         Settings for a collective. | ||||
|       required: | ||||
|         - language | ||||
|         - integrationEnabled | ||||
|       properties: | ||||
|         language: | ||||
|           type: string | ||||
|           format: language | ||||
|         integrationEnabled: | ||||
|           type: boolean | ||||
|           description: | | ||||
|             Whether the collective has the integration endpoint | ||||
|             enabled. | ||||
|     SourceList: | ||||
|       description: | | ||||
|         A list of sources. | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import cats.effect._ | ||||
| import cats.implicits._ | ||||
| import docspell.backend.BackendApp | ||||
| import docspell.backend.auth.AuthToken | ||||
| import docspell.backend.ops.OCollective | ||||
| import docspell.restapi.model._ | ||||
| import docspell.restserver.conv.Conversions | ||||
| import docspell.restserver.http4s._ | ||||
| @@ -28,16 +29,17 @@ object CollectiveRoutes { | ||||
|       case req @ POST -> Root / "settings" => | ||||
|         for { | ||||
|           settings <- req.as[CollectiveSettings] | ||||
|           sett = OCollective.Settings(settings.language, settings.integrationEnabled) | ||||
|           res <- | ||||
|             backend.collective | ||||
|               .updateLanguage(user.account.collective, settings.language) | ||||
|           resp <- Ok(Conversions.basicResult(res, "Language updated.")) | ||||
|               .updateSettings(user.account.collective, sett) | ||||
|           resp <- Ok(Conversions.basicResult(res, "Settings updated.")) | ||||
|         } yield resp | ||||
|  | ||||
|       case GET -> Root / "settings" => | ||||
|         for { | ||||
|           collDb <- backend.collective.find(user.account.collective) | ||||
|           sett = collDb.map(c => CollectiveSettings(c.language)) | ||||
|           sett = collDb.map(c => CollectiveSettings(c.language, c.integrationEnabled)) | ||||
|           resp <- sett.toResponse() | ||||
|         } yield resp | ||||
|  | ||||
|   | ||||
| @@ -59,7 +59,7 @@ object IntegrationEndpointRoutes { | ||||
|   ): EitherT[F, Response[F], Unit] = | ||||
|     for { | ||||
|       opt <- EitherT.liftF(backend.collective.find(coll)) | ||||
|       res <- EitherT.cond[F](opt.isDefined, (), Response.notFound[F]) | ||||
|       res <- EitherT.cond[F](opt.exists(_.integrationEnabled), (), Response.notFound[F]) | ||||
|     } yield res | ||||
|  | ||||
|   def uploadFile[F[_]: Effect]( | ||||
|   | ||||
| @@ -12,7 +12,8 @@ case class Flags( | ||||
|     appName: String, | ||||
|     baseUrl: LenientUri, | ||||
|     signupMode: SignupConfig.Mode, | ||||
|     docspellAssetPath: String | ||||
|     docspellAssetPath: String, | ||||
|     integrationEnabled: Boolean | ||||
| ) | ||||
|  | ||||
| object Flags { | ||||
| @@ -21,7 +22,8 @@ object Flags { | ||||
|       cfg.appName, | ||||
|       cfg.baseUrl, | ||||
|       cfg.backend.signup.mode, | ||||
|       s"/app/assets/docspell-webapp/${BuildInfo.version}" | ||||
|       s"/app/assets/docspell-webapp/${BuildInfo.version}", | ||||
|       cfg.integrationEndpoint.enabled | ||||
|     ) | ||||
|  | ||||
|   implicit val jsonEncoder: Encoder[Flags] = | ||||
|   | ||||
| @@ -0,0 +1,7 @@ | ||||
| ALTER TABLE `collective` | ||||
| ADD COLUMN (`integration_enabled` BOOLEAN); | ||||
|  | ||||
| UPDATE `collective` SET `integration_enabled` = true; | ||||
|  | ||||
| ALTER TABLE `collective` | ||||
| MODIFY `integration_enabled` BOOLEAN NOT NULL; | ||||
| @@ -0,0 +1,7 @@ | ||||
| ALTER TABLE "collective" | ||||
| ADD COLUMN "integration_enabled" BOOLEAN; | ||||
|  | ||||
| UPDATE "collective" SET "integration_enabled" = true; | ||||
|  | ||||
| ALTER TABLE "collective" | ||||
| ALTER COLUMN "integration_enabled" SET NOT NULL; | ||||
| @@ -11,6 +11,7 @@ case class RCollective( | ||||
|     id: Ident, | ||||
|     state: CollectiveState, | ||||
|     language: Language, | ||||
|     integrationEnabled: Boolean, | ||||
|     created: Timestamp | ||||
| ) | ||||
|  | ||||
| @@ -20,12 +21,13 @@ object RCollective { | ||||
|  | ||||
|   object Columns { | ||||
|  | ||||
|     val id       = Column("cid") | ||||
|     val state    = Column("state") | ||||
|     val language = Column("doclang") | ||||
|     val created  = Column("created") | ||||
|     val id          = Column("cid") | ||||
|     val state       = Column("state") | ||||
|     val language    = Column("doclang") | ||||
|     val integration = Column("integration_enabled") | ||||
|     val created     = Column("created") | ||||
|  | ||||
|     val all = List(id, state, language, created) | ||||
|     val all = List(id, state, language, integration, created) | ||||
|   } | ||||
|  | ||||
|   import Columns._ | ||||
| @@ -34,7 +36,7 @@ object RCollective { | ||||
|     val sql = insertRow( | ||||
|       table, | ||||
|       Columns.all, | ||||
|       fr"${value.id},${value.state},${value.language},${value.created}" | ||||
|       fr"${value.id},${value.state},${value.language},${value.integrationEnabled},${value.created}" | ||||
|     ) | ||||
|     sql.update.run | ||||
|   } | ||||
| @@ -56,6 +58,16 @@ object RCollective { | ||||
|   def updateLanguage(cid: Ident, lang: Language): ConnectionIO[Int] = | ||||
|     updateRow(table, id.is(cid), language.setTo(lang)).update.run | ||||
|  | ||||
|   def updateSettings(cid: Ident, settings: Settings): ConnectionIO[Int] = | ||||
|     updateRow( | ||||
|       table, | ||||
|       id.is(cid), | ||||
|       commas( | ||||
|         language.setTo(settings.language), | ||||
|         integration.setTo(settings.integrationEnabled) | ||||
|       ) | ||||
|     ).update.run | ||||
|  | ||||
|   def findById(cid: Ident): ConnectionIO[Option[RCollective]] = { | ||||
|     val sql = selectSimple(all, table, id.is(cid)) | ||||
|     sql.query[RCollective].option | ||||
| @@ -75,4 +87,6 @@ object RCollective { | ||||
|     val sql = selectSimple(all, table, Fragment.empty) ++ orderBy(order(Columns).f) | ||||
|     sql.query[RCollective].stream | ||||
|   } | ||||
|  | ||||
|   case class Settings(language: Language, integrationEnabled: Boolean) | ||||
| } | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| module Comp.Settings exposing | ||||
| module Comp.CollectiveSettingsForm exposing | ||||
|     ( Model | ||||
|     , Msg | ||||
|     , getSettings | ||||
| @@ -13,10 +13,12 @@ import Data.Flags exposing (Flags) | ||||
| import Data.Language exposing (Language) | ||||
| import Html exposing (..) | ||||
| import Html.Attributes exposing (..) | ||||
| import Html.Events exposing (onCheck) | ||||
| 
 | ||||
| 
 | ||||
| type alias Model = | ||||
|     { langModel : Comp.Dropdown.Model Language | ||||
|     , intEnabled : Bool | ||||
|     , initSettings : CollectiveSettings | ||||
|     } | ||||
| 
 | ||||
| @@ -39,6 +41,7 @@ init settings = | ||||
|             , options = Data.Language.all | ||||
|             , selected = Just lang | ||||
|             } | ||||
|     , intEnabled = settings.integrationEnabled | ||||
|     , initSettings = settings | ||||
|     } | ||||
| 
 | ||||
| @@ -51,10 +54,12 @@ getSettings model = | ||||
|             |> Maybe.map Data.Language.toIso3 | ||||
|             |> Maybe.withDefault model.initSettings.language | ||||
|         ) | ||||
|         model.intEnabled | ||||
| 
 | ||||
| 
 | ||||
| type Msg | ||||
|     = LangDropdownMsg (Comp.Dropdown.Msg Language) | ||||
|     | ToggleIntegrationEndpoint | ||||
| 
 | ||||
| 
 | ||||
| update : Flags -> Msg -> Model -> ( Model, Cmd Msg, Maybe CollectiveSettings ) | ||||
| @@ -77,12 +82,42 @@ update _ msg model = | ||||
|             in | ||||
|             ( nextModel, Cmd.map LangDropdownMsg c2, nextSettings ) | ||||
| 
 | ||||
|         ToggleIntegrationEndpoint -> | ||||
|             let | ||||
|                 nextModel = | ||||
|                     { model | intEnabled = not model.intEnabled } | ||||
|             in | ||||
|             ( nextModel, Cmd.none, Just (getSettings nextModel) ) | ||||
| 
 | ||||
| view : Model -> Html Msg | ||||
| view model = | ||||
| 
 | ||||
| view : Flags -> Model -> Html Msg | ||||
| view flags model = | ||||
|     div [ class "ui form" ] | ||||
|         [ div [ class "field" ] | ||||
|             [ label [] [ text "Document Language" ] | ||||
|             , Html.map LangDropdownMsg (Comp.Dropdown.view model.langModel) | ||||
|             , span [ class "small-info" ] | ||||
|                 [ text "The language of your documents. This helps text recognition (OCR) and text analysis." | ||||
|                 ] | ||||
|             ] | ||||
|         , div | ||||
|             [ classList | ||||
|                 [ ( "field", True ) | ||||
|                 , ( "invisible hidden", not flags.config.integrationEnabled ) | ||||
|                 ] | ||||
|             ] | ||||
|             [ div [ class "ui checkbox" ] | ||||
|                 [ input | ||||
|                     [ type_ "checkbox" | ||||
|                     , onCheck (\_ -> ToggleIntegrationEndpoint) | ||||
|                     , checked model.intEnabled | ||||
|                     ] | ||||
|                     [] | ||||
|                 , label [] [ text "Enable integration endpoint" ] | ||||
|                 , span [ class "small-info" ] | ||||
|                     [ text "The integration endpoint allows (local) applications to submit files. " | ||||
|                     , text "You can choose to disable it for your collective." | ||||
|                     ] | ||||
|                 ] | ||||
|             ] | ||||
|         ] | ||||
| @@ -14,6 +14,7 @@ type alias Config = | ||||
|     , baseUrl : String | ||||
|     , signupMode : String | ||||
|     , docspellAssetPath : String | ||||
|     , integrationEnabled : Bool | ||||
|     } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -8,7 +8,7 @@ module Page.CollectiveSettings.Data exposing | ||||
| import Api.Model.BasicResult exposing (BasicResult) | ||||
| import Api.Model.CollectiveSettings exposing (CollectiveSettings) | ||||
| import Api.Model.ItemInsights exposing (ItemInsights) | ||||
| import Comp.Settings | ||||
| import Comp.CollectiveSettingsForm | ||||
| import Comp.SourceManage | ||||
| import Comp.UserManage | ||||
| import Http | ||||
| @@ -18,7 +18,7 @@ type alias Model = | ||||
|     { currentTab : Maybe Tab | ||||
|     , sourceModel : Comp.SourceManage.Model | ||||
|     , userModel : Comp.UserManage.Model | ||||
|     , settingsModel : Comp.Settings.Model | ||||
|     , settingsModel : Comp.CollectiveSettingsForm.Model | ||||
|     , insights : ItemInsights | ||||
|     , submitResult : Maybe BasicResult | ||||
|     } | ||||
| @@ -29,7 +29,7 @@ emptyModel = | ||||
|     { currentTab = Just InsightsTab | ||||
|     , sourceModel = Comp.SourceManage.emptyModel | ||||
|     , userModel = Comp.UserManage.emptyModel | ||||
|     , settingsModel = Comp.Settings.init Api.Model.CollectiveSettings.empty | ||||
|     , settingsModel = Comp.CollectiveSettingsForm.init Api.Model.CollectiveSettings.empty | ||||
|     , insights = Api.Model.ItemInsights.empty | ||||
|     , submitResult = Nothing | ||||
|     } | ||||
| @@ -46,7 +46,7 @@ type Msg | ||||
|     = SetTab Tab | ||||
|     | SourceMsg Comp.SourceManage.Msg | ||||
|     | UserMsg Comp.UserManage.Msg | ||||
|     | SettingsMsg Comp.Settings.Msg | ||||
|     | SettingsFormMsg Comp.CollectiveSettingsForm.Msg | ||||
|     | Init | ||||
|     | GetInsightsResp (Result Http.Error ItemInsights) | ||||
|     | CollectiveSettingsResp (Result Http.Error CollectiveSettings) | ||||
|   | ||||
| @@ -2,7 +2,7 @@ module Page.CollectiveSettings.Update exposing (update) | ||||
|  | ||||
| import Api | ||||
| import Api.Model.BasicResult exposing (BasicResult) | ||||
| import Comp.Settings | ||||
| import Comp.CollectiveSettingsForm | ||||
| import Comp.SourceManage | ||||
| import Comp.UserManage | ||||
| import Data.Flags exposing (Flags) | ||||
| @@ -45,10 +45,10 @@ update flags msg model = | ||||
|             in | ||||
|             ( { model | userModel = m2 }, Cmd.map UserMsg c2 ) | ||||
|  | ||||
|         SettingsMsg m -> | ||||
|         SettingsFormMsg m -> | ||||
|             let | ||||
|                 ( m2, c2, msett ) = | ||||
|                     Comp.Settings.update flags m model.settingsModel | ||||
|                     Comp.CollectiveSettingsForm.update flags m model.settingsModel | ||||
|  | ||||
|                 cmd = | ||||
|                     case msett of | ||||
| @@ -58,7 +58,9 @@ update flags msg model = | ||||
|                         Just sett -> | ||||
|                             Api.setCollectiveSettings flags sett SubmitResp | ||||
|             in | ||||
|             ( { model | settingsModel = m2, submitResult = Nothing }, Cmd.batch [ cmd, Cmd.map SettingsMsg c2 ] ) | ||||
|             ( { model | settingsModel = m2, submitResult = Nothing } | ||||
|             , Cmd.batch [ cmd, Cmd.map SettingsFormMsg c2 ] | ||||
|             ) | ||||
|  | ||||
|         Init -> | ||||
|             ( { model | submitResult = Nothing } | ||||
| @@ -75,7 +77,7 @@ update flags msg model = | ||||
|             ( model, Cmd.none ) | ||||
|  | ||||
|         CollectiveSettingsResp (Ok data) -> | ||||
|             ( { model | settingsModel = Comp.Settings.init data }, Cmd.none ) | ||||
|             ( { model | settingsModel = Comp.CollectiveSettingsForm.init data }, Cmd.none ) | ||||
|  | ||||
|         CollectiveSettingsResp (Err _) -> | ||||
|             ( model, Cmd.none ) | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| module Page.CollectiveSettings.View exposing (view) | ||||
|  | ||||
| import Api.Model.NameCount exposing (NameCount) | ||||
| import Comp.Settings | ||||
| import Comp.CollectiveSettingsForm | ||||
| import Comp.SourceManage | ||||
| import Comp.UserManage | ||||
| import Data.Flags exposing (Flags) | ||||
| @@ -41,8 +41,8 @@ view flags model = | ||||
|                         [ classActive (model.currentTab == Just SettingsTab) "link icon item" | ||||
|                         , onClick (SetTab SettingsTab) | ||||
|                         ] | ||||
|                         [ i [ class "language icon" ] [] | ||||
|                         , text "Document Language" | ||||
|                         [ i [ class "cog icon" ] [] | ||||
|                         , text "Settings" | ||||
|                         ] | ||||
|                     , div | ||||
|                         [ classActive (model.currentTab == Just UserTab) "link icon item" | ||||
| @@ -67,7 +67,7 @@ view flags model = | ||||
|                         viewInsights model | ||||
|  | ||||
|                     Just SettingsTab -> | ||||
|                         viewSettings model | ||||
|                         viewSettings flags model | ||||
|  | ||||
|                     Nothing -> | ||||
|                         [] | ||||
| @@ -176,42 +176,25 @@ viewUsers model = | ||||
|     ] | ||||
|  | ||||
|  | ||||
| viewSettings : Model -> List (Html Msg) | ||||
| viewSettings model = | ||||
|     [ div [ class "ui grid" ] | ||||
|         [ div [ class "row" ] | ||||
|             [ div [ class "sixteen wide colum" ] | ||||
|                 [ h2 [ class "ui header" ] | ||||
|                     [ i [ class "ui language icon" ] [] | ||||
|                     , div [ class "content" ] | ||||
|                         [ text "Document Language" | ||||
|                         ] | ||||
|                     ] | ||||
|                 ] | ||||
|             ] | ||||
|         , div [ class "row" ] | ||||
|             [ div [ class "six wide column" ] | ||||
|                 [ div [ class "ui basic segment" ] | ||||
|                     [ text "The language of your documents. This helps text recognition (OCR) and text analysis." | ||||
|                     ] | ||||
|                 ] | ||||
|             ] | ||||
|         , div [ class "row" ] | ||||
|             [ div [ class "six wide column" ] | ||||
|                 [ Html.map SettingsMsg (Comp.Settings.view model.settingsModel) | ||||
|                 , div | ||||
|                     [ classList | ||||
|                         [ ( "ui message", True ) | ||||
|                         , ( "hidden", Util.Maybe.isEmpty model.submitResult ) | ||||
|                         , ( "success", Maybe.map .success model.submitResult |> Maybe.withDefault False ) | ||||
|                         , ( "error", Maybe.map .success model.submitResult |> Maybe.map not |> Maybe.withDefault False ) | ||||
|                         ] | ||||
|                     ] | ||||
|                     [ Maybe.map .message model.submitResult | ||||
|                         |> Maybe.withDefault "" | ||||
|                         |> text | ||||
|                     ] | ||||
|                 ] | ||||
| viewSettings : Flags -> Model -> List (Html Msg) | ||||
| viewSettings flags model = | ||||
|     [ h2 [ class "ui header" ] | ||||
|         [ i [ class "cog icon" ] [] | ||||
|         , text "Settings" | ||||
|         ] | ||||
|     , div [ class "ui segment" ] | ||||
|         [ Html.map SettingsFormMsg (Comp.CollectiveSettingsForm.view flags model.settingsModel) | ||||
|         ] | ||||
|     , div | ||||
|         [ classList | ||||
|             [ ( "ui message", True ) | ||||
|             , ( "hidden", Util.Maybe.isEmpty model.submitResult ) | ||||
|             , ( "success", Maybe.map .success model.submitResult |> Maybe.withDefault False ) | ||||
|             , ( "error", Maybe.map .success model.submitResult |> Maybe.map not |> Maybe.withDefault False ) | ||||
|             ] | ||||
|         ] | ||||
|         [ Maybe.map .message model.submitResult | ||||
|             |> Maybe.withDefault "" | ||||
|             |> text | ||||
|         ] | ||||
|     ] | ||||
|   | ||||
		Reference in New Issue
	
	Block a user