{-# LANGUAGE OverloadedStrings #-} -- | Module containing the functions directly dealing with twitter's API. Most functions in this module have two versions - one which takes a path to a TOML file containing api keys/secrets and tokens/secrets, the other takes api keys/secrets and tokens/secrets as an argument. module Web.Tweet.API where import Control.Composition import Control.Monad import qualified Data.ByteString.Lazy.Char8 as BSL import Data.Maybe (isJust) import Data.Void import Lens.Micro import Lens.Micro.Extras import Text.Megaparsec.Error import Web.Tweet.Types import Web.Tweet.Utils import Web.Tweet.Utils.API -- | Get tweets (text only) for some user getMarkov :: String -> Maybe Int -> FilePath -> IO [String] getMarkov = fmap (map (view text)) .** getAll -- | Get all tweets by some user getAll :: String -> Maybe Int -> FilePath -> IO Timeline getAll sn maxId filepath = do tweets <- either (error "Parse tweets failed") id <$> getProfileMax sn 200 filepath maxId let lastId = _tweetId <$> tweets^?_last if lastId == maxId then pure [] else do if isJust lastId then putStrLn $ "fetching tweets since " ++ show (lastId^?!_Just) ++ "..." else pure () next <- getAll sn lastId filepath pure (tweets ++ next) -- | tweet, given a `Tweet` and a `Config` containing necessary data to sign the request. tweetDataMem :: Tweet -> Config -> IO Int tweetDataMem tweet config = do let requestString = urlString tweet bytes <- postRequestMem ("https://api.twitter.com/1.1/statuses/update.json" ++ requestString) config putStrLn $ displayTimelineColor . either (error "failed to parse tweet") id . getTweets . BSL.toStrict $ bytes pure . view tweetId . head . either (error "failed to parse tweet") id . getTweets . BSL.toStrict $ bytes -- | tweet, given a `Tweet` and path to credentials. Return id of posted tweet. tweetData :: Tweet -> FilePath -> IO Int tweetData tweet filepath = do let requestString = urlString tweet bytes <- postRequest ("https://api.twitter.com/1.1/statuses/update.json" ++ requestString) filepath -- FIXME fix the coloration putStrLn $ displayTimelineColor . either (error "failed to parse tweet") id . getTweets . BSL.toStrict $ bytes pure . view tweetId . head . either (error "failed to parse tweet") id . getTweets . BSL.toStrict $ bytes -- | Gets user profile with max_id set. getProfileMax :: String -> Int -> FilePath -> Maybe Int -> IO (Either (ParseError Char Void) Timeline) getProfileMax = fmap (getTweets . BSL.toStrict) .*** getProfileRaw -- | Gets user profile with max_id set. getProfileMaxMem :: String -> Int -> Config -> Maybe Int -> IO (Either (ParseError Char Void) Timeline) getProfileMaxMem = fmap (getTweets . BSL.toStrict) .*** getProfileRawMem -- | Gets user profile with max_id set. getProfileRaw :: String -> Int -> FilePath -> Maybe Int -> IO BSL.ByteString getProfileRaw sn count filepath maxId = getRequest ("https://api.twitter.com/1.1/statuses/user_timeline.json" ++ requestString) filepath where requestString = case maxId of { (Just i) -> "?screen_name=" ++ sn ++ "&count=" ++ show count ++ "&max_id=" ++ show i ; Nothing -> "?screen_name=" ++ sn ++ "&count=" ++ show count } -- | Gets user profile with max_id set getProfileRawMem :: String -> Int -> Config -> Maybe Int -> IO BSL.ByteString getProfileRawMem sn count config maxId = getRequestMem ("https://api.twitter.com/1.1/statuses/user_timeline.json" ++ requestString) config where requestString = case maxId of { (Just i) -> "?screen_name=" ++ sn ++ "&count=" ++ show count ++ "&max_id=" ++ show i ; Nothing -> "?screen_name=" ++ sn ++ "&count=" ++ show count } -- | Get mentions and parse response as a list of tweets mentions :: Int -> FilePath -> IO (Either (ParseError Char Void) Timeline) mentions = fmap (getTweets . BSL.toStrict) .* mentionsRaw -- | Get mentions and parse response as a list of tweets mentionsMem :: Int -> Config -> IO (Either (ParseError Char Void) Timeline) mentionsMem = fmap (getTweets . BSL.toStrict) .* mentionsRawMem -- | Gets mentions mentionsRaw :: Int -> FilePath -> IO BSL.ByteString mentionsRaw count = getRequest ("https://api.twitter.com/1.1/statuses/mentions_timeline.json" ++ requestString) where requestString = "?count=" ++ show count -- | Gets mentions mentionsRawMem :: Int -> Config -> IO BSL.ByteString mentionsRawMem count = getRequestMem ("https://api.twitter.com/1.1/statuses/mentions_timeline.json" ++ requestString) where requestString = "?count=" ++ show count -- | Get user profile given screen name and how many tweets to return getProfile :: String -> Int -> FilePath -> IO (Either (ParseError Char Void) Timeline) getProfile sn count filepath = getProfileMax sn count filepath Nothing -- | Mute a user given their screen name mute :: String -> FilePath -> IO () mute = fmap void . muteUserRaw -- | Mute a user given their screen name muteMem :: String -> Config -> IO () muteMem = fmap void . muteUserRawMem -- | Unmute a user given their screen name unmute :: String -> FilePath -> IO () unmute = fmap void . unmuteUserRaw -- | Unmute a user given their screen name unmuteMem :: String -> Config -> IO () unmuteMem = fmap void . unmuteUserRawMem -- | Mute a user given their screen name muteUserRaw :: String -> FilePath -> IO BSL.ByteString muteUserRaw sn = postRequest ("https://api.twitter.com/1.1/mutes/users/create.json?screen_name=" ++ sn) -- | Mute a user given their screen name muteUserRawMem :: String -> Config -> IO BSL.ByteString muteUserRawMem sn = postRequestMem ("https://api.twitter.com/1.1/mutes/users/create.json?screen_name=" ++ sn) -- | Unmute a user given their screen name unmuteUserRaw :: String -> FilePath -> IO BSL.ByteString unmuteUserRaw sn = postRequest ("https://api.twitter.com/1.1/mutes/users/destroy.json?screen_name=" ++ sn) -- | Unmute a user given their screen name unmuteUserRawMem :: String -> Config -> IO BSL.ByteString unmuteUserRawMem sn = postRequestMem ("https://api.twitter.com/1.1/mutes/users/destroy.json?screen_name=" ++ sn) -- | Get user's DMs. getDMsRaw :: Show p => p -> FilePath -> IO BSL.ByteString getDMsRaw count = getRequest ("https://api.twitter.com/1.1/direct_messages.json" ++ requestString) where requestString = "?count=" ++ show count -- | Get a user's favorites getFavorites :: Int -> String -> FilePath -> IO (Either (ParseError Char Void) Timeline) getFavorites count = fmap (fmap (take count) . getTweets . BSL.toStrict) .* favoriteTweetListRaw -- | Get a timeline getTimeline :: Int -> FilePath -> IO (Either (ParseError Char Void) Timeline) getTimeline = fmap (getTweets . BSL.toStrict) .* getTimelineRaw -- | Get a timeline getTimelineMem :: Int -> Config -> IO (Either (ParseError Char Void) Timeline) getTimelineMem = fmap (getTweets . BSL.toStrict) .* getTimelineRawMem -- | Get a user's timeline and return response as a bytestring getTimelineRaw :: Int -> FilePath -> IO BSL.ByteString getTimelineRaw count = getRequest ("https://api.twitter.com/1.1/statuses/home_timeline.json" ++ requestString) where requestString = "?count=" ++ show count -- | Get a user's timeline and return response as a bytestring getTimelineRawMem :: Int -> Config -> IO BSL.ByteString getTimelineRawMem count = getRequestMem ("https://api.twitter.com/1.1/statuses/home_timeline.json" ++ requestString) where requestString = "?count=" ++ show count -- | Delete a tweet given its id deleteTweet :: Integer -> FilePath -> IO () deleteTweet = fmap void . deleteTweetRaw -- | Delete a tweet given its id deleteTweetMem :: Integer -> Config -> IO () deleteTweetMem = fmap void . deleteTweetRawMem -- | Get response, i.e. the tweet deleted deleteTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Void) Timeline) deleteTweetResponse = fmap (getTweets . BSL.toStrict) .* deleteTweetRaw -- | Get response, i.e. the tweet deleted deleteTweetResponseMem :: Integer -> Config -> IO (Either (ParseError Char Void) Timeline) deleteTweetResponseMem = fmap (getTweets . BSL.toStrict) .* deleteTweetRawMem -- | Favorite a tweet given its id favoriteTweet :: Integer -> FilePath -> IO () favoriteTweet = fmap void . favoriteTweetRaw -- | Favorite a tweet given its id favoriteTweetMem :: Integer -> Config -> IO () favoriteTweetMem = fmap void . favoriteTweetRawMem -- | Favorite a tweet and returned the (parsed) response favoriteTweetList :: String -> FilePath -> IO (Either (ParseError Char Void) Timeline) favoriteTweetList = fmap (getTweets . BSL.toStrict) .* favoriteTweetListRaw -- | Favorite a tweet and returned the (parsed) response favoriteTweetListMem :: String -> Config -> IO (Either (ParseError Char Void) Timeline) favoriteTweetListMem = fmap (getTweets . BSL.toStrict) .* favoriteTweetListRawMem -- | Favorite a tweet and returned the (parsed) response favoriteTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Void) Timeline) favoriteTweetResponse = fmap (getTweets . BSL.toStrict) .* favoriteTweetRaw -- | Unfavorite a tweet given its id unfavoriteTweet :: Integer -> FilePath -> IO () unfavoriteTweet = fmap void . unfavoriteTweetRaw -- | Unfavorite a tweet given its id unfavoriteTweetMem :: Integer -> Config -> IO () unfavoriteTweetMem = fmap void . unfavoriteTweetRawMem -- | Unfavorite a tweet and returned the (parsed) response unfavoriteTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Void) Timeline) unfavoriteTweetResponse = fmap (getTweets . BSL.toStrict) .* unfavoriteTweetRaw -- | Unfavorite a tweet and returned the (parsed) response unfavoriteTweetResponseMem :: Integer -> Config -> IO (Either (ParseError Char Void) Timeline) unfavoriteTweetResponseMem = fmap (getTweets . BSL.toStrict) .* unfavoriteTweetRawMem -- | Unretweet a tweet given its id unretweetTweet :: Integer -> FilePath -> IO () unretweetTweet = fmap void . unretweetTweetRaw -- | Unretweet a tweet given its id unretweetTweetMem :: Integer -> Config -> IO () unretweetTweetMem = fmap void . unretweetTweetRawMem -- | Unretweet a tweet and returned the (parsed) response unretweetTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Void) Timeline) unretweetTweetResponse = fmap (getTweets . BSL.toStrict) .* unretweetTweetRaw -- | Unretweet a tweet and returned the (parsed) response unretweetTweetResponseMem :: Integer -> Config -> IO (Either (ParseError Char Void) Timeline) unretweetTweetResponseMem = fmap (getTweets . BSL.toStrict) .* unretweetTweetRawMem -- | Unfollow a user given their screen name unfollow :: String -> FilePath -> IO () unfollow = fmap void . unfollowUserRaw -- | Unfollow a user given their screen name unfollowMem :: String -> Config -> IO () unfollowMem = fmap void . unfollowUserRawMem -- | Follow a user given their screen name follow :: String -> FilePath -> IO () follow = fmap void . followUserRaw -- | Follow a user given their screen name followMem :: String -> Config -> IO () followMem = fmap void . followUserRawMem -- | Block a user given their screen name block :: String -> FilePath -> IO () block = fmap void . blockUserRaw -- | Block a user given their screen name blockMem :: String -> Config -> IO () blockMem = fmap void . blockUserRawMem -- | Unblock a user given their screen name unblock :: String -> FilePath -> IO () unblock = fmap void . unblockUserRaw -- | Unblock a user given their screen name unblockMem :: String -> Config -> IO () unblockMem = fmap void . unblockUserRawMem -- | Retweet a tweet given its id retweetTweet :: Integer -> FilePath -> IO () retweetTweet = fmap void . retweetTweetRaw -- | Retweet a tweet given its id retweetTweetMem :: Integer -> Config -> IO () retweetTweetMem = fmap void . retweetTweetRawMem -- | Retweet a tweet and returned the (parsed) response retweetTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Void) Timeline) retweetTweetResponse = fmap (getTweets . BSL.toStrict) .* retweetTweetRaw -- | Retweet a tweet and returned the (parsed) response retweetTweetResponseMem :: Integer -> Config -> IO (Either (ParseError Char Void) Timeline) retweetTweetResponseMem = fmap (getTweets . BSL.toStrict) .* retweetTweetRawMem -- | Get a lisr of favorited tweets by screen name; return bytestring response favoriteTweetListRaw :: String -> FilePath -> IO BSL.ByteString favoriteTweetListRaw sn = getRequest ("https://api.twitter.com/1.1/favorites/list.json?screen_name=" ++ sn) -- | Get a lisr of favorited tweets by screen name; return bytestring response favoriteTweetListRawMem :: String -> Config -> IO BSL.ByteString favoriteTweetListRawMem sn = getRequestMem ("https://api.twitter.com/1.1/favorites/list.json?screen_name=" ++ sn) -- | Favorite a tweet given its id; return bytestring response favoriteTweetRaw :: Integer -> FilePath -> IO BSL.ByteString favoriteTweetRaw idNum = postRequest ("https://api.twitter.com/1.1/favorites/create.json?id=" ++ show idNum) -- | Favorite a tweet given its idNum; return bytestring response favoriteTweetRawMem :: Integer -> Config -> IO BSL.ByteString favoriteTweetRawMem idNum = postRequestMem ("https://api.twitter.com/1.1/favorites/create.json?id=" ++ show idNum) -- | Retweet a tweet given its idNum; return bytestring response retweetTweetRaw :: Integer -> FilePath -> IO BSL.ByteString retweetTweetRaw idNum = postRequest ("https://api.twitter.com/1.1/statuses/retweet/" ++ show idNum ++ ".json") -- | Retweet a tweet given its idNum; return bytestring response retweetTweetRawMem :: Integer -> Config -> IO BSL.ByteString retweetTweetRawMem idNum = postRequestMem ("https://api.twitter.com/1.1/statuses/retweet/" ++ show idNum ++ ".json") -- | Send a DM given text, screen name of recipient. sendDMRaw :: String -> String -> FilePath -> IO BSL.ByteString sendDMRaw txt sn = postRequest ("https://api.twitter.com/1.1/direct_messages/new.json?text=" ++ encoded ++ "&screen_name" ++ sn ++ ".json") where encoded = strEncode txt -- | Get DMs, return bytestring of response getDMs :: Int -> FilePath -> IO BSL.ByteString getDMs count = getRequest ("https://dev.twitter.com/rest/reference/get/direct_messages.json?count=" ++ show count) -- | Get DMs, return bytestring of response getDMMem :: Int -> Config -> IO BSL.ByteString getDMMem count = getRequestMem ("https://dev.twitter.com/rest/reference/get/direct_messages.json?count=" ++ show count) -- | Follow a user given their screen name followUserRaw :: String -> FilePath -> IO BSL.ByteString followUserRaw sn = postRequest ("https://api.twitter.com/1.1/friendships/create.json?screen_name=" ++ sn) -- | Follow a user given their screen name followUserRawMem :: String -> Config -> IO BSL.ByteString followUserRawMem sn = postRequestMem ("https://api.twitter.com/1.1/friendships/create.json?screen_name=" ++ sn) -- | Block a user given their screen name blockUserRaw :: String -> FilePath -> IO BSL.ByteString blockUserRaw sn = postRequest ("https://api.twitter.com/1.1/blocks/create.json?screen_name=" ++ sn) -- | Block a user given their screen name blockUserRawMem :: String -> Config -> IO BSL.ByteString blockUserRawMem sn = postRequestMem ("https://api.twitter.com/1.1/blocks/create.json?screen_name=" ++ sn) -- | Unblock a user given their screen name unblockUserRaw :: String -> FilePath -> IO BSL.ByteString unblockUserRaw sn = postRequest ("https://api.twitter.com/1.1/blocks/destroy.json?screen_name=" ++ sn) -- | Unblock a user given their screen name unblockUserRawMem :: String -> Config -> IO BSL.ByteString unblockUserRawMem sn = postRequestMem ("https://api.twitter.com/1.1/blocks/destroy.json?screen_name=" ++ sn) -- | Follow a user given their screen name unfollowUserRaw :: String -> FilePath -> IO BSL.ByteString unfollowUserRaw sn = postRequest ("https://api.twitter.com/1.1/friendships/destroy.json?screen_name=" ++ sn) -- | Follow a user given their screen name unfollowUserRawMem :: String -> Config -> IO BSL.ByteString unfollowUserRawMem sn = postRequestMem ("https://api.twitter.com/1.1/friendships/destroy.json?screen_name=" ++ sn) -- | Unretweet a tweet given its id; return bytestring response unretweetTweetRaw :: Integer -> FilePath -> IO BSL.ByteString unretweetTweetRaw idNum = postRequest ("https://api.twitter.com/1.1/statuses/unretweet/" ++ show idNum ++ ".json") -- | Unretweet a tweet given its idNum; return bytestring response unretweetTweetRawMem :: Integer -> Config -> IO BSL.ByteString unretweetTweetRawMem idNum = postRequestMem ("https://api.twitter.com/1.1/statuses/unretweet/" ++ show idNum ++ ".json") -- | Unfavorite a tweet given its idNum; return bytestring response unfavoriteTweetRaw :: Integer -> FilePath -> IO BSL.ByteString unfavoriteTweetRaw idNum = postRequest ("https://api.twitter.com/1.1/favorites/destroy.json?id=" ++ show idNum) -- | Unfavorite a tweet given its idNum; return bytestring response unfavoriteTweetRawMem :: Integer -> Config -> IO BSL.ByteString unfavoriteTweetRawMem idNum = postRequestMem ("https://api.twitter.com/1.1/favorites/destroy.json?id=" ++ show idNum) -- | Delete a tweet given its idNum; return bytestring response deleteTweetRaw :: Integer -> FilePath -> IO BSL.ByteString deleteTweetRaw idNum = postRequest ("https://api.twitter.com/1.1/statuses/destroy/" ++ show idNum ++ ".json") -- | Delete a tweet given its idNum; return bytestring response deleteTweetRawMem :: Integer -> Config -> IO BSL.ByteString deleteTweetRawMem idNum = postRequestMem ("https://api.twitter.com/1.1/statuses/destroy/" ++ show idNum ++ ".json")