Compare commits
No commits in common. "4ef8471585faa8997a75062d84038e7bc8183912" and "c3ed5c4cd1a61fb2dfb1540e80576bd5bdf5b23c" have entirely different histories.
4ef8471585
...
c3ed5c4cd1
13
src/Main.elm
13
src/Main.elm
@ -5,7 +5,6 @@ import Scylla.Room exposing (OpenRooms, applySync)
|
|||||||
import Scylla.Sync exposing (..)
|
import Scylla.Sync exposing (..)
|
||||||
import Scylla.Sync.Events exposing (toMessageEvent, getType, getSender, getUnsigned)
|
import Scylla.Sync.Events exposing (toMessageEvent, getType, getSender, getUnsigned)
|
||||||
import Scylla.Sync.AccountData exposing (..)
|
import Scylla.Sync.AccountData exposing (..)
|
||||||
import Scylla.Sync.Push exposing (..)
|
|
||||||
import Scylla.ListUtils exposing (..)
|
import Scylla.ListUtils exposing (..)
|
||||||
import Scylla.Messages exposing (..)
|
import Scylla.Messages exposing (..)
|
||||||
import Scylla.Login exposing (..)
|
import Scylla.Login exposing (..)
|
||||||
@ -52,6 +51,7 @@ init _ url key =
|
|||||||
, sending = Dict.empty
|
, sending = Dict.empty
|
||||||
, transactionId = 0
|
, transactionId = 0
|
||||||
, userData = Dict.empty
|
, userData = Dict.empty
|
||||||
|
, roomNames = Dict.empty
|
||||||
, connected = True
|
, connected = True
|
||||||
, searchText = ""
|
, searchText = ""
|
||||||
, rooms = emptyOpenRooms
|
, rooms = emptyOpenRooms
|
||||||
@ -314,13 +314,10 @@ updateSyncResponse model r notify =
|
|||||||
userDataCmd sr = newUsersCmd model
|
userDataCmd sr = newUsersCmd model
|
||||||
<| newUsers model
|
<| newUsers model
|
||||||
<| allUsers sr
|
<| allUsers sr
|
||||||
notification sr =
|
notification sr = findFirstBy
|
||||||
getPushRuleset model.accountData
|
(\(s, e) -> e.originServerTs)
|
||||||
|> Maybe.map (\rs -> getNotificationEvents rs sr)
|
(\(s, e) -> e.sender /= model.loginUsername)
|
||||||
|> Maybe.withDefault []
|
<| getNotificationEvents sr
|
||||||
|> findFirstBy
|
|
||||||
(\(s, e) -> e.originServerTs)
|
|
||||||
(\(s, e) -> e.sender /= model.loginUsername)
|
|
||||||
notificationCmd sr = if notify
|
notificationCmd sr = if notify
|
||||||
then Maybe.withDefault Cmd.none
|
then Maybe.withDefault Cmd.none
|
||||||
<| Maybe.map (\(s, e) -> sendNotificationPort
|
<| Maybe.map (\(s, e) -> sendNotificationPort
|
||||||
|
@ -4,7 +4,6 @@ import Scylla.Sync exposing (SyncResponse, HistoryResponse)
|
|||||||
import Scylla.ListUtils exposing (findFirst)
|
import Scylla.ListUtils exposing (findFirst)
|
||||||
import Scylla.Room exposing (OpenRooms)
|
import Scylla.Room exposing (OpenRooms)
|
||||||
import Scylla.Sync.Rooms exposing (JoinedRoom)
|
import Scylla.Sync.Rooms exposing (JoinedRoom)
|
||||||
import Scylla.Sync.Push exposing (Ruleset)
|
|
||||||
import Scylla.Sync.AccountData exposing (AccountData, directMessagesDecoder)
|
import Scylla.Sync.AccountData exposing (AccountData, directMessagesDecoder)
|
||||||
import Scylla.Login exposing (LoginResponse, Username, Password)
|
import Scylla.Login exposing (LoginResponse, Username, Password)
|
||||||
import Scylla.UserData exposing (UserData)
|
import Scylla.UserData exposing (UserData)
|
||||||
@ -37,6 +36,7 @@ type alias Model =
|
|||||||
, sending : Dict Int (RoomId, SendingMessage)
|
, sending : Dict Int (RoomId, SendingMessage)
|
||||||
, transactionId : Int
|
, transactionId : Int
|
||||||
, userData : Dict Username UserData
|
, userData : Dict Username UserData
|
||||||
|
, roomNames : Dict RoomId String
|
||||||
, connected : Bool
|
, connected : Bool
|
||||||
, searchText : String
|
, searchText : String
|
||||||
, rooms : OpenRooms
|
, rooms : OpenRooms
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
port module Scylla.Notification exposing (..)
|
port module Scylla.Notification exposing (..)
|
||||||
import Scylla.Sync exposing (SyncResponse, joinedRoomsTimelineEvents)
|
import Scylla.Sync exposing (SyncResponse, joinedRoomsTimelineEvents)
|
||||||
import Scylla.Sync.Events exposing (RoomEvent, MessageEvent, toMessageEvent)
|
import Scylla.Sync.Events exposing (RoomEvent, MessageEvent, toMessageEvent)
|
||||||
import Scylla.Sync.Push exposing (Ruleset, getEventNotification)
|
|
||||||
import Json.Decode as Decode exposing (string, field)
|
import Json.Decode as Decode exposing (string, field)
|
||||||
import Dict
|
import Dict
|
||||||
|
|
||||||
@ -19,14 +18,13 @@ getText re = case (Decode.decodeValue (field "msgtype" string) re.content) of
|
|||||||
Ok "m.text" -> Result.withDefault "" <| (Decode.decodeValue (field "body" string) re.content)
|
Ok "m.text" -> Result.withDefault "" <| (Decode.decodeValue (field "body" string) re.content)
|
||||||
_ -> ""
|
_ -> ""
|
||||||
|
|
||||||
getNotificationEvents : Ruleset -> SyncResponse -> List (String, MessageEvent)
|
getNotificationEvents : SyncResponse -> List (String, MessageEvent)
|
||||||
getNotificationEvents rs s = s.rooms
|
getNotificationEvents s =
|
||||||
|> Maybe.andThen .join
|
let
|
||||||
|> Maybe.map (Dict.map (\k v -> v.timeline
|
applyPair k = List.map (\v -> (k, v))
|
||||||
|> Maybe.andThen .events
|
in
|
||||||
|> Maybe.map (List.filter <| getEventNotification rs k)
|
List.sortBy (\(k, v) -> v.originServerTs)
|
||||||
|> Maybe.map (List.filterMap <| toMessageEvent)
|
<| List.filterMap (\(k, e) -> Maybe.map (\me -> (k, me)) <| toMessageEvent e)
|
||||||
|> Maybe.withDefault []))
|
<| Dict.foldl (\k v a -> a ++ applyPair k v) []
|
||||||
|> Maybe.withDefault Dict.empty
|
<| joinedRoomsTimelineEvents s
|
||||||
|> Dict.toList
|
|
||||||
|> List.concatMap (\(k, vs) -> List.map (\v -> (k, v)) vs)
|
|
||||||
|
@ -2,8 +2,7 @@ module Scylla.Sync.AccountData exposing (..)
|
|||||||
import Scylla.ListUtils exposing (..)
|
import Scylla.ListUtils exposing (..)
|
||||||
import Scylla.Sync.DecodeTools exposing (maybeDecode)
|
import Scylla.Sync.DecodeTools exposing (maybeDecode)
|
||||||
import Scylla.Sync.Events exposing (Event, eventDecoder)
|
import Scylla.Sync.Events exposing (Event, eventDecoder)
|
||||||
import Scylla.Sync.Push exposing (Ruleset, rulesetDecoder)
|
import Json.Decode as Decode exposing (Decoder, list, decodeValue)
|
||||||
import Json.Decode as Decode exposing (Decoder, list, field, decodeValue)
|
|
||||||
import Dict exposing (Dict)
|
import Dict exposing (Dict)
|
||||||
|
|
||||||
type alias AccountData =
|
type alias AccountData =
|
||||||
@ -49,6 +48,3 @@ getAccountData key d ad = ad.events
|
|||||||
|
|
||||||
getDirectMessages : AccountData -> Maybe DirectMessages
|
getDirectMessages : AccountData -> Maybe DirectMessages
|
||||||
getDirectMessages = getAccountData "m.direct" directMessagesDecoder
|
getDirectMessages = getAccountData "m.direct" directMessagesDecoder
|
||||||
|
|
||||||
getPushRuleset : AccountData -> Maybe Ruleset
|
|
||||||
getPushRuleset = getAccountData "m.push_rules" (field "global" rulesetDecoder)
|
|
||||||
|
@ -38,8 +38,8 @@ type RoomEvent
|
|||||||
|
|
||||||
roomEventDecoder : Decoder RoomEvent
|
roomEventDecoder : Decoder RoomEvent
|
||||||
roomEventDecoder = oneOf
|
roomEventDecoder = oneOf
|
||||||
[ Decode.map StateRoomEvent stateEventDecoder
|
[ Decode.map MessageRoomEvent messageEventDecoder
|
||||||
, Decode.map MessageRoomEvent messageEventDecoder
|
, Decode.map StateRoomEvent stateEventDecoder
|
||||||
]
|
]
|
||||||
|
|
||||||
type alias MessageEvent =
|
type alias MessageEvent =
|
||||||
@ -124,12 +124,6 @@ getType re =
|
|||||||
StateRoomEvent e -> e.type_
|
StateRoomEvent e -> e.type_
|
||||||
MessageRoomEvent e -> e.type_
|
MessageRoomEvent e -> e.type_
|
||||||
|
|
||||||
getContent : RoomEvent -> Decode.Value
|
|
||||||
getContent re =
|
|
||||||
case re of
|
|
||||||
StateRoomEvent e -> e.content
|
|
||||||
MessageRoomEvent e -> e.content
|
|
||||||
|
|
||||||
toStateEvent : RoomEvent -> Maybe StateEvent
|
toStateEvent : RoomEvent -> Maybe StateEvent
|
||||||
toStateEvent re =
|
toStateEvent re =
|
||||||
case re of
|
case re of
|
||||||
|
@ -1,167 +0,0 @@
|
|||||||
module Scylla.Sync.Push exposing (..)
|
|
||||||
import Scylla.Sync.DecodeTools exposing (maybeDecode)
|
|
||||||
import Scylla.Sync.Events exposing (RoomEvent, getSender, getContent, getType)
|
|
||||||
import Scylla.Route exposing (RoomId)
|
|
||||||
import Json.Decode as Decode exposing (Decoder, string, int, field, value, bool, list)
|
|
||||||
import Json.Decode.Pipeline exposing (required, optional)
|
|
||||||
|
|
||||||
type Condition
|
|
||||||
= EventMatch String String
|
|
||||||
| ContainsDisplayName
|
|
||||||
| RoomMemberCount Int
|
|
||||||
| SenderNotificationPermission String
|
|
||||||
|
|
||||||
conditionDecoder : Decoder Condition
|
|
||||||
conditionDecoder =
|
|
||||||
let
|
|
||||||
eventMatchDecoder =
|
|
||||||
Decode.succeed EventMatch
|
|
||||||
|> required "key" string
|
|
||||||
|> required "pattern" string
|
|
||||||
containsDisplayNameDecoder =
|
|
||||||
Decode.succeed ContainsDisplayName
|
|
||||||
roomMemberCountDecoder =
|
|
||||||
Decode.succeed RoomMemberCount
|
|
||||||
|> required "is"
|
|
||||||
(Decode.map (Maybe.withDefault 0 << String.toInt) string)
|
|
||||||
senderNotifPermissionDecoder =
|
|
||||||
Decode.succeed SenderNotificationPermission
|
|
||||||
|> required "key" string
|
|
||||||
dispatchDecoder k =
|
|
||||||
case k of
|
|
||||||
"event_match" -> eventMatchDecoder
|
|
||||||
"contains_display_name" -> containsDisplayNameDecoder
|
|
||||||
"room_member_count" -> roomMemberCountDecoder
|
|
||||||
"sender_notification_permission" -> senderNotifPermissionDecoder
|
|
||||||
_ -> Decode.fail "Unknown condition code"
|
|
||||||
in
|
|
||||||
field "kind" string
|
|
||||||
|> Decode.andThen dispatchDecoder
|
|
||||||
|
|
||||||
type Action
|
|
||||||
= Notify
|
|
||||||
| DontNotify
|
|
||||||
| Coalesce
|
|
||||||
| SetTweak String (Maybe Decode.Value)
|
|
||||||
|
|
||||||
actionDecoder : Decoder Action
|
|
||||||
actionDecoder =
|
|
||||||
let
|
|
||||||
dispatchStringDecoder s =
|
|
||||||
case s of
|
|
||||||
"notify" -> Decode.succeed Notify
|
|
||||||
"dont_notify" -> Decode.succeed DontNotify
|
|
||||||
"coalesce" -> Decode.succeed Coalesce
|
|
||||||
_ -> Decode.fail "Unknown action string"
|
|
||||||
objectDecoder =
|
|
||||||
Decode.succeed SetTweak
|
|
||||||
|> required "set_tweak" string
|
|
||||||
|> maybeDecode "value" value
|
|
||||||
in
|
|
||||||
Decode.oneOf
|
|
||||||
[ string |> Decode.andThen dispatchStringDecoder
|
|
||||||
, objectDecoder
|
|
||||||
]
|
|
||||||
|
|
||||||
type alias Rule =
|
|
||||||
{ ruleId : String
|
|
||||||
, default : Bool
|
|
||||||
, enabled : Bool
|
|
||||||
, conditions : List Condition
|
|
||||||
, actions : List Action
|
|
||||||
}
|
|
||||||
|
|
||||||
ruleDecoder : Decoder Rule
|
|
||||||
ruleDecoder =
|
|
||||||
let
|
|
||||||
patternDecoder = Decode.oneOf
|
|
||||||
[ field "pattern" string
|
|
||||||
|> Decode.andThen
|
|
||||||
(\p -> Decode.succeed <| \r ->
|
|
||||||
{ r | conditions = (EventMatch "content.body" p)::r.conditions })
|
|
||||||
, Decode.succeed identity
|
|
||||||
]
|
|
||||||
basicRuleDecoder = Decode.succeed Rule
|
|
||||||
|> required "rule_id" string
|
|
||||||
|> optional "default" bool True
|
|
||||||
|> optional "enabled" bool False
|
|
||||||
|> optional "conditions" (list conditionDecoder) []
|
|
||||||
|> required "actions" (list actionDecoder)
|
|
||||||
in
|
|
||||||
patternDecoder
|
|
||||||
|> Decode.andThen (\f -> Decode.map f basicRuleDecoder)
|
|
||||||
|
|
||||||
type alias Ruleset =
|
|
||||||
{ content : List Rule
|
|
||||||
, override : List Rule
|
|
||||||
, room : List Rule
|
|
||||||
, sender : List Rule
|
|
||||||
, underride : List Rule
|
|
||||||
}
|
|
||||||
|
|
||||||
rulesetDecoder : Decoder Ruleset
|
|
||||||
rulesetDecoder = Decode.succeed Ruleset
|
|
||||||
|> optional "content" (list ruleDecoder) []
|
|
||||||
|> optional "override" (list ruleDecoder) []
|
|
||||||
|> optional "room" (list ruleDecoder) []
|
|
||||||
|> optional "sender" (list ruleDecoder) []
|
|
||||||
|> optional "underride" (list ruleDecoder) []
|
|
||||||
|
|
||||||
checkCondition : RoomEvent -> Condition -> Bool
|
|
||||||
checkCondition re c =
|
|
||||||
let
|
|
||||||
pathDecoder xs p =
|
|
||||||
Decode.at xs string
|
|
||||||
|> Decode.map (String.contains p << String.toLower)
|
|
||||||
matchesPattern xs p =
|
|
||||||
case Decode.decodeValue (pathDecoder xs p) (getContent re) of
|
|
||||||
Ok True -> True
|
|
||||||
_ -> False
|
|
||||||
in
|
|
||||||
case c of
|
|
||||||
EventMatch k p ->
|
|
||||||
case String.split "." k of
|
|
||||||
"content"::xs -> matchesPattern xs p
|
|
||||||
"type"::[] -> String.contains p <| getType re
|
|
||||||
_ -> False
|
|
||||||
ContainsDisplayName -> False
|
|
||||||
RoomMemberCount _ -> False
|
|
||||||
SenderNotificationPermission _ -> False
|
|
||||||
|
|
||||||
applyAction : Action -> List Action -> List Action
|
|
||||||
applyAction a as_ =
|
|
||||||
case a of
|
|
||||||
Notify -> Notify :: List.filter (\a_ -> a_ /= DontNotify) as_
|
|
||||||
DontNotify -> DontNotify :: List.filter (\a_ -> a_ /= Notify) as_
|
|
||||||
Coalesce -> Coalesce :: List.filter (\a_ -> a_ /= DontNotify) as_
|
|
||||||
a_ -> a_ :: as_
|
|
||||||
|
|
||||||
applyActions : List Action -> List Action -> List Action
|
|
||||||
applyActions l r = List.foldl applyAction r l
|
|
||||||
|
|
||||||
updatePushRuleActions : Rule -> RoomEvent -> List Action -> List Action
|
|
||||||
updatePushRuleActions r re as_ =
|
|
||||||
if List.all (checkCondition re) r.conditions
|
|
||||||
then applyActions r.actions as_
|
|
||||||
else as_
|
|
||||||
|
|
||||||
updatePushActions : List Rule -> RoomEvent -> List Action -> List Action
|
|
||||||
updatePushActions rs re as_ =
|
|
||||||
List.filter .enabled rs
|
|
||||||
|> List.foldl (\r -> updatePushRuleActions r re) as_
|
|
||||||
|
|
||||||
getPushActions : Ruleset -> RoomId -> RoomEvent -> List Action
|
|
||||||
getPushActions rs rid re =
|
|
||||||
let
|
|
||||||
roomRules = List.filter (((==) rid) << .ruleId) rs.room
|
|
||||||
senderRules = List.filter (((==) <| getSender re) << .ruleId) rs.sender
|
|
||||||
in
|
|
||||||
updatePushActions rs.underride re []
|
|
||||||
|> updatePushActions senderRules re
|
|
||||||
|> updatePushActions roomRules re
|
|
||||||
|> updatePushActions rs.override re
|
|
||||||
|
|
||||||
getEventNotification : Ruleset -> RoomId -> RoomEvent -> Bool
|
|
||||||
getEventNotification rs rid re =
|
|
||||||
getPushActions rs rid re
|
|
||||||
|> List.member Notify
|
|
Loading…
Reference in New Issue
Block a user