Add stub form scan-mailbox form

This commit is contained in:
Eike Kettner 2020-05-18 09:55:49 +02:00
parent a4be63fd77
commit 0d6677f90b
6 changed files with 576 additions and 0 deletions

View File

@ -1755,8 +1755,113 @@ paths:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/usertask/scanmailbox:
get:
tags: [ User Tasks ]
summary: Get settings for "Scan Mailbox" task
description: |
Return the current settings for the scan mailbox task of the
authenticated user. Users can periodically fetch mails to be
imported into docspell.
security:
- authTokenHeader: []
responses:
200:
description: Ok
content:
application/json:
schema:
$ref: "#/components/schemas/ScanMailboxSettings"
post:
tags: [ User Tasks ]
summary: Change current settings for "Scan Mailbox" task
description: |
Change the current settings for the scan-mailbox task of the
authenticated user.
security:
- authTokenHeader: []
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/ScanMailboxSettings"
responses:
200:
description: Ok
content:
application/json:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/usertask/scanmailbox/startonce:
post:
tags: [ User Tasks ]
summary: Start the "Scan Mailbox" task once
description: |
Starts the scan-mailbox task just once, discarding the
schedule and not updating the periodic task.
security:
- authTokenHeader: []
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/ScanMailboxSettings"
responses:
200:
description: Ok
content:
application/json:
schema:
$ref: "#/components/schemas/BasicResult"
components:
schemas:
ScanMailboxSettings:
description: |
Settings for the scan mailbox task.
required:
- id
- enabled
- imapConnection
- schedule
- folders
properties:
id:
type: string
format: ident
enabled:
type: boolean
imapConnection:
type: string
format: ident
folders:
type: array
items:
type: string
schedule:
type: string
format: calevent
receivedSinceHours:
type: integer
description: |
Look only for mails newer than `receivedSinceHours' hours.
targetFolder:
type: string
description: |
The folder to move all mails into that have been
successfully submitted to docspell.
deleteMail:
type: boolean
description: |
Whether to delete all successfully imported mails. This
only applies, if `targetFolder' is not set.
direction:
type: string
format: direction
description: |
The direction to apply to items resulting from importing
mails. If not set, the value is guessed based on the from
and to mail headers and your address book.
ImapSettingsList:
description: |
A list of user email settings.

View File

@ -30,6 +30,7 @@ module Api exposing
, getOrganizations
, getPersons
, getPersonsLight
, getScanMailbox
, getSentMails
, getSources
, getTags
@ -64,7 +65,9 @@ module Api exposing
, setTags
, setUnconfirmed
, startOnceNotifyDueItems
, startOnceScanMailbox
, submitNotifyDueItems
, submitScanMailbox
, upload
, uploadSingle
, versionInfo
@ -105,6 +108,7 @@ import Api.Model.Person exposing (Person)
import Api.Model.PersonList exposing (PersonList)
import Api.Model.ReferenceList exposing (ReferenceList)
import Api.Model.Registration exposing (Registration)
import Api.Model.ScanMailboxSettings exposing (ScanMailboxSettings)
import Api.Model.SentMails exposing (SentMails)
import Api.Model.SimpleMail exposing (SimpleMail)
import Api.Model.Source exposing (Source)
@ -127,6 +131,50 @@ import Util.Http as Http2
--- Scan Mailboxes
startOnceScanMailbox :
Flags
-> ScanMailboxSettings
-> (Result Http.Error BasicResult -> msg)
-> Cmd msg
startOnceScanMailbox flags settings receive =
Http2.authPost
{ url = flags.config.baseUrl ++ "/api/v1/sec/usertask/scanmailbox/startonce"
, account = getAccount flags
, body = Http.jsonBody (Api.Model.ScanMailboxSettings.encode settings)
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
}
submitScanMailbox :
Flags
-> ScanMailboxSettings
-> (Result Http.Error BasicResult -> msg)
-> Cmd msg
submitScanMailbox flags settings receive =
Http2.authPost
{ url = flags.config.baseUrl ++ "/api/v1/sec/usertask/scanmailbox"
, account = getAccount flags
, body = Http.jsonBody (Api.Model.ScanMailboxSettings.encode settings)
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
}
getScanMailbox :
Flags
-> (Result Http.Error ScanMailboxSettings -> msg)
-> Cmd msg
getScanMailbox flags receive =
Http2.authGet
{ url = flags.config.baseUrl ++ "/api/v1/sec/usertask/scanmailbox"
, account = getAccount flags
, expect = Http.expectJson receive Api.Model.ScanMailboxSettings.decoder
}
--- NotifyDueItems

