Manage notification channels separately and migrate

It's more convenient to manage notification channels separately, as it
is done with email settings. Notification hook and other forms are
adopted to only select channels. Hooks can now use more than one
channel.
This commit is contained in:
eikek
2022-01-19 21:51:18 +01:00
parent d41490dd88
commit 23cb34a6ff
78 changed files with 2583 additions and 1422 deletions

View File

@ -7,27 +7,63 @@
module Data.ChannelRef exposing (..)
import Api.Model.NotificationChannelRef exposing (NotificationChannelRef)
import Data.ChannelType exposing (ChannelType)
import Json.Decode as D
import Json.Encode as E
import Html exposing (Attribute, Html, div, span, text)
import Html.Attributes exposing (class)
import Messages.Data.ChannelType as M
import Util.List
type alias ChannelRef =
{ id : String
, channelType : ChannelType
}
channelType : NotificationChannelRef -> Maybe ChannelType
channelType ref =
Data.ChannelType.fromString ref.channelType
decoder : D.Decoder ChannelRef
decoder =
D.map2 ChannelRef
(D.field "id" D.string)
(D.field "channelType" Data.ChannelType.decoder)
split : M.Texts -> NotificationChannelRef -> ( String, String )
split texts ref =
let
chStr =
channelType ref
|> Maybe.map texts
|> Maybe.withDefault ref.channelType
name =
Maybe.withDefault (String.slice 0 6 ref.id) ref.name
in
( chStr, name )
encode : ChannelRef -> E.Value
encode cref =
E.object
[ ( "id", E.string cref.id )
, ( "channelType", Data.ChannelType.encode cref.channelType )
asString : M.Texts -> NotificationChannelRef -> String
asString texts ref =
let
( chStr, name ) =
split texts ref
in
chStr ++ " (" ++ name ++ ")"
asDiv : List (Attribute msg) -> M.Texts -> NotificationChannelRef -> Html msg
asDiv attrs texts ref =
let
( chStr, name ) =
split texts ref
in
div attrs
[ text chStr
, span [ class "ml-1 text-xs opacity-75" ]
[ text ("(" ++ name ++ ")")
]
]
asStringJoined : M.Texts -> List NotificationChannelRef -> String
asStringJoined texts refs =
List.map (asString texts) refs
|> Util.List.distinct
|> String.join ", "
asDivs : M.Texts -> List (Attribute msg) -> List NotificationChannelRef -> List (Html msg)
asDivs texts inner refs =
List.map (asDiv inner texts) refs

View File

@ -12,17 +12,18 @@ module Data.NotificationChannel exposing
, decoder
, empty
, encode
, getRef
, setTypeGotify
, setTypeHttp
, setTypeMail
, setTypeMatrix
)
import Api.Model.NotificationChannelRef exposing (NotificationChannelRef)
import Api.Model.NotificationGotify exposing (NotificationGotify)
import Api.Model.NotificationHttp exposing (NotificationHttp)
import Api.Model.NotificationMail exposing (NotificationMail)
import Api.Model.NotificationMatrix exposing (NotificationMatrix)
import Data.ChannelRef exposing (ChannelRef)
import Data.ChannelType exposing (ChannelType)
import Json.Decode as D
import Json.Encode as E
@ -33,7 +34,6 @@ type NotificationChannel
| Mail NotificationMail
| Gotify NotificationGotify
| Http NotificationHttp
| Ref ChannelRef
empty : ChannelType -> NotificationChannel
@ -87,46 +87,49 @@ decoder =
, D.map Mail Api.Model.NotificationMail.decoder
, D.map Matrix Api.Model.NotificationMatrix.decoder
, D.map Http Api.Model.NotificationHttp.decoder
, D.map Ref Data.ChannelRef.decoder
]
fold :
(NotificationMail -> a)
-> (NotificationGotify -> a)
-> (NotificationMatrix -> a)
-> (NotificationHttp -> a)
-> NotificationChannel
-> a
fold fa fb fc fd channel =
case channel of
Mail ch ->
fa ch
Gotify ch ->
fb ch
Matrix ch ->
fc ch
Http ch ->
fd ch
encode : NotificationChannel -> E.Value
encode channel =
case channel of
Matrix ch ->
Api.Model.NotificationMatrix.encode ch
Mail ch ->
Api.Model.NotificationMail.encode ch
Gotify ch ->
Api.Model.NotificationGotify.encode ch
Http ch ->
Api.Model.NotificationHttp.encode ch
Ref ch ->
Data.ChannelRef.encode ch
fold
Api.Model.NotificationMail.encode
Api.Model.NotificationGotify.encode
Api.Model.NotificationMatrix.encode
Api.Model.NotificationHttp.encode
channel
channelType : NotificationChannel -> Maybe ChannelType
channelType ch =
case ch of
Matrix m ->
Data.ChannelType.fromString m.channelType
Mail m ->
Data.ChannelType.fromString m.channelType
Gotify m ->
Data.ChannelType.fromString m.channelType
Http m ->
Data.ChannelType.fromString m.channelType
Ref m ->
Just m.channelType
fold
(.channelType >> Data.ChannelType.fromString)
(.channelType >> Data.ChannelType.fromString)
(.channelType >> Data.ChannelType.fromString)
(.channelType >> Data.ChannelType.fromString)
ch
asString : NotificationChannel -> String
@ -144,5 +147,12 @@ asString channel =
Http ch ->
"Http @ " ++ ch.url
Ref ch ->
"Ref(" ++ Data.ChannelType.asString ch.channelType ++ "/" ++ ch.id ++ ")"
getRef : NotificationChannel -> NotificationChannelRef
getRef channel =
fold
(\c -> NotificationChannelRef c.id c.channelType c.name)
(\c -> NotificationChannelRef c.id c.channelType c.name)
(\c -> NotificationChannelRef c.id c.channelType c.name)
(\c -> NotificationChannelRef c.id c.channelType c.name)
channel

