packages feed

twitchapi-0.0.3: src/Web/TwitchAPI/Helix/ChannelPoints.hs

{-# LANGUAGE RecordWildCards     #-}
{-# LANGUAGE OverloadedStrings   #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Web.TwitchAPI.Helix.ChannelPoints where

import Prelude

import qualified Data.ByteString.Char8 as BS
import qualified Data.Time             as Time
import qualified Data.Time.RFC3339     as Time ( parseTimeRFC3339 )
import qualified Data.Text             as Text
import qualified Network.HTTP.Client   as HTTP

import Data.Maybe ( fromMaybe )
import Data.Aeson ( FromJSON(..), (.:), withObject
                  , ToJSON(..), (.=), object, encode
                  , Object
                  )

import qualified Web.TwitchAPI.Helix.Request as Req

class RewardDetails a where
    broadcasterId :: a -> Integer
    prompt :: a -> Maybe String
    backgroundColor :: a -> String
    maxPerStream :: a -> Maybe Integer
    maxPerUser :: a -> Maybe Integer
    autoFulfilled :: a -> Bool

data Create = Create { forBroadcasterId :: Integer
                     , title :: String
                     , setPrompt :: Maybe String
                     , cost :: Integer
                     , enabled :: Maybe Bool
                     , setBackgroundColor :: Maybe String
                     , setMaxPerStream :: Maybe Integer
                     , setMaxPerUser :: Maybe Integer
                     , cooldownSeconds :: Maybe Integer
                     , setAutoFulfilled :: Maybe Bool
                     } deriving ( Show, Eq )

instance ToJSON Create where
    toJSON Create{..} =
        object [ "title"      .= Text.pack title
               , "prompt"     .= (Text.pack <$> setPrompt)
               , "cost"       .= cost
               , "is_enabled" .= fromMaybe True enabled
               , "background_color" .= (Text.pack <$> setBackgroundColor)
               , "is_user_input_required" .= fmap (const True) setPrompt
               , "is_max_per_stream_enabled" .= fmap (const True) setMaxPerStream
               , "max_per_stream" .= setMaxPerStream
               , "is_max_per_user_per_stream_enabled" .= fmap (const True) setMaxPerUser
               , "max_per_user_per_stream" .= setMaxPerUser
               , "is_global_cooldown_enabled" .= fmap (const True) cooldownSeconds
               , "global_cooldown_seconds" .= cooldownSeconds
               , "should_redemptions_skip_request_queue" .= setAutoFulfilled
               ]

instance Req.HelixRequest Create where
    toRequest create =
        let setQuery  = HTTP.setQueryString [("broadcaster_id", Just . BS.pack . show $ (broadcasterId :: Create -> Integer) create)]
            setBody r = r{ HTTP.requestBody = HTTP.RequestBodyLBS . encode . toJSON $ create }
        in setBody . setQuery $ HTTP.parseRequest_ "POST https://api.twitch.tv/helix/channel_points/custom_rewards"
    scope Create{} = Just "channel:manage:redemptions"

instance RewardDetails Create where
    broadcasterId = forBroadcasterId
    prompt = setPrompt
    backgroundColor = fromMaybe "" . setBackgroundColor
    maxPerStream = setMaxPerStream
    maxPerUser = setMaxPerUser
    autoFulfilled = fromMaybe False . setAutoFulfilled

data RewardImages = RewardImages { tiny :: Maybe String
                                 , large :: Maybe String
                                 , huge :: Maybe String
                                 } deriving ( Show, Eq )

instance FromJSON RewardImages where
    parseJSON = withObject "RewardImages" $ \o -> do
        tiny <- o .: "url_1x"
        large <- o .: "url_2x"
        huge <- o .: "url_4x"
        return RewardImages{..}

data CreateResponse = CreateResponse { broadcaster :: Integer
                                     , broadcasterLogin :: String
                                     , broadcasterName :: String
                                     , rewardId :: String
                                     , rewardTitle :: String
                                     , rewardPrompt :: Maybe String
                                     , rewardCost :: Integer
                                     , rewardImage :: Maybe RewardImages
                                     , defaultImage :: RewardImages
                                     , rewardBackgroundColor :: String
                                     , rewardMaxPerStream :: Maybe Integer
                                     , rewardMaxPerUser :: Maybe Integer
                                     , cooldown :: Maybe Integer
                                     , paused :: Bool
                                     , inStock :: Bool
                                     , rewardAutoFulfilled :: Bool
                                     , redemptionCount :: Integer
                                     , cooldownExpires :: Maybe Time.UTCTime
                                     } deriving ( Show, Eq )

instance FromJSON CreateResponse where
    parseJSON = withObject "CreateResponse" $ \o -> do
        bid <- o .: "broadcaster_id"
        let broadcaster = read bid :: Integer
        broadcasterLogin <- o .: "broadcaster_login"
        broadcasterName <- o .: "broadcaster_name"
        rewardId <- o .: "id"
        rewardTitle <- o .: "title"

        promptText <- o .: "prompt"
        promptEnabled :: Bool <- o .: "is_user_input_required"
        let rewardPrompt = if promptEnabled then Just promptText else Nothing

        rewardCost <- o .: "cost"
        rewardImage <- o .: "image"
        defaultImage <- o .: "default_image"
        rewardBackgroundColor <- o .: "background_color"

        maxObject :: Object <- o .: "max_per_stream_setting"
        maxEnabled <- maxObject .: "is_enabled"
        streamMax <- maxObject .: "max_per_stream"
        let rewardMaxPerStream = if maxEnabled then Just streamMax else Nothing

        userMaxObject :: Object <- o .: "max_per_user_per_stream_setting"
        userMaxEnabled <- userMaxObject .: "is_enabled"
        userMax <- userMaxObject .: "max_per_user_per_stream"
        let rewardMaxPerUser = if userMaxEnabled then Just userMax else Nothing

        cooldownObject :: Object <- o .: "global_cooldown_setting"
        cooldownEnabled <- cooldownObject .: "is_enabled"
        cooldownSeconds <- cooldownObject .: "global_cooldown_seconds"
        let cooldown = if cooldownEnabled then Just cooldownSeconds else Nothing

        paused <- o .: "is_paused"
        inStock <- o .: "is_in_stock"
        rewardAutoFulfilled <- o .: "should_redemptions_skip_request_queue"
        redemptionCount <- o .: "redemptions_redeemed_current_stream"
        cooldownExpiry :: Maybe String <- o .: "cooldown_expires_at"
        let cooldownExpires = Time.zonedTimeToUTC <$> (Time.parseTimeRFC3339 =<< cooldownExpiry)
        return CreateResponse{..}

instance RewardDetails CreateResponse where
    broadcasterId = broadcaster
    prompt = rewardPrompt
    backgroundColor = rewardBackgroundColor
    maxPerStream = rewardMaxPerStream
    maxPerUser = rewardMaxPerUser
    autoFulfilled = rewardAutoFulfilled