-- | Contains user-related actions, like finding friends or retrieving a
--   user's comments or information.
module Reddit.Actions.User
  ( getUserInfo
  , aboutMe
  , getUserComments
  , getUserComments'
  , getUserPosts
  , getUserPosts'
  , isUsernameAvailable
  , getBlockedUsers
  , getFriends
  , lookupUserFlair
  , setUserFlair ) where

import Reddit.Types.Comment
import Reddit.Types.Empty
import Reddit.Types.Flair hiding (user)
import Reddit.Types.Error
import Reddit.Types.Listing
import Reddit.Types.Options
import Reddit.Types.Post
import Reddit.Types.Reddit
import Reddit.Types.Subreddit
import Reddit.Types.User
import qualified Reddit.Routes.User as Route

import Control.Monad
import Data.Default.Class
import Data.Text (Text)
import Network.API.Builder.Error
import qualified Data.Text as Text

-- | Get the information Reddit exposes on user behind the specified username
getUserInfo :: Monad m => Username -> RedditT m User
getUserInfo :: Username -> RedditT m User
getUserInfo = Route -> RedditT m User
forall a (m :: * -> *).
(FromJSON a, Monad m) =>
Route -> RedditT m a
runRoute (Route -> RedditT m User)
-> (Username -> Route) -> Username -> RedditT m User
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Username -> Route
Route.aboutUser

-- | Get the listing of comments authored by the specified user.
getUserComments :: Monad m => Username -> RedditT m CommentListing
getUserComments :: Username -> RedditT m CommentListing
getUserComments = Options CommentID -> Username -> RedditT m CommentListing
forall (m :: * -> *).
Monad m =>
Options CommentID -> Username -> RedditT m CommentListing
getUserComments' Options CommentID
forall a. Default a => a
def

-- | Get the listing of comments authored by the specified user, with Options.
getUserComments' :: Monad m => Options CommentID -> Username -> RedditT m CommentListing
getUserComments' :: Options CommentID -> Username -> RedditT m CommentListing
getUserComments' Options CommentID
opts Username
user = Route -> RedditT m CommentListing
forall a (m :: * -> *).
(FromJSON a, Monad m) =>
Route -> RedditT m a
runRoute (Route -> RedditT m CommentListing)
-> Route -> RedditT m CommentListing
forall a b. (a -> b) -> a -> b
$ Options CommentID -> Username -> Route
Route.userComments Options CommentID
opts Username
user

-- | Get the listing of posts authored by the specified user.
getUserPosts :: Monad m => Username -> RedditT m PostListing
getUserPosts :: Username -> RedditT m PostListing
getUserPosts = Options PostID -> Username -> RedditT m PostListing
forall (m :: * -> *).
Monad m =>
Options PostID -> Username -> RedditT m PostListing
getUserPosts' Options PostID
forall a. Default a => a
def

-- | Get the listing of posts authored by the specified user, with Options.
getUserPosts' :: Monad m => Options PostID -> Username -> RedditT m PostListing
getUserPosts' :: Options PostID -> Username -> RedditT m PostListing
getUserPosts' Options PostID
opts Username
user = Route -> RedditT m PostListing
forall a (m :: * -> *).
(FromJSON a, Monad m) =>
Route -> RedditT m a
runRoute (Route -> RedditT m PostListing) -> Route -> RedditT m PostListing
forall a b. (a -> b) -> a -> b
$ Options PostID -> Username -> Route
Route.userPosts Options PostID
opts Username
user

-- | Check whether the specified username is still available or has been taken.
isUsernameAvailable :: Monad m => Username -> RedditT m Bool
isUsernameAvailable :: Username -> RedditT m Bool
isUsernameAvailable = Route -> RedditT m Bool
forall a (m :: * -> *).
(FromJSON a, Monad m) =>
Route -> RedditT m a
runRoute (Route -> RedditT m Bool)
-> (Username -> Route) -> Username -> RedditT m Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Username -> Route
Route.usernameAvailable

-- | Get information of the currently-logged-in user.
aboutMe :: Monad m => RedditT m User
aboutMe :: RedditT m User
aboutMe = Route -> RedditT m User
forall a (m :: * -> *).
(FromJSON a, Monad m) =>
Route -> RedditT m a
runRoute Route
Route.aboutMe