View File

@ -0,0 +1,372 @@
module Comp.ScanMailboxForm exposing
( Model
, Msg
, init
, update
, view
)
import Api
import Api.Model.BasicResult exposing (BasicResult)
import Api.Model.ImapSettingsList exposing (ImapSettingsList)
import Api.Model.ScanMailboxSettings exposing (ScanMailboxSettings)
import Api.Model.Tag exposing (Tag)
import Api.Model.TagList exposing (TagList)
import Comp.CalEventInput
import Comp.Dropdown
import Comp.EmailInput
import Comp.IntField
import Data.CalEvent exposing (CalEvent)
import Data.Flags exposing (Flags)
import Data.Validated exposing (Validated(..))
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onCheck, onClick)
import Http
import Util.Http
import Util.Maybe
import Util.Update
type alias Model =
{ settings : ScanMailboxSettings
, connectionModel : Comp.Dropdown.Model String
, enabled : Bool
, schedule : Validated CalEvent
, scheduleModel : Comp.CalEventInput.Model
, formMsg : Maybe BasicResult
, loading : Int
}
type Msg
= Submit
| ConnMsg (Comp.Dropdown.Msg String)
| ConnResp (Result Http.Error ImapSettingsList)
| ToggleEnabled
| CalEventMsg Comp.CalEventInput.Msg
| SetScanMailboxSettings (Result Http.Error ScanMailboxSettings)
| SubmitResp (Result Http.Error BasicResult)
| StartOnce
initCmd : Flags -> Cmd Msg
initCmd flags =
Cmd.batch
[ Api.getImapSettings flags "" ConnResp
, Api.getScanMailbox flags SetScanMailboxSettings
]
init : Flags -> ( Model, Cmd Msg )
init flags =
let
initialSchedule =
Data.Validated.Unknown Data.CalEvent.everyMonth
( sm, sc ) =
Comp.CalEventInput.init flags Data.CalEvent.everyMonth
in
( { settings = Api.Model.ScanMailboxSettings.empty
, connectionModel =
Comp.Dropdown.makeSingle
{ makeOption = \a -> { value = a, text = a }
, placeholder = "Select connection..."
}
, enabled = False
, schedule = initialSchedule
, scheduleModel = sm
, formMsg = Nothing
, loading = 3
}
, Cmd.batch
[ initCmd flags
, Cmd.map CalEventMsg sc
]
)
--- Update
makeSettings : Model -> Validated ScanMailboxSettings
makeSettings model =
let
prev =
model.settings
conn =
Comp.Dropdown.getSelected model.connectionModel
|> List.head
|> Maybe.map Valid
|> Maybe.withDefault (Invalid [ "Connection missing" ] "")
make smtp timer =
{ prev
| imapConnection = smtp
, enabled = model.enabled
, schedule = Data.CalEvent.makeEvent timer
}
in
Data.Validated.map2 make
conn
model.schedule
withValidSettings : (ScanMailboxSettings -> Cmd Msg) -> Model -> ( Model, Cmd Msg )
withValidSettings mkcmd model =
case makeSettings model of
Valid set ->
( { model | formMsg = Nothing }
, mkcmd set
)
Invalid errs _ ->
let
errMsg =
String.join ", " errs
in
( { model | formMsg = Just (BasicResult False errMsg) }, Cmd.none )
Unknown _ ->
( { model | formMsg = Just (BasicResult False "An unknown error occured") }
, Cmd.none
)
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
update flags msg model =
case msg of
CalEventMsg lmsg ->
let
( cm, cc, cs ) =
Comp.CalEventInput.update flags
(Data.Validated.value model.schedule)
lmsg
model.scheduleModel
in
( { model
| schedule = cs
, scheduleModel = cm
, formMsg = Nothing
}
, Cmd.map CalEventMsg cc
)
ConnMsg m ->
let
( cm, cc ) =
Comp.Dropdown.update m model.connectionModel
in
( { model
| connectionModel = cm
, formMsg = Nothing
}
, Cmd.map ConnMsg cc
)
ConnResp (Ok list) ->
let
names =
List.map .name list.items
cm =
Comp.Dropdown.makeSingleList
{ makeOption = \a -> { value = a, text = a }
, placeholder = "Select Connection..."
, options = names
, selected = List.head names
}
in
( { model
| connectionModel = cm
, loading = model.loading - 1
, formMsg =
if names == [] then
Just
(BasicResult False
"No E-Mail connections configured. Goto E-Mail Settings to add one."
)
else
Nothing
}
, Cmd.none
)
ConnResp (Err err) ->
( { model
| formMsg = Just (BasicResult False (Util.Http.errorToString err))
, loading = model.loading - 1
}
, Cmd.none
)
ToggleEnabled ->
( { model
| enabled = not model.enabled
, formMsg = Nothing
}
, Cmd.none
)
SetScanMailboxSettings (Ok s) ->
let
imap =
Util.Maybe.fromString s.imapConnection
|> Maybe.map List.singleton
|> Maybe.withDefault []
( nm, nc ) =
Util.Update.andThen1
[ update flags (ConnMsg (Comp.Dropdown.SetSelection imap))
]
model
newSchedule =
Data.CalEvent.fromEvent s.schedule
|> Maybe.withDefault Data.CalEvent.everyMonth
( sm, sc ) =
Comp.CalEventInput.init flags newSchedule
in
( { nm
| settings = s
, enabled = s.enabled
, schedule = Data.Validated.Unknown newSchedule
, scheduleModel = sm
, formMsg = Nothing
, loading = model.loading - 1
}
, Cmd.batch
[ nc
, Cmd.map CalEventMsg sc
]
)
SetScanMailboxSettings (Err err) ->
( { model
| formMsg = Just (BasicResult False (Util.Http.errorToString err))
, loading = model.loading - 1
}
, Cmd.none
)
Submit ->
withValidSettings
(\set -> Api.submitScanMailbox flags set SubmitResp)
model
StartOnce ->
withValidSettings
(\set -> Api.startOnceScanMailbox flags set SubmitResp)
model
SubmitResp (Ok res) ->
( { model | formMsg = Just res }
, Cmd.none
)
SubmitResp (Err err) ->
( { model
| formMsg = Just (BasicResult False (Util.Http.errorToString err))
}
, Cmd.none
)
--- View
isFormError : Model -> Bool
isFormError model =
Maybe.map .success model.formMsg
|> Maybe.map not
|> Maybe.withDefault False
isFormSuccess : Model -> Bool
isFormSuccess model =
Maybe.map .success model.formMsg
|> Maybe.withDefault False
view : String -> Model -> Html Msg
view extraClasses model =
div
[ classList
[ ( "ui form", True )
, ( extraClasses, True )
, ( "error", isFormError model )
, ( "success", isFormSuccess model )
]
]
[ div
[ classList
[ ( "ui dimmer", True )
, ( "active", model.loading > 0 )
]
]
[ div [ class "ui text loader" ]
[ text "Loading..."
]
]
, div [ class "required field" ]
[ label [] [ text "Send via" ]
, Html.map ConnMsg (Comp.Dropdown.view model.connectionModel)
, span [ class "small-info" ]
[ text "The IMAP connection to use when sending notification mails."
]
]
, div [ class "required field" ]
[ label []
[ text "Schedule"
, a
[ class "right-float"
, href "https://github.com/eikek/calev#what-are-calendar-events"
, target "_blank"
]
[ i [ class "help icon" ] []
, text "Click here for help"
]
]
, Html.map CalEventMsg
(Comp.CalEventInput.view ""
(Data.Validated.value model.schedule)
model.scheduleModel
)
, span [ class "small-info" ]
[ text "Specify how often and when this task should run. "
, text "Use English 3-letter weekdays. Either a single value, "
, text "a list (ex. 1,2,3), a range (ex. 1..3) or a '*' (meaning all) "
, text "is allowed for each part."
]
]
, div [ class "ui divider" ] []
, div
[ classList
[ ( "ui message", True )
, ( "success", isFormSuccess model )
, ( "error", isFormError model )
, ( "hidden", model.formMsg == Nothing )
]
]
[ Maybe.map .message model.formMsg
|> Maybe.withDefault ""
|> text
]
, button
[ class "ui primary button"
, onClick Submit
]
[ text "Submit"
]
, button
[ class "ui right floated button"
, onClick StartOnce
]
[ text "Start Once"
]
]