View File

@ -1,62 +0,0 @@
{-
Copyright 2020 Eike K. & Contributors
SPDX-License-Identifier: AGPL-3.0-or-later
-}
module Data.NotificationHook exposing (NotificationHook, decoder, empty, encode)
import Data.ChannelType exposing (ChannelType)
import Data.EventType exposing (EventType)
import Data.NotificationChannel exposing (NotificationChannel)
import Json.Decode as D
import Json.Encode as E
type alias NotificationHook =
{ id : String
, enabled : Bool
, channel : NotificationChannel
, allEvents : Bool
, eventFilter : Maybe String
, events : List EventType
}
empty : ChannelType -> NotificationHook
empty ct =
{ id = ""
, enabled = True
, channel = Data.NotificationChannel.empty ct
, allEvents = False
, eventFilter = Nothing
, events = []
}
decoder : D.Decoder NotificationHook
decoder =
D.map6 NotificationHook
(D.field "id" D.string)
(D.field "enabled" D.bool)
(D.field "channel" Data.NotificationChannel.decoder)
(D.field "allEvents" D.bool)
(D.field "eventFilter" (D.maybe D.string))
(D.field "events" (D.list Data.EventType.decoder))
encode : NotificationHook -> E.Value
encode hook =
E.object
[ ( "id", E.string hook.id )
, ( "enabled", E.bool hook.enabled )
, ( "channel", Data.NotificationChannel.encode hook.channel )
, ( "allEvents", E.bool hook.allEvents )
, ( "eventFilter", Maybe.map E.string hook.eventFilter |> Maybe.withDefault E.null )
, ( "events", E.list Data.EventType.encode hook.events )
]
--- private

View File