-- | Get users blocked by the currently-logged-in user.
getBlockedUsers :: Monad m => RedditT m [Relationship]
getBlockedUsers :: RedditT m [Relationship]
getBlockedUsers = do
  UserList [Relationship]
rs <- Route -> RedditT m UserList
forall a (m :: * -> *).
(FromJSON a, Monad m) =>
Route -> RedditT m a
runRoute Route
Route.blocked
  [Relationship] -> RedditT m [Relationship]
forall (m :: * -> *) a. Monad m => a -> m a
return [Relationship]
rs

-- | Get friends of the currently-logged-in user.
getFriends :: Monad m => RedditT m [Relationship]
getFriends :: RedditT m [Relationship]
getFriends = do
  UserList [Relationship]
rs <- Route -> RedditT m UserList
forall a (m :: * -> *).
(FromJSON a, Monad m) =>
Route -> RedditT m a
runRoute Route
Route.friends
  [Relationship] -> RedditT m [Relationship]
forall (m :: * -> *) a. Monad m => a -> m a
return [Relationship]
rs

-- | Check if a user has chosen (or been assign) user flair on a particular
--   subreddit. Requires moderator privileges on the specified subreddit.
lookupUserFlair :: Monad m => SubredditName -> Username -> RedditT m Flair
lookupUserFlair :: SubredditName -> Username -> RedditT m Flair
lookupUserFlair SubredditName
r Username
u = do
  FlairListing
res <- (FList -> FlairListing)
-> RedditT m FList -> RedditT m FlairListing
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM FList -> FlairListing
flistToListing (RedditT m FList -> RedditT m FlairListing)
-> RedditT m FList -> RedditT m FlairListing
forall a b. (a -> b) -> a -> b
$ Route -> RedditT m FList
forall a (m :: * -> *).
(FromJSON a, Monad m) =>
Route -> RedditT m a
runRoute (SubredditName -> Username -> Route
Route.lookupUserFlair SubredditName
r Username
u)
  case FlairListing
res of
    Listing Maybe UserID
_ Maybe UserID
_ [Flair
f] -> Flair -> RedditT m Flair
forall (m :: * -> *) a. Monad m => a -> m a
return Flair
f
    FlairListing
_ -> APIError RedditError -> RedditT m Flair
forall (m :: * -> *) a.
Monad m =>
APIError RedditError -> RedditT m a
failWith (APIError RedditError -> RedditT m Flair)
-> APIError RedditError -> RedditT m Flair
forall a b. (a -> b) -> a -> b
$ RedditError -> APIError RedditError
forall a. a -> APIError a
APIError RedditError
InvalidResponseError

-- | Set a user's flair on the specified subreddit. Requires moderator
--   privileges on the specified subreddit.
setUserFlair :: Monad m => SubredditName -> Username -> Text -> Text -> RedditT m ()
setUserFlair :: SubredditName -> Username -> Text -> Text -> RedditT m ()
setUserFlair SubredditName
r Username
u Text
txt Text
cls =
  if Text -> Int
Text.length Text
txt Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
64
    then APIError RedditError -> RedditT m ()
forall (m :: * -> *) a.
Monad m =>
APIError RedditError -> RedditT m a
failWith (APIError RedditError -> RedditT m ())
-> APIError RedditError -> RedditT m ()
forall a b. (a -> b) -> a -> b
$ RedditError -> APIError RedditError
forall a. a -> APIError a
APIError RedditError
FlairTooLong
    else RedditT m Empty -> RedditT m ()
forall (m :: * -> *). Monad m => m Empty -> m ()
nothing (RedditT m Empty -> RedditT m ())
-> RedditT m Empty -> RedditT m ()
forall a b. (a -> b) -> a -> b
$ Route -> RedditT m Empty
forall a (m :: * -> *).
(FromJSON a, Monad m) =>
Route -> RedditT m a
runRoute (Route -> RedditT m Empty) -> Route -> RedditT m Empty
forall a b. (a -> b) -> a -> b
$ SubredditName -> Username -> Text -> Text -> Route
Route.setUserFlair SubredditName
r Username
u Text
txt Text
cls