{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards   #-}
{-# LANGUAGE TemplateHaskell   #-}

{-|
Module: AWSLambda.Events.SNSEvent
Description: Types for SNS Lambda events

Based on https://github.com/aws/aws-lambda-dotnet/tree/master/Libraries/src/Amazon.Lambda.SNSEvents
-}
module AWSLambda.Events.SNSEvent where

import           Control.Lens
import           Data.Aeson               (FromJSON (..), genericParseJSON)
import           Data.Aeson.Casing        (aesonDrop, pascalCase)
import           Data.Aeson.Embedded
import           Data.Aeson.TextValue
import           Data.Aeson.TH            (deriveFromJSON)
import           Data.ByteString          (ByteString)
import           Data.HashMap.Strict      (HashMap)
import           Data.Text                (Text)
import           Data.Time.Clock          (UTCTime)
import           GHC.Generics             (Generic)
import           Network.AWS.Data.Base64
import           Network.AWS.Data.Text    (FromText)

import           AWSLambda.Events.Records

data MessageAttribute = MessageAttribute
  { MessageAttribute -> Text
_maType  :: !Text
  , MessageAttribute -> Text
_maValue :: !Text
  } deriving (MessageAttribute -> MessageAttribute -> Bool
(MessageAttribute -> MessageAttribute -> Bool)
-> (MessageAttribute -> MessageAttribute -> Bool)
-> Eq MessageAttribute
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: MessageAttribute -> MessageAttribute -> Bool
$c/= :: MessageAttribute -> MessageAttribute -> Bool
== :: MessageAttribute -> MessageAttribute -> Bool
$c== :: MessageAttribute -> MessageAttribute -> Bool
Eq, Int -> MessageAttribute -> ShowS
[MessageAttribute] -> ShowS
MessageAttribute -> String
(Int -> MessageAttribute -> ShowS)
-> (MessageAttribute -> String)
-> ([MessageAttribute] -> ShowS)
-> Show MessageAttribute
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [MessageAttribute] -> ShowS
$cshowList :: [MessageAttribute] -> ShowS
show :: MessageAttribute -> String
$cshow :: MessageAttribute -> String
showsPrec :: Int -> MessageAttribute -> ShowS
$cshowsPrec :: Int -> MessageAttribute -> ShowS
Show)

$(deriveFromJSON (aesonDrop 3 pascalCase) ''MessageAttribute)
$(makeLenses ''MessageAttribute)

data SNSMessage message = SNSMessage
  { SNSMessage message -> TextValue message
_smMessage           :: !(TextValue message )
  , SNSMessage message -> HashMap Text MessageAttribute
_smMessageAttributes :: !(HashMap Text MessageAttribute)
  , SNSMessage message -> Text
_smMessageId         :: !Text
  , SNSMessage message -> Text
_smSignature         :: !Text
  , SNSMessage message -> Text
_smSignatureVersion  :: !Text
  , SNSMessage message -> Text
_smSigningCertUrl    :: !Text
  , SNSMessage message -> Text
_smSubject           :: !Text
  , SNSMessage message -> UTCTime
_smTimestamp         :: !UTCTime
  , SNSMessage message -> Text
_smTopicArn          :: !Text
  , SNSMessage message -> Text
_smType              :: !Text
  , SNSMessage message -> Text
_smUnsubscribeUrl    :: !Text
  } deriving (SNSMessage message -> SNSMessage message -> Bool
(SNSMessage message -> SNSMessage message -> Bool)
-> (SNSMessage message -> SNSMessage message -> Bool)
-> Eq (SNSMessage message)
forall message.
Eq message =>
SNSMessage message -> SNSMessage message -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SNSMessage message -> SNSMessage message -> Bool
$c/= :: forall message.
Eq message =>
SNSMessage message -> SNSMessage message -> Bool
== :: SNSMessage message -> SNSMessage message -> Bool
$c== :: forall message.
Eq message =>
SNSMessage message -> SNSMessage message -> Bool
Eq, Int -> SNSMessage message -> ShowS
[SNSMessage message] -> ShowS
SNSMessage message -> String
(Int -> SNSMessage message -> ShowS)
-> (SNSMessage message -> String)
-> ([SNSMessage message] -> ShowS)
-> Show (SNSMessage message)
forall message. Show message => Int -> SNSMessage message -> ShowS
forall message. Show message => [SNSMessage message] -> ShowS
forall message. Show message => SNSMessage message -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SNSMessage message] -> ShowS
$cshowList :: forall message. Show message => [SNSMessage message] -> ShowS
show :: SNSMessage message -> String
$cshow :: forall message. Show message => SNSMessage message -> String
showsPrec :: Int -> SNSMessage message -> ShowS
$cshowsPrec :: forall message. Show message => Int -> SNSMessage message -> ShowS
Show, (forall x. SNSMessage message -> Rep (SNSMessage message) x)
-> (forall x. Rep (SNSMessage message) x -> SNSMessage message)
-> Generic (SNSMessage message)
forall x. Rep (SNSMessage message) x -> SNSMessage message
forall x. SNSMessage message -> Rep (SNSMessage message) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall message x. Rep (SNSMessage message) x -> SNSMessage message
forall message x. SNSMessage message -> Rep (SNSMessage message) x
$cto :: forall message x. Rep (SNSMessage message) x -> SNSMessage message
$cfrom :: forall message x. SNSMessage message -> Rep (SNSMessage message) x
Generic)

instance FromText message => FromJSON (SNSMessage message) where
  parseJSON :: Value -> Parser (SNSMessage message)
parseJSON = Options -> Value -> Parser (SNSMessage message)
forall a.
(Generic a, GFromJSON Zero (Rep a)) =>
Options -> Value -> Parser a
genericParseJSON (Options -> Value -> Parser (SNSMessage message))
-> Options -> Value -> Parser (SNSMessage message)
forall a b. (a -> b) -> a -> b
$ Int -> ShowS -> Options
aesonDrop Int
3 ShowS
pascalCase

$(makeLenses ''SNSMessage)

data SNSRecord message = SNSRecord
  { SNSRecord message -> Text
_srEventVersion         :: !Text
  , SNSRecord message -> Text
_srEventSubscriptionArn :: !Text
  , SNSRecord message -> Text
_srEventSource          :: !Text
  , SNSRecord message -> SNSMessage message
_srSns                  :: !(SNSMessage message)
  } deriving (SNSRecord message -> SNSRecord message -> Bool
(SNSRecord message -> SNSRecord message -> Bool)
-> (SNSRecord message -> SNSRecord message -> Bool)
-> Eq (SNSRecord message)
forall message.
Eq message =>
SNSRecord message -> SNSRecord message -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SNSRecord message -> SNSRecord message -> Bool
$c/= :: forall message.
Eq message =>
SNSRecord message -> SNSRecord message -> Bool
== :: SNSRecord message -> SNSRecord message -> Bool
$c== :: forall message.
Eq message =>
SNSRecord message -> SNSRecord message -> Bool
Eq, Int -> SNSRecord message -> ShowS
[SNSRecord message] -> ShowS
SNSRecord message -> String
(Int -> SNSRecord message -> ShowS)
-> (SNSRecord message -> String)
-> ([SNSRecord message] -> ShowS)
-> Show (SNSRecord message)
forall message. Show message => Int -> SNSRecord message -> ShowS
forall message. Show message => [SNSRecord message] -> ShowS
forall message. Show message => SNSRecord message -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SNSRecord message] -> ShowS
$cshowList :: forall message. Show message => [SNSRecord message] -> ShowS
show :: SNSRecord message -> String
$cshow :: forall message. Show message => SNSRecord message -> String
showsPrec :: Int -> SNSRecord message -> ShowS
$cshowsPrec :: forall message. Show message => Int -> SNSRecord message -> ShowS
Show, (forall x. SNSRecord message -> Rep (SNSRecord message) x)
-> (forall x. Rep (SNSRecord message) x -> SNSRecord message)
-> Generic (SNSRecord message)
forall x. Rep (SNSRecord message) x -> SNSRecord message
forall x. SNSRecord message -> Rep (SNSRecord message) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall message x. Rep (SNSRecord message) x -> SNSRecord message
forall message x. SNSRecord message -> Rep (SNSRecord message) x
$cto :: forall message x. Rep (SNSRecord message) x -> SNSRecord message
$cfrom :: forall message x. SNSRecord message -> Rep (SNSRecord message) x
Generic)

