matterhorn-90000.0.0: src/Matterhorn/Events/Websocket.hs
module Matterhorn.Events.Websocket
( handleWebsocketEvent
, handleWebsocketActionResponse
)
where
import Prelude ()
import Matterhorn.Prelude
import qualified Data.HashMap.Strict as HM
import qualified Data.Sequence as Seq
import qualified Data.Set as Set
import qualified Data.Text as T
import Network.Mattermost.Lenses
import Network.Mattermost.Types
import Network.Mattermost.WebSocket
import Matterhorn.State.ChannelList
import Matterhorn.State.Channels
import Matterhorn.State.Common
import Matterhorn.State.Flagging
import Matterhorn.State.Messages
import Matterhorn.State.Reactions
import Matterhorn.State.Teams
import Matterhorn.State.Users
import Matterhorn.Types
import Matterhorn.Types.Common
foreachTeam :: (TeamId -> MH ()) -> MH ()
foreachTeam act = do
ts <- use csTeams
let myTIds = HM.keys ts
mapM_ act myTIds
handleWebsocketEvent :: WebsocketEvent -> MH ()
handleWebsocketEvent we = do
myId <- gets myUserId
ts <- use csTeams
let memberOf tId = HM.member tId ts
-- The team ID is one of the teams we're in, or the team ID is
-- absent, which typically indicates a DM channel event since DM
-- channels are not associated with teams.
inMyTeamOrDM (Just i) = memberOf i
inMyTeamOrDM Nothing = True
-- The team ID is one of the teams we're in. A missing team ID
-- yields False.
inMyTeam (Just i) = memberOf i
inMyTeam Nothing = False
case weEvent we of
WMPosted
| Just p <- wepPost (weData we) ->
when (inMyTeamOrDM (wepTeamId (weData we))) $ do
let wasMentioned = maybe False (Set.member myId) $ wepMentions (weData we)
addNewPostedMessage $ RecentPost p wasMentioned
mtId <- use csCurrentTeamId
cId <- case mtId of
Nothing -> return Nothing
Just tId -> use (csCurrentChannelId tId)
when (Just (postChannelId p) /= cId) $
showChannelInSidebar (p^.postChannelIdL) False
| otherwise -> return ()
WMPostEdited
| Just p <- wepPost (weData we) -> do
editMessage p
currTid <- use csCurrentTeamId
foreachTeam $ \tId -> do
cId <- use (csCurrentChannelId tId)
when (Just (postChannelId p) == cId && Just tId == currTid) $
updateViewed False
when (Just (postChannelId p) /= cId) $
showChannelInSidebar (p^.postChannelIdL) False
| otherwise -> return ()
WMPostDeleted
| Just p <- wepPost (weData we) -> do
deleteMessage p
currTid <- use csCurrentTeamId
foreachTeam $ \tId -> do
cId <- use (csCurrentChannelId tId)
when (Just (postChannelId p) == cId && Just tId == currTid) $
updateViewed False
when (Just (postChannelId p) /= cId) $
showChannelInSidebar (p^.postChannelIdL) False
| otherwise -> return ()
WMStatusChange
| Just status <- wepStatus (weData we)
, Just uId <- wepUserId (weData we) ->
setUserStatus uId status
| otherwise -> return ()
-- Despite this event's name, it means "a user was added to a
-- channel". The event that occurs when a new user is added to
-- the server, see WMNewUser.
WMUserAdded
| Just cId <- webChannelId (weBroadcast we) ->
when (wepUserId (weData we) == Just myId &&
inMyTeam (wepTeamId (weData we))) $
handleChannelInvite cId
| otherwise -> return ()
WMNewUser
| Just uId <- wepUserId $ weData we ->
handleNewUsers (Seq.singleton uId) (return ())
| otherwise -> return ()
WMUserRemoved
| Just cId <- wepChannelId (weData we) ->
when (webUserId (weBroadcast we) == Just myId) $
removeChannelFromState cId
| otherwise -> return ()
WMTyping
| Just uId <- wepUserId $ weData we
, Just cId <- webChannelId (weBroadcast we) -> handleTypingUser uId cId (wepParentId $ weData we)
| otherwise -> return ()
WMChannelDeleted
| Just cId <- wepChannelId (weData we) ->
when (inMyTeamOrDM (webTeamId (weBroadcast we))) $
removeChannelFromState cId
| otherwise -> return ()
WMDirectAdded
| Just cId <- webChannelId (weBroadcast we) -> handleChannelInvite cId
| otherwise -> return ()
-- An 'ephemeral message' is just Mattermost's version of our
-- 'client message'. This can be a little bit wacky, e.g.
-- if the user types '/shortcuts' in the browser, we'll get
-- an ephemeral message even in MatterHorn with the browser
-- shortcuts, but it's probably a good idea to handle these
-- messages anyway.
WMEphemeralMessage
| Just p <- wepPost $ weData we -> postInfoMessage (sanitizeUserText $ p^.postMessageL)
| otherwise -> return ()
WMPreferenceChanged
| Just prefs <- wepPreferences (weData we) ->
mapM_ applyPreferenceChange prefs
| otherwise -> return ()
WMPreferenceDeleted
| Just pref <- wepPreferences (weData we)
, Just fps <- mapM preferenceToFlaggedPost pref ->
forM_ fps $ \f ->
updateMessageFlag (flaggedPostId f) False
| otherwise -> return ()
WMReactionAdded
| Just r <- wepReaction (weData we)
, Just cId <- webChannelId (weBroadcast we) -> addReactions cId [r]
| otherwise -> return ()
WMReactionRemoved
| Just r <- wepReaction (weData we)
, Just cId <- webChannelId (weBroadcast we) -> removeReaction r cId
| otherwise -> return ()
WMChannelViewed
| Just cId <- wepChannelId $ weData we -> mhLog LogGeneral "WMChannelViewed received" >> refreshChannelById cId
| otherwise -> return ()
WMMultipleChannelsViewed ->
case wepChannelTimes $ weData we of
Nothing -> return ()
Just m ->
forM_ (HM.keys m) refreshChannelById
WMChannelUpdated
| Just cId <- webChannelId $ weBroadcast we -> do
mChan <- preuse (csChannel(cId))
case mChan of
Just chan -> do
refreshChannelById cId
updateSidebar (chan^.ccInfo.cdTeamId)
Nothing -> return ()
| otherwise -> return ()
WMGroupAdded
| Just cId <- webChannelId (weBroadcast we) -> handleChannelInvite cId
| otherwise -> return ()
WMChannelMemberUpdated
| Just channelMember <- wepChannelMember $ weData we ->
when (channelMemberUserId channelMember == myId) $
updateChannelNotifyProps
(channelMemberChannelId channelMember)
(channelMemberNotifyProps channelMember)
| otherwise -> return ()
WMAddedToTeam
| Just tId <- wepTeamId $ weData we
, Just uId <- wepUserId $ weData we -> do
when (uId == myId && not (memberOf tId)) $ do
handleJoinTeam tId
| otherwise -> return ()
WMUpdateTeam
| Just tId <- webTeamId $ weBroadcast we -> do
when (memberOf tId) $ do
handleUpdateTeam tId
| otherwise -> return ()
WMLeaveTeam
| Just tId <- wepTeamId $ weData we
, Just uId <- wepUserId $ weData we -> do
when (uId == myId && memberOf tId) $ do
handleLeaveTeam tId
| otherwise -> return ()
WMTeamDeleted -> do
mhLog LogGeneral $ T.pack $
"WMTeamDeleted event: " <> show we
WMUserUpdated
| Just user <- wepUser (weData we) -> do
handleUserUpdated user
withCurrentTeam $ \tId ->
withCurrentChannel tId $ \cId _ -> do
refreshChannelById cId
| otherwise -> return ()
-- We deliberately ignore these events:
WMChannelCreated -> return ()
WMEmojiAdded -> return ()
WMWebRTC -> return ()
WMHello -> return ()
WMAuthenticationChallenge -> return ()
WMUserRoleUpdated -> return ()
WMPluginStatusesChanged -> return ()
WMPluginEnabled -> return ()
WMPluginDisabled -> return ()
WMUnknownEvent {} ->
mhLog LogWebsocket $ T.pack $
"Websocket event not handled due to unknown event type: " <> show we
handleWebsocketActionResponse :: WebsocketActionResponse -> MH ()
handleWebsocketActionResponse r =
case warStatus r of
WebsocketActionStatusOK -> return ()