View File

@ -9,6 +9,7 @@ import Comp.ChangePasswordForm
import Comp.EmailSettingsManage
import Comp.ImapSettingsManage
import Comp.NotificationForm
import Comp.ScanMailboxForm
import Data.Flags exposing (Flags)
@ -18,6 +19,7 @@ type alias Model =
, emailSettingsModel : Comp.EmailSettingsManage.Model
, imapSettingsModel : Comp.ImapSettingsManage.Model
, notificationModel : Comp.NotificationForm.Model
, scanMailboxModel : Comp.ScanMailboxForm.Model
}
@ -28,6 +30,7 @@ emptyModel flags =
, emailSettingsModel = Comp.EmailSettingsManage.emptyModel
, imapSettingsModel = Comp.ImapSettingsManage.emptyModel
, notificationModel = Tuple.first (Comp.NotificationForm.init flags)
, scanMailboxModel = Tuple.first (Comp.ScanMailboxForm.init flags)
}
@ -36,6 +39,7 @@ type Tab
| EmailSettingsTab
| ImapSettingsTab
| NotificationTab
| ScanMailboxTab
type Msg
@ -44,3 +48,4 @@ type Msg
| EmailSettingsMsg Comp.EmailSettingsManage.Msg
| NotificationMsg Comp.NotificationForm.Msg
| ImapSettingsMsg Comp.ImapSettingsManage.Msg
| ScanMailboxMsg Comp.ScanMailboxForm.Msg

