module UserManagement.Sessions
    ( getAllUsers
    , getUserByEmail
    , getUserByID
    , getUserID
    , putUser
    , deleteUser
    , updateUserName
    , updateUserEmail
    , updateUserPWHash
    , checkGroupMembership
    , getUserRoleInGroup
    , getLoginRequirements
    , getAllUserRoles
    , addGroup
    , getGroupInfo
    , getAllGroupsOverview
    , deleteGroup
    , updateGroupName
    , updateGroupDescription
    , addRole
    , updateUserRoleInGroup
    , removeUserFromGroup
    , getMembersOfGroup
    , addSuperadmin
    , removeSuperadmin
    , checkSuperadmin
    , checkGroupPermission
    , checkGroupNameExistence
    , getExternalPermission
    , getDocumentGroupID
    , getAllExternalUsersOfDocument
    , addExternalPermission
    , updateExternalPermission
    , deleteExternalPermission
    , createPasswordResetToken
    , getPasswordResetToken
    , markPasswordResetTokenUsed
    , cleanupExpiredTokens
    )
where

import qualified Data.Bifunctor (second)
import Data.Text (Text)
import Data.Time (UTCTime)
import Data.UUID (UUID)
import qualified Docs.Document as Document
import Hasql.Session (Session, statement)
import qualified UserManagement.DocumentPermission as Permission
import qualified UserManagement.Group as Group
import qualified UserManagement.Statements as Statements
import qualified UserManagement.User as User

getAllUsers :: Session [User.User]
getAllUsers :: Session [User]
getAllUsers = () -> Statement () [User] -> Session [User]
forall params result.
params -> Statement params result -> Session result
statement () Statement () [User]
Statements.getAllUsers

getUserID :: Text -> Session User.UserID
getUserID :: Text -> Session UserID
getUserID Text
userEmail = Text -> Statement Text UserID -> Session UserID
forall params result.
params -> Statement params result -> Session result
statement Text
userEmail Statement Text UserID
Statements.getUserID

getLoginRequirements :: Text -> Session (Maybe (User.UserID, Text))
getLoginRequirements :: Text -> Session (Maybe (UserID, Text))
getLoginRequirements Text
userEmail = Text
-> Statement Text (Maybe (UserID, Text))
-> Session (Maybe (UserID, Text))
forall params result.
params -> Statement params result -> Session result
statement Text
userEmail Statement Text (Maybe (UserID, Text))
Statements.getLoginRequirements

getUserByEmail :: Text -> Session (Maybe User.User)
getUserByEmail :: Text -> Session (Maybe User)
getUserByEmail Text
userEmail = Text -> Statement Text (Maybe User) -> Session (Maybe User)
forall params result.
params -> Statement params result -> Session result
statement Text
userEmail Statement Text (Maybe User)
Statements.getUserByEmail

getUserByID :: User.UserID -> Session (Maybe User.User)
getUserByID :: UserID -> Session (Maybe User)
getUserByID UserID
userID = UserID -> Statement UserID (Maybe User) -> Session (Maybe User)
forall params result.
params -> Statement params result -> Session result
statement UserID
userID Statement UserID (Maybe User)
Statements.getUserByID

getAllUserRoles
    :: User.UserID -> Session [(Group.GroupID, Text, Maybe User.Role)]
getAllUserRoles :: UserID -> Session [(GroupID, Text, Maybe Role)]
getAllUserRoles UserID
uid =
    ((GroupID, Text, Text) -> (GroupID, Text, Maybe Role))
-> [(GroupID, Text, Text)] -> [(GroupID, Text, Maybe Role)]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Text -> Maybe Role)
-> (GroupID, Text, Text) -> (GroupID, Text, Maybe Role)
forall b c a. (b -> c) -> (GroupID, a, b) -> (GroupID, a, c)
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
Data.Bifunctor.second Text -> Maybe Role
User.textToRole)
        ([(GroupID, Text, Text)] -> [(GroupID, Text, Maybe Role)])
