{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}

module UserManagement.User
    ( User (..)
    , UserCreate (..)
    , FullUser (..)
    , GroupRole (..)
    , UserInfo (..)
    , Role (..)
    , UserID
    , roleToText
    , textToRole
    )
where

import Data.Aeson (FromJSON, ToJSON)
import Data.OpenApi (ToSchema)
import Data.Text (Text, pack, unpack)
import Data.UUID (UUID)
import GHC.Generics (Generic)
import GHC.Int (Int64)
import Text.Read (readMaybe)

type UserID = UUID

data User = User
    { User -> UserID
userID :: UserID
    , User -> Text
userName :: Text
    , User -> Text
userEmail :: Text
    }
    deriving (User -> User -> Bool
(User -> User -> Bool) -> (User -> User -> Bool) -> Eq User
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: User -> User -> Bool
== :: User -> User -> Bool
$c/= :: User -> User -> Bool
/= :: User -> User -> Bool
Eq, Int -> User -> ShowS
[User] -> ShowS
User -> String
(Int -> User -> ShowS)
-> (User -> String) -> ([User] -> ShowS) -> Show User
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> User -> ShowS
showsPrec :: Int -> User -> ShowS
$cshow :: User -> String
show :: User -> String
$cshowList :: [User] -> ShowS
showList :: [User] -> ShowS
Show, (forall x. User -> Rep User x)
-> (forall x. Rep User x -> User) -> Generic User
forall x. Rep User x -> User
forall x. User -> Rep User x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. User -> Rep User x
from :: forall x. User -> Rep User x
$cto :: forall x. Rep User x -> User
to :: forall x. Rep User x -> User
Generic)

instance ToJSON User
instance FromJSON User
instance ToSchema User

data UserCreate = UserCreate
    { UserCreate -> Text
userCreateName :: Text
    , UserCreate -> Text
userCreateEmail :: Text
    , UserCreate -> Text
userCreatePWHash :: Text
    }

-- | duplicate definition because of import cycle with UserManagement.Group :'(
type GroupID = Int64

data FullUser = FullUser
    { FullUser -> UserID
fullUserID :: UserID
    , FullUser -> Text
fullUserName :: Text
    , FullUser -> Text
fullUserEmail :: Text
    , FullUser -> Bool
fullUserIsSuperadmin :: Bool
    , FullUser -> [GroupRole]
fullUserRoles :: [GroupRole]
    }
    deriving ((forall x. FullUser -> Rep FullUser x)
-> (forall x. Rep FullUser x -> FullUser) -> Generic FullUser
forall x. Rep FullUser x -> FullUser
forall x. FullUser -> Rep FullUser x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. FullUser -> Rep FullUser x
from :: forall x. FullUser -> Rep FullUser x
$cto :: forall x. Rep FullUser x -> FullUser
to :: forall x. Rep FullUser x -> FullUser
Generic)

data GroupRole = GroupRole
    { GroupRole -> GroupID
groupID :: GroupID
    , GroupRole -> Text
groupName :: Text
    , GroupRole -> Role
role :: Role
    }
    deriving ((forall x. GroupRole -> Rep GroupRole x)
-> (forall x. Rep GroupRole x -> GroupRole) -> Generic GroupRole
forall x. Rep GroupRole x -> GroupRole
forall x. GroupRole -> Rep GroupRole x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. GroupRole -> Rep GroupRole x
from :: forall x. GroupRole -> Rep GroupRole x
$cto :: forall x. Rep GroupRole x -> GroupRole
to :: forall x. Rep GroupRole x -> GroupRole
Generic)

instance ToJSON GroupRole
instance ToSchema GroupRole

instance ToJSON FullUser
instance ToSchema FullUser

