Hastodon 0.4.1 → 0.5.0
raw patch · 6 files changed
+547/−50 lines, 6 filesdep +containersPVP ok
version bump matches the API change (PVP)
Dependencies added: containers
API changes (from Hackage documentation)
+ Web.Hastodon: getAccountStatusesWithOption :: HastodonClient -> GetAccountStatusesOption -> Int -> IO (Either JSONException [Status])
+ Web.Hastodon: getBlocksWithOption :: HastodonClient -> RangeOption -> IO (Either JSONException [Account])
+ Web.Hastodon: getFavoritedByWithOption :: HastodonClient -> RangeOption -> Int -> IO (Either JSONException [Account])
+ Web.Hastodon: getFavoritesWithOption :: HastodonClient -> RangeOption -> IO (Either JSONException [Status])
+ Web.Hastodon: getFollowRequestsWithOption :: HastodonClient -> RangeOption -> IO (Either JSONException [Account])
+ Web.Hastodon: getFollowersWithOption :: HastodonClient -> RangeOption -> Int -> IO (Either JSONException [Account])
+ Web.Hastodon: getFollowingWithOption :: HastodonClient -> RangeOption -> Int -> IO (Either JSONException [Account])
+ Web.Hastodon: getHomeTimelineWithOption :: HastodonClient -> TimelineOption -> IO (Either JSONException [Status])
+ Web.Hastodon: getMutesWithOption :: HastodonClient -> RangeOption -> IO (Either JSONException [Account])
+ Web.Hastodon: getNotificationsWithOption :: HastodonClient -> GetNotificationsOption -> IO (Either JSONException [Notification])
+ Web.Hastodon: getPublicTimelineWithOption :: HastodonClient -> TimelineOption -> IO (Either JSONException [Status])
+ Web.Hastodon: getRebloggedByWithOption :: HastodonClient -> RangeOption -> Int -> IO (Either JSONException [Account])
+ Web.Hastodon: getSearchedAccountsWithOption :: HastodonClient -> AccountSearchOption -> String -> IO (Either JSONException [Account])
+ Web.Hastodon: getSearchedResultsWithOption :: HastodonClient -> StatusSearchOption -> String -> IO (Either JSONException [Results])
+ Web.Hastodon: getTaggedTimelineWithOption :: HastodonClient -> TimelineOption -> String -> IO (Either JSONException [Status])
+ Web.Hastodon: postMuteWithOption :: HastodonClient -> PostMuteOption -> Int -> IO (Either JSONException Relationship)
+ Web.Hastodon: postStatusWithOption :: HastodonClient -> PostStatusOption -> String -> IO (Either JSONException Status)
+ Web.Hastodon.Option: VisibilityDirect :: Visibility
+ Web.Hastodon.Option: VisibilityPrivate :: Visibility
+ Web.Hastodon.Option: VisibilityPublic :: Visibility
+ Web.Hastodon.Option: VisibilityUnlisted :: Visibility
+ Web.Hastodon.Option: class IsOption a => IsAccountSearchOption a
+ Web.Hastodon.Option: class IsOption a => IsGetAccountStatusesOption a
+ Web.Hastodon.Option: class IsOption a => IsGetNotificationsOption a
+ Web.Hastodon.Option: class IsOption a => IsGetStatusesOption a
+ Web.Hastodon.Option: class IsOption a => IsLimitOption a
+ Web.Hastodon.Option: class IsOption a => IsPostMuteOption a
+ Web.Hastodon.Option: class IsOption a => IsPostStatusOption a
+ Web.Hastodon.Option: class IsOption a => IsRangeOption a
+ Web.Hastodon.Option: class IsOption a => IsStatusSearchOption a
+ Web.Hastodon.Option: class IsOption a => IsTimelineOption a
+ Web.Hastodon.Option: data AccountSearchOption
+ Web.Hastodon.Option: data GetAccountStatusesOption
+ Web.Hastodon.Option: data GetNotificationsOption
+ Web.Hastodon.Option: data NotificationType
+ Web.Hastodon.Option: data PostMuteOption
+ Web.Hastodon.Option: data PostStatusOption
+ Web.Hastodon.Option: data RangeOption
+ Web.Hastodon.Option: data StatusSearchOption
+ Web.Hastodon.Option: data TimelineOption
+ Web.Hastodon.Option: data Visibility
+ Web.Hastodon.Option: excludeReplies :: IsGetAccountStatusesOption a => a
+ Web.Hastodon.Option: excludeTypes :: IsGetNotificationsOption a => [NotificationType] -> a
+ Web.Hastodon.Option: following :: IsAccountSearchOption a => a
+ Web.Hastodon.Option: inReplyToId :: IsPostStatusOption a => Int -> a
+ Web.Hastodon.Option: instance Data.Semigroup.Semigroup Web.Hastodon.Option.AccountSearchOption
+ Web.Hastodon.Option: instance Data.Semigroup.Semigroup Web.Hastodon.Option.GetAccountStatusesOption
+ Web.Hastodon.Option: instance Data.Semigroup.Semigroup Web.Hastodon.Option.GetNotificationsOption
+ Web.Hastodon.Option: instance Data.Semigroup.Semigroup Web.Hastodon.Option.PostMuteOption
+ Web.Hastodon.Option: instance Data.Semigroup.Semigroup Web.Hastodon.Option.PostStatusOption
+ Web.Hastodon.Option: instance Data.Semigroup.Semigroup Web.Hastodon.Option.RangeOption
+ Web.Hastodon.Option: instance Data.Semigroup.Semigroup Web.Hastodon.Option.StatusSearchOption
+ Web.Hastodon.Option: instance Data.Semigroup.Semigroup Web.Hastodon.Option.TimelineOption
+ Web.Hastodon.Option: instance GHC.Base.Monoid Web.Hastodon.Option.AccountSearchOption
+ Web.Hastodon.Option: instance GHC.Base.Monoid Web.Hastodon.Option.GetAccountStatusesOption
+ Web.Hastodon.Option: instance GHC.Base.Monoid Web.Hastodon.Option.GetNotificationsOption
+ Web.Hastodon.Option: instance GHC.Base.Monoid Web.Hastodon.Option.PostMuteOption
+ Web.Hastodon.Option: instance GHC.Base.Monoid Web.Hastodon.Option.PostStatusOption
+ Web.Hastodon.Option: instance GHC.Base.Monoid Web.Hastodon.Option.RangeOption
+ Web.Hastodon.Option: instance GHC.Base.Monoid Web.Hastodon.Option.StatusSearchOption
+ Web.Hastodon.Option: instance GHC.Base.Monoid Web.Hastodon.Option.TimelineOption
+ Web.Hastodon.Option: instance GHC.Classes.Eq Web.Hastodon.Option.NotificationType
+ Web.Hastodon.Option: instance GHC.Classes.Eq Web.Hastodon.Option.Visibility
+ Web.Hastodon.Option: instance GHC.Classes.Ord Web.Hastodon.Option.NotificationType
+ Web.Hastodon.Option: instance GHC.Classes.Ord Web.Hastodon.Option.Visibility
+ Web.Hastodon.Option: instance GHC.Enum.Bounded Web.Hastodon.Option.NotificationType
+ Web.Hastodon.Option: instance GHC.Enum.Bounded Web.Hastodon.Option.Visibility
+ Web.Hastodon.Option: instance GHC.Enum.Enum Web.Hastodon.Option.NotificationType
+ Web.Hastodon.Option: instance GHC.Enum.Enum Web.Hastodon.Option.Visibility
+ Web.Hastodon.Option: instance GHC.Show.Show Web.Hastodon.Option.AccountSearchOption
+ Web.Hastodon.Option: instance GHC.Show.Show Web.Hastodon.Option.GetAccountStatusesOption
+ Web.Hastodon.Option: instance GHC.Show.Show Web.Hastodon.Option.GetNotificationsOption
+ Web.Hastodon.Option: instance GHC.Show.Show Web.Hastodon.Option.NotificationType
+ Web.Hastodon.Option: instance GHC.Show.Show Web.Hastodon.Option.PostMuteOption
+ Web.Hastodon.Option: instance GHC.Show.Show Web.Hastodon.Option.PostStatusOption
+ Web.Hastodon.Option: instance GHC.Show.Show Web.Hastodon.Option.RangeOption
+ Web.Hastodon.Option: instance GHC.Show.Show Web.Hastodon.Option.StatusSearchOption
+ Web.Hastodon.Option: instance GHC.Show.Show Web.Hastodon.Option.TimelineOption
+ Web.Hastodon.Option: instance GHC.Show.Show Web.Hastodon.Option.Visibility
+ Web.Hastodon.Option: instance Web.Hastodon.Option.IsAccountSearchOption Web.Hastodon.Option.AccountSearchOption
+ Web.Hastodon.Option: instance Web.Hastodon.Option.IsGetAccountStatusesOption Web.Hastodon.Option.GetAccountStatusesOption
+ Web.Hastodon.Option: instance Web.Hastodon.Option.IsGetNotificationsOption Web.Hastodon.Option.GetNotificationsOption
+ Web.Hastodon.Option: instance Web.Hastodon.Option.IsGetStatusesOption Web.Hastodon.Option.GetAccountStatusesOption
+ Web.Hastodon.Option: instance Web.Hastodon.Option.IsGetStatusesOption Web.Hastodon.Option.TimelineOption
+ Web.Hastodon.Option: instance Web.Hastodon.Option.IsLimitOption Web.Hastodon.Option.GetAccountStatusesOption
+ Web.Hastodon.Option: instance Web.Hastodon.Option.IsLimitOption Web.Hastodon.Option.GetNotificationsOption
+ Web.Hastodon.Option: instance Web.Hastodon.Option.IsLimitOption Web.Hastodon.Option.PostMuteOption
+ Web.Hastodon.Option: instance Web.Hastodon.Option.IsLimitOption Web.Hastodon.Option.RangeOption
+ Web.Hastodon.Option: instance Web.Hastodon.Option.IsLimitOption Web.Hastodon.Option.StatusSearchOption
+ Web.Hastodon.Option: instance Web.Hastodon.Option.IsLimitOption Web.Hastodon.Option.TimelineOption
+ Web.Hastodon.Option: instance Web.Hastodon.Option.IsPostMuteOption Web.Hastodon.Option.PostMuteOption
+ Web.Hastodon.Option: instance Web.Hastodon.Option.IsPostStatusOption Web.Hastodon.Option.PostStatusOption
+ Web.Hastodon.Option: instance Web.Hastodon.Option.IsRangeOption Web.Hastodon.Option.GetAccountStatusesOption
+ Web.Hastodon.Option: instance Web.Hastodon.Option.IsRangeOption Web.Hastodon.Option.GetNotificationsOption
+ Web.Hastodon.Option: instance Web.Hastodon.Option.IsRangeOption Web.Hastodon.Option.RangeOption
+ Web.Hastodon.Option: instance Web.Hastodon.Option.IsRangeOption Web.Hastodon.Option.TimelineOption
+ Web.Hastodon.Option: instance Web.Hastodon.Option.IsStatusSearchOption Web.Hastodon.Option.StatusSearchOption
+ Web.Hastodon.Option: instance Web.Hastodon.Option.IsTimelineOption Web.Hastodon.Option.TimelineOption
+ Web.Hastodon.Option: instance Web.Hastodon.Types.IsOption Web.Hastodon.Option.AccountSearchOption
+ Web.Hastodon.Option: instance Web.Hastodon.Types.IsOption Web.Hastodon.Option.GetAccountStatusesOption
+ Web.Hastodon.Option: instance Web.Hastodon.Types.IsOption Web.Hastodon.Option.GetNotificationsOption
+ Web.Hastodon.Option: instance Web.Hastodon.Types.IsOption Web.Hastodon.Option.PostMuteOption
+ Web.Hastodon.Option: instance Web.Hastodon.Types.IsOption Web.Hastodon.Option.PostStatusOption
+ Web.Hastodon.Option: instance Web.Hastodon.Types.IsOption Web.Hastodon.Option.RangeOption
+ Web.Hastodon.Option: instance Web.Hastodon.Types.IsOption Web.Hastodon.Option.StatusSearchOption
+ Web.Hastodon.Option: instance Web.Hastodon.Types.IsOption Web.Hastodon.Option.TimelineOption
+ Web.Hastodon.Option: instanceLocal :: IsTimelineOption a => a
+ Web.Hastodon.Option: limit :: IsLimitOption a => Int -> a
+ Web.Hastodon.Option: maxId :: IsRangeOption a => String -> a
+ Web.Hastodon.Option: mediaIds :: IsPostStatusOption a => [Int] -> a
+ Web.Hastodon.Option: muteNotifications :: IsPostMuteOption a => a
+ Web.Hastodon.Option: onlyMedia :: IsGetStatusesOption a => a
+ Web.Hastodon.Option: pinned :: IsGetAccountStatusesOption a => a
+ Web.Hastodon.Option: resolve :: IsStatusSearchOption a => a
+ Web.Hastodon.Option: sensitive :: IsPostStatusOption a => a
+ Web.Hastodon.Option: sinceId :: IsRangeOption a => String -> a
+ Web.Hastodon.Option: spoilerText :: IsPostStatusOption a => String -> a
+ Web.Hastodon.Option: visibility :: IsPostStatusOption a => Visibility -> a
Files
- Hastodon.cabal +6/−3
- Web/Hastodon.hs +21/−1
- Web/Hastodon/API.hs +134/−42
- Web/Hastodon/Option.hs +323/−0
- Web/Hastodon/Types.hs +15/−1
- Web/Hastodon/Util.hs +48/−3
Hastodon.cabal view
@@ -1,5 +1,5 @@ Name: Hastodon-Version: 0.4.1+Version: 0.5.0 Synopsis: mastodon client module for Haskell Category: Web Description: mastodon client module for Haskell@@ -32,9 +32,12 @@ MissingH, resourcet, text,- transformers+ transformers,+ containers - Exposed-Modules: Web.Hastodon+ Exposed-Modules: Web.Hastodon,+ Web.Hastodon.Option+ Other-Modules: Web.Hastodon.API, Web.Hastodon.Streaming, Web.Hastodon.Types,
Web/Hastodon.hs view
@@ -1,5 +1,7 @@ module Web.Hastodon- ( HastodonClient(..)+ ( module Web.Hastodon.Option++ , HastodonClient(..) , Account(..) , Application(..) , Attachment(..)@@ -21,44 +23,61 @@ , getAccountById , getCurrentAccount , getFollowers+ , getFollowersWithOption , getFollowing+ , getFollowingWithOption , getAccountStatuses+ , getAccountStatusesWithOption , postFollow , postUnfollow , postBlock , postUnblock , postMute+ , postMuteWithOption , postUnmute , getRelationships , getSearchedAccounts+ , getSearchedAccountsWithOption , postApps , getBlocks+ , getBlocksWithOption , getFavorites+ , getFavoritesWithOption , getFollowRequests+ , getFollowRequestsWithOption , postAuthorizeRequest , postRejectRequest , getInstance , postMediaFile , getMutes+ , getMutesWithOption , getNotifications+ , getNotificationsWithOption , getNotificationById , postNotificationsClear , getReports , getSearchedResults+ , getSearchedResultsWithOption , getStatus , getCard , getContext , getRebloggedBy+ , getRebloggedByWithOption , getFavoritedBy+ , getFavoritedByWithOption , postStatus+ , postStatusWithOption , postStatusWithMediaIds , postReblog , postUnreblog , postFavorite , postUnfavorite , getHomeTimeline+ , getHomeTimelineWithOption , getPublicTimeline+ , getPublicTimelineWithOption , getTaggedTimeline+ , getTaggedTimelineWithOption , streamUser , streamPublic@@ -69,6 +88,7 @@ import Web.Hastodon.API+import Web.Hastodon.Option import Web.Hastodon.Streaming import Web.Hastodon.Types import Web.Hastodon.Util
Web/Hastodon/API.hs view
@@ -3,44 +3,61 @@ , getAccountById , getCurrentAccount , getFollowers+ , getFollowersWithOption , getFollowing+ , getFollowingWithOption , getAccountStatuses+ , getAccountStatusesWithOption , postFollow , postUnfollow , postBlock , postUnblock , postMute+ , postMuteWithOption , postUnmute , getRelationships , getSearchedAccounts+ , getSearchedAccountsWithOption , postApps , getBlocks+ , getBlocksWithOption , getFavorites+ , getFavoritesWithOption , getFollowRequests+ , getFollowRequestsWithOption , postAuthorizeRequest , postRejectRequest , getInstance , postMediaFile , getMutes+ , getMutesWithOption , getNotifications+ , getNotificationsWithOption , getNotificationById , postNotificationsClear , getReports , getSearchedResults+ , getSearchedResultsWithOption , getStatus , getCard , getContext , getRebloggedBy+ , getRebloggedByWithOption , getFavoritedBy+ , getFavoritedByWithOption , postStatus+ , postStatusWithOption , postStatusWithMediaIds , postReblog , postUnreblog , postFavorite , postUnfavorite , getHomeTimeline+ , getHomeTimelineWithOption , getPublicTimeline+ , getPublicTimelineWithOption , getTaggedTimeline+ , getTaggedTimelineWithOption ) where import Control.Applicative@@ -56,6 +73,7 @@ import Web.Hastodon.Types import Web.Hastodon.Util+import Web.Hastodon.Option --@@ -127,6 +145,9 @@ res <- httpLBS req return $ getResponseBody res +getHastodonResponseJSONWithOption opt path client =+ mkHastodonRequestWithQuery opt path client >>= httpJSONEither+ getHastodonResponseJSON path client = mkHastodonRequest path client >>= httpJSONEither postAndGetHastodonResult path body client = do@@ -161,22 +182,39 @@ res <- getHastodonResponseJSON pCurrentAccounts client return (getResponseBody res :: Either JSONException Account) --- TODO support options getFollowers :: HastodonClient -> Int -> IO (Either JSONException [Account])-getFollowers client id = do- res <- getHastodonResponseJSON (replace ":id" (show id) pFollowers) client+getFollowers client = getFollowersWithOption client mempty++getFollowersWithOption :: HastodonClient -> RangeOption -> Int -> IO (Either JSONException [Account])+getFollowersWithOption client opt id = do+ res <- getHastodonResponseJSONWithOption+ (optionAsQuery opt)+ (replace ":id" (show id) pFollowers)+ client return (getResponseBody res :: Either JSONException [Account]) getFollowing :: HastodonClient -> Int -> IO (Either JSONException [Account])-getFollowing client id = do- res <- getHastodonResponseJSON (replace ":id" (show id) pFollowing) client+getFollowing client = getFollowingWithOption client mempty++getFollowingWithOption :: HastodonClient -> RangeOption -> Int -> IO (Either JSONException [Account])+getFollowingWithOption client opt id = do+ res <- getHastodonResponseJSONWithOption+ (optionAsQuery opt)+ (replace ":id" (show id) pFollowing)+ client return (getResponseBody res :: Either JSONException [Account]) -getAccountStatuses :: HastodonClient -> Int -> IO (Either JSONException [Status])-getAccountStatuses client id = do- res <- getHastodonResponseJSON (replace ":id" (show id) pAccountStatuses) client+getAccountStatusesWithOption :: HastodonClient -> GetAccountStatusesOption -> Int -> IO (Either JSONException [Status])+getAccountStatusesWithOption client opt id = do+ res <- getHastodonResponseJSONWithOption+ (optionAsQuery opt)+ (replace ":id" (show id) pAccountStatuses)+ client return (getResponseBody res :: Either JSONException [Status]) +getAccountStatuses :: HastodonClient -> Int -> IO (Either JSONException [Status])+getAccountStatuses client = getAccountStatusesWithOption client mempty+ getRelationships :: HastodonClient -> [Int] -> IO (Either JSONException [Relationship]) getRelationships client ids = do let intIds = map (show) ids@@ -184,11 +222,15 @@ res <- getHastodonResponseJSON (pRelationships ++ params) client return (getResponseBody res :: Either JSONException [Relationship]) -getSearchedAccounts :: HastodonClient -> String -> IO (Either JSONException [Account])-getSearchedAccounts client query = do- res <- getHastodonResponseJSON (pSearchAccounts ++ "?q=" ++ query) client+getSearchedAccountsWithOption ::+ HastodonClient -> AccountSearchOption -> String -> IO (Either JSONException [Account])+getSearchedAccountsWithOption client opt query = do+ res <- getHastodonResponseJSONWithOption (optionAsQuery opt) (pSearchAccounts ++ "?q=" ++ query) client return (getResponseBody res :: Either JSONException [Account]) +getSearchedAccounts :: HastodonClient -> String -> IO (Either JSONException [Account])+getSearchedAccounts client = getSearchedAccountsWithOption client mempty+ postFollow :: HastodonClient -> Int -> IO (Either JSONException Relationship) postFollow client id = do res <- postAndGetHastodonResponseJSON (replace ":id" (show id) pFollow) [] client@@ -209,11 +251,16 @@ res <- postAndGetHastodonResponseJSON (replace ":id" (show id) pUnblock) [] client return (getResponseBody res :: Either JSONException Relationship) -postMute :: HastodonClient -> Int -> IO (Either JSONException Relationship)-postMute client id = do- res <- postAndGetHastodonResponseJSON (replace ":id" (show id) pMute) [] client+postMuteWithOption ::+ HastodonClient -> PostMuteOption -> Int -> IO (Either JSONException Relationship)+postMuteWithOption client opt id = do+ let prms = optionAsForm opt+ res <- postAndGetHastodonResponseJSON (replace ":id" (show id) pMute) prms client return (getResponseBody res :: Either JSONException Relationship) +postMute :: HastodonClient -> Int -> IO (Either JSONException Relationship)+postMute client = postMuteWithOption client mempty+ postUnmute :: HastodonClient -> Int -> IO (Either JSONException Relationship) postUnmute client id = do res <- postAndGetHastodonResponseJSON (replace ":id" (show id) pUnmute) [] client@@ -229,21 +276,30 @@ res <- httpJSONEither req return (getResponseBody res :: Either JSONException OAuthClient) -getBlocks :: HastodonClient -> IO (Either JSONException [Account])-getBlocks client = do- res <- getHastodonResponseJSON pBlocks client+getBlocksWithOption :: HastodonClient -> RangeOption -> IO (Either JSONException [Account])+getBlocksWithOption client opt = do+ res <- getHastodonResponseJSONWithOption (optionAsQuery opt) pBlocks client return (getResponseBody res :: Either JSONException [Account]) -getFavorites :: HastodonClient -> IO (Either JSONException [Status])-getFavorites client = do- res <- getHastodonResponseJSON pFavorites client+getBlocks :: HastodonClient -> IO (Either JSONException [Account])+getBlocks client = getBlocksWithOption client mempty++getFavoritesWithOption :: HastodonClient -> RangeOption -> IO (Either JSONException [Status])+getFavoritesWithOption client opt = do+ res <- getHastodonResponseJSONWithOption (optionAsQuery opt) pFavorites client return (getResponseBody res :: Either JSONException [Status]) -getFollowRequests :: HastodonClient -> IO (Either JSONException [Account])-getFollowRequests client = do- res <- getHastodonResponseJSON pFollowRequests client+getFavorites :: HastodonClient -> IO (Either JSONException [Status])+getFavorites client = getFavoritesWithOption client mempty++getFollowRequestsWithOption :: HastodonClient -> RangeOption -> IO (Either JSONException [Account])+getFollowRequestsWithOption client opt = do+ res <- getHastodonResponseJSONWithOption (optionAsQuery opt) pFollowRequests client return (getResponseBody res :: Either JSONException [Account]) +getFollowRequests :: HastodonClient -> IO (Either JSONException [Account])+getFollowRequests client = getFollowRequestsWithOption client mempty+ postAuthorizeRequest :: HastodonClient -> Int -> IO Bool postAuthorizeRequest client id = postAndGetHastodonResult (replace ":id" (show id) pAuthorizeRequest) [] client @@ -266,14 +322,20 @@ res <- httpJSONEither req return (getResponseBody res :: Either JSONException Attachment) -getMutes :: HastodonClient -> IO (Either JSONException [Account])-getMutes client = do- res <- getHastodonResponseJSON pMutes client+getMutesWithOption :: HastodonClient -> RangeOption -> IO (Either JSONException [Account])+getMutesWithOption client opt = do+ res <- getHastodonResponseJSONWithOption (optionAsQuery opt) pMutes client return (getResponseBody res :: Either JSONException [Account]) +getMutes :: HastodonClient -> IO (Either JSONException [Account])+getMutes client = getMutesWithOption client mempty+ getNotifications :: HastodonClient -> IO (Either JSONException [Notification])-getNotifications client = do- res <- getHastodonResponseJSON pNotifications client+getNotifications client = getNotificationsWithOption client mempty++getNotificationsWithOption :: HastodonClient -> GetNotificationsOption -> IO (Either JSONException [Notification])+getNotificationsWithOption client opt = do+ res <- getHastodonResponseJSONWithOption (optionAsQuery opt) pNotifications client return (getResponseBody res :: Either JSONException [Notification]) getNotificationById :: HastodonClient -> Int -> IO (Either JSONException Notification)@@ -290,8 +352,12 @@ return (getResponseBody res :: Either JSONException [Report]) getSearchedResults :: HastodonClient -> String -> IO (Either JSONException [Results])-getSearchedResults client query = do- res <- getHastodonResponseJSON (pSearch ++ "?q=" ++ query) client+getSearchedResults client = getSearchedResultsWithOption client mempty++getSearchedResultsWithOption ::+ HastodonClient -> StatusSearchOption -> String -> IO (Either JSONException [Results])+getSearchedResultsWithOption client opt query = do+ res <- getHastodonResponseJSONWithOption (optionAsQuery opt) (pSearch ++ "?q=" ++ query) client return (getResponseBody res :: Either JSONException [Results]) getStatus :: HastodonClient -> Int -> IO (Either JSONException Status)@@ -309,19 +375,30 @@ res <- getHastodonResponseJSON (replace ":id" (show id) pContext) client return (getResponseBody res :: Either JSONException Context) -getRebloggedBy :: HastodonClient -> Int -> IO (Either JSONException [Account])-getRebloggedBy client id = do- res <- getHastodonResponseJSON (replace ":id" (show id) pRebloggedBy) client+getRebloggedByWithOption :: HastodonClient -> RangeOption -> Int -> IO (Either JSONException [Account])+getRebloggedByWithOption client opt id = do+ res <- getHastodonResponseJSONWithOption (optionAsQuery opt) (replace ":id" (show id) pRebloggedBy) client return (getResponseBody res :: Either JSONException [Account]) -getFavoritedBy :: HastodonClient -> Int -> IO (Either JSONException [Account])-getFavoritedBy client id = do- res <- getHastodonResponseJSON (replace ":id" (show id) pFavoritedBy) client+getRebloggedBy :: HastodonClient -> Int -> IO (Either JSONException [Account])+getRebloggedBy client = getRebloggedByWithOption client mempty++getFavoritedByWithOption :: HastodonClient -> RangeOption -> Int -> IO (Either JSONException [Account])+getFavoritedByWithOption client opt id = do+ res <- getHastodonResponseJSONWithOption (optionAsQuery opt) (replace ":id" (show id) pFavoritedBy) client return (getResponseBody res :: Either JSONException [Account]) +getFavoritedBy :: HastodonClient -> Int -> IO (Either JSONException [Account])+getFavoritedBy client = getFavoritedByWithOption client mempty+ postStatus :: HastodonClient -> String -> IO (Either JSONException Status)-postStatus client status = do- res <- postAndGetHastodonResponseJSON pStatuses [(Char8.pack "status", utf8ToChar8 status)] client+postStatus client = postStatusWithOption client mempty++postStatusWithOption ::+ HastodonClient -> PostStatusOption -> String -> IO (Either JSONException Status)+postStatusWithOption client opt status = do+ let prms = [(Char8.pack "status", utf8ToChar8 status)] ++ optionAsForm opt+ res <- postAndGetHastodonResponseJSON pStatuses prms client return (getResponseBody res :: Either JSONException Status) postStatusWithMediaIds :: HastodonClient -> String -> [HastodonId] -> IO (Either JSONException Status)@@ -352,13 +429,20 @@ return (getResponseBody res :: Either JSONException Status) getHomeTimeline :: HastodonClient -> IO (Either JSONException [Status])-getHomeTimeline client = do- res <- getHastodonResponseJSON pHomeTimeline client+getHomeTimeline client = getHomeTimelineWithOption client mempty++getHomeTimelineWithOption :: HastodonClient -> TimelineOption -> IO (Either JSONException [Status])+getHomeTimelineWithOption client opt = do+ res <- getHastodonResponseJSONWithOption (optionAsQuery opt) pHomeTimeline client return (getResponseBody res :: Either JSONException [Status]) + getPublicTimeline :: HastodonClient -> IO (Either JSONException [Status])-getPublicTimeline client = do- res <- getHastodonResponseJSON pPublicTimeline client+getPublicTimeline client = getPublicTimelineWithOption client mempty++getPublicTimelineWithOption :: HastodonClient -> TimelineOption -> IO (Either JSONException [Status])+getPublicTimelineWithOption client opt = do+ res <- getHastodonResponseJSONWithOption (optionAsQuery opt) pPublicTimeline client return (getResponseBody res :: Either JSONException [Status]) getTaggedTimeline :: HastodonClient -> String -> IO (Either JSONException [Status])@@ -366,3 +450,11 @@ res <- getHastodonResponseJSON (replace ":hashtag" hashtag pTaggedTimeline) client return (getResponseBody res :: Either JSONException [Status]) +getTaggedTimelineWithOption ::+ HastodonClient -> TimelineOption -> String -> IO (Either JSONException [Status])+getTaggedTimelineWithOption client opt hashtag = do+ res <- getHastodonResponseJSONWithOption+ (optionAsQuery opt)+ (replace ":hashtag" hashtag pTaggedTimeline)+ client+ return (getResponseBody res :: Either JSONException [Status])
+ Web/Hastodon/Option.hs view
@@ -0,0 +1,323 @@+module Web.Hastodon.Option+ (+ -- * Limit Options+ IsLimitOption+ , limit++ -- * Range Options+ , RangeOption ()+ , IsRangeOption+ , maxId+ , sinceId++ -- * Timeline Options+ , TimelineOption ()+ , IsTimelineOption+ , instanceLocal++ -- * Status search Options+ , StatusSearchOption ()+ , IsStatusSearchOption+ , resolve++ -- * Account search Options+ , AccountSearchOption ()+ , IsAccountSearchOption+ , following++ -- * Status getting options+ , IsGetStatusesOption+ , onlyMedia++ -- * Account status getting options+ , GetAccountStatusesOption ()+ , IsGetAccountStatusesOption+ , pinned+ , excludeReplies++ -- * Notification getting options+ , GetNotificationsOption ()+ , IsGetNotificationsOption+ , NotificationType+ , excludeTypes++ -- * Status posting options+ , PostStatusOption ()+ , IsPostStatusOption+ , Visibility (..)+ , inReplyToId+ , mediaIds+ , sensitive+ , spoilerText+ , visibility++ -- * Mute options+ , PostMuteOption ()+ , IsPostMuteOption+ , muteNotifications+ )+where++import Data.Semigroup+import Data.Monoid hiding ((<>))+import Control.Applicative+import qualified Data.Map as Map++import Web.Hastodon.Types+import Web.Hastodon.Util+++--+-- Limit option+--+class IsOption a => IsLimitOption a where {}++limit :: IsLimitOption a => Int -> a+limit i = mkOption "limit" $ Just (show i)+++--+-- Range options+--+newtype RangeOption = RangeOption { unRangeOption :: OptionImpl } deriving Show++instance IsOption RangeOption where+ fromOptionImpl = RangeOption+ toOptionImpl = unRangeOption++instance Semigroup RangeOption where+ (<>) = optionMappend++instance Monoid RangeOption where+ mempty = optionMempty+ mappend = (<>)++class IsOption a => IsRangeOption a where {}++instance IsLimitOption RangeOption where {}+instance IsRangeOption RangeOption where {}++sinceId :: IsRangeOption a => String -> a+sinceId i = mkOption "since_id" $ Just i++maxId :: IsRangeOption a => String -> a+maxId i = mkOption "max_id" $ Just i++--+-- Timeline options+--+newtype TimelineOption = TimelineOption { unTimelineOption :: OptionImpl } deriving Show++instance IsOption TimelineOption where+ fromOptionImpl = TimelineOption+ toOptionImpl = unTimelineOption++instance Semigroup TimelineOption where+ (<>) = optionMappend++instance Monoid TimelineOption where+ mempty = optionMempty+ mappend = (<>)++class IsOption a => IsTimelineOption a where {}++instance IsLimitOption TimelineOption where {}+instance IsRangeOption TimelineOption where {}+instance IsGetStatusesOption TimelineOption where {}+instance IsTimelineOption TimelineOption where {}++instanceLocal :: IsTimelineOption a => a+instanceLocal = mkOption "local" $ Nothing++--+-- Status getting options+--+class IsOption a => IsGetStatusesOption a where {}++onlyMedia :: IsGetStatusesOption a => a+onlyMedia = mkOption "only_media" Nothing++--+-- AccountStatus getting options+--+newtype GetAccountStatusesOption = GetAccountStatusesOption { unGetAccountStatusesOption :: OptionImpl } deriving Show++instance IsOption GetAccountStatusesOption where+ fromOptionImpl = GetAccountStatusesOption+ toOptionImpl = unGetAccountStatusesOption++instance Semigroup GetAccountStatusesOption where+ (<>) = optionMappend++instance Monoid GetAccountStatusesOption where+ mempty = optionMempty+ mappend = (<>)++class IsOption a => IsGetAccountStatusesOption a where {}++instance IsLimitOption GetAccountStatusesOption where {}+instance IsRangeOption GetAccountStatusesOption where {}+instance IsGetStatusesOption GetAccountStatusesOption where {}+instance IsGetAccountStatusesOption GetAccountStatusesOption where {}++pinned :: IsGetAccountStatusesOption a => a+pinned = mkOption "pinned" Nothing++excludeReplies :: IsGetAccountStatusesOption a => a+excludeReplies = mkOption "exclude_replies" Nothing++--+-- Notification getting options+--+newtype GetNotificationsOption = GetNotificationsOption {+ unGetNotificationsOption :: OptionImpl+ } deriving Show++instance IsOption GetNotificationsOption where+ fromOptionImpl = GetNotificationsOption+ toOptionImpl = unGetNotificationsOption++instance Semigroup GetNotificationsOption where+ (<>) = optionMappend++instance Monoid GetNotificationsOption where+ mempty = optionMempty+ mappend = (<>)++class IsOption a => IsGetNotificationsOption a where {}++instance IsLimitOption GetNotificationsOption where {}+instance IsRangeOption GetNotificationsOption where {}+instance IsGetNotificationsOption GetNotificationsOption where {}++data NotificationType =+ NotificationFollow | NotificationFavourite | NotificationReblog | NotificationMention+ deriving (Eq, Show, Ord,Enum, Bounded)++formatNt :: NotificationType -> String+formatNt NotificationFollow = "follow"+formatNt NotificationFavourite = "favourite"+formatNt NotificationReblog = "reblog"+formatNt NotificationMention = "mention"++excludeTypes :: IsGetNotificationsOption a => [NotificationType] -> a+excludeTypes ts = mkArrayOption "exclude_types" $ map formatNt ts++--+-- AccountSearch options+--+newtype AccountSearchOption = AccountSearchOption { unAccountSearchOption :: OptionImpl } deriving Show++instance IsOption AccountSearchOption where+ fromOptionImpl = AccountSearchOption+ toOptionImpl = unAccountSearchOption++instance Semigroup AccountSearchOption where+ (<>) = optionMappend++instance Monoid AccountSearchOption where+ mempty = optionMempty+ mappend = (<>)++class IsOption a => IsAccountSearchOption a where {}++instance IsAccountSearchOption AccountSearchOption where {}++following :: IsAccountSearchOption a => a+following = mkOption "following" $ Nothing++--+-- StatusSearch options+--+newtype StatusSearchOption = StatusSearchOption { unStatusSearchOption :: OptionImpl } deriving Show++instance IsOption StatusSearchOption where+ fromOptionImpl = StatusSearchOption+ toOptionImpl = unStatusSearchOption++instance Semigroup StatusSearchOption where+ (<>) = optionMappend++instance Monoid StatusSearchOption where+ mempty = optionMempty+ mappend = (<>)++class IsOption a => IsStatusSearchOption a where {}++instance IsLimitOption StatusSearchOption where {}+instance IsStatusSearchOption StatusSearchOption where {}++resolve :: IsStatusSearchOption a => a+resolve = mkOption "resolve" $ Nothing++--+-- Status posting options+--+newtype PostStatusOption = PostStatusOption { unPostStatusOption :: OptionImpl } deriving Show++instance IsOption PostStatusOption where+ fromOptionImpl = PostStatusOption+ toOptionImpl = unPostStatusOption++instance Semigroup PostStatusOption where+ (<>) = optionMappend++instance Monoid PostStatusOption where+ mempty = optionMempty+ mappend = (<>)++class IsOption a => IsPostStatusOption a where {}++instance IsPostStatusOption PostStatusOption where {}++data Visibility =+ VisibilityDirect | VisibilityPrivate | VisibilityUnlisted | VisibilityPublic+ deriving (Eq, Show, Ord, Enum, Bounded)++formatVis :: Visibility -> String+formatVis VisibilityDirect = "direct"+formatVis VisibilityPrivate = "private"+formatVis VisibilityUnlisted = "unlisted"+formatVis VisibilityPublic = "public"++inReplyToId :: IsPostStatusOption a => Int -> a+inReplyToId i = mkOption "in_reply_to_id" (Just $ show i)++mediaIds :: IsPostStatusOption a => [Int] -> a+mediaIds l = mkArrayOption "media_ids" $ show <$> l++sensitive :: IsPostStatusOption a => a+sensitive = mkOption "sensitive" Nothing++spoilerText :: IsPostStatusOption a => String -> a+spoilerText str = mkOption "spoiler_text" (Just str)++visibility :: IsPostStatusOption a => Visibility -> a+visibility vis = mkOption "visibility" (Just $ formatVis vis)++--+-- PostMute options+--+newtype PostMuteOption = PostMuteOption { unPostMuteOption :: OptionImpl } deriving Show++instance IsOption PostMuteOption where+ fromOptionImpl = PostMuteOption+ toOptionImpl = unPostMuteOption++instance Semigroup PostMuteOption where+ (<>) = optionMappend++instance Monoid PostMuteOption where+ mempty = optionMempty+ mappend = (<>)++class IsOption a => IsPostMuteOption a where {}++instance IsLimitOption PostMuteOption where {}+instance IsPostMuteOption PostMuteOption where {}++muteNotifications :: IsPostMuteOption a => a+muteNotifications = mkOption "notifications" $ Nothing+++
Web/Hastodon/Types.hs view
@@ -16,12 +16,16 @@ , Results(..) , Status(..) , Tag(..)+ , OptionVal+ , OptionImpl+ , IsOption(..) ) where import Data.Aeson import qualified Data.Text as T import qualified Data.Text.Encoding as T-+import qualified Data.ByteString.Char8 as Char8+import qualified Data.Map as Map type HastodonId = String @@ -277,3 +281,13 @@ parseJSON (Object v) = Tag <$> (v .: "name") <*> (v .: "url")++-- Left : Array parameter, Right : Single parameter+type OptionVal = Either [Char8.ByteString] (Maybe Char8.ByteString)++type OptionImpl = Map.Map Char8.ByteString OptionVal++class IsOption a where+ fromOptionImpl :: OptionImpl -> a+ toOptionImpl :: a -> OptionImpl+
Web/Hastodon/Util.hs view
@@ -1,17 +1,27 @@ module Web.Hastodon.Util ( HastodonClient(..) , mkHastodonHeader+ , mkHastodonRequestWithQuery , mkHastodonRequest+ , mkOption+ , mkArrayOption+ , optionMempty+ , optionMappend+ , optionAsQuery+ , optionAsForm , utf8ToChar8 ) where +import Data.Maybe (fromMaybe) import qualified Data.ByteString.Char8 as Char8 import qualified Data.Text as T import qualified Data.Text.Encoding as T+import qualified Data.Map as Map import Network.HTTP.Simple import Network.HTTP.Types.Header +import Web.Hastodon.Types data HastodonClient = HastodonClient { host :: String,@@ -19,11 +29,16 @@ } -mkHastodonRequest :: String -> HastodonClient -> IO Request-mkHastodonRequest path client = do+mkHastodonRequestWithQuery ::+ [(Char8.ByteString, Maybe Char8.ByteString)] -> String -> HastodonClient -> IO Request+mkHastodonRequestWithQuery opt path client = do initReq <- parseRequest $ "https://" ++ (host client) ++ path- return $ mkHastodonHeader (token client) $ initReq+ return $+ mkHastodonHeader (token client) $+ setRequestQueryString opt $ initReq +mkHastodonRequest :: String -> HastodonClient -> IO Request+mkHastodonRequest = mkHastodonRequestWithQuery [] mkHastodonHeader :: String -> Request -> Request mkHastodonHeader token =@@ -32,3 +47,33 @@ utf8ToChar8 :: String -> Char8.ByteString utf8ToChar8 = T.encodeUtf8 . T.pack+++mkOption :: IsOption a => String -> Maybe String -> a+mkOption key val = fromOptionImpl $ Map.singleton (utf8ToChar8 key) (Right $ utf8ToChar8 <$> val)+++mkArrayOption :: IsOption a => String -> [String] -> a+mkArrayOption key val = fromOptionImpl $ Map.singleton (utf8ToChar8 key) (Left $ utf8ToChar8 <$> val)+++optionMempty :: IsOption a => a+optionMempty = fromOptionImpl Map.empty+++optionMappend :: IsOption a => a -> a -> a+optionMappend x y = fromOptionImpl $ Map.union (toOptionImpl x) (toOptionImpl y)+++optionAsQuery :: IsOption a => a -> [(Char8.ByteString, Maybe Char8.ByteString)]+optionAsQuery x = do+ (k, v) <- Map.toList $ toOptionImpl x+ let k' = k `mappend` Char8.pack "[]" -- The Rails convention of list query parameter+ case v of+ Left l -> [(k, Just x) | x <- l]+ Right r -> [(k, r)]+++optionAsForm :: IsOption a => a -> [(Char8.ByteString, Char8.ByteString)]+optionAsForm opt = fmap cnv $ optionAsQuery opt+ where cnv (x, y) = (x, fromMaybe (Char8.pack "true") y)