{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE StrictData #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}

-- |
-- Module      : Network.Reddit.Types.Account
-- Copyright   : (c) 2021 Rory Tyler Hayford
-- License     : BSD-3-Clause
-- Maintainer  : rory.hayford@protonmail.com
-- Stability   : experimental
-- Portability : GHC
--
module Network.Reddit.Types.Account
    ( Username
    , mkUsername
    , UserID(UserID)
    , Account(..)
    , AccountSearchOpts(..)
    , AccountSearchSort(..)
    , Friend(..)
    , FriendList
    , Karma(..)
    , KarmaList
    , UserSummary(..)
    , UserSummaryList
    , Preferences(..)
    , MediaPreference(..)
    , AcceptPMs(..)
    , usernameToDisplayName
    ) where

import           Control.Monad                  ( (<=<) )
import           Control.Monad.Catch            ( MonadThrow )

import           Data.Aeson
                 ( (.!=)
                 , (.:)
                 , (.:?)
                 , Array
                 , FromJSON(..)
                 , Options(fieldLabelModifier, constructorTagModifier)
                 , ToJSON(toJSON)
                 , Value(..)
                 , defaultOptions
                 , genericParseJSON
                 , genericToJSON
                 , withArray
                 , withObject
                 , withText
                 )
import           Data.Aeson.Casing              ( snakeCase )
import           Data.Char                      ( toLower )
import           Data.Coerce                    ( coerce )
import           Data.Foldable                  ( asum )
import           Data.Generics.Product          ( HasField(field) )
import qualified Data.HashMap.Strict            as HM
import           Data.Maybe                     ( catMaybes )
import           Data.Sequence                  ( Seq )
import           Data.Text                      ( Text )
import           Data.Time                      ( UTCTime )
import           Data.Traversable               ( for )

import           GHC.Exts                       ( IsList(toList), fromList )
import           GHC.Generics                   ( Generic )

import           Lens.Micro

import           Network.Reddit.Types.Internal
import           Network.Reddit.Types.Subreddit

import           Web.FormUrlEncoded             ( ToForm(toForm) )
import           Web.HttpApiData                ( ToHttpApiData(..) )

-- | Reddit username
newtype Username = Username Text
    deriving stock ( Int -> Username -> ShowS
[Username] -> ShowS
Username -> String
(Int -> Username -> ShowS)
-> (Username -> String) -> ([Username] -> ShowS) -> Show Username
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Username] -> ShowS
$cshowList :: [Username] -> ShowS
show :: Username -> String
$cshow :: Username -> String
showsPrec :: Int -> Username -> ShowS
$cshowsPrec :: Int -> Username -> ShowS
Show, (forall x. Username -> Rep Username x)
-> (forall x. Rep Username x -> Username) -> Generic Username
forall x. Rep Username x -> Username
forall x. Username -> Rep Username x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Username x -> Username
$cfrom :: forall x. Username -> Rep Username x
Generic )
    deriving newtype ( Value -> Parser [Username]
Value -> Parser Username
(Value -> Parser Username)
-> (Value -> Parser [Username]) -> FromJSON Username
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [Username]
$cparseJSONList :: Value -> Parser [Username]
parseJSON :: Value -> Parser Username
$cparseJSON :: Value -> Parser Username
FromJSON, [Username] -> Encoding
[Username] -> Value
Username -> Encoding
Username -> Value
(Username -> Value)
-> (Username -> Encoding)
-> ([Username] -> Value)
-> ([Username] -> Encoding)
-> ToJSON Username
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [Username] -> Encoding
$ctoEncodingList :: [Username] -> Encoding
toJSONList :: [Username] -> Value
$ctoJSONList :: [Username] -> Value
toEncoding :: Username -> Encoding
$ctoEncoding :: Username -> Encoding
toJSON :: Username -> Value
$ctoJSON :: Username -> Value
ToJSON, Username -> ByteString
Username -> Builder
Username -> Text
(Username -> Text)
-> (Username -> Builder)
-> (Username -> ByteString)
-> (Username -> Text)
-> ToHttpApiData Username
forall a.
(a -> Text)
-> (a -> Builder)
-> (a -> ByteString)
-> (a -> Text)
-> ToHttpApiData a
toQueryParam :: Username -> Text
$ctoQueryParam :: Username -> Text
toHeader :: Username -> ByteString
$ctoHeader :: Username -> ByteString
toEncodedUrlPiece :: Username -> Builder
$ctoEncodedUrlPiece :: Username -> Builder
toUrlPiece :: Username -> Text
$ctoUrlPiece :: Username -> Text
ToHttpApiData )
    deriving ( Username -> Username -> Bool
(Username -> Username -> Bool)
-> (Username -> Username -> Bool) -> Eq Username
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Username -> Username -> Bool
$c/= :: Username -> Username -> Bool
== :: Username -> Username -> Bool
$c== :: Username -> Username -> Bool
Eq ) via CIText Username

-- | Smart constructor for 'Username', which must be between 3 and 20 chars,
-- and may only include upper\/lowercase alphanumeric chars, underscores, or
-- hyphens
mkUsername :: MonadThrow m => Text -> m Username
mkUsername :: Text -> m Username
mkUsername = Maybe String -> Maybe (Int, Int) -> Text -> Text -> m Username
forall (m :: * -> *) a.
(MonadThrow m, Coercible a Text) =>
Maybe String -> Maybe (Int, Int) -> Text -> Text -> m a
validateName Maybe String
forall a. Maybe a
Nothing Maybe (Int, Int)
forall a. Maybe a
Nothing Text
"Username"

-- | Prefix the username with \"u_\"
usernameToDisplayName :: Username -> Text
usernameToDisplayName :: Username -> Text
usernameToDisplayName (Username Text
uname) = Text
"u_" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
uname

-- | A unique, site-wide ID for an account
newtype UserID = UserID Text
    deriving stock ( Int -> UserID -> ShowS
[UserID] -> ShowS
UserID -> String
(Int -> UserID -> ShowS)
-> (UserID -> String) -> ([UserID] -> ShowS) -> Show UserID
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [UserID] -> ShowS
$cshowList :: [UserID] -> ShowS
show :: UserID -> String
$cshow :: UserID -> String
showsPrec :: Int -> UserID -> ShowS
$cshowsPrec :: Int -> UserID -> ShowS
Show, (forall x. UserID -> Rep UserID x)
-> (forall x. Rep UserID x -> UserID) -> Generic UserID
forall x. Rep UserID x -> UserID
forall x. UserID -> Rep UserID x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep UserID x -> UserID
$cfrom :: forall x. UserID -> Rep UserID x
Generic )
    deriving newtype ( UserID -> UserID -> Bool
(UserID -> UserID -> Bool)
-> (UserID -> UserID -> Bool) -> Eq UserID
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: UserID -> UserID -> Bool
$c/= :: UserID -> UserID -> Bool
== :: UserID -> UserID -> Bool
$c== :: UserID -> UserID -> Bool
Eq )

instance FromJSON UserID where
    parseJSON :: Value -> Parser UserID
parseJSON = String -> (Text -> Parser UserID) -> Value -> Parser UserID
forall a. String -> (Text -> Parser a) -> Value -> Parser a
withText String
"UserID" ((Text -> Parser UserID) -> Value -> Parser UserID)
-> (Text -> Parser UserID) -> Value -> Parser UserID
forall a b. (a -> b) -> a -> b
$ Parser Text -> Parser UserID
coerce (Parser Text -> Parser UserID)
-> (Text -> Parser Text) -> Text -> Parser UserID
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RedditKind -> Text -> Parser Text
dropTypePrefix RedditKind
AccountKind