-- | used for necessary user info inside a group
data UserInfo = UserInfo
    { UserInfo -> UserID
userInfoID :: UserID
    , UserInfo -> Text
userInfoName :: Text
    , UserInfo -> Text
userInfoEmail :: Text
    , UserInfo -> Role
userInfoRole :: Role
    }
    deriving (UserInfo -> UserInfo -> Bool
(UserInfo -> UserInfo -> Bool)
-> (UserInfo -> UserInfo -> Bool) -> Eq UserInfo
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: UserInfo -> UserInfo -> Bool
== :: UserInfo -> UserInfo -> Bool
$c/= :: UserInfo -> UserInfo -> Bool
/= :: UserInfo -> UserInfo -> Bool
Eq, Int -> UserInfo -> ShowS
[UserInfo] -> ShowS
UserInfo -> String
(Int -> UserInfo -> ShowS)
-> (UserInfo -> String) -> ([UserInfo] -> ShowS) -> Show UserInfo
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> UserInfo -> ShowS
showsPrec :: Int -> UserInfo -> ShowS
$cshow :: UserInfo -> String
show :: UserInfo -> String
$cshowList :: [UserInfo] -> ShowS
showList :: [UserInfo] -> ShowS
Show, (forall x. UserInfo -> Rep UserInfo x)
-> (forall x. Rep UserInfo x -> UserInfo) -> Generic UserInfo
forall x. Rep UserInfo x -> UserInfo
forall x. UserInfo -> Rep UserInfo x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. UserInfo -> Rep UserInfo x
from :: forall x. UserInfo -> Rep UserInfo x
$cto :: forall x. Rep UserInfo x -> UserInfo
to :: forall x. Rep UserInfo x -> UserInfo
Generic)

instance ToJSON UserInfo
instance ToSchema UserInfo

data Role = Member | Admin
    deriving (Role -> Role -> Bool
(Role -> Role -> Bool) -> (Role -> Role -> Bool) -> Eq Role
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Role -> Role -> Bool
== :: Role -> Role -> Bool
$c/= :: Role -> Role -> Bool
/= :: Role -> Role -> Bool
Eq, (forall x. Role -> Rep Role x)
-> (forall x. Rep Role x -> Role) -> Generic Role
forall x. Rep Role x -> Role
forall x. Role -> Rep Role x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Role -> Rep Role x
from :: forall x. Role -> Rep Role x
$cto :: forall x. Rep Role x -> Role
to :: forall x. Rep Role x -> Role
Generic, Maybe Role
Value -> Parser [Role]
Value -> Parser Role
(Value -> Parser Role)
-> (Value -> Parser [Role]) -> Maybe Role -> FromJSON Role
forall a.
(Value -> Parser a)
-> (Value -> Parser [a]) -> Maybe a -> FromJSON a
$cparseJSON :: Value -> Parser Role
parseJSON :: Value -> Parser Role
$cparseJSONList :: Value -> Parser [Role]
parseJSONList :: Value -> Parser [Role]
$comittedField :: Maybe Role
omittedField :: Maybe Role
FromJSON)

instance ToJSON Role
instance ToSchema Role

instance Show Role where
    show :: Role -> String
show = \case
        Role
Member -> String
"member"
        Role
Admin -> String
"admin"

instance Read Role where
    readsPrec :: Int -> ReadS Role
readsPrec Int
_ String
s = case ReadS String
lex String
s of
        [(String
"member", String
rs)] -> [(Role
Member, String
rs)]
        [(String
"admin", String
rs)] -> [(Role
Admin, String
rs)]
        [(String, String)]
_ -> []

-- Convert to/from Text
roleToText :: Role -> Text
roleToText :: Role -> Text
roleToText = String -> Text
pack (String -> Text) -> (Role -> String) -> Role -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Role -> String
forall a. Show a => a -> String
show

textToRole :: Text -> Maybe Role
textToRole :: Text -> Maybe Role
textToRole = String -> Maybe Role
forall a. Read a => String -> Maybe a
readMaybe (String -> Maybe Role) -> (Text -> String) -> Text -> Maybe Role
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
unpack