instance FromText message => FromJSON (SNSRecord message) where
  parseJSON :: Value -> Parser (SNSRecord message)
parseJSON = Options -> Value -> Parser (SNSRecord message)
forall a.
(Generic a, GFromJSON Zero (Rep a)) =>
Options -> Value -> Parser a
genericParseJSON (Options -> Value -> Parser (SNSRecord message))
-> Options -> Value -> Parser (SNSRecord message)
forall a b. (a -> b) -> a -> b
$ Int -> ShowS -> Options
aesonDrop Int
3 ShowS
pascalCase

$(makeLenses ''SNSRecord)

-- | SNSEvent.
-- The 'message' type is parameterised. To treat it as a text value
-- use @SNSEvent Text@.
-- To extract an embedded event object use the 'Embedded' type.
-- E.g. @SNSEvent (Embedded S3Event)@ will treat the message
-- as an embedded S3Event.
-- To extract embedded Base64 encoded binary use
-- @SNSEvent Base64@
type SNSEvent message = RecordsEvent (SNSRecord message)

-- | A Traversal to get messages from an SNSEvent
messages :: Traversal (SNSEvent message) (SNSEvent message') message message'
messages :: (message -> f message')
-> SNSEvent message -> f (SNSEvent message')
messages = ([SNSRecord message] -> f [SNSRecord message'])
-> SNSEvent message -> f (SNSEvent message')
forall a1 a2. Iso (RecordsEvent a1) (RecordsEvent a2) [a1] [a2]
reRecords (([SNSRecord message] -> f [SNSRecord message'])
 -> SNSEvent message -> f (SNSEvent message'))
-> ((message -> f message')
    -> [SNSRecord message] -> f [SNSRecord message'])
-> (message -> f message')
-> SNSEvent message
-> f (SNSEvent message')
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (SNSRecord message -> f (SNSRecord message'))
-> [SNSRecord message] -> f [SNSRecord message']
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse ((SNSRecord message -> f (SNSRecord message'))
 -> [SNSRecord message] -> f [SNSRecord message'])
-> ((message -> f message')
    -> SNSRecord message -> f (SNSRecord message'))
-> (message -> f message')
-> [SNSRecord message]
-> f [SNSRecord message']
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (SNSMessage message -> f (SNSMessage message'))
-> SNSRecord message -> f (SNSRecord message')
forall message message.
Lens
  (SNSRecord message)
  (SNSRecord message)
  (SNSMessage message)
  (SNSMessage message)
srSns ((SNSMessage message -> f (SNSMessage message'))
 -> SNSRecord message -> f (SNSRecord message'))
-> ((message -> f message')
    -> SNSMessage message -> f (SNSMessage message'))
-> (message -> f message')
-> SNSRecord message
-> f (SNSRecord message')
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (TextValue message -> f (TextValue message'))
-> SNSMessage message -> f (SNSMessage message')
forall message message.
Lens
  (SNSMessage message)
  (SNSMessage message)
  (TextValue message)
  (TextValue message)
smMessage ((TextValue message -> f (TextValue message'))
 -> SNSMessage message -> f (SNSMessage message'))
-> ((message -> f message')
    -> TextValue message -> f (TextValue message'))
-> (message -> f message')
-> SNSMessage message
-> f (SNSMessage message')
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (message -> f message')
-> TextValue message -> f (TextValue message')
forall a1 a2. Iso (TextValue a1) (TextValue a2) a1 a2
unTextValue

-- | A Traversal to get embedded JSON values from an SNSEvent
embedded :: Traversal (SNSEvent (Embedded v)) (SNSEvent (Embedded v')) v v'
embedded :: (v -> f v') -> SNSEvent (Embedded v) -> f (SNSEvent (Embedded v'))
embedded = (Embedded v -> f (Embedded v'))
-> SNSEvent (Embedded v) -> f (SNSEvent (Embedded v'))
forall message message'.
Traversal (SNSEvent message) (SNSEvent message') message message'
messages ((Embedded v -> f (Embedded v'))
 -> SNSEvent (Embedded v) -> f (SNSEvent (Embedded v')))
-> ((v -> f v') -> Embedded v -> f (Embedded v'))
-> (v -> f v')
-> SNSEvent (Embedded v)
-> f (SNSEvent (Embedded v'))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (v -> f v') -> Embedded v -> f (Embedded v')
forall a1 a2. Iso (Embedded a1) (Embedded a2) a1 a2
unEmbed

binary :: Traversal' (SNSEvent Base64) ByteString
binary :: (ByteString -> f ByteString)
-> SNSEvent Base64 -> f (SNSEvent Base64)
binary = (Base64 -> f Base64) -> SNSEvent Base64 -> f (SNSEvent Base64)
forall message message'.
Traversal (SNSEvent message) (SNSEvent message') message message'
messages ((Base64 -> f Base64) -> SNSEvent Base64 -> f (SNSEvent Base64))
-> ((ByteString -> f ByteString) -> Base64 -> f Base64)
-> (ByteString -> f ByteString)
-> SNSEvent Base64
-> f (SNSEvent Base64)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> f ByteString) -> Base64 -> f Base64
Iso' Base64 ByteString
_Base64