instance Thing UserID where
    fullname :: UserID -> Text
fullname (UserID Text
uid) = RedditKind -> Text -> Text
prependType RedditKind
AccountKind Text
uid

-- | Account information. Most @Maybe@ fields denote data that Reddit sets to null
-- if the requester does not own the account in question
data Account = Account
    { Account -> UserID
userID               :: UserID
    , Account -> Username
username             :: Username
    , Account -> UTCTime
created              :: UTCTime
    , Account -> Integer
commentKarma         :: Integer
    , Account -> Integer
linkKarma            :: Integer
    , Account -> Integer
totalKarma           :: Integer
    , Account -> Maybe Integer
awarderKarma         :: Maybe Integer
    , Account -> Maybe Integer
awardeeKarma         :: Maybe Integer
    , Account -> Bool
isFriend             :: Bool
    , Account -> Bool
isGold               :: Bool
    , Account -> Bool
isMod                :: Bool
    , Account -> Text
iconImg              :: URL
    , Account -> Subreddit
subreddit            :: Subreddit
    , Account -> Maybe Integer
numFriends           :: Maybe Integer
    , Account -> Maybe Integer
inboxCount           :: Maybe Integer
    , Account -> Maybe Integer
creddits             :: Maybe Integer
    , Account -> Maybe Text
modHash              :: Maybe Text
    , Account -> Maybe Bool
over18               :: Maybe Bool
    , Account -> Maybe Bool
hasMail              :: Maybe Bool
    , Account -> Maybe Bool
hasModMail           :: Maybe Bool
    , Account -> Maybe Bool
hasVerifiedEmail     :: Maybe Bool
    , Account -> Maybe Bool
hasGoldSubscription  :: Maybe Bool
    , Account -> Maybe UTCTime
goldExpiration       :: Maybe UTCTime
    , Account -> Maybe Bool
isSuspended          :: Maybe Bool
    , Account -> Maybe UTCTime
suspensionExpiration :: Maybe UTCTime
    }
    deriving stock ( Int -> Account -> ShowS
[Account] -> ShowS
Account -> String
(Int -> Account -> ShowS)
-> (Account -> String) -> ([Account] -> ShowS) -> Show Account
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Account] -> ShowS
$cshowList :: [Account] -> ShowS
show :: Account -> String
$cshow :: Account -> String
showsPrec :: Int -> Account -> ShowS
$cshowsPrec :: Int -> Account -> ShowS
Show, (forall x. Account -> Rep Account x)
-> (forall x. Rep Account x -> Account) -> Generic Account
forall x. Rep Account x -> Account
forall x. Account -> Rep Account x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Account x -> Account
$cfrom :: forall x. Account -> Rep Account x
Generic )

instance FromJSON Account where
    parseJSON :: Value -> Parser Account
parseJSON Value
v = [Parser Account] -> Parser Account
forall (t :: * -> *) (f :: * -> *) a.
(Foldable t, Alternative f) =>
t (f a) -> f a
asum [ String -> (Object -> Parser Account) -> Value -> Parser Account
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"Account" Object -> Parser Account
accountP Value
v
                       , RedditKind
-> String -> (Object -> Parser Account) -> Value -> Parser Account
forall b a.
FromJSON b =>
RedditKind -> String -> (b -> Parser a) -> Value -> Parser a
withKind RedditKind
AccountKind String
"Account" Object -> Parser Account
accountP Value
v
                       ]
      where
        accountP :: Object -> Parser Account
accountP Object
o = do
            UserID
userID <- Object
o Object -> Text -> Parser UserID
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"id"
            Username
username <- Object
o Object -> Text -> Parser Username
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"name"
            UTCTime
created <- Integer -> UTCTime
integerToUTC (Integer -> UTCTime) -> Parser Integer -> Parser UTCTime
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
o Object -> Text -> Parser Integer
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"created_utc"
            Integer
commentKarma <- Object
o Object -> Text -> Parser Integer
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"comment_karma"
            Integer
linkKarma <- Object
o Object -> Text -> Parser Integer
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"link_karma"
            Integer
totalKarma <- Object
o Object -> Text -> Parser (Maybe Integer)
forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
.:? Text
"total_karma" Parser (Maybe Integer) -> Integer -> Parser Integer
forall a. Parser (Maybe a) -> a -> Parser a
.!= (Integer
commentKarma Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
linkKarma)
            Maybe Integer
awarderKarma <- Object
o Object -> Text -> Parser (Maybe Integer)
forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
.:? Text
"awarder_karma"
            Maybe Integer
awardeeKarma <- Object
o Object -> Text -> Parser (Maybe Integer)
forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
.:? Text
"awardee_karma"
            Maybe Integer
numFriends <- Object
o Object -> Text -> Parser (Maybe Integer)
forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
.:? Text
"num_friends"
            Bool
isFriend <- Object
o Object -> Text -> Parser (Maybe Bool)
forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
.:? Text
"is_friend" Parser (Maybe Bool) -> Bool -> Parser Bool
forall a. Parser (Maybe a) -> a -> Parser a
.!= Bool
False
            Bool
isGold <- Object
o Object -> Text -> Parser Bool
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"is_gold"
            Bool
isMod <- Object
o Object -> Text -> Parser Bool
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"is_mod"
            Text
iconImg <- Object
o Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"icon_img"
            Subreddit
subreddit <- Object
o Object -> Text -> Parser Subreddit
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"subreddit" Parser Subreddit -> (Subreddit -> Subreddit) -> Parser Subreddit
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> forall s t a b. HasField "created" s t a b => Lens s t a b
forall (field :: Symbol) s t a b.
HasField field s t a b =>
Lens s t a b
field @"created" ((UTCTime -> Identity UTCTime) -> Subreddit -> Identity Subreddit)
-> UTCTime -> Subreddit -> Subreddit
forall s t a b. ASetter s t a b -> b -> s -> t
.~ UTCTime
created
            Maybe Integer
inboxCount <- Object
o Object -> Text -> Parser (Maybe Integer)
forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
.:? Text
"inbox_count"
            Maybe Integer
creddits <- Object
o Object -> Text -> Parser (Maybe Integer)
forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
.:? Text
"gold_creddits"
            Maybe Text
modHash <- Object
o Object -> Text -> Parser (Maybe Text)
forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
.:? Text
"modhash"
            Maybe Bool
over18 <- Object
o Object -> Text -> Parser (Maybe Bool)
forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
.:? Text
"over_18"
            Maybe Bool
hasMail <- Object
o Object -> Text -> Parser (Maybe Bool)
forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
.:? Text
"has_mail"
            Maybe Bool
hasModMail <- Object
o Object -> Text -> Parser (Maybe Bool)
forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
.:? Text
"has_mod_mail"
            Maybe Bool
hasVerifiedEmail <- Object
o Object -> Text -> Parser (Maybe Bool)
forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
.:? Text
"has_verified_email"
            Maybe Bool
hasGoldSubscription <- Object
o Object -> Text -> Parser (Maybe Bool)
forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
.:? Text
"has_gold_subscription"
            Maybe UTCTime
goldExpiration <- Object
o Object -> Text -> Parser (Maybe UTCTime)
forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
.:? Text
"gold_expiration"
            Maybe Bool
isSuspended <- Object
o Object -> Text -> Parser (Maybe Bool)
forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
.:? Text
"is_suspended"
            Maybe UTCTime
