{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveFunctor #-}
module Matterhorn.Types.Users
( UserInfo(..)
, UserStatus(..)
, Users
, uiName, uiId, uiStatus, uiInTeam, uiNickName, uiFirstName, uiLastName, uiEmail
, uiDeleted
, userInfoFromUser
, getUsernameSet
, trimUserSigil
, statusFromText
, findUserById
, findUserByUsername
, findUserByNickname
, noUsers, addUser, allUsers
, modifyUserById
, userDeleted
, TypingUsers
, noTypingUsers
, addTypingUser
, allTypingUsers
, expireTypingUsers
, getAllUserIds
)
where
import Prelude ()
import Matterhorn.Prelude
import qualified Data.HashMap.Strict as HM
import qualified Data.Set as S
import Data.Semigroup ( Max(..) )
import qualified Data.Text as T
import Lens.Micro.Platform ( (%~), makeLenses, ix )
import Network.Mattermost.Types ( UserId(..), User(..) )
import Matterhorn.Types.Common
import Matterhorn.Constants ( userSigil )
data UserInfo = UserInfo
{ _uiName :: Text
, _uiId :: UserId
, _uiStatus :: UserStatus
, _uiInTeam :: Bool
, _uiNickName :: Maybe Text
, _uiFirstName :: Text
, _uiLastName :: Text
, _uiEmail :: Text
, _uiDeleted :: Bool
} deriving (Eq, Show)
userDeleted :: User -> Bool
userDeleted u =
case userCreateAt u of
Nothing -> False
Just c -> userDeleteAt u > c
userInfoFromUser :: User -> Bool -> UserInfo
userInfoFromUser up inTeam = UserInfo
{ _uiName = userUsername up
, _uiId = userId up
, _uiStatus = Offline
, _uiInTeam = inTeam
, _uiNickName =
let nick = sanitizeUserText $ userNickname up
in if T.null nick then Nothing else Just nick
, _uiFirstName = sanitizeUserText $ userFirstName up
, _uiLastName = sanitizeUserText $ userLastName up
, _uiEmail = sanitizeUserText $ userEmail up
, _uiDeleted = userDeleted up
}
data UserStatus
= Online
| Away
| Offline
| DoNotDisturb
| Other Text
deriving (Eq, Show)
statusFromText :: Text -> UserStatus
statusFromText t = case t of
"online" -> Online
"offline" -> Offline
"away" -> Away
"dnd" -> DoNotDisturb
_ -> Other t
makeLenses ''UserInfo
data AllMyUsers a =
AllUsers { _ofUsers :: HashMap UserId a
, _usernameSet :: S.Set Text
}
deriving Functor
makeLenses ''AllMyUsers
type Users = AllMyUsers UserInfo
getUsernameSet :: Users -> S.Set Text
getUsernameSet = _usernameSet
noUsers :: Users
noUsers = AllUsers HM.empty mempty
getAllUserIds :: Users -> [UserId]
getAllUserIds = HM.keys . _ofUsers
addUser :: UserInfo -> Users -> Users
addUser userinfo u =
u & ofUsers %~ HM.insert (userinfo^.uiId) userinfo
& usernameSet %~ S.insert (userinfo^.uiName)
allUsers :: Users -> [UserInfo]
allUsers = HM.elems . _ofUsers
type TypingUsers = AllMyUsers (Max UTCTime)
noTypingUsers :: TypingUsers
noTypingUsers = AllUsers HM.empty mempty
addTypingUser :: UserId -> UTCTime -> TypingUsers -> TypingUsers
addTypingUser uId ts = ofUsers %~ HM.insertWith (<>) uId (Max ts)
allTypingUsers :: TypingUsers -> [UserId]
allTypingUsers = HM.keys . _ofUsers
expireTypingUsers :: UTCTime -> TypingUsers -> TypingUsers
expireTypingUsers expiryTimestamp =
ofUsers %~ HM.filter (\(Max ts') -> ts' >= expiryTimestamp)
findUserById :: UserId -> Users -> Maybe UserInfo
findUserById uId = HM.lookup uId . _ofUsers
findUserByUsername :: Text -> Users -> Maybe (UserId, UserInfo)
findUserByUsername name allusers =
case filter ((== trimUserSigil name) . _uiName . snd) $ HM.toList $ _ofUsers allusers of
(usr : []) -> Just usr
_ -> Nothing
findUserByNickname:: Text -> Users -> Maybe (UserId, UserInfo)
findUserByNickname nick us =
case filter ((== (Just $ trimUserSigil nick)) . _uiNickName . snd) $ HM.toList $ _ofUsers us of
(pair : []) -> Just pair
_ -> Nothing
trimUserSigil :: Text -> Text
trimUserSigil n
| userSigil `T.isPrefixOf` n = T.tail n
| otherwise = n
modifyUserById :: UserId -> (UserInfo -> UserInfo) -> Users -> Users
modifyUserById uId f = ofUsers.ix(uId) %~ f