-> Session [(GroupID, Text, Text)]
-> Session [(GroupID, Text, Maybe Role)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> UserID
-> Statement UserID [(GroupID, Text, Text)]
-> Session [(GroupID, Text, Text)]
forall params result.
params -> Statement params result -> Session result
statement UserID
uid Statement UserID [(GroupID, Text, Text)]
Statements.getAllUserRoles

checkGroupMembership :: User.UserID -> Group.GroupID -> Session Bool
checkGroupMembership :: UserID -> GroupID -> Session Bool
checkGroupMembership UserID
userID GroupID
groupID = (UserID, GroupID)
-> Statement (UserID, GroupID) Bool -> Session Bool
forall params result.
params -> Statement params result -> Session result
statement (UserID
userID, GroupID
groupID) Statement (UserID, GroupID) Bool
Statements.checkGroupMembership

getUserRoleInGroup :: User.UserID -> Group.GroupID -> Session (Maybe User.Role)
getUserRoleInGroup :: UserID -> GroupID -> Session (Maybe Role)
getUserRoleInGroup UserID
uid GroupID
group =
    Maybe Role -> (Text -> Maybe Role) -> Maybe Text -> Maybe Role
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Maybe Role
forall a. Maybe a
Nothing Text -> Maybe Role
User.textToRole
        (Maybe Text -> Maybe Role)
-> Session (Maybe Text) -> Session (Maybe Role)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (UserID, GroupID)
-> Statement (UserID, GroupID) (Maybe Text) -> Session (Maybe Text)
forall params result.
params -> Statement params result -> Session result
statement (UserID
uid, GroupID
group) Statement (UserID, GroupID) (Maybe Text)
Statements.getUserRoleInGroup

putUser :: User.UserCreate -> Session User.UserID
putUser :: UserCreate -> Session UserID
putUser UserCreate
user = UserCreate -> Statement UserCreate UserID -> Session UserID
forall params result.
params -> Statement params result -> Session result
statement UserCreate
user Statement UserCreate UserID
Statements.putUser

deleteUser :: User.UserID -> Session ()
deleteUser :: UserID -> Session ()
deleteUser UserID
uid = UserID -> Statement UserID () -> Session ()
forall params result.
params -> Statement params result -> Session result
statement UserID
uid Statement UserID ()
Statements.deleteUser

updateUserName :: User.UserID -> Text -> Session ()
updateUserName :: UserID -> Text -> Session ()
updateUserName UserID
uid Text
name = (Text, UserID) -> Statement (Text, UserID) () -> Session ()
forall params result.
params -> Statement params result -> Session result
statement (Text
name, UserID
uid) Statement (Text, UserID) ()
Statements.updateUserName

updateUserEmail :: User.UserID -> Text -> Session ()
updateUserEmail :: UserID -> Text -> Session ()
updateUserEmail UserID
uid Text
email = (Text, UserID) -> Statement (Text, UserID) () -> Session ()
forall params result.
params -> Statement params result -> Session result
statement (Text
email, UserID
uid) Statement (Text, UserID) ()
Statements.updateUserEmail

updateUserPWHash :: User.UserID -> Text -> Session ()
updateUserPWHash :: UserID -> Text -> Session ()
updateUserPWHash UserID
uid Text
pwhash = (Text, UserID) -> Statement (Text, UserID) () -> Session ()
forall params result.
params -> Statement params result -> Session result
statement (Text
pwhash, UserID
uid) Statement (Text, UserID) ()
Statements.updateUserPWHash

addGroup :: Text -> Maybe Text -> Session Group.GroupID
addGroup :: Text -> Maybe Text -> Session GroupID
addGroup Text
group Maybe Text
description = (Text, Maybe Text)
-> Statement (Text, Maybe Text) GroupID -> Session GroupID
forall params result.
params -> Statement params result -> Session result
statement (Text
group, Maybe Text
description) Statement (Text, Maybe Text) GroupID
Statements.addGroup

-- | returns name and description of specified group
getGroupInfo :: Group.GroupID -> Session Group.GroupOverview
getGroupInfo :: GroupID -> Session GroupOverview
getGroupInfo GroupID
groupID =
    (Text -> Maybe Text -> GroupOverview)
-> (Text, Maybe Text) -> GroupOverview
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry (GroupID -> Text -> Maybe Text -> GroupOverview
Group.GroupOverview GroupID
groupID)
        ((Text, Maybe Text) -> GroupOverview)
-> Session (Text, Maybe Text) -> Session GroupOverview
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GroupID
-> Statement GroupID (Text, Maybe Text)
-> Session (Text, Maybe Text)
forall params result.
params -> Statement params result -> Session result
statement GroupID
groupID Statement GroupID (Text, Maybe Text)
Statements.getGroupInfo

getAllGroupsOverview :: Session [Group.GroupOverview]
getAllGroupsOverview :: Session [GroupOverview]
getAllGroupsOverview = () -> Statement () [GroupOverview] -> Session [GroupOverview]
forall params result.
params -> Statement params result -> Session result
statement () Statement () [GroupOverview]
Statements.getAllGroupsOverview

deleteGroup :: Group.GroupID -> Session ()
deleteGroup :: GroupID -> Session ()
deleteGroup GroupID
groupID = GroupID -> Statement GroupID () -> Session ()
forall params result.
params -> Statement params result -> Session result
statement GroupID
groupID Statement GroupID ()
Statements.deleteGroup

updateGroupName :: Group.GroupID -> Text -> Session ()
updateGroupName :: GroupID -> Text -> Session ()
updateGroupName GroupID
groupID Text
name = (Text, GroupID) -> Statement (Text, GroupID) () -> Session ()
forall params result.
params -> Statement params result -> Session result
statement (Text
name, GroupID
groupID) Statement (Text, GroupID) ()
Statements.updateGroupName

updateGroupDescription :: Group.GroupID -> Maybe Text -> Session ()
updateGroupDescription :: GroupID -> Maybe Text -> Session ()
updateGroupDescription GroupID
groupID Maybe Text
desc = (Maybe Text, GroupID)
-> Statement (Maybe Text, GroupID) () -> Session ()
forall params result.
params -> Statement params result -> Session result
statement (Maybe Text
desc, GroupID
groupID) Statement (Maybe Text, GroupID) ()
Statements.updateGroupDescription

addRole :: User.UserID -> Group.GroupID -> User.Role -> Session ()
addRole :: UserID -> GroupID -> Role -> Session ()
addRole UserID
uid GroupID
gid Role
role =
    let sqlrole :: Text
sqlrole = Role -> Text
User.roleToText Role
role
     in (UserID, GroupID, Text)
-> Statement (UserID, GroupID, Text) () -> Session ()
forall params result.
params -> Statement params result -> Session result
statement (UserID
uid, GroupID
gid, Text
sqlrole) Statement (UserID, GroupID, Text) ()
Statements.addRole

updateUserRoleInGroup :: User.UserID -> Group.GroupID -> User.Role -> Session ()
updateUserRoleInGroup :: UserID -> GroupID -> Role -> Session ()
updateUserRoleInGroup UserID
uid GroupID
gid Role
role =
    let roletext :: Text
roletext = Role -> Text
User.roleToText Role
role
     in (UserID, GroupID, Text)
-> Statement (UserID, GroupID, Text) () -> Session ()
forall params result.
params -> Statement params result -> Session result
statement (UserID
uid, GroupID
gid, Text
roletext) Statement (UserID, GroupID, Text) ()
Statements.updateUserRoleInGroup

removeUserFromGroup :: User.UserID -> Group.GroupID -> Session ()
removeUserFromGroup :: UserID -> GroupID -> Session ()
removeUserFromGroup UserID
uid GroupID
gid = (UserID, GroupID) -> Statement (UserID, GroupID) () -> Session ()
forall params result.
params -> Statement params result -> Session result
statement (UserID
uid, GroupID
gid) Statement (UserID, GroupID) ()
Statements.removeUserFromGroup

getMembersOfGroup :: Group.GroupID -> Session [User.UserInfo]
getMembersOfGroup :: GroupID -> Session [UserInfo]
getMembersOfGroup GroupID
group_id = GroupID -> Statement GroupID [UserInfo] -> Session [UserInfo]
forall params result.
params -> Statement params result -> Session result
statement GroupID
group_id Statement GroupID [UserInfo]
Statements.getMembersOfGroup

addSuperadmin :: User.UserID -> Session ()
addSuperadmin :: UserID -> Session ()
addSuperadmin UserID
uid = UserID -> Statement UserID () -> Session ()
forall params result.
params -> Statement params result -> Session result
statement UserID
uid Statement UserID ()
Statements.addSuperadmin

removeSuperadmin :: User.UserID -> Session ()
removeSuperadmin :: UserID -> Session ()
removeSuperadmin UserID
uid = UserID -> Statement UserID () -> Session ()
forall params result.
params -> Statement params result -> Session result
statement UserID
uid Statement UserID ()
Statements.removeSuperadmin

checkSuperadmin :: User.UserID -> Session Bool
checkSuperadmin :: UserID -> Session Bool
checkSuperadmin UserID
uid = UserID -> Statement UserID Bool -> Session Bool
forall params result.
params -> Statement params result -> Session result
statement UserID
uid Statement UserID Bool
Statements.checkSuperadmin

checkGroupPermission :: User.UserID -> Document.DocumentID -> Session Bool
checkGroupPermission :: UserID -> DocumentID -> Session Bool
checkGroupPermission UserID
uid DocumentID
did = (UserID, DocumentID)
-> Statement (UserID, DocumentID) Bool -> Session Bool
forall params result.
params -> Statement params result -> Session result
statement (UserID
uid, DocumentID
did) Statement (UserID, DocumentID) Bool
Statements.checkGroupPermission

checkGroupNameExistence :: Text -> Session Bool
checkGroupNameExistence :: Text -> Session Bool
checkGroupNameExistence Text
name = Text -> Statement Text Bool -> Session Bool
forall params result.
params -> Statement params result -> Session result
statement Text
name Statement Text Bool
Statements.checkGroupNameExistence

getExternalPermission
    :: User.UserID -> Document.DocumentID -> Session (Maybe Permission.Permission)
getExternalPermission :: UserID -> DocumentID -> Session (Maybe Permission)
getExternalPermission UserID
uid DocumentID
did = (UserID, DocumentID)
-> Statement (UserID, DocumentID) (Maybe Permission)
-> Session (Maybe Permission)
forall params result.
params -> Statement params result -> Session result
statement (UserID
uid, DocumentID
did) Statement (UserID, DocumentID) (Maybe Permission)
Statements.getExternalPermission

getDocumentGroupID :: Document.DocumentID -> Session (Maybe Group.GroupID)
getDocumentGroupID :: DocumentID -> Session (Maybe GroupID)
getDocumentGroupID DocumentID
did = DocumentID
-> Statement DocumentID (Maybe GroupID) -> Session (Maybe GroupID)
forall params result.
params -> Statement params result -> Session result
statement DocumentID
did Statement DocumentID (Maybe GroupID)
Statements.getDocumentGroupID

getAllExternalUsersOfDocument
    :: Document.DocumentID -> Session [(User.UserID, Permission.Permission)]
getAllExternalUsersOfDocument :: DocumentID -> Session [(UserID, Permission)]
getAllExternalUsersOfDocument DocumentID
did = do
    [(UserID, Maybe Permission)]
users <- DocumentID
-> Statement DocumentID [(UserID, Maybe Permission)]
-> Session [(UserID, Maybe Permission)]
forall params result.
params -> Statement params result -> Session result
statement DocumentID
did Statement DocumentID [(UserID, Maybe Permission)]
Statements.getAllExternalUsersOfDocument
    [(UserID, Permission)] -> Session [(UserID, Permission)]
forall a. a -> Session a
forall (m :: * -> *) a. Monad m => a -> m a
return [(UserID
user, Permission
perm) | (UserID
user, Just Permission
perm) <- [(UserID, Maybe Permission)]
users]

addExternalPermission
    :: User.UserID -> Document.DocumentID -> Permission.Permission -> Session ()
addExternalPermission :: UserID -> DocumentID -> Permission -> Session ()
addExternalPermission UserID
uid DocumentID
did Permission
perm =
    let perm' :: Text
perm' = Permission -> Text
Permission.permissionToText Permission
perm
     in (UserID, DocumentID, Text)
-> Statement (UserID, DocumentID, Text) () -> Session ()
forall params result.
params -> Statement params result -> Session result
statement (UserID
uid, DocumentID
did, Text
perm') Statement (UserID, DocumentID, Text) ()
Statements.addExternalPermission

updateExternalPermission
    :: User.UserID -> Document.DocumentID -> Permission.Permission -> Session ()
updateExternalPermission :: UserID -> DocumentID -> Permission -> Session ()
updateExternalPermission UserID
uid DocumentID
did Permission
perm =
    let perm' :: Text
perm' = Permission -> Text
Permission.permissionToText Permission
perm
     in (UserID, DocumentID, Text)
-> Statement (UserID, DocumentID, Text) () -> Session ()
forall params result.
params -> Statement params result -> Session result
statement (UserID
uid, DocumentID
did, Text
perm') Statement (UserID, DocumentID, Text) ()
Statements.updateExternalPermission

deleteExternalPermission :: User.UserID -> Document.DocumentID -> Session ()
deleteExternalPermission :: UserID -> DocumentID -> Session ()
deleteExternalPermission UserID
uid DocumentID
did = (UserID, DocumentID)
-> Statement (UserID, DocumentID) () -> Session ()
forall params result.
params -> Statement params result -> Session result
statement (UserID
uid, DocumentID
did) Statement (UserID, DocumentID) ()
Statements.deleteExternalPermission

-- Password Reset Functions

createPasswordResetToken :: User.UserID -> Text -> UTCTime -> Session UUID
createPasswordResetToken :: UserID -> Text -> UTCTime -> Session UserID
createPasswordResetToken UserID
uid Text
tokenHash UTCTime
expiresAt = (UserID, Text, UTCTime)
-> Statement (UserID, Text, UTCTime) UserID -> Session UserID
forall params result.
params -> Statement params result -> Session result
statement (UserID
uid, Text
tokenHash, UTCTime
expiresAt) Statement (UserID, Text, UTCTime) UserID
Statements.createPasswordResetToken

getPasswordResetToken
    :: Text
    -> Session (Maybe (UUID, User.UserID, Text, UTCTime, UTCTime, Maybe UTCTime))
getPasswordResetToken :: Text
-> Session
     (Maybe (UserID, UserID, Text, UTCTime, UTCTime, Maybe UTCTime))
getPasswordResetToken Text
tokenHash = Text
-> Statement
     Text
     (Maybe (UserID, UserID, Text, UTCTime, UTCTime, Maybe UTCTime))
-> Session
     (Maybe (UserID, UserID, Text, UTCTime, UTCTime, Maybe UTCTime))
forall params result.
params -> Statement params result -> Session result
statement Text
tokenHash Statement
  Text
  (Maybe (UserID, UserID, Text, UTCTime, UTCTime, Maybe UTCTime))
Statements.getPasswordResetToken

markPasswordResetTokenUsed :: Text -> Session ()
markPasswordResetTokenUsed :: Text -> Session ()
markPasswordResetTokenUsed Text
tokenHash = Text -> Statement Text () -> Session ()
forall params result.
params -> Statement params result -> Session result
statement Text
tokenHash Statement Text ()
Statements.markPasswordResetTokenUsed

cleanupExpiredTokens :: Session ()
cleanupExpiredTokens :: Session ()
cleanupExpiredTokens = () -> Statement () () -> Session ()
forall params result.
params -> Statement params result -> Session result
statement () Statement () ()
Statements.cleanupExpiredTokens