suspensionExpiration
                <- (Integer -> UTCTime) -> Maybe Integer -> Maybe UTCTime
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Integer -> UTCTime
integerToUTC (Maybe Integer -> Maybe UTCTime)
-> Parser (Maybe Integer) -> Parser (Maybe UTCTime)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
o Object -> Text -> Parser (Maybe Integer)
forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
.:? Text
"suspension_expiration"
            Account -> Parser Account
forall (f :: * -> *) a. Applicative f => a -> f a
pure Account :: UserID
-> Username
-> UTCTime
-> Integer
-> Integer
-> Integer
-> Maybe Integer
-> Maybe Integer
-> Bool
-> Bool
-> Bool
-> Text
-> Subreddit
-> Maybe Integer
-> Maybe Integer
-> Maybe Integer
-> Maybe Text
-> Maybe Bool
-> Maybe Bool
-> Maybe Bool
-> Maybe Bool
-> Maybe Bool
-> Maybe UTCTime
-> Maybe Bool
-> Maybe UTCTime
-> Account
Account { Bool
Integer
Maybe Bool
Maybe Integer
Maybe Text
Maybe UTCTime
Text
UTCTime
Subreddit
UserID
Username
suspensionExpiration :: Maybe UTCTime
isSuspended :: Maybe Bool
goldExpiration :: Maybe UTCTime
hasGoldSubscription :: Maybe Bool
hasVerifiedEmail :: Maybe Bool
hasModMail :: Maybe Bool
hasMail :: Maybe Bool
over18 :: Maybe Bool
modHash :: Maybe Text
creddits :: Maybe Integer
inboxCount :: Maybe Integer
subreddit :: Subreddit
iconImg :: Text
isMod :: Bool
isGold :: Bool
isFriend :: Bool
numFriends :: Maybe Integer
awardeeKarma :: Maybe Integer
awarderKarma :: Maybe Integer
totalKarma :: Integer
linkKarma :: Integer
commentKarma :: Integer
created :: UTCTime
username :: Username
userID :: UserID
$sel:suspensionExpiration:Account :: Maybe UTCTime
$sel:isSuspended:Account :: Maybe Bool
$sel:goldExpiration:Account :: Maybe UTCTime
$sel:hasGoldSubscription:Account :: Maybe Bool
$sel:hasVerifiedEmail:Account :: Maybe Bool
$sel:hasModMail:Account :: Maybe Bool
$sel:hasMail:Account :: Maybe Bool
$sel:over18:Account :: Maybe Bool
$sel:modHash:Account :: Maybe Text
$sel:creddits:Account :: Maybe Integer
$sel:inboxCount:Account :: Maybe Integer
$sel:numFriends:Account :: Maybe Integer
$sel:subreddit:Account :: Subreddit
$sel:iconImg:Account :: Text
$sel:isMod:Account :: Bool
$sel:isGold:Account :: Bool
$sel:isFriend:Account :: Bool
$sel:awardeeKarma:Account :: Maybe Integer
$sel:awarderKarma:Account :: Maybe Integer
$sel:totalKarma:Account :: Integer
$sel:linkKarma:Account :: Integer
$sel:commentKarma:Account :: Integer
$sel:created:Account :: UTCTime
$sel:username:Account :: Username
$sel:userID:Account :: UserID
.. }

instance Paginable Account where
    type PaginateOptions Account = AccountSearchOpts

    type PaginateThing Account = UserID

    defaultOpts :: PaginateOptions Account
defaultOpts = AccountSearchOpts :: AccountSearchSort -> Maybe Bool -> Maybe Text -> AccountSearchOpts
AccountSearchOpts
        { $sel:resultSort:AccountSearchOpts :: AccountSearchSort
resultSort      = AccountSearchSort
RelevantAccounts
        , $sel:typeaheadActive:AccountSearchOpts :: Maybe Bool
typeaheadActive = Maybe Bool
forall a. Maybe a
Nothing
        , $sel:searchQueryID:AccountSearchOpts :: Maybe Text
searchQueryID   = Maybe Text
forall a. Maybe a
Nothing
        }

    getFullname :: Account -> PaginateThing Account
getFullname Account { UserID
userID :: UserID
$sel:userID:Account :: Account -> UserID
userID } = PaginateThing Account
UserID
userID

-- | Options for search @Listing@s of 'Account's
data AccountSearchOpts = AccountSearchOpts
    { AccountSearchOpts -> AccountSearchSort
resultSort      :: AccountSearchSort
    , AccountSearchOpts -> Maybe Bool
typeaheadActive :: Maybe Bool
      -- | A UUID. This is not clearly documented in the API docs. Presumably,
      -- it refers to an identifier for an existing search
    , AccountSearchOpts -> Maybe Text
searchQueryID   :: Maybe Text
    }
    deriving stock ( Int -> AccountSearchOpts -> ShowS
[AccountSearchOpts] -> ShowS
AccountSearchOpts -> String
(Int -> AccountSearchOpts -> ShowS)
-> (AccountSearchOpts -> String)
-> ([AccountSearchOpts] -> ShowS)
-> Show AccountSearchOpts
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [AccountSearchOpts] -> ShowS
$cshowList :: [AccountSearchOpts] -> ShowS
show :: AccountSearchOpts -> String
$cshow :: AccountSearchOpts -> String
showsPrec :: Int -> AccountSearchOpts -> ShowS
$cshowsPrec :: Int -> AccountSearchOpts -> ShowS
Show, AccountSearchOpts -> AccountSearchOpts -> Bool
(AccountSearchOpts -> AccountSearchOpts -> Bool)
-> (AccountSearchOpts -> AccountSearchOpts -> Bool)
-> Eq AccountSearchOpts
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AccountSearchOpts -> AccountSearchOpts -> Bool
$c/= :: AccountSearchOpts -> AccountSearchOpts -> Bool
== :: AccountSearchOpts -> AccountSearchOpts -> Bool
$c== :: AccountSearchOpts -> AccountSearchOpts -> Bool
Eq, (forall x. AccountSearchOpts -> Rep AccountSearchOpts x)
-> (forall x. Rep AccountSearchOpts x -> AccountSearchOpts)
-> Generic AccountSearchOpts
forall x. Rep AccountSearchOpts x -> AccountSearchOpts
forall x. AccountSearchOpts -> Rep AccountSearchOpts x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep AccountSearchOpts x -> AccountSearchOpts
$cfrom :: forall x. AccountSearchOpts -> Rep AccountSearchOpts x
Generic )

instance ToForm AccountSearchOpts where
    toForm :: AccountSearchOpts -> Form
toForm AccountSearchOpts { Maybe Bool
Maybe Text
AccountSearchSort
searchQueryID :: Maybe Text
typeaheadActive :: Maybe Bool
resultSort :: AccountSearchSort
$sel:searchQueryID:AccountSearchOpts :: AccountSearchOpts -> Maybe Text
$sel:typeaheadActive:AccountSearchOpts :: AccountSearchOpts -> Maybe Bool
$sel:resultSort:AccountSearchOpts :: AccountSearchOpts -> AccountSearchSort
.. } = [Item Form] -> Form
forall l. IsList l => [Item l] -> l
fromList
        ([Item Form] -> Form) -> [Item Form] -> Form
forall a b. (a -> b) -> a -> b
$ [ (Text
"sort", AccountSearchSort -> Text
forall a. ToHttpApiData a => a -> Text
toQueryParam AccountSearchSort
resultSort) ]
        [(Text, Text)] -> [(Text, Text)] -> [(Text, Text)]
