{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE TypeApplications #-}

-- |
-- Module      : Network.Reddit.Live
-- Copyright   : (c) 2021 Rory Tyler Hayford
-- License     : BSD-3-Clause
-- Maintainer  : rory.hayford@protonmail.com
-- Stability   : experimental
-- Portability : GHC
--
-- Actions for working with 'LiveThread's
--
module Network.Reddit.Live
    ( -- * Actions
      getLiveThread
    , getLiveInfo
    , getAllLiveInfo
    , getLiveUpdates
    , getLiveUpdate
    , getLiveDiscussions
    , getLiveContributors
    , reportLiveThread
    , createLiveThread
    , closeLiveThread
    , updateLiveThread
    , addLiveUpdate
    , strikeLiveUpdate
    , deleteLiveUpdate
      -- ** Live thread contribution
    , removeLiveContributor
    , removeLiveContributorByName
    , updateLiveContributor
    , abdicateLiveContributor
    , inviteLiveContributor
    , inviteLiveContributorWithPerms
    , revokeLiveInvitation
    , revokeLiveInvitationByName
      -- * Types
    , module M
    ) where

import           Control.Monad.Catch             ( MonadThrow(throwM) )

import qualified Data.Foldable                   as F
import           Data.Generics.Product           ( HasField(field) )
import           Data.Generics.Wrapped           ( wrappedTo )
import           Data.List.Split                 ( chunksOf )
import           Data.Sequence                   ( Seq((:<|)) )
import           Data.Traversable                ( for )

import           Lens.Micro

import           Network.Reddit.Internal
import           Network.Reddit.Types
import           Network.Reddit.Types.Account
import           Network.Reddit.Types.Live
import           Network.Reddit.Types.Live       as M
                 ( LiveContributor(LiveContributor)
                 , LivePermission(..)
                 , LiveReportType(..)
                 , LiveState(..)
                 , LiveThread(LiveThread)
                 , LiveThreadID(LiveThreadID)
                 , LiveUpdate(LiveUpdate)
                 , LiveUpdateEmbed(LiveUpdateEmbed)
                 , LiveUpdateID(LiveUpdateID)
                 , NewLiveThread
                 , PostableLiveThread(PostableLiveThread)
                 , UpdatedLiveThread
                 , liveThreadToPostable
                 , mkNewLiveThread
                 )
import           Network.Reddit.Types.Submission
import           Network.Reddit.User
import           Network.Reddit.Utils

import           Web.FormUrlEncoded              ( ToForm(toForm) )
import           Web.HttpApiData                 ( ToHttpApiData(..) )
import           Web.Internal.FormUrlEncoded     ( Form )

-- | Get the details on a single 'LiveThread' given its ID
getLiveThread :: MonadReddit m => LiveThreadID -> m LiveThread
getLiveThread :: LiveThreadID -> m LiveThread
getLiveThread LiveThreadID
ltid =
    APIAction LiveThread -> m LiveThread
forall a (m :: * -> *).
(MonadReddit m, FromJSON a) =>
APIAction a -> m a
runAction APIAction Any
forall a. APIAction a
defaultAPIAction
              { $sel:pathSegments:APIAction :: [PathSegment]
pathSegments = [PathSegment] -> [PathSegment]
liveThreadPath [ LiveThreadID -> PathSegment
forall a. ToHttpApiData a => a -> PathSegment
toQueryParam LiveThreadID
ltid, PathSegment
"about" ] }

-- | Get information about live threads corresponding to each of the
-- 'LiveThreadID's in the given container. Invalid IDs are silently discarded
-- by this endpoint
--
-- __Note__: This endpoint will only accept a maximum of 100 'LiveThreadID's. If
-- you would like to get all of the information for a larger number of 'LiveThread's
-- at once, see 'getAllLiveInfo'
getLiveInfo :: (MonadReddit m, Foldable t)
            => t LiveThreadID
            -> Paginator LiveThreadID LiveThread
            -> m (Listing LiveThreadID LiveThread)
getLiveInfo :: t LiveThreadID
-> Paginator LiveThreadID LiveThread
-> m (Listing LiveThreadID LiveThread)
getLiveInfo t LiveThreadID
ltids Paginator LiveThreadID LiveThread
paginator =
    APIAction (Listing LiveThreadID LiveThread)
-> m (Listing LiveThreadID LiveThread)
forall a (m :: * -> *).
(MonadReddit m, FromJSON a) =>
APIAction a -> m a
runAction APIAction Any
forall a. APIAction a
defaultAPIAction
              { $sel:pathSegments:APIAction :: [PathSegment]
pathSegments = [PathSegment] -> [PathSegment]
liveThreadPath [ PathSegment
"by_id", t LiveThreadID -> PathSegment
forall (t :: * -> *) a.
(Foldable t, ToHttpApiData a) =>
t a -> PathSegment
joinParams t LiveThreadID
ltids ]
              , $sel:requestData:APIAction :: WithData
requestData  = Paginator LiveThreadID LiveThread -> WithData
forall t a. (Thing t, Paginable a) => Paginator t a -> WithData
paginatorToFormData Paginator LiveThreadID LiveThread
paginator
              }

-- | Get all of the 'LiveThread's corresponding to a container of 'LiveThreadID's,
-- without a limit
getAllLiveInfo
    :: (MonadReddit m, Traversable t) => t LiveThreadID -> m (Seq LiveThread)
getAllLiveInfo :: t LiveThreadID -> m (Seq LiveThread)
getAllLiveInfo t LiveThreadID
ltids = ([Seq LiveThread] -> Seq LiveThread)
-> m [Seq LiveThread] -> m (Seq LiveThread)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Seq LiveThread] -> Seq LiveThread
forall a. Monoid a => [a] -> a
mconcat (m [Seq LiveThread] -> m (Seq LiveThread))
-> (([LiveThreadID] -> m (Seq LiveThread)) -> m [Seq LiveThread])
-> ([LiveThreadID] -> m (Seq LiveThread))
-> m (Seq LiveThread)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[LiveThreadID]]
-> ([LiveThreadID] -> m (Seq LiveThread)) -> m [Seq LiveThread]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
t a -> (a -> f b) -> f (t b)
for (t LiveThreadID -> [[LiveThreadID]]
forall e. t e -> [[e]]
chunked t LiveThreadID
ltids) (([LiveThreadID] -> m (Seq LiveThread)) -> m (Seq LiveThread))
-> ([LiveThreadID] -> m (Seq LiveThread)) -> m (Seq LiveThread)
forall a b. (a -> b) -> a -> b
$ \[LiveThreadID]
ls ->
    [LiveThreadID]
