{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE StrictData #-} {-# LANGUAGE TypeFamilies #-} -- | -- Module : Network.Reddit.Types.Item -- Copyright : (c) 2021 Rory Tyler Hayford -- License : BSD-3-Clause -- Maintainer : rory.hayford@protonmail.com -- Stability : experimental -- Portability : GHC -- module Network.Reddit.Types.Item ( Item(..) , ItemID(..) , PostedItem , Vote(..) , Report , mkReport ) where import Control.Monad.Catch ( MonadThrow(throwM) ) import Data.Aeson ( (.:) , FromJSON(..) , Options(sumEncoding) , SumEncoding(UntaggedValue) , Value(Object) , defaultOptions , genericParseJSON , withObject ) import Data.Text ( Text ) import qualified Data.Text as T import GHC.Generics ( Generic ) import Network.Reddit.Types.Comment import Network.Reddit.Types.Internal import Network.Reddit.Types.Submission import Web.HttpApiData ( ToHttpApiData ) -- | Wraps either a 'CommentID' or a 'SubmissionID'. This is required to use -- 'Item's with 'Paginator's data ItemID = CommentItemID CommentID | SubmissionItemID SubmissionID deriving stock ( Show, Eq, Generic ) instance Thing ItemID where fullname (CommentItemID cid) = fullname cid fullname (SubmissionItemID sid) = fullname sid instance FromJSON ItemID where parseJSON = genericParseJSON defaultOptions { sumEncoding = UntaggedValue } -- | Certain endpoints will return either 'Comment's or a 'Submission's, or both data Item = CommentItem Comment | SubmissionItem Submission deriving stock ( Show, Eq, Generic ) instance Paginable Item where type PaginateOptions Item = ItemOpts type PaginateThing Item = ItemID defaultOpts = defaultItemOpts getFullname = \case CommentItem Comment { commentID } -> CommentItemID commentID SubmissionItem Submission { submissionID } -> SubmissionItemID submissionID instance FromJSON Item where parseJSON = withObject "Item" $ \o -> o .: "kind" >>= \case x | x == CommentKind -> CommentItem <$> parseJSON (Object o) | x == SubmissionKind -> SubmissionItem <$> parseJSON (Object o) | otherwise -> mempty -- | Wrapper for parsing new 'Item's, 'Comment's, or 'Submission's that are returned -- after requesting their creation newtype PostedItem a = PostedItem a deriving stock ( Show, Generic ) deriving newtype instance Eq a => Eq (PostedItem a) instance FromJSON (PostedItem Comment) where parseJSON = withObject "PostedItem Comment" $ \o -> postedCommentP =<< ((.: "things") =<< (.: "data") =<< o .: "json") where postedCommentP [ Object o ] = PostedItem <$> (commentP =<< o .: "data") postedCommentP _ = mempty instance FromJSON (PostedItem Submission) where parseJSON = withObject "PostedItem Submission" $ \o -> postedSubmissionP =<< ((.: "things") =<< (.: "data") =<< o .: "json") where postedSubmissionP [ Object o ] = PostedItem <$> (submissionP =<< o .: "data") postedSubmissionP _ = mempty instance FromJSON (PostedItem Item) where parseJSON = withObject "PostedItem Item" $ \o -> postedItemP =<< ((.: "things") =<< (.: "data") =<< o .: "json") where postedItemP [ Object o ] = (o .: "kind") >>= \case k | k == CommentKind -> PostedItem . CommentItem <$> (commentP =<< o .: "data") | k == SubmissionKind -> PostedItem . SubmissionItem <$> (submissionP =<< o .: "data") | otherwise -> mempty postedItemP _ = mempty -- | The direction in which to vote data Vote = Downvote | Unvote | Upvote deriving stock ( Show, Eq, Generic, Ord ) -- | The reason for issuing a report. The length of the contained text must be <= -- 100 characters newtype Report = Report Text deriving stock ( Show, Generic ) deriving newtype ( Eq, ToHttpApiData ) -- | Smart constructor for 'Report's, which may be no longer than 100 characters -- in length mkReport :: MonadThrow m => Text -> m Report mkReport txt | T.length txt > 100 = throwM $ OtherError "mkReport: length must not exceed 100 characters" | otherwise = pure $ Report txt