forall a. Semigroup a => a -> a -> a
<> [Maybe (Text, Text)] -> [(Text, Text)]
forall a. [Maybe a] -> [a]
catMaybes [ (Text
"typeahead_active", ) (Text -> (Text, Text)) -> (Bool -> Text) -> Bool -> (Text, Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Text
forall a. ToHttpApiData a => a -> Text
toQueryParam
                       (Bool -> (Text, Text)) -> Maybe Bool -> Maybe (Text, Text)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Bool
typeaheadActive
                     , (Text
"search_query_id", ) (Text -> (Text, Text)) -> (Text -> Text) -> Text -> (Text, Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
forall a. ToHttpApiData a => a -> Text
toQueryParam (Text -> (Text, Text)) -> Maybe Text -> Maybe (Text, Text)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Text
searchQueryID
                     ]

-- | The item sort for 'Account' searches
data AccountSearchSort
    = RelevantAccounts
    | ActiveAccounts
    deriving stock ( Int -> AccountSearchSort -> ShowS
[AccountSearchSort] -> ShowS
AccountSearchSort -> String
(Int -> AccountSearchSort -> ShowS)
-> (AccountSearchSort -> String)
-> ([AccountSearchSort] -> ShowS)
-> Show AccountSearchSort
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [AccountSearchSort] -> ShowS
$cshowList :: [AccountSearchSort] -> ShowS
show :: AccountSearchSort -> String
$cshow :: AccountSearchSort -> String
showsPrec :: Int -> AccountSearchSort -> ShowS
$cshowsPrec :: Int -> AccountSearchSort -> ShowS
Show, AccountSearchSort -> AccountSearchSort -> Bool
(AccountSearchSort -> AccountSearchSort -> Bool)
-> (AccountSearchSort -> AccountSearchSort -> Bool)
-> Eq AccountSearchSort
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AccountSearchSort -> AccountSearchSort -> Bool
$c/= :: AccountSearchSort -> AccountSearchSort -> Bool
== :: AccountSearchSort -> AccountSearchSort -> Bool
$c== :: AccountSearchSort -> AccountSearchSort -> Bool
Eq, (forall x. AccountSearchSort -> Rep AccountSearchSort x)
-> (forall x. Rep AccountSearchSort x -> AccountSearchSort)
-> Generic AccountSearchSort
forall x. Rep AccountSearchSort x -> AccountSearchSort
forall x. AccountSearchSort -> Rep AccountSearchSort x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep AccountSearchSort x -> AccountSearchSort
$cfrom :: forall x. AccountSearchSort -> Rep AccountSearchSort x
Generic )

instance ToHttpApiData AccountSearchSort where
    toQueryParam :: AccountSearchSort -> Text
toQueryParam = \case
        AccountSearchSort
RelevantAccounts -> Text
"relevance"
        AccountSearchSort
ActiveAccounts   -> Text
"activity"

-- | A user\'s friend
data Friend = Friend
    { Friend -> Username
username :: Username
    , Friend -> UserID
userID   :: UserID
    , Friend -> UTCTime
since    :: UTCTime
    , Friend -> Maybe Text
note     :: Maybe Text
    }
    deriving stock ( Int -> Friend -> ShowS
[Friend] -> ShowS
Friend -> String
(Int -> Friend -> ShowS)
-> (Friend -> String) -> ([Friend] -> ShowS) -> Show Friend
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Friend] -> ShowS
$cshowList :: [Friend] -> ShowS
show :: Friend -> String
$cshow :: Friend -> String
showsPrec :: Int -> Friend -> ShowS
$cshowsPrec :: Int -> Friend -> ShowS
Show, Friend -> Friend -> Bool
(Friend -> Friend -> Bool)
-> (Friend -> Friend -> Bool) -> Eq Friend
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Friend -> Friend -> Bool
$c/= :: Friend -> Friend -> Bool
== :: Friend -> Friend -> Bool
$c== :: Friend -> Friend -> Bool
Eq, (forall x. Friend -> Rep Friend x)
-> (forall x. Rep Friend x -> Friend) -> Generic Friend
forall x. Rep Friend x -> Friend
forall x. Friend -> Rep Friend x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Friend x -> Friend
$cfrom :: forall x. Friend -> Rep Friend x
Generic )

instance FromJSON Friend where
    parseJSON :: Value -> Parser Friend
parseJSON = String -> (Object -> Parser Friend) -> Value -> Parser Friend
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"Friend" ((Object -> Parser Friend) -> Value -> Parser Friend)
-> (Object -> Parser Friend) -> Value -> Parser Friend
forall a b. (a -> b) -> a -> b
$ \Object
o -> Username -> UserID -> UTCTime -> Maybe Text -> Friend
Friend (Username -> UserID -> UTCTime -> Maybe Text -> Friend)
-> Parser Username
-> Parser (UserID -> UTCTime -> Maybe Text -> Friend)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
o Object -> Text -> Parser Username
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"name"
        Parser (UserID -> UTCTime -> Maybe Text -> Friend)
-> Parser UserID -> Parser (UTCTime -> Maybe Text -> Friend)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
o Object -> Text -> Parser UserID
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"id"
        Parser (UTCTime -> Maybe Text -> Friend)
-> Parser UTCTime -> Parser (Maybe Text -> Friend)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Integer -> UTCTime
integerToUTC (Integer -> UTCTime) -> Parser Integer -> Parser UTCTime
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
o Object -> Text -> Parser Integer
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"date")
        Parser (Maybe Text -> Friend)
-> Parser (Maybe Text) -> Parser Friend
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Parser (Maybe Text)
-> (Text -> Parser (Maybe Text))
-> Maybe Text
-> Parser (Maybe Text)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Maybe Text -> Parser (Maybe Text)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe Text
forall a. Maybe a
Nothing) Text -> Parser (Maybe Text)
forall a. FromJSON a => Text -> Parser (Maybe a)
nothingTxtNull (Maybe Text -> Parser (Maybe Text))
-> Parser (Maybe Text) -> Parser (Maybe Text)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Object
o Object -> Text -> Parser (Maybe Text)
forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
.:? Text
"note")

-- | Wrapper for parsing JSON objects listing 'Friend's
newtype FriendList = FriendList (Seq Friend)
    deriving stock ( Int -> FriendList -> ShowS
[FriendList] -> ShowS
FriendList -> String
(Int -> FriendList -> ShowS)
-> (FriendList -> String)
-> ([FriendList] -> ShowS)
-> Show FriendList
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [FriendList] -> ShowS
$cshowList :: [FriendList] -> ShowS
show :: FriendList -> String
$cshow :: FriendList -> String
showsPrec :: Int -> FriendList -> ShowS
$cshowsPrec :: Int -> FriendList -> ShowS
Show, (forall x. FriendList -> Rep FriendList x)
-> (forall x. Rep FriendList x -> FriendList) -> Generic FriendList
forall x. Rep FriendList x -> FriendList
forall x. FriendList -> Rep FriendList x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep FriendList x -> FriendList
$cfrom :: forall x. FriendList -> Rep FriendList x
Generic )

instance FromJSON FriendList where
    parseJSON :: Value -> Parser FriendList
parseJSON = RedditKind
-> String
-> (Object -> Parser FriendList)
-> Value
-> Parser FriendList
forall b a.
FromJSON b =>
RedditKind -> String -> (b -> Parser a) -> Value -> Parser a
withKind RedditKind
UserListKind String
"FriendList"
        ((Object -> Parser FriendList) -> Value -> Parser FriendList)
