{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} -- | -- Module : Network.Reddit.Types.Wiki -- Copyright : (c) 2021 Rory Tyler Hayford -- License : BSD-3-Clause -- Maintainer : rory.hayford@protonmail.com -- Stability : experimental -- Portability : GHC -- module Network.Reddit.Types.Wiki ( WikiPage(..) , WikiRevisionID(WikiRevisionID) , WikiPageName , mkWikiPageName , WikiPageListing , WikiRevision(..) , WikiPageSettings(..) , WikiPermLevel(..) ) where import Data.Aeson ( (.:) , (.:?) , Array , FromJSON(..) , withArray , withObject , withScientific , withText ) import Data.Coerce ( coerce ) import Data.Sequence ( Seq ) import Data.Text ( Text ) import qualified Data.Text as T import Data.Time ( UTCTime ) import Data.Traversable ( for ) import GHC.Exts ( IsList(toList, fromList) ) import GHC.Generics ( Generic ) import Network.Reddit.Types.Internal import Web.HttpApiData ( ToHttpApiData(..) ) -- | An individual subreddit wikipage along with its revision information data WikiPage = WikiPage { -- | The page content, as markdown content :: Body , contentHTML :: Body , revisionBy :: Username , revisionDate :: UTCTime -- | Indicates whether the authenticated user -- can revise this particular wikipage , mayRevise :: Bool } deriving stock ( Show, Eq, Generic ) instance FromJSON WikiPage where parseJSON = withKind WikiPageKind "WikiPage" $ \o -> WikiPage <$> o .: "content_md" <*> o .: "content_html" <*> ((.: "name") =<< (.: "data") =<< o .: "revision_by") <*> (integerToUTC <$> o .: "revision_date") <*> o .: "may_revise" -- | The name of an individual wiki page. The name forms part of the URL, and -- should not contain spaces or uppercase characters newtype WikiPageName = WikiPageName Text deriving stock ( Show, Generic ) deriving newtype ( Eq, FromJSON, ToHttpApiData ) -- | Smart constructor for 'WikiPageName's. Lowercases the contained text, and -- replaces each space with a single underscore mkWikiPageName :: Text -> WikiPageName mkWikiPageName = coerce . T.toLower . T.replace " " "_" -- | Information regarding a single 'WikiPage' revision data WikiRevision = WikiRevision { revisionID :: WikiRevisionID , page :: WikiPageName , timestamp :: UTCTime , author :: Username -- | The reason for editing the page, if any , reason :: Maybe Text -- | If the revision has been hidden , hidden :: Maybe Bool } deriving stock ( Show, Eq, Generic ) instance FromJSON WikiRevision where parseJSON = withObject "WikiRevision" $ \o -> WikiRevision <$> o .: "id" <*> o .: "page" <*> (integerToUTC <$> o .: "timestamp") <*> ((.: "name") =<< (.: "data") =<< o .: "author") <*> (maybe (pure Nothing) nothingTxtNull =<< o .:? "reason") <*> o .:? "revision_hidden" -- The endpoints that list revisions are a @Listing@, but there are no additional -- options that can be passed to them. Giving this dummy instance at least allows -- using a @Listing ... WikiRevision@ with existing convenience functions instance Paginable WikiRevision where type PaginateOptions WikiRevision = () type PaginateThing WikiRevision = WikiRevisionID defaultOpts = () optsToForm _ = mempty getFullname WikiRevision { revisionID } = revisionID -- | ID for a wikipage revision newtype WikiRevisionID = WikiRevisionID Text deriving stock ( Show, Generic ) deriving newtype ( Eq, ToHttpApiData ) instance FromJSON WikiRevisionID where parseJSON = withText "WikiRevisionID" (breakOnType "WikiRevision") instance Thing WikiRevisionID where fullname (WikiRevisionID r) = "WikiRevision_" <> r -- | Wrapper for listings of @WikiPage@s, which have their own @RedditKind@ newtype WikiPageListing = WikiPageListing (Seq WikiPageName) deriving stock ( Show, Generic ) instance FromJSON WikiPageListing where parseJSON = withKind @Array WikiPageListingKind "WikiPageListing" $ fmap (WikiPageListing . fromList) . traverse parseJSON . toList -- | The settings that moderators have configured for a single 'WikiPage' data WikiPageSettings = WikiPageSettings { permlevel :: WikiPermLevel , listed :: Bool , allowedEditors :: Seq Username } deriving stock ( Show, Eq, Generic ) instance FromJSON WikiPageSettings where parseJSON = withKind WikiPageSettingsKind "WikiPageSettings" $ \o -> WikiPageSettings <$> o .: "permlevel" <*> o .: "listed" <*> (fromList <$> (editorsP =<< o .: "editors")) where editorsP = withArray "[User]" $ \as -> for (toList as) . withObject "User" $ \o -> (.: "name") =<< o .: "data" -- | Editing permission level configured for a single 'WikiPage' data WikiPermLevel = FollowWikiSettings | ApprovedEditorsOnly | ModEditsOnly deriving stock ( Show, Eq, Generic, Ord ) instance FromJSON WikiPermLevel where parseJSON = withScientific "WikiPermLevel" $ \case 0.0 -> pure FollowWikiSettings 1.0 -> pure ApprovedEditorsOnly 2.0 -> pure ModEditsOnly _ -> mempty instance ToHttpApiData WikiPermLevel where toQueryParam = \case FollowWikiSettings -> "0" ApprovedEditorsOnly -> "1" ModEditsOnly -> "2"