heddit 0.0.3 → 0.1
raw patch · 29 files changed
+1068/−225 lines, 29 filesdep ~timePVP ok
version bump matches the API change (PVP)
Dependency ranges changed: time
API changes (from Hackage documentation)
- Network.Reddit: InvalidJSON :: JSONError -> APIException
- Network.Reddit: JSONError :: [Text] -> Text -> Text -> Text -> JSONError
- Network.Reddit: data JSONError
- Network.Reddit.Types.Account: Trophy :: Name -> Maybe Text -> Maybe Text -> Maybe Body -> Maybe UTCTime -> Trophy
- Network.Reddit.Types.Account: [$sel:awardID:Trophy] :: Trophy -> Maybe Text
- Network.Reddit.Types.Account: [$sel:description:Trophy] :: Trophy -> Maybe Body
- Network.Reddit.Types.Account: [$sel:grantedAt:Trophy] :: Trophy -> Maybe UTCTime
- Network.Reddit.Types.Account: [$sel:name:Trophy] :: Trophy -> Name
- Network.Reddit.Types.Account: [$sel:trophyID:Trophy] :: Trophy -> Maybe Text
- Network.Reddit.Types.Account: data Trophy
- Network.Reddit.Types.Account: data TrophyList
- Network.Reddit.Types.Account: instance Data.Aeson.Types.FromJSON.FromJSON Network.Reddit.Types.Account.Trophy
- Network.Reddit.Types.Account: instance Data.Aeson.Types.FromJSON.FromJSON Network.Reddit.Types.Account.TrophyList
- Network.Reddit.Types.Account: instance GHC.Classes.Eq Network.Reddit.Types.Account.Trophy
- Network.Reddit.Types.Account: instance GHC.Generics.Generic Network.Reddit.Types.Account.Trophy
- Network.Reddit.Types.Account: instance GHC.Generics.Generic Network.Reddit.Types.Account.TrophyList
- Network.Reddit.Types.Account: instance GHC.Show.Show Network.Reddit.Types.Account.Trophy
- Network.Reddit.Types.Account: instance GHC.Show.Show Network.Reddit.Types.Account.TrophyList
- Network.Reddit.Types.Internal: InvalidJSON :: JSONError -> APIException
- Network.Reddit.Types.Internal: JSONError :: [Text] -> Text -> Text -> Text -> JSONError
- Network.Reddit.Types.Internal: [$sel:explanation:JSONError] :: JSONError -> Text
- Network.Reddit.Types.Internal: [$sel:fields:JSONError] :: JSONError -> [Text]
- Network.Reddit.Types.Internal: [$sel:message:JSONError] :: JSONError -> Text
- Network.Reddit.Types.Internal: [$sel:reason:JSONError] :: JSONError -> Text
- Network.Reddit.Types.Internal: data JSONError
- Network.Reddit.Types.Internal: instance Data.Aeson.Types.FromJSON.FromJSON Network.Reddit.Types.Internal.JSONError
- Network.Reddit.Types.Internal: instance GHC.Classes.Eq (Network.Reddit.Types.Internal.ItemOpts a)
- Network.Reddit.Types.Internal: instance GHC.Classes.Eq Network.Reddit.Types.Internal.JSONError
- Network.Reddit.Types.Internal: instance GHC.Generics.Generic (Network.Reddit.Types.Internal.ItemOpts a)
- Network.Reddit.Types.Internal: instance GHC.Generics.Generic Network.Reddit.Types.Internal.JSONError
- Network.Reddit.Types.Internal: instance GHC.Show.Show (Network.Reddit.Types.Internal.ItemOpts a)
- Network.Reddit.Types.Internal: instance GHC.Show.Show Network.Reddit.Types.Internal.JSONError
- Network.Reddit.Types.Internal: instance Web.Internal.FormUrlEncoded.ToForm (Network.Reddit.Types.Internal.ItemOpts a)
- Network.Reddit.Types.Moderation: instance Data.Aeson.Types.FromJSON.FromJSON Network.Reddit.Types.Moderation.SubredditType
- Network.Reddit.Types.Moderation: instance GHC.Classes.Eq Network.Reddit.Types.Moderation.SubredditType
- Network.Reddit.Types.Moderation: instance GHC.Generics.Generic Network.Reddit.Types.Moderation.SubredditType
- Network.Reddit.Types.Moderation: instance GHC.Show.Show Network.Reddit.Types.Moderation.SubredditType
- Network.Reddit.Types.Moderation: instance Web.Internal.HttpApiData.ToHttpApiData Network.Reddit.Types.Moderation.SubredditType
- Network.Reddit.User: Trophy :: Name -> Maybe Text -> Maybe Text -> Maybe Body -> Maybe UTCTime -> Trophy
+ Network.Reddit: InsufficientCoins :: ErrorMessage
+ Network.Reddit: InvalidPOST :: POSTError -> APIException
+ Network.Reddit: POSTError :: [Text] -> Text -> Text -> Text -> POSTError
+ Network.Reddit: data POSTError
+ Network.Reddit.Comment: awardComment :: MonadReddit m => Award -> CommentID -> m AwardingsSummary
+ Network.Reddit.Comment: getCommentByURL :: MonadReddit m => URL -> m Comment
+ Network.Reddit.Comment: gildComment :: MonadReddit m => CommentID -> m AwardingsSummary
+ Network.Reddit.Item: Award :: AwardID -> Bool -> Maybe Body -> Award
+ Network.Reddit.Item: AwardID :: Text -> AwardID
+ Network.Reddit.Item: AwardingsSummary :: Seq Awarding -> HashMap AwardID Integer -> Integer -> AwardingsSummary
+ Network.Reddit.Item: award :: MonadReddit m => Award -> ItemID -> m AwardingsSummary
+ Network.Reddit.Item: data Award
+ Network.Reddit.Item: data AwardingsSummary
+ Network.Reddit.Item: gild :: MonadReddit m => ItemID -> m AwardingsSummary
+ Network.Reddit.Item: mkAward :: AwardID -> Award
+ Network.Reddit.Item: newtype AwardID
+ Network.Reddit.Item: pattern Argentium :: AwardID
+ Network.Reddit.Item: pattern Gold :: AwardID
+ Network.Reddit.Item: pattern Platinum :: AwardID
+ Network.Reddit.Item: pattern Silver :: AwardID
+ Network.Reddit.Item: pattern Ternion :: AwardID
+ Network.Reddit.Me: getMySubreddit :: MonadReddit m => m Subreddit
+ Network.Reddit.Me: getMySubredditSettings :: MonadReddit m => m SubredditSettings
+ Network.Reddit.Submission: awardSubmission :: MonadReddit m => Award -> SubmissionID -> m AwardingsSummary
+ Network.Reddit.Submission: gildSubmission :: MonadReddit m => SubmissionID -> m AwardingsSummary
+ Network.Reddit.Types.Account: [$sel:awardeeKarma:Account] :: Account -> Maybe Integer
+ Network.Reddit.Types.Account: [$sel:awarderKarma:Account] :: Account -> Maybe Integer
+ Network.Reddit.Types.Account: [$sel:creddits:Account] :: Account -> Maybe Integer
+ Network.Reddit.Types.Account: [$sel:goldExpiration:Account] :: Account -> Maybe UTCTime
+ Network.Reddit.Types.Account: [$sel:hasGoldSubscription:Account] :: Account -> Maybe Bool
+ Network.Reddit.Types.Account: [$sel:iconImg:Account] :: Account -> URL
+ Network.Reddit.Types.Account: [$sel:isFriend:Account] :: Account -> Bool
+ Network.Reddit.Types.Account: [$sel:isSuspended:Account] :: Account -> Maybe Bool
+ Network.Reddit.Types.Account: [$sel:numFriends:Account] :: Account -> Maybe Integer
+ Network.Reddit.Types.Account: [$sel:subreddit:Account] :: Account -> Subreddit
+ Network.Reddit.Types.Account: [$sel:suspensionExpiration:Account] :: Account -> Maybe UTCTime
+ Network.Reddit.Types.Account: [$sel:totalKarma:Account] :: Account -> Integer
+ Network.Reddit.Types.Account: usernameToDisplayName :: Username -> Text
+ Network.Reddit.Types.Award: Award :: AwardID -> Bool -> Maybe Body -> Award
+ Network.Reddit.Types.Award: AwardID :: Text -> AwardID
+ Network.Reddit.Types.Award: AwardingsSummary :: Seq Awarding -> HashMap AwardID Integer -> Integer -> AwardingsSummary
+ Network.Reddit.Types.Award: Community :: AwardType
+ Network.Reddit.Types.Award: Global :: AwardType
+ Network.Reddit.Types.Award: [$sel:allAwardings:AwardingsSummary] :: AwardingsSummary -> Seq Awarding
+ Network.Reddit.Types.Award: [$sel:awardID:Award] :: Award -> AwardID
+ Network.Reddit.Types.Award: [$sel:coins:AwardingsSummary] :: AwardingsSummary -> Integer
+ Network.Reddit.Types.Award: [$sel:gildings:AwardingsSummary] :: AwardingsSummary -> HashMap AwardID Integer
+ Network.Reddit.Types.Award: [$sel:isAnonymous:Award] :: Award -> Bool
+ Network.Reddit.Types.Award: [$sel:message:Award] :: Award -> Maybe Body
+ Network.Reddit.Types.Award: data Award
+ Network.Reddit.Types.Award: data AwardType
+ Network.Reddit.Types.Award: data Awarding
+ Network.Reddit.Types.Award: data AwardingsSummary
+ Network.Reddit.Types.Award: data Trophy
+ Network.Reddit.Types.Award: data TrophyList
+ Network.Reddit.Types.Award: instance Data.Aeson.Types.FromJSON.FromJSON Network.Reddit.Types.Award.AwardID
+ Network.Reddit.Types.Award: instance Data.Aeson.Types.FromJSON.FromJSON Network.Reddit.Types.Award.AwardType
+ Network.Reddit.Types.Award: instance Data.Aeson.Types.FromJSON.FromJSON Network.Reddit.Types.Award.Awarding
+ Network.Reddit.Types.Award: instance Data.Aeson.Types.FromJSON.FromJSON Network.Reddit.Types.Award.AwardingsSummary
+ Network.Reddit.Types.Award: instance Data.Aeson.Types.FromJSON.FromJSON Network.Reddit.Types.Award.Trophy
+ Network.Reddit.Types.Award: instance Data.Aeson.Types.FromJSON.FromJSON Network.Reddit.Types.Award.TrophyList
+ Network.Reddit.Types.Award: instance Data.Aeson.Types.FromJSON.FromJSONKey Network.Reddit.Types.Award.AwardID
+ Network.Reddit.Types.Award: instance Data.Hashable.Class.Hashable Network.Reddit.Types.Award.AwardID
+ Network.Reddit.Types.Award: instance GHC.Classes.Eq Network.Reddit.Types.Award.Award
+ Network.Reddit.Types.Award: instance GHC.Classes.Eq Network.Reddit.Types.Award.AwardID
+ Network.Reddit.Types.Award: instance GHC.Classes.Eq Network.Reddit.Types.Award.AwardType
+ Network.Reddit.Types.Award: instance GHC.Classes.Eq Network.Reddit.Types.Award.Awarding
+ Network.Reddit.Types.Award: instance GHC.Classes.Eq Network.Reddit.Types.Award.AwardingsSummary
+ Network.Reddit.Types.Award: instance GHC.Classes.Eq Network.Reddit.Types.Award.Trophy
+ Network.Reddit.Types.Award: instance GHC.Generics.Generic Network.Reddit.Types.Award.Award
+ Network.Reddit.Types.Award: instance GHC.Generics.Generic Network.Reddit.Types.Award.AwardID
+ Network.Reddit.Types.Award: instance GHC.Generics.Generic Network.Reddit.Types.Award.AwardType
+ Network.Reddit.Types.Award: instance GHC.Generics.Generic Network.Reddit.Types.Award.Awarding
+ Network.Reddit.Types.Award: instance GHC.Generics.Generic Network.Reddit.Types.Award.AwardingsSummary
+ Network.Reddit.Types.Award: instance GHC.Generics.Generic Network.Reddit.Types.Award.Trophy
+ Network.Reddit.Types.Award: instance GHC.Generics.Generic Network.Reddit.Types.Award.TrophyList
+ Network.Reddit.Types.Award: instance GHC.Show.Show Network.Reddit.Types.Award.Award
+ Network.Reddit.Types.Award: instance GHC.Show.Show Network.Reddit.Types.Award.AwardID
+ Network.Reddit.Types.Award: instance GHC.Show.Show Network.Reddit.Types.Award.AwardType
+ Network.Reddit.Types.Award: instance GHC.Show.Show Network.Reddit.Types.Award.Awarding
+ Network.Reddit.Types.Award: instance GHC.Show.Show Network.Reddit.Types.Award.AwardingsSummary
+ Network.Reddit.Types.Award: instance GHC.Show.Show Network.Reddit.Types.Award.Trophy
+ Network.Reddit.Types.Award: instance GHC.Show.Show Network.Reddit.Types.Award.TrophyList
+ Network.Reddit.Types.Award: instance Web.Internal.FormUrlEncoded.ToForm Network.Reddit.Types.Award.Award
+ Network.Reddit.Types.Award: instance Web.Internal.HttpApiData.ToHttpApiData Network.Reddit.Types.Award.AwardID
+ Network.Reddit.Types.Award: mkAward :: AwardID -> Award
+ Network.Reddit.Types.Award: newtype AwardID
+ Network.Reddit.Types.Award: pattern Argentium :: AwardID
+ Network.Reddit.Types.Award: pattern Gold :: AwardID
+ Network.Reddit.Types.Award: pattern Platinum :: AwardID
+ Network.Reddit.Types.Award: pattern Silver :: AwardID
+ Network.Reddit.Types.Award: pattern Ternion :: AwardID
+ Network.Reddit.Types.Award: type TrophyID = Text
+ Network.Reddit.Types.Comment: [$sel:allAwardings:Comment] :: Comment -> Seq Awarding
+ Network.Reddit.Types.Internal: Archived :: SubredditType
+ Network.Reddit.Types.Internal: EmployeesOnly :: SubredditType
+ Network.Reddit.Types.Internal: GoldOnly :: SubredditType
+ Network.Reddit.Types.Internal: GoldRestricted :: SubredditType
+ Network.Reddit.Types.Internal: InsufficientCoins :: ErrorMessage
+ Network.Reddit.Types.Internal: InvalidPOST :: POSTError -> APIException
+ Network.Reddit.Types.Internal: POSTError :: [Text] -> Text -> Text -> Text -> POSTError
+ Network.Reddit.Types.Internal: Private :: SubredditType
+ Network.Reddit.Types.Internal: Public :: SubredditType
+ Network.Reddit.Types.Internal: Restricted :: SubredditType
+ Network.Reddit.Types.Internal: UserSubreddit :: SubredditType
+ Network.Reddit.Types.Internal: [$sel:explanation:POSTError] :: POSTError -> Text
+ Network.Reddit.Types.Internal: [$sel:fields:POSTError] :: POSTError -> [Text]
+ Network.Reddit.Types.Internal: [$sel:message:POSTError] :: POSTError -> Text
+ Network.Reddit.Types.Internal: [$sel:reason:POSTError] :: POSTError -> Text
+ Network.Reddit.Types.Internal: breakOnTypeLenient :: Coercible a Text => Text -> Text -> Parser a
+ Network.Reddit.Types.Internal: data POSTError
+ Network.Reddit.Types.Internal: data SubredditType
+ Network.Reddit.Types.Internal: fromOptional :: (FromJSON (Item b), IsList b, Monoid b) => Object -> Text -> Parser b
+ Network.Reddit.Types.Internal: instance Data.Aeson.Types.FromJSON.FromJSON Network.Reddit.Types.Internal.POSTError
+ Network.Reddit.Types.Internal: instance Data.Aeson.Types.FromJSON.FromJSON Network.Reddit.Types.Internal.SubredditType
+ Network.Reddit.Types.Internal: instance GHC.Classes.Eq Network.Reddit.Types.Internal.ItemOpts
+ Network.Reddit.Types.Internal: instance GHC.Classes.Eq Network.Reddit.Types.Internal.POSTError
+ Network.Reddit.Types.Internal: instance GHC.Classes.Eq Network.Reddit.Types.Internal.SubredditType
+ Network.Reddit.Types.Internal: instance GHC.Generics.Generic Network.Reddit.Types.Internal.ItemOpts
+ Network.Reddit.Types.Internal: instance GHC.Generics.Generic Network.Reddit.Types.Internal.POSTError
+ Network.Reddit.Types.Internal: instance GHC.Generics.Generic Network.Reddit.Types.Internal.SubredditType
+ Network.Reddit.Types.Internal: instance GHC.Show.Show Network.Reddit.Types.Internal.ItemOpts
+ Network.Reddit.Types.Internal: instance GHC.Show.Show Network.Reddit.Types.Internal.POSTError
+ Network.Reddit.Types.Internal: instance GHC.Show.Show Network.Reddit.Types.Internal.SubredditType
+ Network.Reddit.Types.Internal: instance Web.Internal.FormUrlEncoded.ToForm Network.Reddit.Types.Internal.ItemOpts
+ Network.Reddit.Types.Internal: instance Web.Internal.HttpApiData.ToHttpApiData Network.Reddit.Types.Internal.SubredditType
+ Network.Reddit.Types.Submission: [$sel:allAwardings:Submission] :: Submission -> Seq Awarding
+ Network.Reddit.Types.Subreddit: [$sel:allowImages:Subreddit] :: Subreddit -> Bool
+ Network.Reddit.Types.Subreddit: [$sel:allowPolls:Subreddit] :: Subreddit -> Bool
+ Network.Reddit.Types.Subreddit: [$sel:allowVideoGIFs:Subreddit] :: Subreddit -> Bool
+ Network.Reddit.Types.Subreddit: [$sel:allowVideos:Subreddit] :: Subreddit -> Bool
+ Network.Reddit.Types.Subreddit: [$sel:bannerImg:Subreddit] :: Subreddit -> Maybe URL
+ Network.Reddit.Types.Subreddit: [$sel:bannerSize:Subreddit] :: Subreddit -> Maybe (Int, Int)
+ Network.Reddit.Types.Subreddit: [$sel:freeFormReports:Subreddit] :: Subreddit -> Bool
+ Network.Reddit.Types.Subreddit: [$sel:headerImg:Subreddit] :: Subreddit -> Maybe URL
+ Network.Reddit.Types.Subreddit: [$sel:headerSize:Subreddit] :: Subreddit -> Maybe (Int, Int)
+ Network.Reddit.Types.Subreddit: [$sel:iconImg:Subreddit] :: Subreddit -> Maybe URL
+ Network.Reddit.Types.Subreddit: [$sel:keyColor:Subreddit] :: Subreddit -> Maybe RGBText
+ Network.Reddit.Types.Subreddit: [$sel:linkFlairEnabled:Subreddit] :: Subreddit -> Bool
+ Network.Reddit.Types.Subreddit: [$sel:restrictCommenting:Subreddit] :: Subreddit -> Bool
+ Network.Reddit.Types.Subreddit: [$sel:restrictPosting:Subreddit] :: Subreddit -> Bool
+ Network.Reddit.Types.Subreddit: [$sel:spoilersEnabled:Subreddit] :: Subreddit -> Maybe Bool
+ Network.Reddit.Types.Subreddit: [$sel:submitText:Subreddit] :: Subreddit -> Maybe Text
+ Network.Reddit.Types.Subreddit: [$sel:submitTextHTML:Subreddit] :: Subreddit -> Maybe Text
+ Network.Reddit.Types.Subreddit: [$sel:submitTextLabel:Subreddit] :: Subreddit -> Maybe Text
+ Network.Reddit.Types.Subreddit: [$sel:subredditType:Subreddit] :: Subreddit -> SubredditType
+ Network.Reddit.Types.Subreddit: [$sel:userIsContributor:Subreddit] :: Subreddit -> Bool
+ Network.Reddit.Types.Subreddit: [$sel:userIsMuted:Subreddit] :: Subreddit -> Bool
+ Network.Reddit.User: gildUser :: MonadReddit m => Maybe Word -> Username -> m ()
- Network.Reddit: ItemOpts :: Maybe ItemSort -> Maybe ItemType -> Maybe Time -> Maybe Word -> ItemOpts a
+ Network.Reddit: ItemOpts :: Maybe ItemSort -> Maybe ItemType -> Maybe Time -> Maybe Word -> ItemOpts
- Network.Reddit: data ItemOpts a
+ Network.Reddit: data ItemOpts
- Network.Reddit: defaultItemOpts :: ItemOpts a
+ Network.Reddit: defaultItemOpts :: ItemOpts
- Network.Reddit.Comment: Comment :: CommentID -> Username -> Body -> Body -> Seq ChildComment -> Maybe Integer -> Maybe Integer -> Maybe Integer -> UTCTime -> Maybe UTCTime -> SubredditName -> SubredditID -> Int -> Maybe Bool -> SubmissionID -> Maybe URL -> Maybe Username -> URL -> Seq ItemReport -> Seq ItemReport -> Maybe Integer -> Maybe Distinction -> Bool -> Bool -> Comment
+ Network.Reddit.Comment: Comment :: CommentID -> Username -> Body -> Body -> Seq ChildComment -> Maybe Integer -> Maybe Integer -> Maybe Integer -> UTCTime -> Maybe UTCTime -> SubredditName -> SubredditID -> Int -> Maybe Bool -> SubmissionID -> Maybe URL -> Maybe Username -> URL -> Seq ItemReport -> Seq ItemReport -> Maybe Integer -> Maybe Distinction -> Bool -> Bool -> Seq Awarding -> Comment
- Network.Reddit.Comment: getComments :: (MonadReddit m, Foldable t) => ItemOpts Comment -> t CommentID -> m (Seq Comment)
+ Network.Reddit.Comment: getComments :: (MonadReddit m, Foldable t) => ItemOpts -> t CommentID -> m (Seq Comment)
- Network.Reddit.Comment: loadMoreComments :: forall m. MonadReddit m => Maybe Word -> ItemOpts Comment -> SubmissionID -> MoreComments -> m (Seq ChildComment)
+ Network.Reddit.Comment: loadMoreComments :: forall m. MonadReddit m => Maybe Word -> ItemOpts -> SubmissionID -> MoreComments -> m (Seq ChildComment)
- Network.Reddit.Comment: withReplies :: MonadReddit m => ItemOpts a -> Comment -> m Comment
+ Network.Reddit.Comment: withReplies :: MonadReddit m => ItemOpts -> Comment -> m Comment
- Network.Reddit.Live: LiveContributor :: UserID -> Username -> Seq LivePermission -> LiveContributor
+ Network.Reddit.Live: LiveContributor :: UserID -> Username -> [LivePermission] -> LiveContributor
- Network.Reddit.Moderation: ModAccount :: Username -> UserID -> RelID -> Maybe FlairText -> Maybe CSSClass -> UTCTime -> Maybe (Seq ModPermission) -> ModAccount
+ Network.Reddit.Moderation: ModAccount :: Username -> UserID -> RelID -> Maybe FlairText -> Maybe CSSClass -> UTCTime -> Maybe [ModPermission] -> ModAccount
- Network.Reddit.Submission: Submission :: SubmissionID -> Title -> Username -> SubmissionContent -> SubredditName -> UTCTime -> Maybe UTCTime -> URL -> Domain -> Integer -> Integer -> Maybe Integer -> Maybe Integer -> Maybe Rational -> Integer -> Seq ItemReport -> Seq ItemReport -> Maybe Integer -> Maybe Distinction -> Bool -> Bool -> Bool -> Bool -> Bool -> Maybe PollData -> Submission
+ Network.Reddit.Submission: Submission :: SubmissionID -> Title -> Username -> SubmissionContent -> SubredditName -> UTCTime -> Maybe UTCTime -> URL -> Domain -> Integer -> Integer -> Maybe Integer -> Maybe Integer -> Maybe Rational -> Integer -> Seq ItemReport -> Seq ItemReport -> Maybe Integer -> Maybe Distinction -> Bool -> Bool -> Bool -> Bool -> Bool -> Maybe PollData -> Seq Awarding -> Submission
- Network.Reddit.Submission: getSubmissions :: (MonadReddit m, Foldable t) => ItemOpts Submission -> t SubmissionID -> m (Seq Submission)
+ Network.Reddit.Submission: getSubmissions :: (MonadReddit m, Foldable t) => ItemOpts -> t SubmissionID -> m (Seq Submission)
- Network.Reddit.Subreddit: Subreddit :: SubredditID -> SubredditName -> Title -> UTCTime -> Body -> Maybe Body -> Body -> Integer -> Bool -> Maybe Bool -> Maybe Bool -> Maybe Bool -> Maybe Bool -> Maybe Bool -> Bool -> Subreddit
+ Network.Reddit.Subreddit: Subreddit :: SubredditID -> SubredditName -> Title -> UTCTime -> SubredditType -> Integer -> Body -> Maybe RGBText -> Body -> Maybe Body -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe URL -> Maybe URL -> Maybe (Int, Int) -> Maybe URL -> Maybe (Int, Int) -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Maybe Bool -> Maybe Bool -> Maybe Bool -> Subreddit
- Network.Reddit.Types.Account: Account :: UserID -> Username -> UTCTime -> Int -> Bool -> Bool -> Int -> Maybe Integer -> Maybe Text -> Maybe Bool -> Maybe Bool -> Maybe Bool -> Maybe Bool -> Account
+ Network.Reddit.Types.Account: Account :: UserID -> Username -> UTCTime -> Integer -> Integer -> Integer -> Maybe Integer -> Maybe Integer -> Bool -> Bool -> Bool -> URL -> 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
- Network.Reddit.Types.Account: [$sel:commentKarma:Account] :: Account -> Int
+ Network.Reddit.Types.Account: [$sel:commentKarma:Account] :: Account -> Integer
- Network.Reddit.Types.Account: [$sel:linkKarma:Account] :: Account -> Int
+ Network.Reddit.Types.Account: [$sel:linkKarma:Account] :: Account -> Integer
- Network.Reddit.Types.Comment: Comment :: CommentID -> Username -> Body -> Body -> Seq ChildComment -> Maybe Integer -> Maybe Integer -> Maybe Integer -> UTCTime -> Maybe UTCTime -> SubredditName -> SubredditID -> Int -> Maybe Bool -> SubmissionID -> Maybe URL -> Maybe Username -> URL -> Seq ItemReport -> Seq ItemReport -> Maybe Integer -> Maybe Distinction -> Bool -> Bool -> Comment
+ Network.Reddit.Types.Comment: Comment :: CommentID -> Username -> Body -> Body -> Seq ChildComment -> Maybe Integer -> Maybe Integer -> Maybe Integer -> UTCTime -> Maybe UTCTime -> SubredditName -> SubredditID -> Int -> Maybe Bool -> SubmissionID -> Maybe URL -> Maybe Username -> URL -> Seq ItemReport -> Seq ItemReport -> Maybe Integer -> Maybe Distinction -> Bool -> Bool -> Seq Awarding -> Comment
- Network.Reddit.Types.Internal: ItemOpts :: Maybe ItemSort -> Maybe ItemType -> Maybe Time -> Maybe Word -> ItemOpts a
+ Network.Reddit.Types.Internal: ItemOpts :: Maybe ItemSort -> Maybe ItemType -> Maybe Time -> Maybe Word -> ItemOpts
- Network.Reddit.Types.Internal: [$sel:context:ItemOpts] :: ItemOpts a -> Maybe Word
+ Network.Reddit.Types.Internal: [$sel:context:ItemOpts] :: ItemOpts -> Maybe Word
- Network.Reddit.Types.Internal: [$sel:itemSort:ItemOpts] :: ItemOpts a -> Maybe ItemSort
+ Network.Reddit.Types.Internal: [$sel:itemSort:ItemOpts] :: ItemOpts -> Maybe ItemSort
- Network.Reddit.Types.Internal: [$sel:itemTime:ItemOpts] :: ItemOpts a -> Maybe Time
+ Network.Reddit.Types.Internal: [$sel:itemTime:ItemOpts] :: ItemOpts -> Maybe Time
- Network.Reddit.Types.Internal: [$sel:itemType:ItemOpts] :: ItemOpts a -> Maybe ItemType
+ Network.Reddit.Types.Internal: [$sel:itemType:ItemOpts] :: ItemOpts -> Maybe ItemType
- Network.Reddit.Types.Internal: data ItemOpts a
+ Network.Reddit.Types.Internal: data ItemOpts
- Network.Reddit.Types.Internal: defaultItemOpts :: ItemOpts a
+ Network.Reddit.Types.Internal: defaultItemOpts :: ItemOpts
- Network.Reddit.Types.Live: LiveContributor :: UserID -> Username -> Seq LivePermission -> LiveContributor
+ Network.Reddit.Types.Live: LiveContributor :: UserID -> Username -> [LivePermission] -> LiveContributor
- Network.Reddit.Types.Live: [$sel:permissions:LiveContributor] :: LiveContributor -> Seq LivePermission
+ Network.Reddit.Types.Live: [$sel:permissions:LiveContributor] :: LiveContributor -> [LivePermission]
- Network.Reddit.Types.Moderation: ModAccount :: Username -> UserID -> RelID -> Maybe FlairText -> Maybe CSSClass -> UTCTime -> Maybe (Seq ModPermission) -> ModAccount
+ Network.Reddit.Types.Moderation: ModAccount :: Username -> UserID -> RelID -> Maybe FlairText -> Maybe CSSClass -> UTCTime -> Maybe [ModPermission] -> ModAccount
- Network.Reddit.Types.Moderation: [$sel:permissions:ModAccount] :: ModAccount -> Maybe (Seq ModPermission)
+ Network.Reddit.Types.Moderation: [$sel:permissions:ModAccount] :: ModAccount -> Maybe [ModPermission]
- Network.Reddit.Types.Submission: Submission :: SubmissionID -> Title -> Username -> SubmissionContent -> SubredditName -> UTCTime -> Maybe UTCTime -> URL -> Domain -> Integer -> Integer -> Maybe Integer -> Maybe Integer -> Maybe Rational -> Integer -> Seq ItemReport -> Seq ItemReport -> Maybe Integer -> Maybe Distinction -> Bool -> Bool -> Bool -> Bool -> Bool -> Maybe PollData -> Submission
+ Network.Reddit.Types.Submission: Submission :: SubmissionID -> Title -> Username -> SubmissionContent -> SubredditName -> UTCTime -> Maybe UTCTime -> URL -> Domain -> Integer -> Integer -> Maybe Integer -> Maybe Integer -> Maybe Rational -> Integer -> Seq ItemReport -> Seq ItemReport -> Maybe Integer -> Maybe Distinction -> Bool -> Bool -> Bool -> Bool -> Bool -> Maybe PollData -> Seq Awarding -> Submission
- Network.Reddit.Types.Subreddit: Subreddit :: SubredditID -> SubredditName -> Title -> UTCTime -> Body -> Maybe Body -> Body -> Integer -> Bool -> Maybe Bool -> Maybe Bool -> Maybe Bool -> Maybe Bool -> Maybe Bool -> Bool -> Subreddit
+ Network.Reddit.Types.Subreddit: Subreddit :: SubredditID -> SubredditName -> Title -> UTCTime -> SubredditType -> Integer -> Body -> Maybe RGBText -> Body -> Maybe Body -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe URL -> Maybe URL -> Maybe (Int, Int) -> Maybe URL -> Maybe (Int, Int) -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Maybe Bool -> Maybe Bool -> Maybe Bool -> Subreddit
- Network.Reddit.Types.Subreddit: [$sel:userIsBanned:Subreddit] :: Subreddit -> Maybe Bool
+ Network.Reddit.Types.Subreddit: [$sel:userIsBanned:Subreddit] :: Subreddit -> Bool
- Network.Reddit.Types.Subreddit: [$sel:userIsModerator:Subreddit] :: Subreddit -> Maybe Bool
+ Network.Reddit.Types.Subreddit: [$sel:userIsModerator:Subreddit] :: Subreddit -> Bool
- Network.Reddit.Types.Subreddit: [$sel:userIsSubscriber:Subreddit] :: Subreddit -> Maybe Bool
+ Network.Reddit.Types.Subreddit: [$sel:userIsSubscriber:Subreddit] :: Subreddit -> Bool
- Network.Reddit.User: Account :: UserID -> Username -> UTCTime -> Int -> Bool -> Bool -> Int -> Maybe Integer -> Maybe Text -> Maybe Bool -> Maybe Bool -> Maybe Bool -> Maybe Bool -> Account
+ Network.Reddit.User: Account :: UserID -> Username -> UTCTime -> Integer -> Integer -> Integer -> Maybe Integer -> Maybe Integer -> Bool -> Bool -> Bool -> URL -> 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
Files
- CHANGELOG.org +13/−1
- README.org +1/−0
- doc/awards.org +106/−0
- heddit.cabal +4/−3
- io-tests/SubredditSpec.hs +1/−1
- src/Network/Reddit.hs +1/−1
- src/Network/Reddit/Comment.hs +25/−5
- src/Network/Reddit/Internal.hs +9/−1
- src/Network/Reddit/Item.hs +31/−0
- src/Network/Reddit/Me.hs +18/−5
- src/Network/Reddit/Moderation.hs +0/−1
- src/Network/Reddit/Multireddit.hs +0/−1
- src/Network/Reddit/Submission.hs +16/−2
- src/Network/Reddit/Types/Account.hs +64/−62
- src/Network/Reddit/Types/Award.hs +222/−0
- src/Network/Reddit/Types/Comment.hs +8/−4
- src/Network/Reddit/Types/Internal.hs +64/−13
- src/Network/Reddit/Types/Item.hs +1/−1
- src/Network/Reddit/Types/Live.hs +2/−2
- src/Network/Reddit/Types/Moderation.hs +1/−24
- src/Network/Reddit/Types/Submission.hs +4/−1
- src/Network/Reddit/Types/Subreddit.hs +96/−27
- src/Network/Reddit/Types/Widget.hs +1/−7
- src/Network/Reddit/User.hs +25/−2
- src/Network/Reddit/Utils.hs +50/−28
- tests/Main.hs +10/−0
- tests/data/types/awarding.json +170/−0
- tests/data/types/awardings-summary.json +39/−0
- tests/data/types/subreddit.json +86/−33
CHANGELOG.org view
@@ -1,10 +1,22 @@ #+TITLE: CHANGELOG +* 0.1++ Add actions for awarding/gilding items and gilding users++ New module ~Network.Reddit.Types.Award~ exports ~Award~, ~AwardID~, ~Awarding~, and ~AwardingsSummary~ types; ~Trophy~ moved to this module as well++ Add ~allAwardings~ field to ~Submission~ and ~Comment~++ Document [[file:./doc/awards.org][a big list of different awards]]++ Add ~InsufficientCoins~ to ~ErrorMessage~++ Add ~getCommentByURL~++ Rename ~JSONError~ to ~POSTError~++ Remove redundant phantom type parameter from ~ItemOpts~++ Added several more fields to ~Account~ and ~Subreddit~++ ~Subredddit~ now supports the special user subreddit; the actions ~getMySubreddit~ and ~getMySubredditSettings~ were added for convenience+ * 0.0.3 + Fixes to cabal release * 0.0.2-+ Add more documentation and examples programs++ Add more documentation and example programs + Export ~Paginable~ class from ~Reddit.hs~ + ~firstPage~ now gets the API limit of items (100)
README.org view
@@ -99,6 +99,7 @@ - It is currently alpha quality. It needs more tests and users to work out some of the bugs that are assuredly lurking deep within. The exposed API is a little weird and may be difficult to work with. - The Reddit API seems overwhemlingly geared towards dynamic representations of data. This can cause obvious issues when decoding its JSON responses in Haskell. If an exception is thrown when trying to hit an endpoint, please let me know by opening an issue or PR! - ~heddit~ only supports authenticating via OAuth (see [[file:./doc/auth.org][Authenticating]]) and cannot access Reddit's old JSON API. This means that it is not possible to create a truly anonymous client. Instead, you must register all applications, even those without a user context.+- At the moment, it doesn't build on GHC < 8.8.3, so if you are working with an older GHC version, ~heddit~ will not be suitable. * Examples Here are some executable examples using different features from ~heddit~ that hopefully illustrate how to use the library and accomplish different tasks. At the moment, the available example programs are:
+ doc/awards.org view
@@ -0,0 +1,106 @@+#+TITLE: Global Reddit Awards+#+STARTUP: shrink+#+STARTUP: align++Here is a list of global Reddit awards, adapted from the [[https://github.com/praw-dev/praw/blob/c818949c848f4520df08b16c098f80a41e897ab5/docs/code_overview/models/awards.txt][praw docs]]+++| Name | ID | Cost | Icon |+|----------------------------+--------------------------------------+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|+| Silver | gid_1 | 100 | https://www.redditstatic.com/gold/awards/icon/silver_64.png |+| Gold | gid_2 | 500 | https://www.redditstatic.com/gold/awards/icon/gold_64.png |+| Platinum | gid_3 | 1800 | https://www.redditstatic.com/gold/awards/icon/platinum_64.png |+| LOVE | 5eac457f-ebac-449b-93a7-eb17b557f03c | 20 | https://preview.redd.it/award_images/t5_22cerq/j3azv69qjfn51_LOVE.png?width=64&height=64&crop=smart&auto=webp&s=405d338bf34818596ab84bc26a09316917def8bb |+| Starstruck | abb865cf-620b-4219-8777-3658cf9091fb | 20 | https://www.redditstatic.com/gold/awards/icon/Starstruck_64.png |+| All-Seeing Upvote | b4ff447e-05a5-42dc-9002-63568807cfe6 | 30 | https://preview.redd.it/award_images/t5_22cerq/rg960rc47jj41_All-SeeingUpvote.png?width=64&height=64&crop=smart&auto=webp&s=46a9f176646afded7050299a1fbad5c66e6ed1e6 |+| Narwhal Salute | a2506925-fc82-4d6c-ae3b-b7217e09d7f0 | 30 | https://preview.redd.it/award_images/t5_22cerq/80j20o397jj41_NarwhalSalute.png?width=64&height=64&crop=smart&auto=webp&s=8629e84ef3188ad75ebca713afb4a0f97e4c3c70 |+| Wholesome Seal of Approval | c4b2e438-16bb-4568-88e7-7893b7662944 | 30 | https://preview.redd.it/award_images/t5_22cerq/b9ks3a5k7jj41_WholesomeSealofApproval.png?width=64&height=64&crop=smart&auto=webp&s=2bcedd41a51b17ff305fc0ec6eb7c5a631a90c60 |+| Ally | 69c94eb4-d6a3-48e7-9cf2-0f39fed8b87c | 50 | https://preview.redd.it/award_images/t5_22cerq/5nswjpyy44551_Ally.png?width=64&height=64&crop=smart&auto=webp&s=655fb8310589a3964a82ac0e56d016eb97aa6d4d |+| I am disappoint | 03c4f93d-efc7-463b-98a7-c01814462ab0 | 50 | https://preview.redd.it/award_images/t5_22cerq/3ekkailk5s551_Iamdisappoint.png?width=64&height=64&crop=smart&auto=webp&s=3aa59d2aa096aba2d6cba9709f79b788676e3731 |+| Looking Busy | d33fddd7-a58a-4472-b1a2-3157d8c8b76f | 50 | https://i.redd.it/award_images/t5_22cerq/k0qzautvyyk51_LookingBusy.png |+| Take My Energy | 02d9ab2c-162e-4c01-8438-317a016ed3d9 | 50 | https://preview.redd.it/award_images/t5_22cerq/898sygoknoo41_TakeMyEnergy.png?width=64&height=64&crop=smart&auto=webp&s=e62f7cf1108ff17381b1ed42b1edca26f721dce0 |+| Wearing is Caring | 80d4d339-95d0-43ac-b051-bc3fe0a9bab8 | 50 | https://preview.redd.it/award_images/t5_22cerq/lcswc5d07hb51_WearingisCaring.png?width=64&height=64&crop=smart&auto=webp&s=50da94b41c2b6c8bbe2723243ed0985059bba9fa |+| Facepalm | b1b44fa1-8179-4d84-a9ed-f25bb81f1c5f | 70 | https://preview.redd.it/award_images/t5_22cerq/ey2iodron2s41_Facepalm.png?width=64&height=64&crop=smart&auto=webp&s=9d3c8e8642dc97c655867ea5ba37b7d76d653203 |+| Faith In Humanity Restored | 7becef23-fb0b-4d62-b8a6-01d5759367cb | 70 | https://preview.redd.it/award_images/t5_22cerq/gva4vt20qc751_FaithInHumanityRestored.png?width=64&height=64&crop=smart&auto=webp&s=a76d915a6eb1cd6d5efa2e0280d90740d2f74de9 |+| Snek | 99d95969-6100-45b2-b00c-0ec45ae19596 | 70 | https://preview.redd.it/award_images/t5_22cerq/rc5iesz2z8t41_Snek.png?width=64&height=64&crop=smart&auto=webp&s=2856d19d59c0af0d38fd0b6058622f6a1e91956a |+| Tree Hug | b92370bb-b7de-4fb3-9608-c5b4a22f714a | 70 | https://preview.redd.it/award_images/t5_22cerq/fukjtec638u41_TreeHug.png?width=64&height=64&crop=smart&auto=webp&s=b46d14cae99b5519775167d0aea8418c480c28c0 |+| Bravo Grande! | 9663243a-e77f-44cf-abc6-850ead2cd18d | 75 | https://www.redditstatic.com/gold/awards/icon/SnooClappingPremium_64.png |+| Party Train | 75f9bc56-eba3-4988-a1af-aec974404a0b | 75 | https://www.redditstatic.com/gold/awards/icon/Train/Train_silver_64.png |+| Take My Power | 92cb6518-a71a-4217-9f8f-7ecbd7ab12ba | 75 | https://www.redditstatic.com/gold/awards/icon/TakeMyPower_64.png |+| Hugz | 8352bdff-3e03-4189-8a08-82501dd8f835 | 80 | https://preview.redd.it/award_images/t5_22cerq/niiatoknifn51_Hugz.png?width=64&height=64&crop=smart&auto=webp&s=840debef89811f54b3f1b498bddf55c118eb62cb |+| 'MURICA | 869d4135-8738-41e5-8630-de593b4f049f | 100 | https://preview.redd.it/award_images/t5_22cerq/18mwqw5th9e51_MURICA.png?width=64&height=64&crop=smart&auto=webp&s=759d235c371d6ae8ad5efb1c98a74b259a3ff8fe |+| Cosplay Famous | 6f0a496f-c3e2-484c-90d0-d26bffb2e286 | 100 | https://preview.redd.it/award_images/t5_22cerq/7ptj05lgqys51_CosplayFamous.png?width=64&height=64&crop=smart&auto=webp&s=405250108b91c08113cd9c38b4d872d9b521d116 |+| Dread | 81cf5c92-8500-498c-9c94-3e4034cece0a | 100 | https://preview.redd.it/award_images/t5_22cerq/nvfe4gyawnf51_Dread.png?width=64&height=64&crop=smart&auto=webp&s=34247d8bba8dc5aa7eaed6e81135da0c935d37f3 |+| Evil Cackle | 483d8e29-bbe5-404e-a09a-c2d7b16c4fff | 100 | https://preview.redd.it/award_images/t5_22cerq/43zl6dfcg9e51_EvilCackle.png?width=64&height=64&crop=smart&auto=webp&s=bd7d6c66b7594ac91ff2d8a7d86340a0f49a153c |+| Excited | 74fe5152-7906-4991-9016-bc2d8e261200 | 100 | https://preview.redd.it/award_images/t5_22cerq/x069ow7ewnf51_Excited.png?width=64&height=64&crop=smart&auto=webp&s=b1d186a93a86d3bae5ad3bee36e41a9e93d35281 |+| Glow Up | 01178870-6a4f-4172-8f36-9ed5092ee4f9 | 100 | https://preview.redd.it/award_images/t5_22cerq/2754pa5jvsj51_GlowUp.png?width=64&height=64&crop=smart&auto=webp&s=60f710eccc52d9d05db204bb2b962372a1e45671 |+| Heartwarming | 19860e30-3331-4bac-b3d1-bd28de0c7974 | 100 | https://preview.redd.it/award_images/t5_22cerq/v1mxw8i6wnf51_Heartwarming.png?width=64&height=64&crop=smart&auto=webp&s=c09f506dc0be92c9849ee7dd2cfe9d65852d6064 |+| I'll Drink to That | 3267ca1c-127a-49e9-9a3d-4ba96224af18 | 100 | https://preview.redd.it/award_images/t5_22cerq/45aeu8mzvsj51_IllDrinktoThat.png?width=64&height=64&crop=smart&auto=webp&s=94580e58d47d0a1eb1c6cc776437c574b5bbad7c |+| Keep Calm | 1da6ff27-7c0d-4524-9954-86e5cda5fcac | 100 | https://preview.redd.it/award_images/t5_22cerq/g77c4oud7hb51_KeepCalm.png?width=64&height=64&crop=smart&auto=webp&s=9510d2496464d0fa8ff2288e1f0e17f114226383 |+| Kiss | 1e516e18-cbee-4668-b338-32d5530f91fe | 100 | https://preview.redd.it/award_images/t5_22cerq/sb42u5gmwsj51_Kiss.png?width=64&height=64&crop=smart&auto=webp&s=12e56d5bba8f00fe467d3efe0c962e70bcbc92ed |+| Last Minute Costume | a0c3e268-87e7-4918-9a36-f6aa462e4dee | 100 | https://preview.redd.it/award_images/t5_22cerq/icn71p34nct51_LastMinuteCostume.png?width=64&height=64&crop=smart&auto=webp&s=f6865e93870b4386ab4a7c32662200b961870d22 |+| Lawyer Up | ae89e420-c4a5-47b8-a007-5dacf1c0f0d4 | 100 | https://preview.redd.it/award_images/t5_22cerq/iq0sgwn5bzy41_LawyerUp.png?width=64&height=64&crop=smart&auto=webp&s=3baf45de6ba3e1535df885b91a2aa714e5ece9d5 |+| Masterpiece | b4072731-c0fb-4440-adc7-1063d6a5e6a0 | 100 | https://preview.redd.it/award_images/t5_22cerq/2juh333m40n51_Masterpiece.png?width=64&height=64&crop=smart&auto=webp&s=0183ad39a56ba3e46c4bcb5d8938392f75d5d9d5 |+| Shocked | fbe9527a-adb3-430e-af1a-5fd3489e641b | 100 | https://preview.redd.it/award_images/t5_22cerq/fck3iedi2ug51_Shocked.png?width=64&height=64&crop=smart&auto=webp&s=627fbd255cb9cce5b72551255cb061bf0c8af71a |+| Spacefaring Snoo | a3df1615-dcf8-4f5f-ac7c-3c2be31332a7 | 100 | https://preview.redd.it/award_images/t5_22cerq/0dy3wj06qys51_SpacefaringSnoo.png?width=64&height=64&crop=smart&auto=webp&s=fb6e1c4f29f00c5229c58b769f788842f4bcb85d |+| Sweet Tooth | bd6ccb1d-118a-462a-a451-f550cd3133d2 | 100 | https://preview.redd.it/award_images/t5_22cerq/gbsaculna3u51_SweetTooth.png?width=64&height=64&crop=smart&auto=webp&s=5ce49bdf63d850847bb4dfced763fb80a8a99024 |+| Tearing Up | 43f3bf99-92d6-47ab-8205-130d26e7929f | 100 | https://preview.redd.it/award_images/t5_22cerq/lop66ut2wnf51_TearingUp.png?width=64&height=64&crop=smart&auto=webp&s=a6ee8b3c876bdc7a022072134f8157a7ea85d884 |+| Yummy | ae7f17fb-6538-4c75-9ff4-5f48b4cdaa94 | 100 | https://preview.redd.it/award_images/t5_22cerq/a7dhg27hvnf51_Yummy.png?width=64&height=64&crop=smart&auto=webp&s=7a70c563dbc8bb2659271ddd451c8e657f3a3aa8 |+| Wholesome | 5f123e3d-4f48-42f4-9c11-e98b566d5897 | 125 | https://preview.redd.it/award_images/t5_22cerq/5izbv4fn0md41_Wholesome.png?width=64&height=64&crop=smart&auto=webp&s=89a077c4955b50fa2e57449eebf8c19e7f23ceb7 |+| Bless Up | 77ba55a2-c33c-4351-ac49-807455a80148 | 150 | https://preview.redd.it/award_images/t5_22cerq/trfv6ems1md41_BlessUp.png?width=64&height=64&crop=smart&auto=webp&s=5e84fe0dae062adff22f01c384d86c0633d06b28 |+| Buff Doge | c42dc561-0b41-40b6-a23d-ef7e110e739e | 150 | https://preview.redd.it/award_images/t5_22cerq/zc4a9vk5zmc51_BuffDoge.png?width=64&height=64&crop=smart&auto=webp&s=04b5cf5717304307515af46c73431f11bb66c3bd |+| Cake | 5fb42699-4911-42a2-884c-6fc8bdc36059 | 150 | https://preview.redd.it/award_images/t5_22cerq/aoa99054n2s41_Cake.png?width=64&height=64&crop=smart&auto=webp&s=a1564ae45fe22bcd07a9a98d0b4c321c497ba194 |+| Helpful | f44611f1-b89e-46dc-97fe-892280b13b82 | 150 | https://preview.redd.it/award_images/t5_22cerq/klvxk1wggfd41_Helpful.png?width=64&height=64&crop=smart&auto=webp&s=cc59d3722210878a975f8d97eb62f3092e472693 |+| Press F | 88fdcafc-57a0-48db-99cc-76276bfaf28b | 150 | https://preview.redd.it/award_images/t5_22cerq/tcofsbf92md41_PressF.png?width=64&height=64&crop=smart&auto=webp&s=b33bda0aa0310bbe1877ba2d02a259d7cc52d616 |+| Take My Money | a7f9cbd7-c0f1-4569-a913-ebf8d18de00b | 150 | https://preview.redd.it/award_images/t5_22cerq/9jr8pv84v7i51_TakeMyMoney.png?width=64&height=64&crop=smart&auto=webp&s=8cae8bb3d91b20e0d13b24010a103842e365ff9f |+| Giggle | e813313c-1002-49bf-ac37-e966710f605f | 200 | https://www.redditstatic.com/gold/awards/icon/Giggle_64.png |+| Got the W | 8dc476c7-1478-4d41-b940-f139e58f7756 | 200 | https://preview.redd.it/award_images/t5_22cerq/9avdcwgupta41_GottheW.png?width=64&height=64&crop=smart&auto=webp&s=d7c1acaee0770a6a0ff7853606ba9992824cdcec |+| I'd Like to Thank... | 1703f934-cf44-40cc-a96d-3729d0b48262 | 200 | https://preview.redd.it/award_images/t5_22cerq/8ad2jffnclf41_Thanks.png?width=64&height=64&crop=smart&auto=webp&s=430fa4cf2928cc37ed0a3344c8da31277a53929c |+| I'm Deceased | b28d9565-4137-433d-bb65-5d4aa82ade4c | 200 | https://preview.redd.it/award_images/t5_22cerq/2jd92wtn25g41_ImDeceased.png?width=64&height=64&crop=smart&auto=webp&s=106ba80d6001af5b5b47b874b4f86da6ca88113f |+| Looking | 4922c1be-3646-4d62-96ea-19a56798df51 | 200 | https://preview.redd.it/award_images/t5_22cerq/kjpl76213ug51_Looking.png?width=64&height=64&crop=smart&auto=webp&s=5d6beac8304bc8fe28e0d6acb1b4b1339abecc67 |+| Plus One | f7562045-905d-413e-9ed2-0a16d4bfe349 | 200 | https://preview.redd.it/award_images/t5_22cerq/6vgr8y21i9741_PlusOne.png?width=64&height=64&crop=smart&auto=webp&s=ecea37cb71525e80d9ca2dbf2bd504b9f934606e |+| Stonks Falling | 9ee30a8f-463e-4ef7-9da9-a09f270ec026 | 200 | https://preview.redd.it/award_images/t5_22cerq/ree13odobef41_StonksFalling.png?width=64&height=64&crop=smart&auto=webp&s=b1016427b3550d229b4ec93437ac8b69c28c5ae2 |+| Stonks Rising | d125d124-5c03-490d-af3d-d07c462003da | 200 | https://preview.redd.it/award_images/t5_22cerq/s5edqq9abef41_StonksRising.png?width=64&height=64&crop=smart&auto=webp&s=8c11db37505feb2a3e4130eb15e9470e72e65b63 |+| This is 2020 | dc391ef9-0df8-468f-bd3c-7b177092de35 | 200 | https://preview.redd.it/award_images/t5_22cerq/ncon692ev7i51_Thisis2020.png?width=64&height=64&crop=smart&auto=webp&s=eb415a44432807861d7bac64d9e26c5c6ea194bb |+| 1UP | 11be92ba-509e-46d3-991b-593239006521 | 250 | https://www.redditstatic.com/gold/awards/icon/Levelup_64.png |+| Awesome Answer | 2adc49e8-d6c9-4923-9293-2bfab1648569 | 250 | https://preview.redd.it/award_images/t5_22cerq/71v56o5a5v541_AwesomeAnswer.png?width=64&height=64&crop=smart&auto=webp&s=a6c7ee017a2cbab3e291b81823eb179faeb96b99 |+| It's Cute! | cc540de7-dfdb-4a68-9acf-6f9ce6b17d21 | 250 | https://preview.redd.it/award_images/t5_22cerq/n94bgm83in941_ItsCute.png?width=64&height=64&crop=smart&auto=webp&s=2632d9c9236d0501427072373b789fdb5a59377a |+| Mind Blown | 9583d210-a7d0-4f3c-b0c7-369ad579d3d4 | 250 | https://preview.redd.it/award_images/t5_22cerq/wa987k0p4v541_MindBlown.png?width=64&height=64&crop=smart&auto=webp&s=5bcf973d6d2b64223cc5a2995c95b797bcf68dd2 |+| Original | d306c865-0d49-4a36-a1ab-a4122a0e3480 | 250 | https://preview.redd.it/award_images/t5_22cerq/b8xt4z8yajz31_Original.png?width=64&height=64&crop=smart&auto=webp&s=8ca70e1f45c2ddca559d456a74798fcedf36427e |+| Timeless Beauty | 31260000-2f4a-4b40-ad20-f5aa46a577bf | 250 | https://www.redditstatic.com/gold/awards/icon/Timeless_512.png |+| Today I Learned | a67d649d-5aa5-407e-a98b-32fd9e3a9696 | 250 | https://preview.redd.it/award_images/t5_22cerq/bph2png4ajz31_TodayILearned.png?width=64&height=64&crop=smart&auto=webp&s=0dec60a8d3226978d4b824226b0c864b663293b3 |+| Yas Queen | d48aad4b-286f-4a3a-bb41-ec05b3cd87cc | 250 | https://preview.redd.it/award_images/t5_22cerq/kthj3e4h3bm41_YasQueen.png?width=64&height=64&crop=smart&auto=webp&s=98b385524aee26412e9dcf25bd20b4cff0eb2376 |+| Coin Gift | 3dd248bc-3438-4c5b-98d4-24421fd6d670 | 300 | https://preview.redd.it/award_images/t5_22cerq/cr1mq4yysv541_CoinGift.png?width=64&height=64&crop=smart&auto=webp&s=d39d0850925a193c9f2ca8203243c694d15fb40a |+| Crab Rave | f7a4fd5e-7cd1-4c11-a1c9-c18d05902e81 | 300 | https://www.redditstatic.com/gold/awards/icon/CrabRave_64.png |+| Frankensnoo | aef30fbe-92e4-4593-8aa7-4b82cfe8d172 | 300 | https://www.redditstatic.com/gold/awards/icon/Electric_64.png |+| GOAT | cc299d65-77de-4828-89de-708b088349a0 | 300 | https://preview.redd.it/award_images/t5_22cerq/x52x5be57fd41_GOAT.png?width=64&height=64&crop=smart&auto=webp&s=d8a0ff8871eeebadc700284d0186073b8e56ac58 |+| Rocket Like | 28e8196b-d4e9-45bc-b612-cd4c7d3ed4b3 | 300 | https://preview.redd.it/award_images/t5_22cerq/94pn64yuas941_RocketLike.png?width=64&height=64&crop=smart&auto=webp&s=381ec4bd15ab6029d5009a180f749093de815e60 |+| Spooky Season | 176a3f8a-2229-4a12-bcdc-86464cfd6dc1 | 300 | https://www.redditstatic.com/gold/awards/icon/Spooky_64.png |+| Table Flip | 3e000ecb-c1a4-49dc-af14-c8ac2029ca97 | 300 | https://preview.redd.it/award_images/t5_22cerq/a05z7bb9v7i51_TableFlip.png?width=64&height=64&crop=smart&auto=webp&s=3efc978414612ce3b518813a124501b8a204e56b |+| This | 68ba1ee3-9baf-4252-be52-b808c1e8bdc4 | 300 | https://preview.redd.it/award_images/t5_22cerq/vu6om0xnb7e41_This.png?width=64&height=64&crop=smart&auto=webp&s=4b2a7c5439da6b4a9e2173bbf3cf9a610538600d |+| Updoot | 725b427d-320b-4d02-8fb0-8bb7aa7b78aa | 300 | https://preview.redd.it/award_images/t5_22cerq/7atjjqpy1mc41_Updoot.png?width=64&height=64&crop=smart&auto=webp&s=f07dcd6402653b86d321cff6ded773cfa13d918a |+| Spit-take | 3409a4c0-ba69-43a0-be9f-27bc27c159cc | 325 | https://www.redditstatic.com/gold/awards/icon/Spits_drink_64.png |+| Super Heart Eyes | 6220ecfe-4552-4949-aa13-fb1fb7db537c | 325 | https://www.redditstatic.com/gold/awards/icon/Superheart_64.png |+| Table Slap | 9f928aff-c9f5-4e7e-aa91-8619dce60f1c | 325 | https://www.redditstatic.com/gold/awards/icon/TableSlap_64.png |+| To The Stars | 2bc47247-b107-44a8-a78c-613da21869ff | 325 | https://www.redditstatic.com/gold/awards/icon/Rocket_64.png |+| Aww-some | e55d1889-11f2-4d04-8abb-44b1de7dd53d | 350 | https://www.redditstatic.com/gold/awards/icon/Awwsome2_64.png |+| Heartbeat | 11eb6af3-3d0d-4d70-8261-22d216ab591d | 350 | https://www.redditstatic.com/gold/awards/icon/Heartbeat_64.png |+| Into the Magic Portal | 2ff1fdd0-ff73-47e6-a43c-bde6d4de8fbd | 350 | https://www.redditstatic.com/gold/awards/icon/TeleportIn_64.png |+| Out of the Magic Portal | 7fe72f36-1141-4a39-ba76-0d481889b390 | 350 | https://www.redditstatic.com/gold/awards/icon/TeleportOut_64.png |+| Bravo! | 84276b1e-cc8f-484f-a19c-be6c09adc1a5 | 400 | https://www.redditstatic.com/gold/awards/icon/SnooClapping_64.png |+| Doot 🎵 Doot | 5b39e8fd-7a58-4cbe-8ca0-bdedd5ed1f5a | 400 | https://www.redditstatic.com/gold/awards/icon/Updoot_64.png |+| Pumpkin Spice | 89164d08-80db-453b-a7aa-74c50fa84bfa | 400 | https://preview.redd.it/award_images/t5_22cerq/c1ll7h6zedq51_PumpkinSpice.png?width=64&height=64&crop=smart&auto=webp&s=c8a3297c17b9b70255353e933f5ed0a5b5bb3934 |+| Bless Up (Pro) | 43c43a35-15c5-4f73-91ef-fe538426435a | 500 | https://preview.redd.it/award_images/t5_22cerq/xe5mw55w5v541_BlessUp.png?width=64&height=64&crop=smart&auto=webp&s=54b7d71c74cf41fc8ada4a2110babf8b68d2f172 |+| Brighten My Day | 9591a26e-b2e4-4ef2-bed4-28ff69246691 | 500 | https://www.redditstatic.com/gold/awards/icon/Sunny_64.png |+| Eureka! | 65f78ca2-45d8-4cb6-bf79-a67beadf2e47 | 500 | https://www.redditstatic.com/gold/awards/icon/Bulb_64.png |+| Heart Eyes | a9009ea5-1a36-42ae-aab2-5967563ee054 | 500 | https://preview.redd.it/award_images/t5_22cerq/12kz7a7j4v541_HeartEyes.png?width=64&height=64&crop=smart&auto=webp&s=02bb7182aad468e16e0a711b594110225679c79e |+| Helpful (Pro) | 2ae56630-cfe0-424e-b810-4945b9145358 | 500 | https://preview.redd.it/award_images/t5_22cerq/trz28na8ajz31_Helpful.png?width=64&height=64&crop=smart&auto=webp&s=5dfea529ee529d33105b592b42696d05e7b734c2 |+| Made Me Smile | a7a04d6a-8dd8-41bb-b906-04fa8f144014 | 500 | https://preview.redd.it/award_images/t5_22cerq/hwnbr9l67s941_MadeMeSmile.png?width=64&height=64&crop=smart&auto=webp&s=918705b3b6804a6151b6ce4f8b1c86dfa604a470 |+| Snoo Nice | 27d3176c-b388-4616-80ec-11b8ece5b7ee | 500 | https://preview.redd.it/award_images/t5_22cerq/9r7hexe6pta41_SnooNice.png?width=64&height=64&crop=smart&auto=webp&s=88748b0fe08311b512dc08909acdcdbe8d91d747 |+| Starry | 0e957fb0-c8f1-4ba1-a8ef-e1e524b60d7d | 500 | https://www.redditstatic.com/gold/awards/icon/Starry_512.png |+| Wholesome (Pro) | 1f0462ee-18f5-4f33-89cf-f1f79336a452 | 500 | https://preview.redd.it/award_images/t5_22cerq/0o2j782f00e41_WholesomeSuperpro.png?width=64&height=64&crop=smart&auto=webp&s=2a04235b56e4fbc90106067bfe0d61bd60300c4f |+| Pot o' Coins | 35c78e6e-507b-4f1d-b3d8-ed4384090 | 1000 | https://preview.redd.it/award_images/t5_22cerq/wg3lzllyg9n41_PotoCoins.png?width=64&height=64&crop=smart&auto=webp&s=7bb8b7ab622f25b5e6f7f2068663b5ea964d2957 |+| Cornucopia | 9a123cdb-d26d-4d0c-b7fa-46750b8289fa | 2000 | https://preview.redd.it/award_images/t5_22cerq/27xs8z0ja3u51_Cornucopia.png?width=64&height=64&crop=smart&auto=webp&s=4298b88d2511a0951817f440fe5244f6dcf513a9 |+| Argentium | 4ca5a4e6-8873-4ac5-99b9-71b1d5161a91 | 20000 | https://www.redditstatic.com/gold/awards/icon/Mithril_64.png |+| Ternion All-Powerful | 2385c499-a1fb-44ec-b9b7-d260f3dc55de | 50000 | https://www.redditstatic.com/gold/awards/icon/Trinity_64.png |+| | | | <14> |
heddit.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: heddit-version: 0.0.3+version: 0.1 synopsis: Reddit API bindings description: See the README at https://gitlab.com/ngua/heddit license: BSD-3-Clause@@ -60,6 +60,7 @@ Network.Reddit.Subreddit Network.Reddit.Types Network.Reddit.Types.Account+ Network.Reddit.Types.Award Network.Reddit.Types.Comment Network.Reddit.Types.Emoji Network.Reddit.Types.Flair@@ -107,7 +108,7 @@ , scientific ^>=0.3.6 , split ^>=0.2.3 , text ^>=1.2- , time >=1.8 && <1.12+ , time >=1.9 && <1.13 , unliftio ^>=0.2 , unordered-containers ^>=0.2.10 , uri-bytestring ^>=0.3@@ -224,7 +225,7 @@ , hspec >=2.0 && <3.0 , microlens-ghc ^>=0.4.10 , text ^>=1.2- , time >=1.8 && <1.12+ , time >=1.9 && <1.13 , unliftio ^>=0.2 other-modules:
io-tests/SubredditSpec.hs view
@@ -15,7 +15,7 @@ import Test.Hspec spec :: Spec-spec = beforeAll (loadClient Nothing) . describe "Network.Reddit.Submission"+spec = beforeAll (loadClient Nothing) . describe "Network.Reddit.Subreddit" $ sequence_ [ getInfo , getTop , nameSearch
src/Network/Reddit.hs view
@@ -66,7 +66,7 @@ , ErrorMessage(..) , StatusMessage(StatusMessage) , StatusCode- , JSONError(JSONError)+ , POSTError(POSTError) -- * Auth , ClientState , AppType(..)
src/Network/Reddit/Comment.hs view
@@ -21,6 +21,7 @@ ( -- * Reading comments getComments , getComment+ , getCommentByURL , withReplies , loadMoreComments , loadMoreCommentsDef@@ -37,6 +38,10 @@ , upvoteComment , downvoteComment , unvoteComment+ -- * Awarding+ , awardComment+ , gildComment+ -- * Misc , reportComment -- * Types , module M@@ -70,7 +75,7 @@ -- | Get the 'Comment's corresponding to a container of 'CommentID's getComments :: (MonadReddit m, Foldable t)- => ItemOpts Comment+ => ItemOpts -> t CommentID -> m (Seq Comment) getComments = getMany@@ -82,6 +87,11 @@ comment :<| _ -> pure comment _ -> throwM $ InvalidResponse "getComment: No results" +-- | Get a comment based on its permalink URL, which must be of the form+-- https:\/\/{www.}reddit.com\/r\/\<SUB\>\/comments\/\<SID\>\/\<NAME\>/\<ID\>+getCommentByURL :: MonadReddit m => URL -> m Comment+getCommentByURL url = getComment =<< commentIDFromURL url+ -- | Get new 'Comment's, either for the site as a whole or for a single subreddit, -- given its 'SubredditName' getNewComments :: MonadReddit m@@ -98,7 +108,7 @@ -- | Update a 'Comment' to include its 'ChildComment's, returning the updated -- 'Comment'. This will probably be necessary if the original 'Comment' was obtained -- by getting a 'Username'\'s or 'Subreddit'\'s comments, etc...-withReplies :: MonadReddit m => ItemOpts a -> Comment -> m Comment+withReplies :: MonadReddit m => ItemOpts -> Comment -> m Comment withReplies ItemOpts { .. } Comment { .. } = runAction @WithReplies r <&> wrappedTo where@@ -150,6 +160,16 @@ unvoteComment :: MonadReddit m => CommentID -> m () unvoteComment = vote Unvote . CommentItemID +-- | Grant an 'Award' to a comment. See 'mkAward' for creating an award with+-- default values, as well as the pattern synonyms for common awards+awardComment :: MonadReddit m => Award -> CommentID -> m AwardingsSummary+awardComment a = award a . CommentItemID++-- | Convenience action to anonymously give 'Gold' to the author of a comment,+-- without a message. See 'awardComment' if you need more fine-grained control+gildComment :: MonadReddit m => CommentID -> m AwardingsSummary+gildComment = gild . CommentItemID+ -- | Report a comment to the subreddit\'s mods reportComment :: MonadReddit m => Report -> CommentID -> m () reportComment r = report r . CommentItemID@@ -164,7 +184,7 @@ :: forall m. MonadReddit m => Maybe Word- -> ItemOpts Comment+ -> ItemOpts -> SubmissionID -> MoreComments -> m (Seq ChildComment)@@ -188,8 +208,8 @@ more = case remaining of Seq.Empty -> mempty- cids -> Seq.singleton . More- $ MoreComments cids (count - fromIntegral limit)+ cids -> Seq.singleton . More . MoreComments cids+ $ count - fromIntegral limit (toFetch, remaining) = Seq.splitAt limit childIDs
src/Network/Reddit/Internal.hs view
@@ -26,6 +26,7 @@ , getMany , redditURL , oauthURL+ , getMe ) where import Conduit ( (.|), runConduit )@@ -71,6 +72,7 @@ import qualified Network.HTTP.Types as H import Network.Reddit.Auth import Network.Reddit.Types+import Network.Reddit.Types.Account import Network.Reddit.Utils import UnliftIO.IORef@@ -227,7 +229,7 @@ -- 'Seq' of 'Network.Reddit.Types.Comment.Comment's getMany :: forall a b t m. (MonadReddit m, Foldable t, Thing b, FromJSON a, FromJSON b)- => ItemOpts a+ => ItemOpts -> t b -> m (Seq a) getMany opts ids = mconcat <$> traverse getChunk (chunked ids)@@ -246,3 +248,9 @@ , ("limit", toQueryParam @Int apiRequestLimit) ] }++-- NOTE+-- This action needs to be in this module to avoid cyclic module dependencies+-- | Get account information for the currently logged-in user+getMe :: MonadReddit m => m Account+getMe = runAction defaultAPIAction { pathSegments = [ "api", "v1", "me" ] }
src/Network/Reddit/Item.hs view
@@ -21,6 +21,8 @@ , report , save , unsave+ , award+ , gild , setInboxReplies , getGildedItems -- * Types@@ -33,6 +35,13 @@ import Network.Reddit.Internal import Network.Reddit.Types+import Network.Reddit.Types.Award+import Network.Reddit.Types.Award as M+ ( Award(Award)+ , AwardID(..)+ , AwardingsSummary(AwardingsSummary)+ , mkAward+ ) import Network.Reddit.Types.Comment import Network.Reddit.Types.Item ( PostedItem ) import Network.Reddit.Types.Item as M@@ -45,6 +54,7 @@ import Network.Reddit.Types.Subreddit import Network.Reddit.Utils +import Web.FormUrlEncoded ( ToForm(toForm) ) import Web.HttpApiData ( ToHttpApiData(toQueryParam, toUrlPiece) )@@ -128,6 +138,27 @@ , method = POST , requestData = mkTextFormData [ ("id", fullname iid) ] }++-- | Grant an award to the author of an 'Item'. See the docs for 'Award' for+-- information about the available options when awarding as well as 'mkAward'+-- to use defaults.+--+-- To grant a common award, such as gold, see the bundled pattern synonyms of+-- 'AwardID'. If you wish to anonymously gild an item without a message, see the+-- 'gild' action in this module, provided for convenience+award :: MonadReddit m => Award -> ItemID -> m AwardingsSummary+award aw iid =+ runAction defaultAPIAction+ { pathSegments = [ "api", "v2", "gold", "gild" ]+ , method = POST+ , requestData = WithForm+ $ mkTextForm [ ("thing_id", fullname iid) ] <> toForm aw+ }++-- | Gild an item anonymously, without a message. To grant other types of+-- awards to items, or to gild non-anonymously\/with a message, see 'award'+gild :: MonadReddit m => ItemID -> m AwardingsSummary+gild = award $ mkAward Gold -- | Enable or disable inbox replies for an item given its 'ItemID' setInboxReplies :: MonadReddit m => Bool -> ItemID -> m ()
src/Network/Reddit/Me.hs view
@@ -21,6 +21,7 @@ getMe , getPreferences , updatePreferences+ , getMySubreddit , getMyOverview , getMySaved , getMyComments@@ -39,6 +40,7 @@ , getMyModerated , getMyContributing , getMyMultireddits+ , getMySubredditSettings ) where import Control.Monad.Catch@@ -55,6 +57,8 @@ import Lens.Micro import Network.Reddit.Internal+import Network.Reddit.Moderation+import Network.Reddit.Subreddit import Network.Reddit.Types import Network.Reddit.Types.Account import Network.Reddit.Types.Comment@@ -62,17 +66,12 @@ import Network.Reddit.Types.Item import Network.Reddit.Types.Multireddit import Network.Reddit.Types.Submission-import Network.Reddit.Types.Subreddit import Network.Reddit.User import Network.Reddit.Utils import Web.FormUrlEncoded ( ToForm(toForm) ) import Web.HttpApiData ( ToHttpApiData(..) ) --- | Get account information for the currently logged-in user-getMe :: MonadReddit m => m Account-getMe = runAction defaultAPIAction { pathSegments = mePath mempty }- -- | Get the user 'Preferences' for the currently authenticated user getPreferences :: MonadReddit m => m Preferences getPreferences =@@ -92,6 +91,20 @@ , method = PATCH , requestData = mkTextFormData [ ("json", textEncode prefs) ] }++-- | Get the special user 'Subreddit' associated with the authenticated account+getMySubreddit :: MonadReddit m => m Subreddit+getMySubreddit = do+ Account { username } <- getMe+ getSubreddit =<< mkSubredditName (usernameToDisplayName username)++-- | Get settings for the special user 'Subreddit' associated with the authenticated+-- account. In order to update the settings, you can use 'setSubredditSettings'+-- directly, as it requires the subreddit ID+getMySubredditSettings :: MonadReddit m => m SubredditSettings+getMySubredditSettings = do+ Account { username } <- getMe+ getSubredditSettings =<< mkSubredditName (usernameToDisplayName username) -- | Get an overview of the authenticated user\'s 'Comment's and 'Submission's getMyOverview
src/Network/Reddit/Moderation.hs view
@@ -263,7 +263,6 @@ import Network.HTTP.Client.MultipartFormData ( partBS, partFile ) import Network.Reddit.Internal-import Network.Reddit.Me import Network.Reddit.Submission import Network.Reddit.Types import Network.Reddit.Types.Account
src/Network/Reddit/Multireddit.hs view
@@ -40,7 +40,6 @@ import Data.Foldable ( traverse_ ) import Network.Reddit.Internal-import Network.Reddit.Me import Network.Reddit.Types import Network.Reddit.Types.Account import Network.Reddit.Types.Multireddit
src/Network/Reddit/Submission.hs view
@@ -55,8 +55,11 @@ , upvoteSubmission , downvoteSubmission , unvoteSubmission- , reportSubmission+ -- * Awards+ , awardSubmission+ , gildSubmission -- * Misc+ , reportSubmission , unmarkNSFW , markNSFW , setOC@@ -143,7 +146,7 @@ -- | Get a information on 'Submission's given a container of 'SubmissionID's getSubmissions :: (MonadReddit m, Foldable t)- => ItemOpts Submission+ => ItemOpts -> t SubmissionID -> m (Seq Submission) getSubmissions = getMany@@ -495,6 +498,17 @@ -- | Remove an existing vote on a submission unvoteSubmission :: MonadReddit m => SubmissionID -> m () unvoteSubmission = vote Unvote . SubmissionItemID++-- | Grant an 'Award' to a submission. See 'mkAward' for creating an award with+-- default values, as well as the pattern synonyms for common awards+awardSubmission+ :: MonadReddit m => Award -> SubmissionID -> m AwardingsSummary+awardSubmission a = award a . SubmissionItemID++-- | Convenience action to anonymously give 'Gold' to the author of a submission,+-- without a message. See 'awardSubmission' if you need more fine-grained control+gildSubmission :: MonadReddit m => SubmissionID -> m AwardingsSummary+gildSubmission = gild . SubmissionItemID -- | Report a submission to the subreddit\'s mods reportSubmission :: MonadReddit m => Report -> SubmissionID -> m ()
src/Network/Reddit/Types/Account.hs view
@@ -32,20 +32,20 @@ , FriendList , Karma(..) , KarmaList- , Trophy(..)- , TrophyList , UserSummary(..) , UserSummaryList , Preferences(..) , MediaPreference(..) , AcceptPMs(..)+ , usernameToDisplayName ) where import Control.Monad ( (<=<) ) import Control.Monad.Catch ( MonadThrow ) import Data.Aeson- ( (.:)+ ( (.!=)+ , (.:) , (.:?) , Array , FromJSON(..)@@ -89,40 +89,54 @@ deriving ( 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+-- and may only include upper\/lowercase alphanumeric chars, underscores, or -- hyphens mkUsername :: MonadThrow m => Text -> m Username mkUsername = validateName Nothing Nothing "Username" +-- | Prefix the username with \"u_\"+usernameToDisplayName :: Username -> Text+usernameToDisplayName (Username uname) = "u_" <> uname+ -- | A unique, site-wide ID for an account newtype UserID = UserID Text deriving stock ( Show, Generic ) deriving newtype ( Eq ) instance FromJSON UserID where- parseJSON = withText "UserID" (coerce . dropTypePrefix AccountKind)+ parseJSON = withText "UserID" $ coerce . dropTypePrefix AccountKind instance Thing UserID where fullname (UserID uid) = prependType AccountKind uid --- | Account information. @Maybe@ fields denote data that Reddit sets to null if--- the requester does not own the account in question. Note that this does /not/--- include all of the possible fields that may be present in Reddit's response ---- which are quite numerous in total and poorly documented+-- | 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- { userID :: UserID- , username :: Username- , created :: UTCTime- , commentKarma :: Int- , isGold :: Bool- , isMod :: Bool- , linkKarma :: Int- , inboxCount :: Maybe Integer- , modHash :: Maybe Text- , over18 :: Maybe Bool- , hasMail :: Maybe Bool- , hasModMail :: Maybe Bool- , hasVerifiedEmail :: Maybe Bool+ { userID :: UserID+ , username :: Username+ , created :: UTCTime+ , commentKarma :: Integer+ , linkKarma :: Integer+ , totalKarma :: Integer+ , awarderKarma :: Maybe Integer+ , awardeeKarma :: Maybe Integer+ , isFriend :: Bool+ , isGold :: Bool+ , isMod :: Bool+ , iconImg :: URL+ , subreddit :: Subreddit+ , numFriends :: Maybe Integer+ , inboxCount :: Maybe Integer+ , creddits :: Maybe Integer+ , modHash :: Maybe Text+ , over18 :: Maybe Bool+ , hasMail :: Maybe Bool+ , hasModMail :: Maybe Bool+ , hasVerifiedEmail :: Maybe Bool+ , hasGoldSubscription :: Maybe Bool+ , goldExpiration :: Maybe UTCTime+ , isSuspended :: Maybe Bool+ , suspensionExpiration :: Maybe UTCTime } deriving stock ( Show, Generic ) @@ -131,19 +145,34 @@ , withKind AccountKind "Account" accountP v ] where- accountP o = Account <$> (o .: "id")- <*> o .: "name"- <*> (integerToUTC <$> o .: "created_utc")- <*> o .: "comment_karma"- <*> o .: "is_gold"- <*> o .: "is_mod"- <*> o .: "link_karma"- <*> o .:? "inbox_count"- <*> o .:? "modhash"- <*> o .:? "over_18"- <*> o .:? "has_mail"- <*> o .:? "has_mod_mail"- <*> o .:? "has_verified_email"+ accountP o = do+ userID <- o .: "id"+ username <- o .: "name"+ created <- integerToUTC <$> o .: "created_utc"+ commentKarma <- o .: "comment_karma"+ linkKarma <- o .: "link_karma"+ totalKarma <- o .:? "total_karma" .!= (commentKarma + linkKarma)+ awarderKarma <- o .:? "awarder_karma"+ awardeeKarma <- o .:? "awardee_karma"+ numFriends <- o .:? "num_friends"+ isFriend <- o .:? "is_friend" .!= False+ isGold <- o .: "is_gold"+ isMod <- o .: "is_mod"+ iconImg <- o .: "icon_img"+ subreddit <- o .: "subreddit" <&> field @"created" .~ created+ inboxCount <- o .:? "inbox_count"+ creddits <- o .:? "gold_creddits"+ modHash <- o .:? "modhash"+ over18 <- o .:? "over_18"+ hasMail <- o .:? "has_mail"+ hasModMail <- o .:? "has_mod_mail"+ hasVerifiedEmail <- o .:? "has_verified_email"+ hasGoldSubscription <- o .:? "has_gold_subscription"+ goldExpiration <- o .:? "gold_expiration"+ isSuspended <- o .:? "is_suspended"+ suspensionExpiration+ <- fmap integerToUTC <$> o .:? "suspension_expiration"+ pure Account { .. } instance Paginable Account where type PaginateOptions Account = AccountSearchOpts@@ -234,33 +263,6 @@ instance FromJSON KarmaList where parseJSON = withKind @Array KarmaListKind "KarmaList" $ fmap (KarmaList . fromList) . traverse parseJSON . toList---- | A Reddit award, such as the \"one-year club\"-data Trophy = Trophy- { name :: Name- , trophyID :: Maybe Text- , awardID :: Maybe Text- , description :: Maybe Body- , grantedAt :: Maybe UTCTime- }- deriving stock ( Show, Eq, Generic )--instance FromJSON Trophy where- parseJSON = withKind AwardKind "Trophy" $ \o -> Trophy <$> o .: "name"- <*> o .:? "id"- <*> o .:? "award_id"- <*> o .:? "description"- <*> (fmap integerToUTC <$> o .:? "granted_at")---- | Wrapper for parsing JSON objects listing 'Trophy's-newtype TrophyList = TrophyList (Seq Trophy)- deriving stock ( Show, Generic )--instance FromJSON TrophyList where- parseJSON = withKind TrophyListKind "TrophyList"- $ fmap (TrophyList . fromList) . (trophiesP <=< (.: "trophies"))- where- trophiesP = withArray "[Trophy]" (traverse parseJSON . toList) -- | A brief summary of a user, with significantly less information than a -- 'Account'
+ src/Network/Reddit/Types/Award.hs view
@@ -0,0 +1,222 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE StrictData #-}+{-# LANGUAGE TupleSections #-}++-- |+-- Module : Network.Reddit.Types.Award+-- Copyright : (c) 2021 Rory Tyler Hayford+-- License : BSD-3-Clause+-- Maintainer : rory.hayford@protonmail.com+-- Stability : experimental+-- Portability : GHC+--+module Network.Reddit.Types.Award+ ( Awarding+ , AwardID(AwardID, Silver, Gold, Platinum, Argentium, Ternion)+ , AwardType(..)+ , Award(..)+ , mkAward+ , Trophy+ , TrophyID+ , TrophyList+ , AwardingsSummary(..)+ ) where++import Control.Monad ( (<=<) )++import Data.Aeson+ ( (.:)+ , (.:?)+ , FromJSON(parseJSON)+ , FromJSONKey+ , Options(..)+ , defaultOptions+ , genericParseJSON+ , withArray+ , withText+ )+import Data.Aeson.Casing ( snakeCase )+import Data.Char ( toLower )+import Data.HashMap.Strict ( HashMap )+import Data.Hashable ( Hashable )+import Data.Sequence ( Seq )+import Data.Text ( Text )+import Data.Time ( UTCTime )++import GHC.Exts ( IsList(fromList, toList) )+import GHC.Generics ( Generic )++import Network.Reddit.Types.Internal+import Network.Reddit.Types.Subreddit++import Web.FormUrlEncoded ( ToForm(toForm) )+import Web.HttpApiData ( ToHttpApiData(..) )++-- | Information about a Reddit award that has been granted. This can be a+-- \"global\" award that may be granted site-wide, or a \"community\" award+-- that is limited to a single subreddit+data Awarding = Awarding+ { awardID :: AwardID+ , name :: Name+ -- | This will only be present for 'Community' awards+ , description :: Body+ , subredditID :: Maybe SubredditID+ , awardType :: AwardType+ , count :: Int+ -- | The number of \"creddits\" required to grant the award+ , coinPrice :: Int+ -- | The number of \"creddits\" given to the recipient+ , coinReward :: Int+ -- | How many days of premium Reddit the awardee is granted+ , daysOfPremium :: Int+ -- | URL of Reddit-hosted icon image+ , iconURL :: URL+ -- | Width of the icon in pixels+ , iconHeight :: Int+ -- | Width of the icon in pixels+ , iconWidth :: Int+ }+ deriving stock ( Show, Eq, Generic )++instance FromJSON Awarding where+ parseJSON = genericParseJSON defaultOptions { fieldLabelModifier }+ where+ fieldLabelModifier = \case+ "awardID" -> "id"+ "subredditID" -> "subreddit_id"+ "iconURL" -> "icon_url"+ s -> snakeCase s++-- | The ID for an award, which users can grant each other. If you want to create+-- a new 'AwardID', see the bundled pattern synonyms for this type, which include+-- various common awards. Also see \"doc/awards.org\" in this repository for a list+-- of awards and their IDs.+--+-- __Note__: Most newer awards are composed of a UUID identifier and an \"award_\"+-- prefix. If you construct this type directly, you should omit the prefix, which+-- will be added for you when making API requests+newtype AwardID = AwardID Text+ deriving stock ( Show, Generic )+ deriving newtype ( Eq, FromJSONKey, Hashable )++instance FromJSON AwardID where+ parseJSON = withText "AwardID" $ breakOnTypeLenient "award"++instance ToHttpApiData AwardID where+ toQueryParam aw@(AwardID a)+ | aw `elem` [ Silver, Gold, Platinum ] = a+ | otherwise = "award_" <> a++-- | The type of the 'Awarding', either site-wide (\"global\") or limited to a+-- \"community\"+data AwardType+ = Global+ | Community+ deriving stock ( Show, Eq, Generic )++instance FromJSON AwardType where+ parseJSON = genericParseJSON --+ defaultOptions { constructorTagModifier = fmap toLower }++-- | Options for awarding an item+data Award = Award+ { -- | The ID of the award you wish to grant. See 'AwardID' and+ -- its bundled pattern synonyms for common awards (e.g. gold)+ awardID :: AwardID+ -- | If the award is issued anonymously+ , isAnonymous :: Bool+ -- | Optional message sent to the recipient+ , message :: Maybe Body+ }+ deriving stock ( Show, Eq, Generic )++instance ToForm Award where+ toForm Award { .. } = fromList+ $ [ ("gild_type", toQueryParam awardID)+ , ("is_anonymous", toQueryParam isAnonymous)+ , ("api_type", "json")+ ]+ <> foldMap pure (("award", ) <$> message)++-- | Create a new anonymous 'Awarding' without a message, given an 'AwardID'+mkAward :: AwardID -> Award+mkAward awardID = Award { isAnonymous = True, message = Nothing, .. }++-- | A summary of your 'Awardings', returned after you have awarded an item+data AwardingsSummary = AwardingsSummary+ { -- | All of the awardings issued by the current user+ allAwardings :: Seq Awarding+ -- | A mapping of award IDs to the number of times the+ -- authenticated user has granted each one+ , gildings :: HashMap AwardID Integer+ -- | Coin balance for the authenticated user+ , coins :: Integer+ }+ deriving stock ( Show, Eq, Generic )++instance FromJSON AwardingsSummary where+ parseJSON =+ genericParseJSON defaultOptions { fieldLabelModifier = snakeCase }++-- | A Reddit trophy, such as the \"one-year club\", that the Reddit grants+-- users. Redditors cannot gift each other these trophies+data Trophy = Trophy+ { name :: Name+ , trophyID :: Maybe TrophyID+ -- | It is not clear what this field is referring to, as 'Trophy's and+ -- 'Award's are supposed to be entirely distinct, according to Reddit+ , awardID :: Maybe Text+ , description :: Maybe Body+ , grantedAt :: Maybe UTCTime+ , url :: Maybe URL+ -- | URL for a 41x41 px icon+ , icon40 :: URL+ -- | URL for a 71x71 px icon+ , icon70 :: URL+ }+ deriving stock ( Show, Eq, Generic )++instance FromJSON Trophy where+ parseJSON = withKind AwardKind "Trophy" $ \o -> Trophy <$> o .: "name"+ <*> o .:? "id"+ <*> o .:? "award_id"+ <*> o .:? "description"+ <*> (fmap integerToUTC <$> o .:? "granted_at")+ <*> o .:? "url"+ <*> o .: "icon_40"+ <*> o .: "icon_70"++-- | The ID of a 'Trophy'+type TrophyID = Text++-- | Wrapper for parsing JSON objects listing 'Trophy's+newtype TrophyList = TrophyList (Seq Trophy)+ deriving stock ( Show, Generic )++instance FromJSON TrophyList where+ parseJSON = withKind TrophyListKind "TrophyList"+ $ fmap (TrophyList . fromList) . (trophiesP <=< (.: "trophies"))+ where+ trophiesP = withArray "[Trophy]" (traverse parseJSON . toList)++pattern Silver :: AwardID+pattern Silver = AwardID "gid_1"++pattern Gold :: AwardID+pattern Gold = AwardID "gid_2"++pattern Platinum :: AwardID+pattern Platinum = AwardID "gid_3"++pattern Argentium :: AwardID+pattern Argentium = AwardID "4ca5a4e6-8873-4ac5-99b9-71b1d5161a91"++pattern Ternion :: AwardID+pattern Ternion = AwardID "2385c499-a1fb-44ec-b9b7-d260f3dc55de"
src/Network/Reddit/Types/Comment.hs view
@@ -54,6 +54,7 @@ import Lens.Micro import Network.Reddit.Types.Account+import Network.Reddit.Types.Award import Network.Reddit.Types.Internal import Network.Reddit.Types.Submission ( SubmissionID ) import Network.Reddit.Types.Subreddit@@ -100,6 +101,7 @@ -- | Whether the author of the comment is also the submission author , isSubmitter :: Bool , stickied :: Bool+ , allAwardings :: Seq Awarding } deriving stock ( Show, Eq, Generic ) @@ -133,6 +135,7 @@ distinguished <- o .:? "distinguished" isSubmitter <- o .: "is_submitter" stickied <- o .: "stickied"+ allAwardings <- o .: "all_awardings" pure Comment { .. } where repliesP (String _) = pure mempty@@ -141,7 +144,7 @@ repliesP _ = mempty instance Paginable Comment where- type PaginateOptions Comment = ItemOpts Comment+ type PaginateOptions Comment = ItemOpts type PaginateThing Comment = CommentID @@ -196,10 +199,11 @@ deriving newtype ( Eq ) instance FromJSON LoadedChildren where- parseJSON = withObject "LoadedChildren" $ \o -> LoadedChildren . fromList- <$> (loadedP =<< ((.: "things") =<< (.: "data") =<< o .: "json"))+ parseJSON = withObject "LoadedChildren"+ $ fmap (LoadedChildren . fromList)+ . (loadedP <=< (.: "things") <=< (.: "data") <=< (.: "json")) where- loadedP = withArray "[ChildComment]" (traverse parseJSON . toList)+ loadedP = withArray "[ChildComment]" $ traverse parseJSON . toList -- | A link to load more children 'Comment's data MoreComments = MoreComments
src/Network/Reddit/Types/Internal.hs view
@@ -10,6 +10,8 @@ {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-}++{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE RoleAnnotations #-} {-# LANGUAGE ScopedTypeVariables #-}@@ -45,6 +47,7 @@ , Time(..) , ItemType(..) , UploadURL+ , SubredditType(..) , Body , Title , URL@@ -62,7 +65,7 @@ , ErrorMessage(..) , StatusCode , StatusMessage(..)- , JSONError(..)+ , POSTError(..) -- * Utilities , dropTypePrefix , integerToUTC@@ -79,12 +82,15 @@ , textEncode , withKinds , breakOnType+ , breakOnTypeLenient , getVals , mkTextForm+ , fromOptional ) where import Conduit ( ConduitM ) +import Control.Applicative ( optional ) import Control.Exception ( Exception(..), SomeException ) import Control.Monad ( guard ) import Control.Monad.Catch ( MonadThrow(throwM) )@@ -93,6 +99,7 @@ ( (.:) , (.:?) , FromJSON(..)+ , Object , Options(constructorTagModifier) , ToJSON(toJSON) , Value(..)@@ -104,6 +111,7 @@ , withObject , withText )+import Data.Aeson.Casing ( snakeCase ) import Data.Aeson.Text ( encodeToLazyText ) import Data.Aeson.Types ( Pair, Parser ) import Data.Bool ( bool )@@ -132,7 +140,7 @@ import Data.Time.Clock.POSIX ( posixSecondsToUTCTime ) import GHC.Exts ( Coercible- , IsList(fromList, toList)+ , IsList(fromList, toList, Item) ) import GHC.Generics ( Generic ) @@ -313,9 +321,8 @@ HKD Identity a = a HKD f a = f a --- | Options that can be applied to comments or submissions, as represented by the--- phantom type parameter-data ItemOpts a = ItemOpts+-- | Options that can be applied to comments or submissions+data ItemOpts = ItemOpts { itemSort :: Maybe ItemSort , itemType :: Maybe ItemType , itemTime :: Maybe Time@@ -325,7 +332,7 @@ } deriving stock ( Show, Eq, Generic ) -instance ToForm (ItemOpts a) where+instance ToForm ItemOpts where toForm ItemOpts { .. } = fromList $ catMaybes [ ("sort", ) . toQueryParam <$> itemSort , ("type", ) . toQueryParam <$> itemType@@ -334,7 +341,7 @@ ] -- | Defaults for fetching items, like comments or submissions-defaultItemOpts :: ItemOpts a+defaultItemOpts :: ItemOpts defaultItemOpts = ItemOpts { itemSort = Nothing , itemType = Nothing@@ -438,6 +445,29 @@ deriving stock ( Show, Generic ) deriving newtype ( Eq, FromJSON, ToJSON, ToHttpApiData ) +-- | The privacy level for the subreddit+data SubredditType+ = Public+ | Restricted+ | Private+ | Archived+ | GoldRestricted+ | EmployeesOnly+ | GoldOnly+ | UserSubreddit+ deriving stock ( Show, Eq, Generic )++instance FromJSON SubredditType where+ parseJSON = genericParseJSON --+ defaultOptions { constructorTagModifier }+ where+ constructorTagModifier = \case+ "UserSubreddit" -> "user"+ s -> snakeCase s++instance ToHttpApiData SubredditType where+ toQueryParam = showTextData+ -- | Type synonym for URLs type URL = Text @@ -493,7 +523,7 @@ = ErrorWithStatus StatusMessage | ErrorWithMessage ErrorMessage | InvalidCredentials OAauthError- | InvalidJSON JSONError+ | InvalidPOST POSTError -- ^ Sent if errors occur when posting JSON | JSONParseError Text LB.ByteString -- ^ With the response body, for further debugging@@ -515,7 +545,7 @@ parseJSON = withObject "APIException" $ \(Object -> o) -> asum [ ErrorWithStatus <$> parseJSON o , ErrorWithMessage <$> parseJSON o- , InvalidJSON <$> parseJSON o+ , InvalidPOST <$> parseJSON o , InvalidCredentials <$> parseJSON o ] @@ -549,6 +579,7 @@ | TooShort | BadCaptcha | UserRequired+ | InsufficientCoins deriving stock ( Show, Eq, Generic ) instance FromJSON ErrorMessage where@@ -575,6 +606,7 @@ "BAD_CAPTCHA" : _ -> pure BadCaptcha "TOO_SHORT" : _ -> pure TooShort "USER_REQUIRED" : _ -> pure UserRequired+ "INSUFFICIENT_COINS_WITH_AMOUNT" : _ -> pure InsufficientCoins v -> pure $ OtherErrorMessage v -- | Type synonym for status codes in responses@@ -589,9 +621,10 @@ parseJSON = withObject "StatusMessage" $ \o -> StatusMessage <$> (o .: "error") <*> (o .: "message") --- | Details about a non-200 response when posting JSON-data JSONError = JSONError- { -- | The fields of the object containing errors+-- | Details about a non-200 response when sending a POST request+data POSTError = POSTError+ { -- | The fields of the JSON object containing errors (only if+ -- JSON was posted) fields :: [Text] , explanation :: Text , message :: Text@@ -599,7 +632,12 @@ } deriving stock ( Show, Eq, Generic ) -instance FromJSON JSONError+instance FromJSON POSTError where+ parseJSON = withObject "POSTError" $ \o -> POSTError+ <$> fromOptional o "fields"+ <*> o .: "explanation"+ <*> o .: "message"+ <*> o .: "reason" redditExToException :: Exception e => e -> SomeException redditExToException = toException . RedditException@@ -746,6 +784,13 @@ | T.null r -> pure $ coerce prefix | otherwise -> mempty +-- | Split a JSON identifier on \"_\"; if it matches the given type+-- prefix, returning the remaining text. If there are no matches, return+-- the text whole. This is useful if Reddit does not consistently prefix+-- values with the type identifier+breakOnTypeLenient :: (Coercible a Text) => Text -> Text -> Parser a+breakOnTypeLenient ty t = asum [ breakOnType ty t, pure $ coerce t ]+ -- | Get all of the values from a 'HashMap' and place them in a 'Seq', discarding -- the keys getVals :: FromJSON b => HashMap Text Value -> Parser (Seq b)@@ -754,3 +799,9 @@ -- | Make a form from @[(Text, Text)]@ pairs mkTextForm :: [(Text, Text)] -> Form mkTextForm = toForm @[(Text, Text)]++-- Parses a container of values that may be missing from the JSON, in which case+-- it returns @mempty@ as a default value+fromOptional+ :: (FromJSON (Item b), IsList b, Monoid b) => Object -> Text -> Parser b+fromOptional o fld = maybe mempty fromList <$> optional (o .: fld)
src/Network/Reddit/Types/Item.hs view
@@ -72,7 +72,7 @@ deriving stock ( Show, Eq, Generic ) instance Paginable Item where- type PaginateOptions Item = ItemOpts Item+ type PaginateOptions Item = ItemOpts type PaginateThing Item = ItemID
src/Network/Reddit/Types/Live.hs view
@@ -253,7 +253,7 @@ data LiveContributor = LiveContributor { userID :: UserID , username :: Username- , permissions :: Seq LivePermission+ , permissions :: [LivePermission] } deriving stock ( Show, Eq, Generic ) @@ -265,7 +265,7 @@ where permissionsP = withArray "[LivePermission]" $ \a -> case toList a of [ "all" ] -> pure $ fromList [ Edit .. Manage ]- xs -> fromList <$> traverse parseJSON xs+ xs -> traverse parseJSON xs -- | Wrapper to parse lists of 'LiveContributor's newtype LiveContributorList = LiveContributorList (Seq LiveContributor)
src/Network/Reddit/Types/Moderation.hs view
@@ -377,7 +377,7 @@ , flairCSS :: Maybe CSSClass , date :: UTCTime -- | If @Nothing@, indicates the user has all mod permissions- , permissions :: Maybe (Seq ModPermission)+ , permissions :: Maybe [ModPermission] } deriving stock ( Show, Eq, Generic ) @@ -600,29 +600,6 @@ instance ToHttpApiData CrowdControlLevel where toQueryParam = showTextData . fromEnum---- | The privacy level for the subreddit-data SubredditType- = Public- | Restricted- | Private- | Archived- | GoldRestricted- | EmployeesOnly- | GoldOnly- | UserSubreddit- deriving stock ( Show, Eq, Generic )--instance FromJSON SubredditType where- parseJSON = genericParseJSON --- defaultOptions { constructorTagModifier }- where- constructorTagModifier = \case- "UserSubreddit" -> "user"- s -> snakeCase s--instance ToHttpApiData SubredditType where- toQueryParam = showTextData -- | Permissible submissions on the subreddit data ContentOptions
src/Network/Reddit/Types/Submission.hs view
@@ -113,6 +113,7 @@ import GHC.Generics ( Generic ) import Network.Reddit.Types.Account+import Network.Reddit.Types.Award import Network.Reddit.Types.Flair import Network.Reddit.Types.Internal import Network.Reddit.Types.Subreddit@@ -161,6 +162,7 @@ , locked :: Bool , spoiler :: Bool , pollData :: Maybe PollData+ , allAwardings :: Seq Awarding } deriving stock ( Show, Eq, Generic ) @@ -195,6 +197,7 @@ distinguished <- o .:? "distinguished" pollData <- o .:? "poll_data" domain <- o .: "domain"+ allAwardings <- o .: "all_awardings" pure Submission { .. } where contentP v = (v .: "is_self") >>= \case@@ -204,7 +207,7 @@ ] instance Paginable Submission where- type PaginateOptions Submission = ItemOpts Submission+ type PaginateOptions Submission = ItemOpts type PaginateThing Submission = SubmissionID
src/Network/Reddit/Types/Subreddit.hs view
@@ -45,7 +45,8 @@ import Control.Monad.Catch ( MonadThrow ) import Data.Aeson- ( (.:)+ ( (.!=)+ , (.:) , (.:?) , FromJSON(..) , Options(..)@@ -60,6 +61,8 @@ , withText ) import Data.Aeson.Casing ( snakeCase )+import Data.Coerce ( coerce )+import Data.Foldable ( asum ) import Data.Maybe ( catMaybes, fromMaybe ) import Data.Sequence ( Seq ) import Data.Text ( Text )@@ -83,42 +86,106 @@ , name :: SubredditName , title :: Title , created :: UTCTime+ , subredditType :: SubredditType+ , subscribers :: Integer+ -- | Description as shown in searches+ , publicDescription :: Body -- | The description of the subreddit in markdown+ , keyColor :: Maybe RGBText , description :: Body , descriptionHTML :: Maybe Body- -- | Description as shown in searches- , publicDescription :: Body- , subscribers :: Integer+ -- | Text shown when submitting, in markdown+ , submitText :: Maybe Text+ , submitTextHTML :: Maybe Text+ -- | The label shown on the submit button+ , submitTextLabel :: Maybe Text+ , iconImg :: Maybe URL+ -- -- | The sub banner image+ , bannerImg :: Maybe URL+ -- | The dimensions (w, h) for the banner image, if it exists+ , bannerSize :: Maybe (Int, Int)+ , headerImg :: Maybe URL+ -- | The dimensions (w, h) for the header image, if it exists+ , headerSize :: Maybe (Int, Int) , over18 :: Bool- , userIsBanned :: Maybe Bool- , userIsModerator :: Maybe Bool- , userIsSubscriber :: Maybe Bool+ -- | Whether the subreddit is quarantined+ , quarantine :: Bool+ , userIsBanned :: Bool+ , userIsMuted :: Bool+ , userIsModerator :: Bool+ , userIsContributor :: Bool+ , userIsSubscriber :: Bool+ , allowImages :: Bool+ , allowPolls :: Bool+ , allowVideos :: Bool+ , allowVideoGIFs :: Bool+ -- | Whether users can specify custom reasons in reports+ , freeFormReports :: Bool+ -- | Whether users are forbidden from posting submissions+ , restrictPosting :: Bool+ -- | Whether users are forbidden from posting comments+ , restrictCommenting :: Bool+ -- | Whether link flair is enabled at all+ , linkFlairEnabled :: Bool -- | Whether users can assign their own link flair , canAssignLinkFlair :: Maybe Bool -- | Whether users can assign their own user flair , canAssignUserFlair :: Maybe Bool- -- | Whether the subreddit is quarantined- , quarantine :: Bool+ -- | Whether the sub supports marking posts with the+ -- spoiler tag+ , spoilersEnabled :: Maybe Bool } deriving stock ( Show, Eq, Generic ) instance FromJSON Subreddit where- parseJSON = withKind SubredditKind "Subreddit" $ \o -> Subreddit- <$> o .: "id"- <*> o .: "display_name"- <*> o .: "title"- <*> (integerToUTC <$> o .: "created_utc")- <*> o .: "description"- <*> o .: "description_html"- <*> o .: "public_description"- <*> o .: "subscribers"- <*> o .: "over18"- <*> o .: "user_is_banned"- <*> o .: "user_is_moderator"- <*> o .: "user_is_subscriber"- <*> o .:? "can_assign_link_flair"- <*> o .:? "can_assign_user_flair"- <*> o .: "quarantine"+ parseJSON v =+ asum [ withKind SubredditKind "Subreddit" (subredditP "id") v+ , withObject "Subreddit" (subredditP "name") v+ ]+ where+ subredditP idField o = do+ subredditID <- o .: idField+ name <- o .: "display_name"+ title <- o .: "title"+ -- This field is only missing when getting a user's subreddit.+ -- We can use the user's creation date in that case, after+ -- setting an (arbitrary) default here+ created <- integerToUTC <$> o .:? "created_utc" .!= 0+ subredditType <- o .: "subreddit_type"+ keyColor <- nothingTxtNull =<< o .: "key_color"+ description <- o .: "description"+ descriptionHTML <- o .:? "description_html"+ publicDescription <- o .: "public_description"+ submitTextLabel <- o .: "submit_text_label"+ submitText <- o .:? "submit_text"+ submitTextHTML <- o .:? "submit_text_html"+ subscribers <- o .: "subscribers"+ iconImg <- maybe (pure Nothing) nothingTxtNull+ =<< o .:? "icon_img"+ bannerImg <- maybe (pure Nothing) nothingTxtNull+ =<< o .: "banner_img"+ bannerSize <- o .:? "banner_size"+ headerImg <- o .:? "header_img"+ headerSize <- o .:? "header_size"+ over18 <- o .: "over_18" <|> o .: "over18"+ quarantine <- o .: "quarantine"+ userIsBanned <- o .: "user_is_banned"+ userIsMuted <- o .: "user_is_muted"+ userIsModerator <- o .: "user_is_moderator"+ userIsContributor <- o .: "user_is_contributor"+ userIsSubscriber <- o .: "user_is_subscriber"+ allowImages <- o .:? "allow_images" .!= True+ allowVideos <- o .:? "allow_videos" .!= True+ allowPolls <- o .:? "allow_polls" .!= True+ allowVideoGIFs <- o .:? "allow_videogifs" .!= True+ freeFormReports <- o .: "free_form_reports"+ restrictPosting <- o .: "restrict_posting"+ restrictCommenting <- o .: "restrict_commenting"+ linkFlairEnabled <- o .: "link_flair_enabled"+ canAssignLinkFlair <- o .:? "can_assign_link_flair"+ canAssignUserFlair <- o .:? "can_assign_user_flair"+ spoilersEnabled <- o .:? "spoilers_enabled"+ pure Subreddit { .. } -- Dummy instance so that @Listing ... Subreddit@ can work with convenience -- actions@@ -148,8 +215,11 @@ -- | Unique site-wide identifier for a subreddit newtype SubredditID = SubredditID Text deriving stock ( Show, Generic )- deriving newtype ( Eq, FromJSON )+ deriving newtype ( Eq ) +instance FromJSON SubredditID where+ parseJSON = withText "SubredditID" $ coerce . dropTypePrefix SubredditKind+ instance Thing SubredditID where fullname (SubredditID sid) = prependType SubredditKind sid @@ -306,4 +376,3 @@ "notAllowed" -> pure BodyNotAllowed "none" -> pure NoRestriction _ -> mempty-
src/Network/Reddit/Types/Widget.hs view
@@ -103,7 +103,7 @@ import Data.Text ( Text ) import qualified Data.Text as T -import GHC.Exts ( IsList(fromList, Item) )+import GHC.Exts ( IsList(fromList) ) import GHC.Generics ( Generic(Rep) ) import Lens.Micro@@ -909,12 +909,6 @@ defaultWidgetModifier = \case "widgetID" -> "id" s -> s---- Parses a container of values that may be missing from the JSON, in which case--- it returns @mempty@ as a default value-fromOptional- :: (FromJSON (Item b), IsList b, Monoid b) => Object -> Text -> Parser b-fromOptional o fld = maybe mempty fromList <$> optional (o .: fld) withWidgetKind :: WidgetType -> [Char] -> (Value -> Parser a) -> Value -> Parser a
src/Network/Reddit/User.hs view
@@ -3,6 +3,7 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE TypeApplications #-}+{-# LANGUAGE ViewPatterns #-} -- | -- Module : Network.Reddit.User@@ -29,7 +30,8 @@ , getUserGilded , getUserSaved , getUserMultireddits- -- * User @Listing@s and summaries+ , gildUser+ -- ** User @Listing@s and summaries -- | These actions return @Listing@s for special user subreddits, -- user accounts, or 'UserSummary's for existing user IDs , getNewUsers@@ -39,14 +41,18 @@ , getUserSummary -- * Types , module M+ , Trophy ) where +import Control.Monad ( unless ) import Control.Monad.Catch ( MonadThrow(throwM) ) import Data.Aeson ( FromJSON ) import qualified Data.Foldable as F import Data.Generics.Wrapped ( wrappedTo )+import Data.Ix ( Ix(inRange) ) import Data.List.Split ( chunksOf )+import Data.Maybe ( fromMaybe ) import Data.Sequence ( Seq((:<|)) ) import Data.Text ( Text ) @@ -64,12 +70,12 @@ , Karma(Karma) , MediaPreference(..) , Preferences(Preferences)- , Trophy(Trophy) , UserID(UserID) , UserSummary(UserSummary) , Username , mkUsername )+import Network.Reddit.Types.Award import Network.Reddit.Types.Comment import Network.Reddit.Types.Item import Network.Reddit.Types.Multireddit@@ -166,6 +172,23 @@ getUserMultireddits uname = runAction defaultAPIAction { pathSegments = [ "api", "multi", "user", toUrlPiece uname ] }++-- | Give the user Reddit gold, optionally specifying the duration+gildUser :: MonadReddit m+ => Maybe Word+ -- ^ Defaults to 1 when @Nothing@. Must be between 1 and 36+ -> Username+ -> m ()+gildUser (fromMaybe 1 -> months) uname = do+ unless (inRange (1, 36) months) . throwM+ $ InvalidRequest "Duration must be between 1 and 36"+ runAction_ defaultAPIAction+ { pathSegments =+ [ "api", "v1", "gold", "give", toUrlPiece uname ]+ , method = POST+ , requestData =+ mkTextFormData [ ("months", toQueryParam months) ]+ } -- | Get a @Listing@ of special user subreddits, sorted on creation date (newest -- first)
src/Network/Reddit/Utils.hs view
@@ -26,6 +26,7 @@ , mkTextForm , mkTextFormData , submissionIDFromURL+ , commentIDFromURL , subAPIPath , subAboutPath , textObject@@ -43,21 +44,25 @@ import Data.Aeson ( eitherDecode ) import Data.ByteString ( ByteString ) import qualified Data.ByteString.Char8 as C8+import Data.Coerce ( coerce ) import Data.Containers.ListUtils ( nubOrd ) import qualified Data.Foldable as F-import Data.Generics.Wrapped ( wrappedFrom, wrappedTo ) import Data.List ( (\\) ) import qualified Data.Text as T import Data.Text ( Text ) import qualified Data.Text.Encoding as T +import Lens.Micro+ import Network.Reddit.Types+import Network.Reddit.Types.Comment import Network.Reddit.Types.Submission import Network.Reddit.Types.Subreddit import URI.ByteString ( Authority(..) , URIRef(URI, uriPath, uriAuthority)+ , hostBSL , laxURIParserOptions , parseURI )@@ -114,37 +119,53 @@ -- | Parse a 'SubmissionID' from a Reddit URL submissionIDFromURL :: MonadThrow m => Text -> m SubmissionID-submissionIDFromURL url = case parsed of- Left _ -> invalidURL "Invalid URL provided"- Right URI { .. }- | Just Authority { authorityHost } <- uriAuthority --- -> case wrappedTo authorityHost of- host- | host `elem` [ "reddit.com", "www.reddit.com" ] --- -> case splitPath uriPath of- [ "gallery", sid ] -> pure $ mkID sid- ("comments" : sid : _) -> pure $ mkID sid- ("r" : _ : "comments" : sid : _) ->- pure $ mkID sid- _ -> invalidURL- $ mconcat [ "Path must be one of "- , "/r/<SUBREDDIT>/comments/<ID>/<NAME>/, "- , "/gallery/<ID>, or /comments/<ID>/"- ]+submissionIDFromURL = idFromURL f g+ where+ f = \case+ "gallery" : sid : _ -> mkID sid+ "comments" : sid : _ -> mkID sid+ "r" : _ : "comments" : sid : _ -> mkID sid+ _ -> throwM . InvalidRequest+ $ mconcat [ "Path must be one of "+ , "/r/<SUBREDDIT>/comments/<ID>/<NAME>/, "+ , "/gallery/<ID>, or /comments/<ID>/"+ ] - | host == "redd.it" -> case splitPath uriPath of- [ sid ] -> pure $ mkID sid- _ -> invalidURL "Path may only contain /<ID>"+ g = \case+ sid : _ -> mkID sid+ _ -> throwM . InvalidRequest $ "Path may only contain /<ID>" - | otherwise -> invalidURL "Unrecognized host"- | otherwise -> invalidURL "URL authority not present or unrecognized"+ mkID = pure . coerce++-- | Parse a 'SubmissionID' from a Reddit URL+commentIDFromURL :: MonadThrow m => Text -> m CommentID+commentIDFromURL = idFromURL f g where- parsed = parseURI laxURIParserOptions $ T.encodeUtf8 url+ f = \case+ "r" : _ : "comments" : _ : _ : cid : _ -> mkID cid+ _ -> throwM . InvalidRequest+ $ "Path must be /r/<SUBREDDIT>/comments/<SID>/<NAME>/<ID>" - invalidURL = throwM . InvalidRequest+ g = const . throwM . InvalidRequest+ $ "Cannot get comment ID from redd.it hosts" - mkID = wrappedFrom . T.decodeUtf8+ mkID = pure . coerce +idFromURL :: MonadThrow m+ => ([PathSegment] -> m a) -- for various reddit.com hosts+ -> ([PathSegment] -> m a) -- for redd.it host+ -> Text+ -> m a+idFromURL f g url = splitURL url >>= \case+ (host, ps)+ | host `elem` hosts -> f ps+ | host == "redd.it" -> g ps+ | otherwise -> invalidURL "Unrecognized host"+ where+ hosts = [ "reddit.com", "www.reddit.com", "old.reddit.com" ]++ invalidURL = throwM . InvalidRequest+ -- | Get the API path for a subreddit given its 'SubredditName' subAPIPath :: SubredditName -> PathSegment -> [PathSegment] subAPIPath sname path = [ "r", toUrlPiece sname, "api", path ]@@ -181,8 +202,9 @@ splitURL url = case parseURI laxURIParserOptions $ T.encodeUtf8 url of Right URI { .. } | Just Authority { authorityHost } <- uriAuthority --- ->- pure (wrappedTo authorityHost, T.decodeUtf8 <$> splitPath uriPath)+ -> pure ( authorityHost ^. hostBSL+ , T.decodeUtf8 <$> splitPath uriPath+ ) | otherwise -> invalidURL Left _ -> invalidURL where
tests/Main.hs view
@@ -8,6 +8,7 @@ import Network.Reddit.Types import Network.Reddit.Types.Account+import Network.Reddit.Types.Award import Network.Reddit.Types.Comment import Network.Reddit.Types.Emoji import Network.Reddit.Types.Flair@@ -34,6 +35,7 @@ , decodeWidgetTypes , decodeEmojiTypes , decodeLiveTypes+ , decodeAwardTypes ] {- HLINT ignore "Redundant do"-}@@ -230,6 +232,14 @@ liveContributors <- eitherDecodeFileStrict' @LiveContributorList $ typesDataPath "live-contributor-list.json" liveContributors `shouldSatisfy` isRight++decodeAwardTypes :: IO ()+decodeAwardTypes = hspec $ do+ describe "Network.Reddit.Types.Award" $ do+ it "decodes Awarding" $ do+ award <- eitherDecodeFileStrict' @[Awarding]+ $ typesDataPath "awarding.json"+ award `shouldSatisfy` isRight typesDataPath :: FilePath -> FilePath typesDataPath = (<>) "./tests/data/types/"
+ tests/data/types/awarding.json view
@@ -0,0 +1,170 @@+[+ {+ "giver_coin_reward": null,+ "subreddit_id": null,+ "is_new": false,+ "days_of_drip_extension": 0,+ "coin_price": 125,+ "id": "award_5f123e3d-4f48-42f4-9c11-e98b566d5897",+ "penny_donate": null,+ "award_sub_type": "GLOBAL",+ "coin_reward": 0,+ "icon_url": "https://i.redd.it/award_images/t5_22cerq/5izbv4fn0md41_Wholesome.png",+ "days_of_premium": 0,+ "tiers_by_required_awardings": null,+ "resized_icons": [+ {+ "url": "https://preview.redd.it/award_images/t5_22cerq/5izbv4fn0md41_Wholesome.png?width=16&height=16&auto=webp&s=92932f465d58e4c16b12b6eac4ca07d27e3d11c0",+ "width": 16,+ "height": 16+ },+ {+ "url": "https://preview.redd.it/award_images/t5_22cerq/5izbv4fn0md41_Wholesome.png?width=32&height=32&auto=webp&s=d11484a208d68a318bf9d4fcf371171a1cb6a7ef",+ "width": 32,+ "height": 32+ },+ {+ "url": "https://preview.redd.it/award_images/t5_22cerq/5izbv4fn0md41_Wholesome.png?width=48&height=48&auto=webp&s=febdf28b6f39f7da7eb1365325b85e0bb49a9f63",+ "width": 48,+ "height": 48+ },+ {+ "url": "https://preview.redd.it/award_images/t5_22cerq/5izbv4fn0md41_Wholesome.png?width=64&height=64&auto=webp&s=b4406a2d88bf86fa3dc8a45aacf7e0c7bdccc4fb",+ "width": 64,+ "height": 64+ },+ {+ "url": "https://preview.redd.it/award_images/t5_22cerq/5izbv4fn0md41_Wholesome.png?width=128&height=128&auto=webp&s=19555b13e3e196b62eeb9160d1ac1d1b372dcb0b",+ "width": 128,+ "height": 128+ }+ ],+ "icon_width": 2048,+ "static_icon_width": 2048,+ "start_date": null,+ "is_enabled": true,+ "awardings_required_to_grant_benefits": null,+ "description": "When you come across a feel-good thing.",+ "end_date": null,+ "subreddit_coin_reward": 0,+ "count": 1,+ "static_icon_height": 2048,+ "name": "Wholesome",+ "resized_static_icons": [+ {+ "url": "https://preview.redd.it/award_images/t5_22cerq/5izbv4fn0md41_Wholesome.png?width=16&height=16&auto=webp&s=92932f465d58e4c16b12b6eac4ca07d27e3d11c0",+ "width": 16,+ "height": 16+ },+ {+ "url": "https://preview.redd.it/award_images/t5_22cerq/5izbv4fn0md41_Wholesome.png?width=32&height=32&auto=webp&s=d11484a208d68a318bf9d4fcf371171a1cb6a7ef",+ "width": 32,+ "height": 32+ },+ {+ "url": "https://preview.redd.it/award_images/t5_22cerq/5izbv4fn0md41_Wholesome.png?width=48&height=48&auto=webp&s=febdf28b6f39f7da7eb1365325b85e0bb49a9f63",+ "width": 48,+ "height": 48+ },+ {+ "url": "https://preview.redd.it/award_images/t5_22cerq/5izbv4fn0md41_Wholesome.png?width=64&height=64&auto=webp&s=b4406a2d88bf86fa3dc8a45aacf7e0c7bdccc4fb",+ "width": 64,+ "height": 64+ },+ {+ "url": "https://preview.redd.it/award_images/t5_22cerq/5izbv4fn0md41_Wholesome.png?width=128&height=128&auto=webp&s=19555b13e3e196b62eeb9160d1ac1d1b372dcb0b",+ "width": 128,+ "height": 128+ }+ ],+ "icon_format": null,+ "icon_height": 2048,+ "penny_price": null,+ "award_type": "global",+ "static_icon_url": "https://i.redd.it/award_images/t5_22cerq/5izbv4fn0md41_Wholesome.png"+ },+ {+ "giver_coin_reward": null,+ "subreddit_id": "t5_2qzb6",+ "is_new": false,+ "days_of_drip_extension": 0,+ "coin_price": 2000,+ "id": "award_48b83aa4-a3f1-4ea7-9c95-558a6252e773",+ "penny_donate": null,+ "award_sub_type": "COMMUNITY",+ "coin_reward": 0,+ "icon_url": "https://i.redd.it/award_images/t5_2qzb6/n8h85cxvcw731_StarofExcellence.png",+ "days_of_premium": 0,+ "tiers_by_required_awardings": null,+ "resized_icons": [+ {+ "url": "https://preview.redd.it/award_images/t5_2qzb6/n8h85cxvcw731_StarofExcellence.png?width=16\\u0026height=16\\u0026auto=webp\\u0026s=2731c2b6c61a6aeeef7ca07cf02ed3afd581f706",+ "width": 16,+ "height": 16+ },+ {+ "url": "https://preview.redd.it/award_images/t5_2qzb6/n8h85cxvcw731_StarofExcellence.png?width=32\\u0026height=32\\u0026auto=webp\\u0026s=bd98c9c8a0d6f2a9669d341423b632931ec9053e",+ "width": 32,+ "height": 32+ },+ {+ "url": "https://preview.redd.it/award_images/t5_2qzb6/n8h85cxvcw731_StarofExcellence.png?width=48\\u0026height=48\\u0026auto=webp\\u0026s=fce2d3366e64c6a1cc71f1e9fc6006601fa49a5b",+ "width": 48,+ "height": 48+ },+ {+ "url": "https://preview.redd.it/award_images/t5_2qzb6/n8h85cxvcw731_StarofExcellence.png?width=64\\u0026height=64\\u0026auto=webp\\u0026s=f2d6c300dfffec549b0ae2019c778c5074831725",+ "width": 64,+ "height": 64+ },+ {+ "url": "https://preview.redd.it/award_images/t5_2qzb6/n8h85cxvcw731_StarofExcellence.png?width=128\\u0026height=128\\u0026auto=webp\\u0026s=65b616a93309199b6f76b1e3d3b6b162bc7aa5c0",+ "width": 128,+ "height": 128+ }+ ],+ "icon_width": 512,+ "static_icon_width": 512,+ "start_date": null,+ "is_enabled": true,+ "awardings_required_to_grant_benefits": null,+ "description": "Shows the Star of Excellence Award and grants %{coin_symbol}400 Coins to the community. Exclusive to this community.",+ "end_date": null,+ "subreddit_coin_reward": 400,+ "count": 1,+ "static_icon_height": 512,+ "name": "Star of Excellence",+ "resized_static_icons": [+ {+ "url": "https://preview.redd.it/award_images/t5_2qzb6/n8h85cxvcw731_StarofExcellence.png?width=16\\u0026height=16\\u0026auto=webp\\u0026s=2731c2b6c61a6aeeef7ca07cf02ed3afd581f706",+ "width": 16,+ "height": 16+ },+ {+ "url": "https://preview.redd.it/award_images/t5_2qzb6/n8h85cxvcw731_StarofExcellence.png?width=32\\u0026height=32\\u0026auto=webp\\u0026s=bd98c9c8a0d6f2a9669d341423b632931ec9053e",+ "width": 32,+ "height": 32+ },+ {+ "url": "https://preview.redd.it/award_images/t5_2qzb6/n8h85cxvcw731_StarofExcellence.png?width=48\\u0026height=48\\u0026auto=webp\\u0026s=fce2d3366e64c6a1cc71f1e9fc6006601fa49a5b",+ "width": 48,+ "height": 48+ },+ {+ "url": "https://preview.redd.it/award_images/t5_2qzb6/n8h85cxvcw731_StarofExcellence.png?width=64\\u0026height=64\\u0026auto=webp\\u0026s=f2d6c300dfffec549b0ae2019c778c5074831725",+ "width": 64,+ "height": 64+ },+ {+ "url": "https://preview.redd.it/award_images/t5_2qzb6/n8h85cxvcw731_StarofExcellence.png?width=128\\u0026height=128\\u0026auto=webp\\u0026s=65b616a93309199b6f76b1e3d3b6b162bc7aa5c0",+ "width": 128,+ "height": 128+ }+ ],+ "icon_format": null,+ "icon_height": 512,+ "penny_price": null,+ "award_type": "community",+ "static_icon_url": "https://i.redd.it/award_images/t5_2qzb6/n8h85cxvcw731_StarofExcellence.png"+ }+]
+ tests/data/types/awardings-summary.json view
@@ -0,0 +1,39 @@+{+ "subreddit_balance": 0,+ "treatment_tags": [],+ "coins": 0,+ "gildings": { "gid_1": 0, "gid_2": 0, "gid_3": 0 },+ "awarder_karma_received": 16,+ "all_awardings": [+ {+ "giver_coin_reward": null,+ "subreddit_id": null,+ "is_new": false,+ "days_of_drip_extension": 0,+ "coin_price": 150,+ "id": "award_f44611f1-b89e-46dc-97fe-892280b13b82",+ "penny_donate": null,+ "coin_reward": 0,+ "icon_url": "https://i.redd.it/award_images/t5_22cerq/klvxk1wggfd41_Helpful.png",+ "days_of_premium": 0,+ "icon_height": 2048,+ "tiers_by_required_awardings": null,+ "icon_width": 2048,+ "static_icon_width": 2048,+ "start_date": null,+ "is_enabled": true,+ "awardings_required_to_grant_benefits": null,+ "description": "Thank you stranger. Shows the award.",+ "end_date": null,+ "subreddit_coin_reward": 0,+ "count": 1,+ "static_icon_height": 2048,+ "name": "Helpful",+ "icon_format": null,+ "award_sub_type": "GLOBAL",+ "penny_price": null,+ "award_type": "global",+ "static_icon_url": "https://i.redd.it/award_images/t5_22cerq/klvxk1wggfd41_Helpful.png"+ }+ ]+}
tests/data/types/subreddit.json view
@@ -1,47 +1,100 @@ { "kind": "t5", "data": {- "banner_img": "",+ "user_flair_background_color": "", "submit_text_html": null,+ "restrict_posting": true, "user_is_banned": false,- "wiki_enabled": null,- "id": "2r0ij",- "user_is_contributor": false,- "submit_text": "",- "display_name": "<SUBREDDIT_NAME>",+ "free_form_reports": true,+ "wiki_enabled": true,+ "user_is_muted": false,+ "user_can_flair_in_sr": true,+ "display_name": "<SUBREDDIT>", "header_img": null,+ "title": "Title",+ "icon_size": null,+ "primary_color": "",+ "active_user_count": 8,+ "icon_img": null,+ "display_name_prefixed": "r/<SUBREDDIT>",+ "accounts_active": 8,+ "public_traffic": false,+ "subscribers": 1,+ "user_flair_richtext": [{ "e": "text", "t": "" }],+ "videostream_links_count": 0,+ "name": "t5_49n01",+ "quarantine": false,+ "hide_ads": false,+ "emojis_enabled": true,+ "advertiser_category": "",+ "public_description": "no",+ "comment_score_hide_mins": 0,+ "user_has_favorited": false,+ "user_flair_template_id": null,+ "community_icon": "",+ "banner_background_image": "https://styles.redditmedia.com/t5_49n01/styles/bannerBackgroundImage_m2ppq02m.jpg",+ "original_content_tag_enabled": false,+ "submit_text": "", "description_html": "",- "title": "<TITLE>",+ "spoilers_enabled": true,+ "header_title": "",+ "header_size": null,+ "user_flair_position": "right",+ "all_original_content": false,+ "collections_enabled": true,+ "is_enrolled_in_new_modmail": true,+ "key_color": "",+ "event_posts_enabled": true,+ "can_assign_user_flair": false,+ "created": 1503566715.0,+ "wls": null,+ "show_media_preview": true,+ "submission_type": "any",+ "user_is_subscriber": false,+ "disable_contributor_requests": false,+ "allow_videogifs": true,+ "user_flair_type": "richtext",+ "allow_polls": true, "collapse_deleted_comments": false,- "public_description": "",+ "coins": 0,+ "emojis_custom_size": null,+ "public_description_html": "",+ "allow_videos": true,+ "is_crosspostable_subreddit": true,+ "notification_level": null,+ "can_assign_link_flair": true,+ "has_menu_widget": false,+ "accounts_active_is_fuzzed": false,+ "submit_text_label": "",+ "link_flair_position": "left",+ "user_sr_flair_enabled": true,+ "user_flair_enabled_in_sr": true,+ "allow_chat_post_creation": false,+ "allow_discovery": false,+ "user_sr_theme_enabled": true,+ "link_flair_enabled": true,+ "subreddit_type": "restricted",+ "suggested_comment_sort": null,+ "banner_img": null,+ "user_flair_text": "",+ "banner_background_color": "",+ "show_media": true,+ "id": "49n01",+ "user_is_moderator": true, "over18": false,- "public_description_html": null,- "icon_size": [256, 256],- "suggested_comment_sort": "qa",- "icon_img": "",- "header_title": null, "description": "",- "user_is_muted": false,- "submit_link_label": null,- "accounts_active": null,- "public_traffic": false,- "header_size": null,- "subscribers": 11755132,- "submit_text_label": null,+ "is_chat_post_feature_enabled": true,+ "submit_link_label": "",+ "user_flair_text_color": "dark",+ "restrict_commenting": false,+ "user_flair_css_class": "",+ "allow_images": true, "lang": "en",- "key_color": "#ff4500",- "name": "t5_2r0ij",- "created": 1245284901.0,- "url": "/r/<SUBREDDIT_NAME>/",- "quarantine": false,- "hide_ads": false,- "created_utc": 1245256101.0,+ "whitelist_status": null,+ "url": "/r/<SUBREDDIT>/",+ "created_utc": 1503537915.0, "banner_size": null,- "user_is_moderator": false,- "user_sr_theme_enabled": true,- "comment_score_hide_mins": 0,- "subreddit_type": "restricted",- "submission_type": "any",- "user_is_subscriber": true+ "mobile_banner_image": "",+ "user_is_contributor": false } }