-> (Object -> Parser FriendList) -> Value -> Parser FriendList
forall a b. (a -> b) -> a -> b
$ ([Friend] -> FriendList) -> Parser [Friend] -> Parser FriendList
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Seq Friend -> FriendList
FriendList (Seq Friend -> FriendList)
-> ([Friend] -> Seq Friend) -> [Friend] -> FriendList
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Friend] -> Seq Friend
forall l. IsList l => [Item l] -> l
fromList) (Parser [Friend] -> Parser FriendList)
-> (Object -> Parser [Friend]) -> Object -> Parser FriendList
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Value -> Parser [Friend]
friendsP (Value -> Parser [Friend])
-> (Object -> Parser Value) -> Object -> Parser [Friend]
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< (Object -> Text -> Parser Value
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"children"))
      where
        friendsP :: Value -> Parser [Friend]
friendsP = String -> (Array -> Parser [Friend]) -> Value -> Parser [Friend]
forall a. String -> (Array -> Parser a) -> Value -> Parser a
withArray String
"[Friend]" ((Value -> Parser Friend) -> [Value] -> Parser [Friend]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse Value -> Parser Friend
forall a. FromJSON a => Value -> Parser a
parseJSON ([Value] -> Parser [Friend])
-> (Array -> [Value]) -> Array -> Parser [Friend]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Array -> [Value]
forall l. IsList l => l -> [Item l]
toList)

-- | Information about a user\'s karma
data Karma = Karma
    { Karma -> SubredditName
subreddit    :: SubredditName
    , Karma -> Integer
commentKarma :: Integer
    , Karma -> Integer
linkKarma    :: Integer
    }
    deriving stock ( Int -> Karma -> ShowS
[Karma] -> ShowS
Karma -> String
(Int -> Karma -> ShowS)
-> (Karma -> String) -> ([Karma] -> ShowS) -> Show Karma
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Karma] -> ShowS
$cshowList :: [Karma] -> ShowS
show :: Karma -> String
$cshow :: Karma -> String
showsPrec :: Int -> Karma -> ShowS
$cshowsPrec :: Int -> Karma -> ShowS
Show, Karma -> Karma -> Bool
(Karma -> Karma -> Bool) -> (Karma -> Karma -> Bool) -> Eq Karma
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Karma -> Karma -> Bool
$c/= :: Karma -> Karma -> Bool
== :: Karma -> Karma -> Bool
$c== :: Karma -> Karma -> Bool
Eq, (forall x. Karma -> Rep Karma x)
-> (forall x. Rep Karma x -> Karma) -> Generic Karma
forall x. Rep Karma x -> Karma
forall x. Karma -> Rep Karma x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Karma x -> Karma
$cfrom :: forall x. Karma -> Rep Karma x
Generic )

instance FromJSON Karma where
    parseJSON :: Value -> Parser Karma
parseJSON = Options -> Value -> Parser Karma
forall a.
(Generic a, GFromJSON Zero (Rep a)) =>
Options -> Value -> Parser a
genericParseJSON Options
defaultOptions { ShowS
fieldLabelModifier :: ShowS
fieldLabelModifier :: ShowS
fieldLabelModifier }
      where
        fieldLabelModifier :: ShowS
fieldLabelModifier = \case
            String
"subreddit" -> String
"sr"
            String
s           -> ShowS
snakeCase String
s

-- | Wrapper for parsing JSON array of 'Karma'
newtype KarmaList = KarmaList (Seq Karma)
    deriving stock ( Int -> KarmaList -> ShowS
[KarmaList] -> ShowS
KarmaList -> String
(Int -> KarmaList -> ShowS)
-> (KarmaList -> String)
-> ([KarmaList] -> ShowS)
-> Show KarmaList
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [KarmaList] -> ShowS
$cshowList :: [KarmaList] -> ShowS
show :: KarmaList -> String
$cshow :: KarmaList -> String
showsPrec :: Int -> KarmaList -> ShowS
$cshowsPrec :: Int -> KarmaList -> ShowS
Show, (forall x. KarmaList -> Rep KarmaList x)
-> (forall x. Rep KarmaList x -> KarmaList) -> Generic KarmaList
forall x. Rep KarmaList x -> KarmaList
forall x. KarmaList -> Rep KarmaList x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep KarmaList x -> KarmaList
$cfrom :: forall x. KarmaList -> Rep KarmaList x
Generic )

instance FromJSON KarmaList where
    parseJSON :: Value -> Parser KarmaList
parseJSON = RedditKind
-> String
-> (Array -> Parser KarmaList)
-> Value
-> Parser KarmaList
forall b a.
FromJSON b =>
RedditKind -> String -> (b -> Parser a) -> Value -> Parser a
withKind @Array RedditKind
KarmaListKind String
"KarmaList"
        ((Array -> Parser KarmaList) -> Value -> Parser KarmaList)
-> (Array -> Parser KarmaList) -> Value -> Parser KarmaList
forall a b. (a -> b) -> a -> b
$ ([Karma] -> KarmaList) -> Parser [Karma] -> Parser KarmaList
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Seq Karma -> KarmaList
KarmaList (Seq Karma -> KarmaList)
-> ([Karma] -> Seq Karma) -> [Karma] -> KarmaList
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Karma] -> Seq Karma
forall l. IsList l => [Item l] -> l
fromList) (Parser [Karma] -> Parser KarmaList)
-> (Array -> Parser [Karma]) -> Array -> Parser KarmaList
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Value -> Parser Karma) -> [Value] -> Parser [Karma]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse Value -> Parser Karma
forall a. FromJSON a => Value -> Parser a
parseJSON ([Value] -> Parser [Karma])
-> (Array -> [Value]) -> Array -> Parser [Karma]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Array -> [Value]
forall l. IsList l => l -> [Item l]
toList

-- | A brief summary of a user, with significantly less information than a
-- 'Account'
data UserSummary = UserSummary
    { -- | This field will be absent unless the 'UserSummary' is obtained from a
      -- specific endpoint using 'Network.Reddit.Actions.Account.getUserSummaries'.
      -- User summaries are sent as a JSON object with the user IDs as keys, so
      -- this field doesn't exist until the larger structure is parsed
      UserSummary -> Maybe UserID
userID         :: Maybe UserID
    , UserSummary -> Username
name           :: Username
    , UserSummary -> Integer
commentKarma   :: Integer
    , UserSummary -> Integer
linkKarma      :: Integer
    , UserSummary -> UTCTime
created        :: UTCTime
    , UserSummary -> Text
profilePicture :: URL
    , UserSummary -> Maybe Text
profileColor   :: Maybe RGBText
    , UserSummary -> Bool
profileOver18  :: Bool
    }
    deriving stock ( Int -> UserSummary -> ShowS
[UserSummary] -> ShowS
UserSummary -> String
(Int -> UserSummary -> ShowS)
-> (UserSummary -> String)
-> ([UserSummary] -> ShowS)
-> Show UserSummary
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [UserSummary] -> ShowS
$cshowList :: [UserSummary] -> ShowS
show :: UserSummary -> String
$cshow :: UserSummary -> String
showsPrec :: Int -> UserSummary -> ShowS
$cshowsPrec :: Int -> UserSummary -> ShowS
Show, UserSummary -> UserSummary -> Bool
(UserSummary -> UserSummary -> Bool)
-> (UserSummary -> UserSummary -> Bool) -> Eq UserSummary
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: UserSummary -> UserSummary -> Bool
$c/= :: UserSummary -> UserSummary -> Bool
== :: UserSummary -> UserSummary -> Bool
$c== :: UserSummary -> UserSummary -> Bool
Eq, (forall x. UserSummary -> Rep UserSummary x)
-> (forall x. Rep UserSummary x -> UserSummary)
-> Generic UserSummary
forall x. Rep UserSummary x -> UserSummary
forall x. UserSummary -> Rep UserSummary x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep UserSummary x -> UserSummary
$cfrom :: forall x. UserSummary -> Rep UserSummary x
Generic )

