{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TypeApplications #-}
module Network.Reddit.User
(
isUsernameAvailable
, getUser
, getUserTrophies
, getUserComments
, getUserSubmissions
, getUserUpvoted
, getUserDownvoted
, getUserHidden
, getUserOverview
, getUserGilded
, getUserSaved
, getUserMultireddits
, getNewUsers
, getPopularUsers
, searchUsers
, getUserSummaries
, getUserSummary
, module M
) where
import Control.Monad.Catch ( MonadThrow(throwM) )
import Data.Aeson ( FromJSON )
import qualified Data.Foldable as F
import Data.Generics.Wrapped ( wrappedTo )
import Data.List.Split ( chunksOf )
import Data.Sequence ( Seq((:<|)) )
import Data.Text ( Text )
import Lens.Micro
import Network.Reddit.Internal
import Network.Reddit.Types
import Network.Reddit.Types.Account
import Network.Reddit.Types.Account as M
( AcceptPMs(..)
, Account(Account)
, AccountSearchOpts(AccountSearchOpts)
, AccountSearchSort(..)
, Friend(Friend)
, Karma(Karma)
, MediaPreference(..)
, Preferences(Preferences)
, Trophy(Trophy)
, UserID(UserID)
, UserSummary(UserSummary)
, Username
, mkUsername
)
import Network.Reddit.Types.Comment
import Network.Reddit.Types.Item
import Network.Reddit.Types.Multireddit
import Network.Reddit.Types.Submission
import Network.Reddit.Types.Subreddit
import Network.Reddit.Utils
import Web.FormUrlEncoded ( ToForm(toForm) )
import Web.HttpApiData ( ToHttpApiData(..) )
isUsernameAvailable :: MonadReddit m => Username -> m Bool
isUsernameAvailable :: Username -> m Bool
isUsernameAvailable Username
uname =
APIAction Bool -> m Bool
forall a (m :: * -> *).
(MonadReddit m, FromJSON a) =>
APIAction a -> m a
runAction APIAction Any
forall a. APIAction a
defaultAPIAction
{ $sel:requestData:APIAction :: WithData
requestData = [(Text, Text)] -> WithData
mkTextFormData [ (Text
"user", Username -> Text
forall a. ToHttpApiData a => a -> Text
toQueryParam Username
uname) ]
, $sel:pathSegments:APIAction :: [Text]
pathSegments = [ Text
"api", Text
"username_available.json" ]
, $sel:needsAuth:APIAction :: Bool
needsAuth = Bool
False
}
getUser :: MonadReddit m => Username -> m Account
getUser :: Username -> m Account
getUser Username
uname =
APIAction Account -> m Account
forall a (m :: * -> *).
(MonadReddit m, FromJSON a) =>
APIAction a -> m a
runAction APIAction Any
forall a. APIAction a
defaultAPIAction
{ $sel:pathSegments:APIAction :: [Text]
pathSegments = [ Text
"user", Username -> Text
forall a. ToHttpApiData a => a -> Text
toUrlPiece Username
uname, Text
"about" ] }
getUserTrophies :: MonadReddit m => Username -> m (Seq Trophy)
getUserTrophies :: Username -> m (Seq Trophy)
getUserTrophies Username
uname = APIAction TrophyList -> m TrophyList
forall a (m :: * -> *).
(MonadReddit m, FromJSON a) =>
APIAction a -> m a
runAction @TrophyList APIAction TrophyList
forall a. APIAction a
r m TrophyList -> (TrophyList -> Seq Trophy) -> m (Seq Trophy)
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> TrophyList -> Seq Trophy
forall s t a b. Wrapped s t a b => s -> a
wrappedTo
where
r :: APIAction a
r = APIAction Any
forall a. APIAction a
defaultAPIAction
{ $sel:pathSegments:APIAction :: [Text]
pathSegments = [ Text
"user", Username -> Text
forall a. ToHttpApiData a => a -> Text
toUrlPiece Username
uname, Text
"trophies" ] }
getUserComments :: MonadReddit m
=> Username
-> Paginator CommentID Comment
-> m (Listing CommentID Comment)
= Text
-> Username
-> Paginator CommentID Comment
-> m (Listing CommentID Comment)
forall (m :: * -> *) t a.
(MonadReddit m, Thing t, Paginable a, FromJSON a, FromJSON t) =>
Text -> Username -> Paginator t a -> m (Listing t a)
userItems Text
"comments"
getUserSubmissions :: MonadReddit m
=> Username
-> Paginator SubmissionID Submission
-> m (Listing SubmissionID Submission)
getUserSubmissions :: Username
-> Paginator SubmissionID Submission
-> m (Listing SubmissionID Submission)
getUserSubmissions = Text
-> Username
-> Paginator SubmissionID Submission
-> m (Listing SubmissionID Submission)
forall (m :: * -> *) t a.
(MonadReddit m, Thing t, Paginable a, FromJSON a, FromJSON t) =>
Text -> Username -> Paginator t a -> m (Listing t a)
userItems Text
"submitted"
getUserUpvoted, getUserDownvoted, getUserGilded
:: MonadReddit m
=> Username
-> Paginator ItemID Item
-> m (Listing ItemID Item)
getUserUpvoted :: Username -> Paginator ItemID Item -> m (Listing ItemID Item)
getUserUpvoted = Text
-> Username -> Paginator ItemID Item -> m (Listing ItemID Item)
forall (m :: * -> *) t a.
(MonadReddit m, Thing t, Paginable a, FromJSON a, FromJSON t) =>
Text -> Username -> Paginator t a -> m (Listing t a)
userItems Text
"upvoted"
getUserDownvoted :: Username -> Paginator ItemID Item -> m (Listing ItemID Item)
getUserDownvoted = Text
-> Username -> Paginator ItemID Item -> m (Listing ItemID Item)
forall (m :: * -> *) t a.
(MonadReddit m, Thing t, Paginable a, FromJSON a, FromJSON t) =>
Text -> Username -> Paginator t a -> m (Listing t a)
userItems Text
"downvoted"
getUserHidden, getUserOverview, getUserSaved
:: MonadReddit m
=> Username
-> Paginator ItemID Item
-> m (Listing ItemID Item)
getUserGilded :: Username -> Paginator ItemID Item -> m (Listing ItemID Item)
getUserGilded = Text
-> Username -> Paginator ItemID Item -> m (Listing ItemID Item)
forall (m :: * -> *) t a.
(MonadReddit m, Thing t, Paginable a, FromJSON a, FromJSON t) =>
Text -> Username -> Paginator t a -> m (Listing t a)
userItems Text
"gilded"
getUserHidden :: Username -> Paginator ItemID Item -> m (Listing ItemID Item)
getUserHidden = Text
-> Username -> Paginator ItemID Item -> m (Listing ItemID Item)
forall (m :: * -> *) t a.
(MonadReddit m, Thing t, Paginable a, FromJSON a, FromJSON t) =>
Text -> Username -> Paginator t a -> m (Listing t a)
userItems Text
"hidden"
getUserOverview :: Username -> Paginator ItemID Item -> m (Listing ItemID Item)
getUserOverview = Text
-> Username -> Paginator ItemID Item -> m (Listing ItemID Item)
forall (m :: * -> *) t a.
(MonadReddit m, Thing t, Paginable a, FromJSON a, FromJSON t) =>
Text -> Username -> Paginator t a -> m (Listing t a)
userItems Text
"overview"
getUserSaved :: Username -> Paginator ItemID Item -> m (Listing ItemID Item)
getUserSaved = Text
-> Username -> Paginator ItemID Item -> m (Listing ItemID Item)
forall (m :: * -> *) t a.
(MonadReddit m, Thing t, Paginable a, FromJSON a, FromJSON t) =>
Text -> Username -> Paginator t a -> m (Listing t a)
userItems Text
"saved"
userItems :: (MonadReddit m, Thing t, Paginable a, FromJSON a, FromJSON t)
=> Text
-> Username
-> Paginator t a
-> m (Listing t a)
userItems :: Text -> Username -> Paginator t a -> m (Listing t a)
userItems Text
path Username
uname Paginator t a
paginator =
APIAction (Listing t a) -> m (Listing t a)
forall a (m :: * -> *).
(MonadReddit m, FromJSON a) =>
APIAction a -> m a
runAction APIAction Any
forall a. APIAction a
defaultAPIAction
{ $sel:pathSegments:APIAction :: [Text]
pathSegments = [ Text
"user", Username -> Text
forall a. ToHttpApiData a => a -> Text
toUrlPiece Username
uname, Text
path ]
, $sel:requestData:APIAction :: WithData
requestData = Paginator t a -> WithData
forall t a. (Thing t, Paginable a) => Paginator t a -> WithData
paginatorToFormData Paginator t a
paginator
}
getUserMultireddits :: MonadReddit m => Username -> m (Seq Multireddit)
getUserMultireddits :: Username -> m (Seq Multireddit)
getUserMultireddits Username
uname =
APIAction (Seq Multireddit) -> m (Seq Multireddit)
forall a (m :: * -> *).
(MonadReddit m, FromJSON a) =>
APIAction a -> m a
runAction APIAction Any
forall a. APIAction a
defaultAPIAction
{ $sel:pathSegments:APIAction :: [Text]
pathSegments = [ Text
"api", Text
"multi", Text
"user", Username -> Text
forall a. ToHttpApiData a => a -> Text
toUrlPiece Username
uname ] }
getNewUsers :: MonadReddit m
=> Paginator SubredditID Subreddit
-> m (Listing SubredditID Subreddit)
getNewUsers :: Paginator SubredditID Subreddit
-> m (Listing SubredditID Subreddit)
getNewUsers Paginator SubredditID Subreddit
paginator =
APIAction (Listing SubredditID Subreddit)
-> m (Listing SubredditID Subreddit)
forall a (m :: * -> *).
(MonadReddit m, FromJSON a) =>
APIAction a -> m a
runAction APIAction Any
forall a. APIAction a
defaultAPIAction
{ $sel:pathSegments:APIAction :: [Text]
pathSegments = [ Text
"users", Text
"new" ]
, $sel:requestData:APIAction :: WithData
requestData = Paginator SubredditID Subreddit -> WithData
forall t a. (Thing t, Paginable a) => Paginator t a -> WithData
paginatorToFormData Paginator SubredditID Subreddit
paginator
}
getPopularUsers :: MonadReddit m
=> Paginator SubredditID Subreddit
-> m (Listing SubredditID Subreddit)
getPopularUsers :: Paginator SubredditID Subreddit
-> m (Listing SubredditID Subreddit)
getPopularUsers Paginator SubredditID Subreddit
paginator =
APIAction (Listing SubredditID Subreddit)
-> m (Listing SubredditID Subreddit)
forall a (m :: * -> *).
(MonadReddit m, FromJSON a) =>
APIAction a -> m a
runAction APIAction Any
forall a. APIAction a
defaultAPIAction
{ $sel:pathSegments:APIAction :: [Text]
pathSegments = [ Text
"users", Text
"new" ]
, $sel:requestData:APIAction :: WithData
requestData = Paginator SubredditID Subreddit -> WithData
forall t a. (Thing t, Paginable a) => Paginator t a -> WithData
paginatorToFormData Paginator SubredditID Subreddit
paginator
}
searchUsers :: MonadReddit m
=> Text
-> Paginator UserID Account
-> m (Listing UserID Account)
searchUsers :: Text -> Paginator UserID Account -> m (Listing UserID Account)
searchUsers Text
query Paginator UserID Account
paginator =
APIAction (Listing UserID Account) -> m (Listing UserID Account)
forall a (m :: * -> *).
(MonadReddit m, FromJSON a) =>
APIAction a -> m a
runAction APIAction Any
forall a. APIAction a
defaultAPIAction
{ $sel:pathSegments:APIAction :: [Text]
pathSegments = [ Text
"users", Text
"search" ]
, $sel:requestData:APIAction :: WithData
requestData =
Form -> WithData
WithForm (Form -> WithData) -> Form -> WithData
forall a b. (a -> b) -> a -> b
$ [(Text, Text)] -> Form
mkTextForm [ (Text
"q", Text
query) ] Form -> Form -> Form
forall a. Semigroup a => a -> a -> a
<> Paginator UserID Account -> Form
forall a. ToForm a => a -> Form
toForm Paginator UserID Account
paginator
}
getUserSummaries
:: (MonadReddit m, Foldable t) => t UserID -> m (Seq UserSummary)
getUserSummaries :: t UserID -> m (Seq UserSummary)
getUserSummaries t UserID
uids = [Seq UserSummary] -> Seq UserSummary
forall a. Monoid a => [a] -> a
mconcat ([Seq UserSummary] -> Seq UserSummary)
-> m [Seq UserSummary] -> m (Seq UserSummary)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ([UserID] -> m (Seq UserSummary))
-> [[UserID]] -> m [Seq UserSummary]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse [UserID] -> m (Seq UserSummary)
forall (f :: * -> *) a.
(MonadReader Client f, MonadCatch f, MonadUnliftIO f, Thing a) =>
a -> f (Seq UserSummary)
mkAction (t UserID -> [[UserID]]
forall e. t e -> [[e]]
chunked t UserID
uids)
where
chunked :: t e -> [[e]]
chunked = Int -> [e] -> [[e]]
forall e. Int -> [e] -> [[e]]
chunksOf Int
forall n. Num n => n
apiRequestLimit ([e] -> [[e]]) -> (t e -> [e]) -> t e -> [[e]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. t e -> [e]
forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList
mkAction :: a -> f (Seq UserSummary)
mkAction a
ids = APIAction UserSummaryList -> f UserSummaryList
forall a (m :: * -> *).
(MonadReddit m, FromJSON a) =>
APIAction a -> m a
runAction @UserSummaryList APIAction UserSummaryList
forall a. APIAction a
r f UserSummaryList
-> (UserSummaryList -> Seq UserSummary) -> f (Seq UserSummary)
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> UserSummaryList -> Seq UserSummary
forall s t a b. Wrapped s t a b => s -> a
wrappedTo
where
r :: APIAction a
r = APIAction Any
forall a. APIAction a
defaultAPIAction
{ $sel:pathSegments:APIAction :: [Text]
pathSegments = [ Text
"api", Text
"user_data_by_account_ids" ]
, $sel:requestData:APIAction :: WithData
requestData = [(Text, Text)] -> WithData
mkTextFormData [ (Text
"ids", a -> Text
forall a. Thing a => a -> Text
fullname a
ids) ]
}
getUserSummary :: MonadReddit m => UserID -> m UserSummary
getUserSummary :: UserID -> m UserSummary
getUserSummary UserID
uid = [UserID] -> m (Seq UserSummary)
forall (m :: * -> *) (t :: * -> *).
(MonadReddit m, Foldable t) =>
t UserID -> m (Seq UserSummary)
getUserSummaries [ UserID
uid ] m (Seq UserSummary)
-> (Seq UserSummary -> m UserSummary) -> m UserSummary
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
UserSummary
us :<| Seq UserSummary
_ -> UserSummary -> m UserSummary
forall (f :: * -> *) a. Applicative f => a -> f a
pure UserSummary
us
Seq UserSummary
_ -> ClientException -> m UserSummary
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (ClientException -> m UserSummary)
-> ClientException -> m UserSummary
forall a b. (a -> b) -> a -> b
$ Text -> ClientException
InvalidResponse Text
"getUserSummary: No such user"