@ -1,77 +0,0 @@
{-
Copyright 2020 Eike K. & Contributors
SPDX-License-Identifier: AGPL-3.0-or-later
-}
module Data.PeriodicDueItemsSettings exposing (..)
import Api.Model.Tag exposing (Tag)
import Data.ChannelType exposing (ChannelType)
import Data.NotificationChannel exposing (NotificationChannel)
import Json.Decode as Decode
import Json.Decode.Pipeline as P
import Json.Encode as Encode
{--
- Settings for notifying about due items.
--}
type alias PeriodicDueItemsSettings =
{ id : String
, enabled : Bool
, summary : Maybe String
, channel : NotificationChannel
, schedule : String
, remindDays : Int
, capOverdue : Bool
, tagsInclude : List Tag
, tagsExclude : List Tag
}
empty : ChannelType -> PeriodicDueItemsSettings
empty ct =
{ id = ""
, enabled = False
, summary = Nothing
, channel = Data.NotificationChannel.empty ct
, schedule = ""
, remindDays = 0
, capOverdue = False
, tagsInclude = []
, tagsExclude = []
}
decoder : Decode.Decoder PeriodicDueItemsSettings
decoder =
Decode.succeed PeriodicDueItemsSettings
|> P.required "id" Decode.string
|> P.required "enabled" Decode.bool
|> P.optional "summary" (Decode.maybe Decode.string) Nothing
|> P.required "channel" Data.NotificationChannel.decoder
|> P.required "schedule" Decode.string
|> P.required "remindDays" Decode.int
|> P.required "capOverdue" Decode.bool
|> P.required "tagsInclude" (Decode.list Api.Model.Tag.decoder)
|> P.required "tagsExclude" (Decode.list Api.Model.Tag.decoder)
encode : PeriodicDueItemsSettings -> Encode.Value
encode value =
Encode.object
[ ( "id", Encode.string value.id )
, ( "enabled", Encode.bool value.enabled )
, ( "summary", (Maybe.map Encode.string >> Maybe.withDefault Encode.null) value.summary )
, ( "channel", Data.NotificationChannel.encode value.channel )
, ( "schedule", Encode.string value.schedule )
, ( "remindDays", Encode.int value.remindDays )
, ( "capOverdue", Encode.bool value.capOverdue )
, ( "tagsInclude", Encode.list Api.Model.Tag.encode value.tagsInclude )
, ( "tagsExclude", Encode.list Api.Model.Tag.encode value.tagsExclude )
]

View File

@ -1,65 +0,0 @@
{-
Copyright 2020 Eike K. & Contributors
SPDX-License-Identifier: AGPL-3.0-or-later
-}
module Data.PeriodicQuerySettings exposing (PeriodicQuerySettings, decoder, empty, encode)
import Data.ChannelType exposing (ChannelType)
import Data.NotificationChannel exposing (NotificationChannel)
import Json.Decode as D
import Json.Encode as E
type alias PeriodicQuerySettings =
{ id : String
, enabled : Bool
, summary : Maybe String
, channel : NotificationChannel
, query : Maybe String
, bookmark : Maybe String
, contentStart : Maybe String
, schedule : String
}
empty : ChannelType -> PeriodicQuerySettings
empty ct =
{ id = ""
, enabled = False
, summary = Nothing
, channel = Data.NotificationChannel.empty ct
, query = Nothing
, bookmark = Nothing
, contentStart = Nothing
, schedule = ""
}
decoder : D.Decoder PeriodicQuerySettings
decoder =
D.map8 PeriodicQuerySettings
(D.field "id" D.string)
(D.field "enabled" D.bool)
(D.maybe (D.field "summary" D.string))
(D.field "channel" Data.NotificationChannel.decoder)
(D.maybe (D.field "query" D.string))
(D.maybe (D.field "bookmark" D.string))
(D.maybe (D.field "contentStart" D.string))
(D.field "schedule" D.string)
encode : PeriodicQuerySettings -> E.Value
encode s =
E.object
[ ( "id", E.string s.id )
, ( "enabled", E.bool s.enabled )
, ( "summary", Maybe.map E.string s.summary |> Maybe.withDefault E.null )
, ( "channel", Data.NotificationChannel.encode s.channel )
, ( "query", Maybe.map E.string s.query |> Maybe.withDefault E.null )
, ( "bookmark", Maybe.map E.string s.bookmark |> Maybe.withDefault E.null )
, ( "contentStart", Maybe.map E.string s.contentStart |> Maybe.withDefault E.null )
, ( "schedule", E.string s.schedule )
]