View File

@ -4,6 +4,7 @@ import Comp.ChangePasswordForm
import Comp.EmailSettingsManage
import Comp.ImapSettingsManage
import Comp.NotificationForm
import Comp.ScanMailboxForm
import Data.Flags exposing (Flags)
import Page.UserSettings.Data exposing (..)
@ -42,6 +43,14 @@ update flags msg model =
(Tuple.second (Comp.NotificationForm.init flags))
in
( m, initCmd )
ScanMailboxTab ->
let
initCmd =
Cmd.map ScanMailboxMsg
(Tuple.second (Comp.ScanMailboxForm.init flags))
in
( m, initCmd )
in
( m2, cmd )
@ -74,3 +83,12 @@ update flags msg model =
( { model | notificationModel = m2 }
, Cmd.map NotificationMsg c2
)
ScanMailboxMsg lm ->
let
( m2, c2 ) =
Comp.ScanMailboxForm.update flags lm model.scanMailboxModel
in
( { model | scanMailboxModel = m2 }
, Cmd.map ScanMailboxMsg c2
)

View File

@ -4,6 +4,7 @@ import Comp.ChangePasswordForm
import Comp.EmailSettingsManage
import Comp.ImapSettingsManage
import Comp.NotificationForm
import Comp.ScanMailboxForm
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onClick)
@ -24,6 +25,7 @@ view model =
, makeTab model EmailSettingsTab "E-Mail Settings (SMTP)" "mail icon"
, makeTab model ImapSettingsTab "E-Mail Settings (IMAP)" "mail icon"
, makeTab model NotificationTab "Notification Task" "bullhorn icon"
, makeTab model ScanMailboxTab "Scan Mailbox Task" "envelope open outline icon"
]
]
]
@ -42,6 +44,9 @@ view model =
Just ImapSettingsTab ->
viewImapSettings model
Just ScanMailboxTab ->
viewScanMailboxForm model
Nothing ->
[]
)
@ -118,3 +123,26 @@ viewNotificationForm model =
, Html.map NotificationMsg
(Comp.NotificationForm.view "segment" model.notificationModel)
]
viewScanMailboxForm : Model -> List (Html Msg)
viewScanMailboxForm model =
[ h2 [ class "ui header" ]
[ i [ class "ui bullhorn icon" ] []
, div [ class "content" ]
[ text "Scan Mailbox"
]
]
, p []
[ text "Docspell can scan folders of your mailbox for mails to import. "
, text "You need to provide a connection in "
, text "your e-mail (imap) settings."
]
, p []
[ text "Each time this is executed, docspell goes through all configured folders "
, text "and imports mails matching the search criteria. The number of mails to import "
, text "at one task run is limited. Mails already read in are skipped."
]
, Html.map ScanMailboxMsg
(Comp.ScanMailboxForm.view "segment" model.scanMailboxModel)
]