instance FromJSON UserSummary where
    parseJSON :: Value -> Parser UserSummary
parseJSON = String
-> (Object -> Parser UserSummary) -> Value -> Parser UserSummary
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"UserSummary" ((Object -> Parser UserSummary) -> Value -> Parser UserSummary)
-> (Object -> Parser UserSummary) -> Value -> Parser UserSummary
forall a b. (a -> b) -> a -> b
$ \Object
o -> Maybe UserID
-> Username
-> Integer
-> Integer
-> UTCTime
-> Text
-> Maybe Text
-> Bool
-> UserSummary
UserSummary Maybe UserID
forall a. Maybe a
Nothing
        (Username
 -> Integer
 -> Integer
 -> UTCTime
 -> Text
 -> Maybe Text
 -> Bool
 -> UserSummary)
-> Parser Username
-> Parser
     (Integer
      -> Integer -> UTCTime -> Text -> Maybe Text -> Bool -> UserSummary)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
o Object -> Text -> Parser Username
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"name"
        Parser
  (Integer
   -> Integer -> UTCTime -> Text -> Maybe Text -> Bool -> UserSummary)
-> Parser Integer
-> Parser
     (Integer -> UTCTime -> Text -> Maybe Text -> Bool -> UserSummary)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
o Object -> Text -> Parser Integer
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"comment_karma"
        Parser
  (Integer -> UTCTime -> Text -> Maybe Text -> Bool -> UserSummary)
-> Parser Integer
-> Parser (UTCTime -> Text -> Maybe Text -> Bool -> UserSummary)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
o Object -> Text -> Parser Integer
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"link_karma"
        Parser (UTCTime -> Text -> Maybe Text -> Bool -> UserSummary)
-> Parser UTCTime
-> Parser (Text -> Maybe Text -> Bool -> UserSummary)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Integer -> UTCTime
integerToUTC (Integer -> UTCTime) -> Parser Integer -> Parser UTCTime
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
o Object -> Text -> Parser Integer
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"created_utc")
        Parser (Text -> Maybe Text -> Bool -> UserSummary)
-> Parser Text -> Parser (Maybe Text -> Bool -> UserSummary)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Object
o Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"profile_img")
        Parser (Maybe Text -> Bool -> UserSummary)
-> Parser (Maybe Text) -> Parser (Bool -> UserSummary)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Text -> Parser (Maybe Text)
forall a. FromJSON a => Text -> Parser (Maybe a)
nothingTxtNull (Text -> Parser (Maybe Text)) -> Parser Text -> Parser (Maybe Text)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Object
o Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"profile_color")
        Parser (Bool -> UserSummary) -> Parser Bool -> Parser UserSummary
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
o Object -> Text -> Parser Bool
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"profile_over_18"

-- | Wrapper for parsing a JSON object of 'UserSummary's which has user IDs as
-- keys
newtype UserSummaryList = UserSummaryList (Seq UserSummary)
    deriving stock ( Int -> UserSummaryList -> ShowS
[UserSummaryList] -> ShowS
UserSummaryList -> String
(Int -> UserSummaryList -> ShowS)
-> (UserSummaryList -> String)
-> ([UserSummaryList] -> ShowS)
-> Show UserSummaryList
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [UserSummaryList] -> ShowS
$cshowList :: [UserSummaryList] -> ShowS
show :: UserSummaryList -> String
$cshow :: UserSummaryList -> String
showsPrec :: Int -> UserSummaryList -> ShowS
$cshowsPrec :: Int -> UserSummaryList -> ShowS
Show, (forall x. UserSummaryList -> Rep UserSummaryList x)
-> (forall x. Rep UserSummaryList x -> UserSummaryList)
-> Generic UserSummaryList
forall x. Rep UserSummaryList x -> UserSummaryList
forall x. UserSummaryList -> Rep UserSummaryList x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep UserSummaryList x -> UserSummaryList
$cfrom :: forall x. UserSummaryList -> Rep UserSummaryList x
Generic )

instance FromJSON UserSummaryList where
    parseJSON :: Value -> Parser UserSummaryList
parseJSON = String
-> (Object -> Parser UserSummaryList)
-> Value
-> Parser UserSummaryList
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"UserSummaryList"
        ((Object -> Parser UserSummaryList)
 -> Value -> Parser UserSummaryList)
-> (Object -> Parser UserSummaryList)
-> Value
-> Parser UserSummaryList
forall a b. (a -> b) -> a -> b
$ ([UserSummary] -> UserSummaryList)
-> Parser [UserSummary] -> Parser UserSummaryList
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Seq UserSummary -> UserSummaryList
UserSummaryList (Seq UserSummary -> UserSummaryList)
-> ([UserSummary] -> Seq UserSummary)
-> [UserSummary]
-> UserSummaryList
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [UserSummary] -> Seq UserSummary
forall l. IsList l => [Item l] -> l
fromList) (Parser [UserSummary] -> Parser UserSummaryList)
-> (Object -> Parser [UserSummary])
-> Object
-> Parser UserSummaryList
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Object -> Parser [UserSummary]
forall b s b a.
(FromJSON b, FromJSON s, HasField "userID" s b a (Maybe b)) =>
Object -> Parser [b]
userSummariesP
      where
        userSummariesP :: Object -> Parser [b]
userSummariesP Object
o = [(Text, Value)] -> ((Text, Value) -> Parser b) -> Parser [b]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
t a -> (a -> f b) -> f (t b)
for (Object -> [(Text, Value)]
forall k v. HashMap k v -> [(k, v)]
HM.toList Object
o) (((Text, Value) -> Parser b) -> Parser [b])
-> ((Text, Value) -> Parser b) -> Parser [b]
forall a b. (a -> b) -> a -> b
$ \(Text
usid, Value
us) -> do
            b
uid <- Value -> Parser b
forall a. FromJSON a => Value -> Parser a
parseJSON (Text -> Value
String Text
usid)
            s
u <- Value -> Parser s
forall a. FromJSON a => Value -> Parser a
parseJSON Value
us
            b -> Parser b
forall (f :: * -> *) a. Applicative f => a -> f a
pure (b -> Parser b) -> b -> Parser b
forall a b. (a -> b) -> a -> b
$ s
u s -> (s -> b) -> b
forall a b. a -> (a -> b) -> b
& forall s t a b. HasField "userID" s t a b => Lens s t a b
forall (field :: Symbol) s t a b.
HasField field s t a b =>
Lens s t a b
field @"userID" ((a -> Identity (Maybe b)) -> s -> Identity b) -> b -> s -> b
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ b
uid

