packages feed

heddit-0.0.1: src/Network/Reddit/Item.hs

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeApplications #-}

-- |
-- Module      : Network.Reddit.Item
-- Copyright   : (c) 2021 Rory Tyler Hayford
-- License     : BSD-3-Clause
-- Maintainer  : rory.hayford@protonmail.com
-- Stability   : experimental
-- Portability : GHC
--
-- Actions with operate on 'Item's, which can be either 'Comment's or
-- 'Submission's
--
module Network.Reddit.Item
    (  -- * Actions
      delete
    , reply
    , edit
    , vote
    , report
    , save
    , unsave
    , setInboxReplies
    , getGildedItems
      -- * Types
    , module M
    ) where

import           Data.Generics.Wrapped          ( wrappedTo )

import           Lens.Micro

import           Network.Reddit.Internal
import           Network.Reddit.Types
import           Network.Reddit.Types.Comment
import           Network.Reddit.Types.Item      ( PostedItem )
import           Network.Reddit.Types.Item      as M
                 ( Item(..)
                 , ItemID(..)
                 , Report
                 , Vote(..)
                 , mkReport
                 )
import           Network.Reddit.Types.Subreddit
import           Network.Reddit.Utils

import           Web.HttpApiData
                 ( ToHttpApiData(toQueryParam, toUrlPiece)
                 )

-- | Delete an 'Item'
delete :: MonadReddit m => ItemID -> m ()
delete iid =
    runAction_ defaultAPIAction
               { pathSegments = [ "api", "del" ]
               , method       = POST
               , requestData  = mkTextFormData [ ("id", fullname iid) ]
               }

-- | Leave a comment in reply to an 'Item', which can be markdown-formatted. This
-- will return the newly created 'Comment' upon success
reply :: MonadReddit m => ItemID -> Body -> m Comment
reply iid txt = runAction @(PostedItem Comment) r <&> wrappedTo
  where
    r = defaultAPIAction
        { pathSegments = [ "api", "comment" ]
        , method       = POST
        , requestData  = mkTextFormData [ ("thing_id", fullname iid)
                                        , ("text", txt)
                                        , ("api_type", "json")
                                        ]
        }

-- | Edit some item, given its 'ItemID'. The return value will be wrapped in an
-- 'Item' constructor, since it can be either a 'Comment' or 'Submission'
edit :: MonadReddit m => ItemID -> Body -> m Item
edit iid txt = runAction @(PostedItem Item) r <&> wrappedTo
  where
    r = defaultAPIAction
        { pathSegments = [ "api", "editusertext" ]
        , method       = POST
        , requestData  = mkTextFormData [ ("thing_id", fullname iid)
                                        , ("text", txt)
                                        , ("api_type", "json")
                                        ]
        }

-- | Submit a vote. Be careful! Reddit views bot-based vote manipulation as a
-- serious violation
vote :: MonadReddit m => Vote -> ItemID -> m ()
vote v iid =
    runAction defaultAPIAction
              { pathSegments = [ "api", "vote" ]
              , method       = POST
              , requestData  =
                    mkTextFormData [ ("id", fullname iid), ("dir", voteDir) ]
              }
  where
    voteDir = case v of
        Downvote -> "-1"
        Unvote   -> "0"
        Upvote   -> "1"

-- | Report an item, which brings it to the attention of the subreddit moderators
report :: MonadReddit m => Report -> ItemID -> m ()
report r iid =
    runAction_ defaultAPIAction
               { pathSegments = [ "api", "report" ]
               , method       = POST
               , requestData  = mkTextFormData [ ("id", fullname iid)
                                               , ("reason", toQueryParam r)
                                               ]
               }

-- | Save an item
save :: MonadReddit m => ItemID -> m ()
save = saveOrUnsave "save"

-- | Unsave an item
unsave :: MonadReddit m => ItemID -> m ()
unsave = saveOrUnsave "unsave"

saveOrUnsave :: MonadReddit m => PathSegment -> ItemID -> m ()
saveOrUnsave path iid =
    runAction_ defaultAPIAction
               { pathSegments = [ "api", path ]
               , method       = POST
               , requestData  = mkTextFormData [ ("id", fullname iid) ]
               }

-- | Enable or disable inbox replies for an item given its 'ItemID'
setInboxReplies :: MonadReddit m => Bool -> ItemID -> m ()
setInboxReplies p iid =
    runAction_ defaultAPIAction
               { pathSegments = [ "api", "sendreplies" ]
               , requestData  = mkTextFormData [ ("id", fullname iid)
                                               , ("state", toQueryParam p)
                                               ]
               }

-- | Get a @Listing@ of 'Item's that have been gilded
getGildedItems :: MonadReddit m
               => SubredditName
               -> Paginator ItemID Item
               -> m (Listing ItemID Item)
getGildedItems sname paginator =
    runAction defaultAPIAction
              { pathSegments = [ "r", toUrlPiece sname, "gilded" ]
              , requestData  = paginatorToFormData paginator
              }