{-# LANGUAGE TemplateHaskell #-} -- | A User module Calamity.Types.Model.User ( User (..), UserBanner (..), Partial (PartialUser), StatusType (..), ) where import Calamity.Internal.IntColour import Calamity.Types.CDNAsset (CDNAsset (..)) import Calamity.Types.Model.Avatar import {-# SOURCE #-} Calamity.Types.Model.Guild.Member import Calamity.Types.Partial import Calamity.Types.Snowflake import Calamity.Utils.CDNUrl (assetHashFile, cdnURL) import Data.Aeson ((.:), (.:?)) import Data.Aeson qualified as Aeson import Data.Colour (Colour) import Data.Text (Text) import Data.Text qualified as T import Data.Text.Read (decimal) import Data.Word import Network.HTTP.Req ((/:), (/~)) import Optics.TH import TextShow qualified import TextShow.TH data UserBanner = UserBanner { userID :: Snowflake User , hash :: T.Text } deriving (Show, Eq) instance CDNAsset UserBanner where assetURL UserBanner {hash, userID} = cdnURL /: "banners" /~ userID /: assetHashFile hash data User = User { id :: Snowflake User , username :: Text , discriminator :: Text , bot :: Maybe Bool , avatar :: Avatar , mfaEnabled :: Maybe Bool , banner :: Maybe UserBanner , accentColour :: Maybe (Colour Double) , locale :: Maybe Text , verified :: Maybe Bool , email :: Maybe Text , flags :: Maybe Word64 , premiumType :: Maybe Word64 } deriving (Show, Eq) deriving (TextShow.TextShow) via TextShow.FromStringShow User deriving (HasID User) via HasIDField "id" User deriving (HasID Member) via HasIDFieldCoerce' "id" User instance Aeson.FromJSON User where parseJSON = Aeson.withObject "User" $ \v -> do uid <- v .: "id" avatarHash <- v .:? "avatar" discrim <- v .: "discriminator" discrim' <- case decimal discrim of Right (n, _) -> pure n Left e -> fail e let avatar = Avatar avatarHash uid discrim' banner <- (UserBanner uid <$>) <$> v .:? "banner" User <$> pure uid <*> v .: "username" <*> v .: "discriminator" <*> v .:? "bot" <*> pure avatar <*> v .:? "mfa_enabled" <*> pure banner <*> (fmap fromIntColour <$> v .:? "accent_color") <*> v .:? "locale" <*> v .:? "verified" <*> v .:? "email" <*> v .:? "flags" <*> v .:? "premium_type" newtype instance Partial User = PartialUser { id :: Snowflake User } deriving stock (Show, Eq) deriving (HasID User) via HasIDField "id" (Partial User) instance Aeson.FromJSON (Partial User) where parseJSON = Aeson.withObject "Partial User" $ \v -> PartialUser <$> v .: "id" data StatusType = Idle | DND | Online | Offline | Invisible deriving (Eq, Show, Enum) instance Aeson.FromJSON StatusType where parseJSON = Aeson.withText "StatusType" $ \case "idle" -> pure Idle "dnd" -> pure DND "online" -> pure Online "offline" -> pure Offline "invisible" -> pure Invisible _ -> fail "Unknown status type" instance Aeson.ToJSON StatusType where toJSON = Aeson.toJSON @Text . \case Idle -> "idle" DND -> "dnd" Online -> "online" Offline -> "offline" Invisible -> "invisible" $(deriveTextShow 'PartialUser) $(deriveTextShow ''StatusType) $(makeFieldLabelsNoPrefix ''User) $(makeFieldLabelsNoPrefix 'PartialUser) $(makeFieldLabelsNoPrefix ''StatusType)