-- | User preferences
data Preferences = Preferences
    {  -- | Default comment sort
      Preferences -> ItemSort
defaultCommentSort :: ItemSort
      -- | Thumbnail preference
    , Preferences -> MediaPreference
media :: MediaPreference
      -- | Media preview preference
    , Preferences -> MediaPreference
mediaPreview :: MediaPreference
      -- | Minimum score for displaying comments, must be between -100 and 100
    , Preferences -> Int
minCommentScore :: Int
      -- | Minimum score for displaying submissions, must be between -100 and 100
    , Preferences -> Int
minLinkScore :: Int
      -- | Default number of comments to display, must be between 1 and 500
    , Preferences -> Int
numComments :: Int
      -- | Number of submissions to display at once, must be between 1 and 100
    , Preferences -> Int
numSites :: Int
      -- | Interface language, should be in IETF format, with components
      -- separated with underscores
    , Preferences -> Text
lang :: Text
      -- | If @True@, all users can send PMs. Otherwise, only whitelisted
      -- users can
    , Preferences -> AcceptPMs
acceptPMs :: AcceptPMs
      -- | Allows Reddit to use activity to show more relevant ads
    , Preferences -> Bool
activityRelevantAds :: Bool
      -- | Allows Reddit to log outbound clicks for personalization
    , Preferences -> Bool
allowClicktracking :: Bool
      -- | Enrolls user in beta testing Reddit features
    , Preferences -> Bool
beta :: Bool
      -- | Show recently viewed links
    , Preferences -> Bool
clickGadget :: Bool
      -- | Collapse messages after reading them
    , Preferences -> Bool
collapseReadMessages :: Bool
      -- | Compress link display
    , Preferences -> Bool
compress :: Bool
      -- | Use creddit to automatically renew gold upon expiration
    , Preferences -> Maybe Bool
credditAutorenew :: Maybe Bool
      -- | Show additional details in domain text if applicable (e.g.
      -- source subreddit, author URL, etc...)
    , Preferences -> Bool
domainDetails :: Bool
      -- | Send email notifications for chat requests
    , Preferences -> Bool
emailChatRequest :: Bool
      -- | Send email notifications for comments replies
    , Preferences -> Bool
emailCommentReply :: Bool
      -- | Send email digests
    , Preferences -> Bool
emailDigests :: Bool
      -- | Send email notifications for messages
    , Preferences -> Bool
emailMessages :: Bool
      -- | Send email notifications for submission replies
    , Preferences -> Bool
emailPostReply :: Bool
      -- | Send email notifications for PMs
    , Preferences -> Bool
emailPrivateMessage :: Bool
      -- | Unsubscribe from all emails
    , Preferences -> Bool
emailUnsubscribeAll :: Bool
      -- | Send email notifications for comment upvotes
    , Preferences -> Bool
emailUpvoteComment :: Bool
      -- | Send email notifications for submission upvotes
    , Preferences -> Bool
emailUpvotePost :: Bool
      -- | Send email notifications for new followers
    , Preferences -> Bool
emailUserNewFollower :: Bool
      -- | Send email notifications for user mentions
    , Preferences -> Bool
emailUsernameMention :: Bool
    , Preferences -> Bool
enableDefaultThemes :: Bool
      -- | Enable feed recommendations
    , Preferences -> Bool
feedRecommendationsEnabled :: Bool
    , Preferences -> Bool
hideAds :: Bool
      -- | Don't show submissions after downvoting them
    , Preferences -> Bool
hideDowns :: Bool
      -- | Disallow search engine profile indexing
    , Preferences -> Bool
hideFromRobots :: Bool
      -- | Don't show submissions after upvoting them
    , Preferences -> Bool
hideUps :: Bool
      -- | Show a dagger on comments voted controversial
    , Preferences -> Bool
highlightControversial :: Bool
      -- | Highlight new comments
    , Preferences -> Bool
highlightNewComments :: Bool
      -- | Ignore suggested sorts
    , Preferences -> Bool
ignoreSuggestedSort :: Bool
    , Preferences -> Maybe Bool
inRedesignBeta :: Maybe Bool
      -- | Label NSFTW submissions
    , Preferences -> Bool
labelNSFW :: Bool
      -- | Show the legacy search page
    , Preferences -> Bool
legacySearch :: Bool
      -- | Send browser message notifications
    , Preferences -> Bool
liveOrangereds :: Bool
      -- | Mark messages as read after opening the inbox
    , Preferences -> Bool
markMessagesRead :: Bool
      -- | Receive a notification when your username is mentioned by others
    , Preferences -> Bool
monitorMentions :: Bool
      -- | Open links in a new window
    , Preferences -> Bool
newWindow :: Bool
      -- | Enable night mode
    , Preferences -> Bool
nightMode :: Bool
      -- | Hide thumbnails and media previews for NSFW content
    , Preferences -> Bool
noProfanity :: Bool
      -- | Show the spotlight box on the home feed
    , Preferences -> Maybe Bool
organic :: Maybe Bool
      -- | Affirm age and willingness to view adult content
    , Preferences -> Bool
over18 :: Bool
      -- | Enable private RSS feeds
    , Preferences -> Bool
privateFeeds :: Bool
      -- | View user profiles on desktop using legacy mode
    , Preferences -> Bool
profileOptOut :: Bool
      -- | Make votes public
    , Preferences -> Bool
publicVotes :: Bool
      -- | Allow data to be used for \"research\" purposes
    , Preferences -> Bool
research :: Bool
      -- | Include NSFW content in search results
    , Preferences -> Bool
searchIncludeOver18 :: Bool
      -- | Send crosspost messages
    , Preferences -> Bool
sendCrosspostMessages :: Bool
      -- | Send welcome messages
    , Preferences -> Bool
sendWelcomeMessages :: Bool
      -- | Show user flair
    , Preferences -> Bool
showFlair :: Bool
      -- | Show remaining gold on userpage
    , Preferences -> Bool
showGoldExpiration :: Bool
      -- | Show link flair
    , Preferences -> Bool
showLinkFlair :: Bool
      -- | Show location-based recommendations
    , Preferences -> Bool
showLocationBasedRecommendations :: Bool
      -- | Show presence
    , Preferences -> Bool
showPresence :: Bool
    , Preferences -> Maybe Bool
showPromote :: Maybe Bool
      -- | Allow subreddits to display custom themes
    , Preferences -> Bool
showStylesheets :: Bool
      -- | Show trending subreddits
    , Preferences -> Bool
showTrending :: Bool
      -- | Show a link to your Twitter account on your profile
    , Preferences -> Bool
showTwitter :: Bool
      -- | Store visits
    , Preferences -> Bool
storeVisits :: Bool
      -- | Allow Reddit to use 3rd-party data to show more relevant ads
    , Preferences -> Bool
thirdPartyDataPersonalizedAds :: Bool
      -- | Allow ad personalization
    , Preferences -> Bool
thirdPartyPersonalizedAds :: Bool
      -- | Allow ad personalization using 3rd-party data
    , Preferences -> Bool
thirdPartySiteDataPersonalizedAds :: Bool
      -- | Allow content personalization using 3rd-party data
    , Preferences -> Bool
thirdPartySiteDataPersonalizedContent :: Bool
      -- | Show message conversations in the inbox
    , Preferences -> Bool
threadedMessages :: Bool
      -- | Enable threaded modmail display
    , Preferences -> Bool
threadedModmail :: Bool
    , Preferences -> Bool
topKarmaSubreddits :: Bool
    , Preferences -> Bool
useGlobalDefaults :: Bool
      -- | Autoplay Reddit videos on the desktop comments page
    , Preferences -> Bool
videoAutoplay :: Bool
    }
    deriving stock ( Int -> Preferences -> ShowS
[Preferences] -> ShowS
Preferences -> String
(Int -> Preferences -> ShowS)
-> (Preferences -> String)
-> ([Preferences] -> ShowS)
-> Show Preferences
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Preferences] -> ShowS
$cshowList :: [Preferences] -> ShowS
show :: Preferences -> String
$cshow :: Preferences -> String
showsPrec :: Int -> Preferences -> ShowS
$cshowsPrec :: Int -> Preferences -> ShowS
Show, Preferences -> Preferences -> Bool
(Preferences -> Preferences -> Bool)
-> (Preferences -> Preferences -> Bool) -> Eq Preferences
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Preferences -> Preferences -> Bool
$c/= :: Preferences -> Preferences -> Bool
== :: Preferences -> Preferences -> Bool
$c== :: Preferences -> Preferences -> Bool
Eq, (forall x. Preferences -> Rep Preferences x)
-> (forall x. Rep Preferences x -> Preferences)
-> Generic Preferences
forall x. Rep Preferences x -> Preferences
forall x. Preferences -> Rep Preferences x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Preferences x -> Preferences
$cfrom :: forall x. Preferences -> Rep Preferences x
Generic )