-> Paginator LiveThreadID LiveThread
-> m (Listing LiveThreadID LiveThread)
forall (m :: * -> *) (t :: * -> *).
(MonadReddit m, Foldable t) =>
t LiveThreadID
-> Paginator LiveThreadID LiveThread
-> m (Listing LiveThreadID LiveThread)
getLiveInfo [LiveThreadID]
ls Paginator LiveThreadID LiveThread
forall t a. Paginable a => Paginator t a
emptyPaginator { $sel:limit:Paginator :: Word
limit = Word
forall n. Num n => n
apiRequestLimit }
    m (Listing LiveThreadID LiveThread)
-> (Listing LiveThreadID LiveThread -> Seq LiveThread)
-> m (Seq LiveThread)
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> (Listing LiveThreadID LiveThread
-> Getting
     (Seq LiveThread) (Listing LiveThreadID LiveThread) (Seq LiveThread)
-> Seq LiveThread
forall s a. s -> Getting a s a -> a
^. forall s t a b. HasField "children" s t a b => Lens s t a b
forall (field :: Symbol) s t a b.
HasField field s t a b =>
Lens s t a b
field @"children")
  where
    chunked :: t e -> [[e]]
chunked = Int -> [e] -> [[e]]
forall e. Int -> [e] -> [[e]]
chunksOf Int
forall n. Num n => n
apiRequestLimit ([e] -> [[e]]) -> (t e -> [e]) -> t e -> [[e]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. t e -> [e]
forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList

-- | Get a @Listing@ of 'LiveUpdate's for the given live thread
getLiveUpdates :: MonadReddit m
               => LiveThreadID
               -> Paginator LiveUpdateID LiveUpdate
               -> m (Listing LiveUpdateID LiveUpdate)
getLiveUpdates :: LiveThreadID
-> Paginator LiveUpdateID LiveUpdate
-> m (Listing LiveUpdateID LiveUpdate)
getLiveUpdates LiveThreadID
ltid Paginator LiveUpdateID LiveUpdate
paginator =
    APIAction (Listing LiveUpdateID LiveUpdate)
-> m (Listing LiveUpdateID LiveUpdate)
forall a (m :: * -> *).
(MonadReddit m, FromJSON a) =>
APIAction a -> m a
runAction APIAction Any
forall a. APIAction a
defaultAPIAction
              { $sel:pathSegments:APIAction :: [PathSegment]
pathSegments = [ PathSegment
"live", LiveThreadID -> PathSegment
forall a. ToHttpApiData a => a -> PathSegment
toQueryParam LiveThreadID
ltid ]
              , $sel:requestData:APIAction :: WithData
requestData  = Paginator LiveUpdateID LiveUpdate -> WithData
forall t a. (Thing t, Paginable a) => Paginator t a -> WithData
paginatorToFormData Paginator LiveUpdateID LiveUpdate
paginator
              }

-- | Get a single 'LiveUpdate' for the given live thread
getLiveUpdate :: MonadReddit m => LiveThreadID -> LiveUpdateID -> m LiveUpdate
getLiveUpdate :: LiveThreadID -> LiveUpdateID -> m LiveUpdate
getLiveUpdate LiveThreadID
ltid LiveUpdateID
luid = do
    Listing { Seq LiveUpdate
$sel:children:Listing :: forall t a. Listing t a -> Seq a
children :: Seq LiveUpdate
children } <- APIAction (Listing LiveUpdateID LiveUpdate)
-> m (Listing LiveUpdateID LiveUpdate)
forall a (m :: * -> *).
(MonadReddit m, FromJSON a) =>
APIAction a -> m a
runAction @(Listing LiveUpdateID LiveUpdate) APIAction (Listing LiveUpdateID LiveUpdate)
forall a. APIAction a
r
    case Seq LiveUpdate
children of
        LiveUpdate
liveUpdate :<| Seq LiveUpdate
_ -> LiveUpdate -> m LiveUpdate
forall (f :: * -> *) a. Applicative f => a -> f a
pure LiveUpdate
liveUpdate
        Seq LiveUpdate
_                -> ClientException -> m LiveUpdate
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM
            (ClientException -> m LiveUpdate)
-> ClientException -> m LiveUpdate
forall a b. (a -> b) -> a -> b
$ PathSegment -> ClientException
InvalidResponse PathSegment
"getLiveUpdate: No matching live update found"
  where
    r :: APIAction a
r = APIAction Any
forall a. APIAction a
defaultAPIAction
        { $sel:pathSegments:APIAction :: [PathSegment]
pathSegments =
              [ PathSegment
"live", LiveThreadID -> PathSegment
forall a. ToHttpApiData a => a -> PathSegment
toQueryParam LiveThreadID
ltid, PathSegment
"updates", LiveUpdateID -> PathSegment
forall a. ToHttpApiData a => a -> PathSegment
toUrlPiece LiveUpdateID
luid ]
        }

-- | Get a @Listing@ of 'Submission's representing the discussions on the given
-- live thread
getLiveDiscussions :: MonadReddit m
                   => LiveThreadID
                   -> Paginator SubmissionID Submission
                   -> m (Listing SubmissionID Submission)
getLiveDiscussions :: LiveThreadID
-> Paginator SubmissionID Submission
-> m (Listing SubmissionID Submission)
getLiveDiscussions LiveThreadID
ltid Paginator SubmissionID Submission
paginator =
    APIAction (Listing SubmissionID Submission)
-> m (Listing SubmissionID Submission)
forall a (m :: * -> *).
(MonadReddit m, FromJSON a) =>
APIAction a -> m a
runAction APIAction Any
forall a. APIAction a
defaultAPIAction
              { $sel:pathSegments:APIAction :: [PathSegment]
pathSegments =
                    [PathSegment] -> [PathSegment]
liveThreadPath [ LiveThreadID -> PathSegment
forall a. ToHttpApiData a => a -> PathSegment
toQueryParam LiveThreadID
ltid, PathSegment
"discussions" ]
              , $sel:requestData:APIAction :: WithData
requestData  = Paginator SubmissionID Submission -> WithData
forall t a. (Thing t, Paginable a) => Paginator t a -> WithData
paginatorToFormData Paginator SubmissionID Submission
paginator
              }

-- | Get a list of contributors to the live thread
getLiveContributors
    :: MonadReddit m => LiveThreadID -> m (Seq LiveContributor)
getLiveContributors :: LiveThreadID -> m (Seq LiveContributor)
getLiveContributors LiveThreadID
ltid = APIAction LiveContributorList -> m LiveContributorList
forall a (m :: * -> *).
(MonadReddit m, FromJSON a) =>
APIAction a -> m a
runAction @LiveContributorList APIAction LiveContributorList
forall a. APIAction a
r m LiveContributorList
-> (LiveContributorList -> Seq LiveContributor)
-> m (Seq LiveContributor)
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> LiveContributorList -> Seq LiveContributor
forall s t a b. Wrapped s t a b => s -> a
wrappedTo
  where
    r :: APIAction a
r = APIAction Any
forall a. APIAction a
defaultAPIAction
        { $sel:pathSegments:APIAction :: [PathSegment]
pathSegments = [PathSegment] -> [PathSegment]
liveThreadPath [ LiveThreadID -> PathSegment
forall a. ToHttpApiData a => a -> PathSegment
toQueryParam LiveThreadID
ltid, PathSegment
"contributors" ]
        }

-- | Report the given live thread to Reddit admins with the provided reason
reportLiveThread :: MonadReddit m => LiveReportType -> LiveThreadID -> m ()
reportLiveThread :: LiveReportType -> LiveThreadID -> m ()
reportLiveThread LiveReportType
lrt LiveThreadID
ltid =
    APIAction () -> m ()
forall (m :: * -> *). MonadReddit m => APIAction () -> m ()
runAction_ APIAction Any
forall a. APIAction a
defaultAPIAction
               { $sel:pathSegments:APIAction :: [PathSegment]
pathSegments = [PathSegment] -> [PathSegment]
liveThreadPath [ LiveThreadID -> PathSegment
forall a. ToHttpApiData a => a -> PathSegment
toQueryParam LiveThreadID
ltid, PathSegment
"report" ]
               , $sel:method:APIAction :: Method
method       = Method
POST
               , $sel:requestData:APIAction :: WithData
requestData  = [(PathSegment, PathSegment)] -> WithData
mkTextFormData [ (PathSegment
"type", LiveReportType -> PathSegment
forall a. ToHttpApiData a => a -> PathSegment
toQueryParam LiveReportType
lrt)
                                               , (PathSegment
"api_type", PathSegment
"json")
                                               ]
               }

-- | Create a 'NewLiveThread', returning the 'LiveThread' upon success. Also see
-- 'mkNewLiveThread'
createLiveThread :: MonadReddit m => NewLiveThread -> m LiveThread
createLiveThread :: NewLiveThread -> m LiveThread
createLiveThread NewLiveThread
nlt = LiveThreadID -> m LiveThread
forall (m :: * -> *). MonadReddit m => LiveThreadID -> m LiveThread
getLiveThread
    (LiveThreadID -> m LiveThread) -> m LiveThreadID -> m LiveThread
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< (APIAction PostedLiveThread -> m PostedLiveThread
forall a (m :: * -> *).
(MonadReddit m, FromJSON a) =>
APIAction a -> m a
runAction @PostedLiveThread APIAction PostedLiveThread
forall a. APIAction a
r m PostedLiveThread
-> (PostedLiveThread -> LiveThreadID) -> m LiveThreadID
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> PostedLiveThread -> LiveThreadID
forall s t a b. Wrapped s t a b => s -> a
wrappedTo)
  where
    r :: APIAction a
r = APIAction Any
forall a. APIAction a
defaultAPIAction
        { $sel:pathSegments:APIAction :: [PathSegment]
pathSegments = [PathSegment] -> [PathSegment]
liveThreadPath [ PathSegment
"create" ]
        , $sel:method:APIAction :: Method
method       = Method
POST
        , $sel:requestData:APIAction :: WithData
requestData  = Form -> WithData
WithForm (Form -> WithData) -> Form -> WithData
forall a b. (a -> b) -> a -> b
$ NewLiveThread -> Form
forall a. ToForm a => a -> Form
toForm NewLiveThread
nlt
        }

-- | Close an existing live thread. After closing, it is no longer possible to
-- update or modify the live thread
--
-- __Warning__: This action is irreversible
closeLiveThread :: MonadReddit m => LiveThreadID -> m ()
closeLiveThread :: LiveThreadID -> m ()
closeLiveThread LiveThreadID
ltid =
    APIAction () -> m ()
forall (m :: * -> *). MonadReddit m => APIAction () -> m ()
runAction_ APIAction Any
forall a. APIAction a
defaultAPIAction
               { $sel:pathSegments:APIAction :: [PathSegment]
pathSegments =
                     [PathSegment] -> [PathSegment]
liveThreadPath [ LiveThreadID -> PathSegment
forall a. ToHttpApiData a => a -> PathSegment
toQueryParam LiveThreadID
ltid, PathSegment
"close_thread" ]
               , $sel:method:APIAction :: Method
method       = Method
POST
               , $sel:requestData:APIAction :: WithData
requestData  = [(PathSegment, PathSegment)] -> WithData
mkTextFormData [ (PathSegment
"api_type", PathSegment
"json") ]
               }

-- | Update the existing live thread with new settings
updateLiveThread :: MonadReddit m => LiveThreadID -> UpdatedLiveThread -> m ()
updateLiveThread :: LiveThreadID -> NewLiveThread -> m ()
updateLiveThread LiveThreadID
ltid NewLiveThread
ult =
    APIAction () -> m ()
forall a (m :: * -> *).
(MonadReddit m, FromJSON a) =>
APIAction a -> m a
runAction APIAction Any
forall a. APIAction a
defaultAPIAction
              { $sel:pathSegments:APIAction :: [PathSegment]
pathSegments = [PathSegment] -> [PathSegment]
liveThreadPath [ LiveThreadID -> PathSegment
forall a. ToHttpApiData a => a -> PathSegment
toQueryParam LiveThreadID
ltid, PathSegment
"edit" ]
              , $sel:method:APIAction :: Method
method       = Method
POST
              , $sel:requestData:APIAction :: WithData
requestData  = Form -> WithData
WithForm (Form -> WithData) -> Form -> WithData
forall a b. (a -> b) -> a -> b
$ NewLiveThread -> Form
forall a. ToForm a => a -> Form
toForm NewLiveThread
ult
              }

-- | Add an update to the live thread
addLiveUpdate :: MonadReddit m => LiveThreadID -> Body -> m ()
addLiveUpdate :: LiveThreadID -> PathSegment -> m ()
addLiveUpdate LiveThreadID
ltid PathSegment
b =
    APIAction () -> m ()
forall (m :: * -> *). MonadReddit m => APIAction () -> m ()
runAction_ APIAction Any
forall a. APIAction a
defaultAPIAction
               { $sel:pathSegments:APIAction :: [PathSegment]
pathSegments = [PathSegment] -> [PathSegment]
liveThreadPath [ LiveThreadID -> PathSegment
forall a. ToHttpApiData a => a -> PathSegment
toQueryParam LiveThreadID
ltid, PathSegment
"update" ]
               , $sel:method:APIAction :: Method
method       = Method
POST
               , $sel:requestData:APIAction :: WithData
requestData  =
                     [(PathSegment, PathSegment)] -> WithData
mkTextFormData [ (PathSegment
"body", PathSegment
b), (PathSegment
"api_type", PathSegment
"json") ]
               }

-- | Strike the existing 'LiveUpdate', causing its @stricken@ field to be @True@
-- and the content to be crossed-out and marked incorrect on the web UI
strikeLiveUpdate :: MonadReddit m => LiveThreadID -> LiveUpdateID -> m ()
strikeLiveUpdate :: LiveThreadID -> LiveUpdateID -> m ()
strikeLiveUpdate = PathSegment -> LiveThreadID -> LiveUpdateID -> m ()
forall (m :: * -> *).
MonadReddit m =>
PathSegment -> LiveThreadID -> LiveUpdateID -> m ()
strikeDeleteUpdate PathSegment
"strike_update"

-- | Strike the existing 'LiveUpdate', causing its @stricken@ field to be @True@
-- and the content to be crossed-out and marked incorrect on the web UI
deleteLiveUpdate :: MonadReddit m => LiveThreadID -> LiveUpdateID -> m ()
deleteLiveUpdate :: LiveThreadID -> LiveUpdateID -> m ()
deleteLiveUpdate = PathSegment -> LiveThreadID -> LiveUpdateID -> m ()
forall (m :: * -> *).
MonadReddit m =>
PathSegment -> LiveThreadID -> LiveUpdateID -> m ()
strikeDeleteUpdate PathSegment
"delete_update"

strikeDeleteUpdate
    :: MonadReddit m => PathSegment -> LiveThreadID -> LiveUpdateID -> m ()
strikeDeleteUpdate :: PathSegment -> LiveThreadID -> LiveUpdateID -> m ()
strikeDeleteUpdate PathSegment
path LiveThreadID
ltid LiveUpdateID
luid =
    APIAction () -> m ()
forall (m :: * -> *). MonadReddit m => APIAction () -> m ()
runAction_ APIAction Any
forall a. APIAction a
defaultAPIAction
               { $sel:pathSegments:APIAction :: [PathSegment]
pathSegments = [PathSegment] -> [PathSegment]
liveThreadPath [ LiveThreadID -> PathSegment
forall a. ToHttpApiData a => a -> PathSegment
toQueryParam LiveThreadID
ltid, PathSegment
path ]
               , $sel:method:APIAction :: Method
method       = Method
POST
               , $sel:requestData:APIAction :: WithData
requestData  = [(PathSegment, PathSegment)] -> WithData
mkTextFormData [ (PathSegment
"id", LiveUpdateID -> PathSegment
forall a. Thing a => a -> PathSegment
fullname LiveUpdateID
luid)
                                               , (PathSegment
"api_type", PathSegment
"json")
                                               ]
               }

-- | Remove the user as a contributor to the live thread. If you don\'t know the
-- contributor\'s user ID, you can use 'removeLiveContributorByName'
removeLiveContributor :: MonadReddit m => LiveThreadID -> UserID -> m ()
removeLiveContributor :: LiveThreadID -> UserID -> m ()
removeLiveContributor LiveThreadID
ltid UserID
uid =
    APIAction () -> m ()
forall a (m :: * -> *).
(MonadReddit m, FromJSON a) =>
APIAction a -> m a
runAction APIAction Any
forall a. APIAction a
defaultAPIAction
              { $sel:pathSegments:APIAction :: [PathSegment]
pathSegments = [PathSegment] -> [PathSegment]
liveThreadPath [ LiveThreadID -> PathSegment
forall a. ToHttpApiData a => a -> PathSegment
toQueryParam LiveThreadID
ltid
                                              , PathSegment
"remove_live_contributor"
                                              ]
              , $sel:requestData:APIAction :: WithData
requestData  = [(PathSegment, PathSegment)] -> WithData
mkTextFormData [ (PathSegment
"id", UserID -> PathSegment
forall a. Thing a => a -> PathSegment
fullname UserID
uid) ]
              }

-- | Remove the live contributor by username. Note that this action must perform
-- an additional network request to fetch the user ID from the given username
removeLiveContributorByName
    :: MonadReddit m => LiveThreadID -> Username -> m ()
removeLiveContributorByName :: LiveThreadID -> Username -> m ()
removeLiveContributorByName LiveThreadID
ltid Username
uname = do
    Account { UserID
$sel:userID:Account :: Account -> UserID
userID :: UserID
userID } <- Username -> m Account
forall (m :: * -> *). MonadReddit m => Username -> m Account
getUser Username
uname
    LiveThreadID -> UserID -> m ()
forall (m :: * -> *).
MonadReddit m =>
LiveThreadID -> UserID -> m ()
removeLiveContributor LiveThreadID
ltid UserID
userID

-- | Update the permissions for the live contributor
updateLiveContributor
    :: (MonadReddit m, Foldable t)
    => Maybe (t LivePermission)
    -- ^ If @Nothing@, grants all contributor permissions. If @Just@ but empty,
    -- removes all permissions
    -> LiveThreadID
    -> Username
    -> m ()
updateLiveContributor :: Maybe (t LivePermission) -> LiveThreadID -> Username -> m ()
updateLiveContributor Maybe (t LivePermission)
perms LiveThreadID
ltid Username
uname =
    APIAction () -> m ()
forall (m :: * -> *). MonadReddit m => APIAction () -> m ()
runAction_ APIAction Any
forall a. APIAction a
defaultAPIAction
               { $sel:pathSegments:APIAction :: [PathSegment]
pathSegments =
                     [ LiveThreadID -> PathSegment
forall a. ToHttpApiData a => a -> PathSegment
toQueryParam LiveThreadID
ltid, PathSegment
"set_contributor_permissions" ]
               , $sel:method:APIAction :: Method
method       = Method
POST
               , $sel:requestData:APIAction :: WithData
requestData  =
                     [(PathSegment, PathSegment)] -> WithData
mkTextFormData [ (PathSegment
"name", Username -> PathSegment
forall a. ToHttpApiData a => a -> PathSegment
toQueryParam Username
uname)
                                    , (PathSegment
"type", PathSegment
"liveupdate_contributor")
                                    , ( PathSegment
"permissions"
                                      , PathSegment
-> (t LivePermission -> PathSegment)
-> Maybe (t LivePermission)
-> PathSegment
forall b a. b -> (a -> b) -> Maybe a -> b
maybe PathSegment
"+all" t LivePermission -> PathSegment
forall (t :: * -> *) a.
(Foldable t, Ord a, Enum a, Bounded a, ToHttpApiData a) =>
t a -> PathSegment
joinPerms Maybe (t LivePermission)
perms
                                      )
                                    , (PathSegment
"api_type", PathSegment
"json")
                                    ]
               }

-- | Abdicate your role as a live contributor, removing all access and permissions
--
-- __Warning__: This cannot be undone, even if you are the creator of the live
-- thread
abdicateLiveContributor :: MonadReddit m => LiveThreadID -> m ()
abdicateLiveContributor :: LiveThreadID -> m ()
abdicateLiveContributor LiveThreadID
ltid =
    APIAction () -> m ()
forall (m :: * -> *). MonadReddit m => APIAction () -> m ()
runAction_ APIAction Any
forall a. APIAction a
defaultAPIAction
               { $sel:pathSegments:APIAction :: [PathSegment]
pathSegments =
                     [PathSegment] -> [PathSegment]
liveThreadPath [ LiveThreadID -> PathSegment
forall a. ToHttpApiData a => a -> PathSegment
toQueryParam LiveThreadID
ltid, PathSegment
"leave_contributor" ]
               , $sel:method:APIAction :: Method
method       = Method
POST
               , $sel:requestData:APIAction :: WithData
requestData  = [(PathSegment, PathSegment)] -> WithData
mkTextFormData [ (PathSegment
"api_type", PathSegment
"json") ]
               }

-- | Invite a user to contribute to the live thread. Note that this implicitly
-- grants all permissions to the invitee. If you would like more fine-grained
-- control over permissions, see 'inviteLiveContributorWithPerms'
inviteLiveContributor :: MonadReddit m => LiveThreadID -> Username -> m ()
inviteLiveContributor :: LiveThreadID -> Username -> m ()
inviteLiveContributor =
    Form -> LiveThreadID -> Username -> m ()
forall (m :: * -> *).
MonadReddit m =>
Form -> LiveThreadID -> Username -> m ()
inviteContributors (Form -> LiveThreadID -> Username -> m ())
-> Form -> LiveThreadID -> Username -> m ()
forall a b. (a -> b) -> a -> b
$ [(PathSegment, PathSegment)] -> Form
mkTextForm [ (PathSegment
"permissions", PathSegment
"+all") ]

-- | As 'inviteLiveContributor', but allows customization of the permissions
-- granted to the invitee
inviteLiveContributorWithPerms
    :: (MonadReddit m, Foldable t)
    => t LivePermission -- ^ If empty, grants no permissions
    -> LiveThreadID
    -> Username
    -> m ()
inviteLiveContributorWithPerms :: t LivePermission -> LiveThreadID -> Username -> m ()
inviteLiveContributorWithPerms t LivePermission
perms =
    Form -> LiveThreadID -> Username -> m ()
forall (m :: * -> *).
MonadReddit m =>
Form -> LiveThreadID -> Username -> m ()
inviteContributors (Form -> LiveThreadID -> Username -> m ())
-> Form -> LiveThreadID -> Username -> m ()
forall a b. (a -> b) -> a -> b
$ [(PathSegment, PathSegment)] -> Form
mkTextForm [ (PathSegment
"permissions", t LivePermission -> PathSegment
forall (t :: * -> *) a.
(Foldable t, Ord a, Enum a, Bounded a, ToHttpApiData a) =>
t a -> PathSegment
joinPerms t LivePermission
perms) ]

-- | Revoke the invitation to contribute to the live thread. If you don\'t know
-- the contributor\'s user ID, you can use 'revokeLiveInvitationByName'
revokeLiveInvitation :: MonadReddit m => LiveThreadID -> UserID -> m ()
revokeLiveInvitation :: LiveThreadID -> UserID -> m ()
revokeLiveInvitation LiveThreadID
ltid UserID
uid =
    APIAction () -> m ()
forall (m :: * -> *). MonadReddit m => APIAction () -> m ()
runAction_ APIAction Any
forall a. APIAction a
defaultAPIAction
               { $sel:pathSegments:APIAction :: [PathSegment]
pathSegments = [PathSegment] -> [PathSegment]
liveThreadPath [ LiveThreadID -> PathSegment
forall a. ToHttpApiData a => a -> PathSegment
toQueryParam LiveThreadID
ltid
                                               , PathSegment
"rm_contributor_invite"
                                               ]
               , $sel:method:APIAction :: Method
method       = Method
POST
               , $sel:requestData:APIAction :: WithData
requestData  = [(PathSegment, PathSegment)] -> WithData
mkTextFormData [ (PathSegment
"id", UserID -> PathSegment
forall a. Thing a => a -> PathSegment
fullname UserID
uid)
                                               , (PathSegment
"api_type", PathSegment
"json")
                                               ]
               }

-- | Revoke the live invitation by username. Note that this action must perform
-- an additional network request to fetch the user ID from the given username
revokeLiveInvitationByName
    :: MonadReddit m => LiveThreadID -> Username -> m ()
revokeLiveInvitationByName :: LiveThreadID -> Username -> m ()
revokeLiveInvitationByName LiveThreadID
ltid Username
uname = do
    Account { UserID
userID :: UserID
$sel:userID:Account :: Account -> UserID
userID } <- Username -> m Account
forall (m :: * -> *). MonadReddit m => Username -> m Account
getUser Username
uname
    LiveThreadID -> UserID -> m ()
forall (m :: * -> *).
MonadReddit m =>
LiveThreadID -> UserID -> m ()
revokeLiveInvitation LiveThreadID
ltid UserID
userID

inviteContributors
    :: MonadReddit m => Form -> LiveThreadID -> Username -> m ()
inviteContributors :: Form -> LiveThreadID -> Username -> m ()
inviteContributors Form
form LiveThreadID
ltid Username
uname =
    APIAction () -> m ()
forall (m :: * -> *). MonadReddit m => APIAction () -> m ()
runAction_ APIAction Any
forall a. APIAction a
defaultAPIAction
               { $sel:pathSegments:APIAction :: [PathSegment]
pathSegments = [PathSegment] -> [PathSegment]
liveThreadPath [ LiveThreadID -> PathSegment
forall a. ToHttpApiData a => a -> PathSegment
toQueryParam LiveThreadID
ltid
                                               , PathSegment
"invite_contributor"
                                               ]
               , $sel:method:APIAction :: Method
method       = Method
POST
               , $sel:requestData:APIAction :: WithData
requestData  = Form -> WithData
WithForm
                     (Form -> WithData) -> Form -> WithData
forall a b. (a -> b) -> a -> b
$ [(PathSegment, PathSegment)] -> Form
mkTextForm [ (PathSegment
"name", Username -> PathSegment
forall a. ToHttpApiData a => a -> PathSegment
toQueryParam Username
uname)
                                  , (PathSegment
"type", PathSegment
"liveupdate_contributor_invite")
                                  , (PathSegment
"api_type", PathSegment
"json")
                                  ]
                     Form -> Form -> Form
forall a. Semigroup a => a -> a -> a
<> Form
form
               }

liveThreadPath :: [PathSegment] -> [PathSegment]
liveThreadPath :: [PathSegment] -> [PathSegment]
liveThreadPath [PathSegment]
ps = [ PathSegment
"api", PathSegment
"live" ] [PathSegment] -> [PathSegment] -> [PathSegment]
forall a. Semigroup a => a -> a -> a
<> [PathSegment]
ps