instance FromJSON Preferences where
    parseJSON :: Value -> Parser Preferences
parseJSON = Options -> Value -> Parser Preferences
forall a.
(Generic a, GFromJSON Zero (Rep a)) =>
Options -> Value -> Parser a
genericParseJSON --
        Options
defaultOptions { fieldLabelModifier :: ShowS
fieldLabelModifier = ShowS
preferencesModifier }

instance ToJSON Preferences where
    toJSON :: Preferences -> Value
toJSON = Options -> Preferences -> Value
forall a.
(Generic a, GToJSON' Value Zero (Rep a)) =>
Options -> a -> Value
genericToJSON --
        Options
defaultOptions { fieldLabelModifier :: ShowS
fieldLabelModifier = ShowS
preferencesModifier }

preferencesModifier :: Modifier
preferencesModifier :: ShowS
preferencesModifier = \case
    String
"nightMode" -> String
"nightmode"
    String
"over18" -> String
"over_18"
    String
"searchIncludeOver18" -> String
"search_include_over_18"
    String
"numSites" -> String
"numsites"
    String
"newWindow" -> String
"newwindow"
    String
"acceptPMs" -> String
"accept_pms"
    String
"clickGadget" -> String
"clickgadget"
    String
"labelNSFW" -> String
"label_nsfw"
    String
s -> ShowS
snakeCase String
s

-- | How to deal with media previews and thumbnails in your 'Preferences'
data MediaPreference
    = TurnOn
    | TurnOff
    | FollowSubreddit
    deriving stock ( Int -> MediaPreference -> ShowS
[MediaPreference] -> ShowS
MediaPreference -> String
(Int -> MediaPreference -> ShowS)
-> (MediaPreference -> String)
-> ([MediaPreference] -> ShowS)
-> Show MediaPreference
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [MediaPreference] -> ShowS
$cshowList :: [MediaPreference] -> ShowS
show :: MediaPreference -> String
$cshow :: MediaPreference -> String
showsPrec :: Int -> MediaPreference -> ShowS
$cshowsPrec :: Int -> MediaPreference -> ShowS
Show, MediaPreference -> MediaPreference -> Bool
(MediaPreference -> MediaPreference -> Bool)
-> (MediaPreference -> MediaPreference -> Bool)
-> Eq MediaPreference
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: MediaPreference -> MediaPreference -> Bool
$c/= :: MediaPreference -> MediaPreference -> Bool
== :: MediaPreference -> MediaPreference -> Bool
$c== :: MediaPreference -> MediaPreference -> Bool
Eq, (forall x. MediaPreference -> Rep MediaPreference x)
-> (forall x. Rep MediaPreference x -> MediaPreference)
-> Generic MediaPreference
forall x. Rep MediaPreference x -> MediaPreference
forall x. MediaPreference -> Rep MediaPreference x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep MediaPreference x -> MediaPreference
$cfrom :: forall x. MediaPreference -> Rep MediaPreference x
Generic )

instance FromJSON MediaPreference where
    parseJSON :: Value -> Parser MediaPreference
parseJSON = Options -> Value -> Parser MediaPreference
forall a.
(Generic a, GFromJSON Zero (Rep a)) =>
Options -> Value -> Parser a
genericParseJSON --
        Options
defaultOptions { constructorTagModifier :: ShowS
constructorTagModifier = ShowS
mediaPreferenceModifier }

instance ToJSON MediaPreference where
    toJSON :: MediaPreference -> Value
toJSON = Options -> MediaPreference -> Value
forall a.
(Generic a, GToJSON' Value Zero (Rep a)) =>
Options -> a -> Value
genericToJSON --
        Options
defaultOptions { constructorTagModifier :: ShowS
constructorTagModifier = ShowS
mediaPreferenceModifier }

mediaPreferenceModifier :: Modifier
mediaPreferenceModifier :: ShowS
mediaPreferenceModifier = \case
    String
"TurnOn"          -> String
"on"
    String
"TurnOff"         -> String
"off"
    String
"FollowSubreddit" -> String
"subreddit"
    String
s                 -> String
s

-- | Policy for accepting private messages, for use in user 'Preferences'
data AcceptPMs
    = Everyone
    | Whitelisted
    deriving stock ( Int -> AcceptPMs -> ShowS
[AcceptPMs] -> ShowS
AcceptPMs -> String
(Int -> AcceptPMs -> ShowS)
-> (AcceptPMs -> String)
-> ([AcceptPMs] -> ShowS)
-> Show AcceptPMs
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [AcceptPMs] -> ShowS
$cshowList :: [AcceptPMs] -> ShowS
show :: AcceptPMs -> String
$cshow :: AcceptPMs -> String
showsPrec :: Int -> AcceptPMs -> ShowS
$cshowsPrec :: Int -> AcceptPMs -> ShowS
Show, AcceptPMs -> AcceptPMs -> Bool
(AcceptPMs -> AcceptPMs -> Bool)
-> (AcceptPMs -> AcceptPMs -> Bool) -> Eq AcceptPMs
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AcceptPMs -> AcceptPMs -> Bool
$c/= :: AcceptPMs -> AcceptPMs -> Bool
== :: AcceptPMs -> AcceptPMs -> Bool
$c== :: AcceptPMs -> AcceptPMs -> Bool
Eq, (forall x. AcceptPMs -> Rep AcceptPMs x)
-> (forall x. Rep AcceptPMs x -> AcceptPMs) -> Generic AcceptPMs
forall x. Rep AcceptPMs x -> AcceptPMs
forall x. AcceptPMs -> Rep AcceptPMs x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep AcceptPMs x -> AcceptPMs
$cfrom :: forall x. AcceptPMs -> Rep AcceptPMs x
Generic )

instance FromJSON AcceptPMs where
    parseJSON :: Value -> Parser AcceptPMs
parseJSON = Options -> Value -> Parser AcceptPMs
forall a.
(Generic a, GFromJSON Zero (Rep a)) =>
Options -> Value -> Parser a
genericParseJSON --
        Options
defaultOptions { constructorTagModifier :: ShowS
constructorTagModifier = (Char -> Char) -> ShowS
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Char -> Char
toLower }

instance ToJSON AcceptPMs where
    toJSON :: AcceptPMs -> Value
toJSON = Options -> AcceptPMs -> Value
forall a.
(Generic a, GToJSON' Value Zero (Rep a)) =>
Options -> a -> Value
genericToJSON --
        Options
defaultOptions { constructorTagModifier :: ShowS
constructorTagModifier = (Char -> Char) -> ShowS
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Char -> Char
toLower }