module Aws.S3.Commands.DeleteObjects where

import           Aws.Core
import           Aws.S3.Core
import qualified Crypto.Hash          as CH
import qualified Data.Map             as M
import           Data.Maybe
import qualified Data.Text            as T
import qualified Data.Text.Encoding   as T
import qualified Network.HTTP.Conduit as HTTP
import qualified Network.HTTP.Types   as HTTP
import qualified Text.XML             as XML
import qualified Text.XML.Cursor      as Cu
import           Text.XML.Cursor      (($/), (&|))
import qualified Data.ByteString.Char8 as B
import           Data.ByteString.Char8 ({- IsString -})
import           Control.Applicative
import           Prelude

data DeleteObjects
    = DeleteObjects {
        DeleteObjects -> Bucket
dosBucket  :: Bucket
      , DeleteObjects -> [(Bucket, Maybe Bucket)]
dosObjects :: [(Object, Maybe T.Text)] -- snd is an optional versionId
      , DeleteObjects -> Bool
dosQuiet   :: Bool
      , DeleteObjects -> Maybe Bucket
dosMultiFactorAuthentication :: Maybe T.Text
      }
    deriving (Int -> DeleteObjects -> ShowS
[DeleteObjects] -> ShowS
DeleteObjects -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [DeleteObjects] -> ShowS
$cshowList :: [DeleteObjects] -> ShowS
show :: DeleteObjects -> String
$cshow :: DeleteObjects -> String
showsPrec :: Int -> DeleteObjects -> ShowS
$cshowsPrec :: Int -> DeleteObjects -> ShowS
Show)

-- simple use case: neither mfa, nor version specified, quiet
deleteObjects :: Bucket -> [T.Text] -> DeleteObjects
deleteObjects :: Bucket -> [Bucket] -> DeleteObjects
deleteObjects Bucket
bucket [Bucket]
objs =
    DeleteObjects {
            dosBucket :: Bucket
dosBucket  = Bucket
bucket
          , dosObjects :: [(Bucket, Maybe Bucket)]
dosObjects = forall a b. [a] -> [b] -> [(a, b)]
zip [Bucket]
objs forall a b. (a -> b) -> a -> b
$ forall a. a -> [a]
repeat forall a. Maybe a
Nothing
          , dosQuiet :: Bool
dosQuiet   = Bool
True
          , dosMultiFactorAuthentication :: Maybe Bucket
dosMultiFactorAuthentication = forall a. Maybe a
Nothing
          }

data DeleteObjectsResponse
    = DeleteObjectsResponse {
        DeleteObjectsResponse -> [DORDeleted]
dorDeleted :: [DORDeleted]
      , DeleteObjectsResponse -> [DORErrors]
dorErrors  :: [DORErrors]
      }
    deriving (Int -> DeleteObjectsResponse -> ShowS
[DeleteObjectsResponse] -> ShowS
DeleteObjectsResponse -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [DeleteObjectsResponse] -> ShowS
$cshowList :: [DeleteObjectsResponse] -> ShowS
show :: DeleteObjectsResponse -> String
$cshow :: DeleteObjectsResponse -> String
showsPrec :: Int -> DeleteObjectsResponse -> ShowS
$cshowsPrec :: Int -> DeleteObjectsResponse -> ShowS
Show)

--omitting DeleteMarker because it appears superfluous
data DORDeleted
    = DORDeleted {
        DORDeleted -> Bucket
ddKey                   :: T.Text
      , DORDeleted -> Maybe Bucket
ddVersionId             :: Maybe T.Text
      , DORDeleted -> Maybe Bucket
ddDeleteMarkerVersionId :: Maybe T.Text
      }
    deriving (Int -> DORDeleted -> ShowS
[DORDeleted] -> ShowS
DORDeleted -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [DORDeleted] -> ShowS
$cshowList :: [DORDeleted] -> ShowS
show :: DORDeleted -> String
$cshow :: DORDeleted -> String
showsPrec :: Int -> DORDeleted -> ShowS
$cshowsPrec :: Int -> DORDeleted -> ShowS
Show)

data DORErrors
    = DORErrors {
        DORErrors -> Bucket
deKey     :: T.Text
      , DORErrors -> Bucket
deCode    :: T.Text
      , DORErrors -> Bucket
deMessage :: T.Text
      }
    deriving (Int -> DORErrors -> ShowS
[DORErrors] -> ShowS
DORErrors -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [DORErrors] -> ShowS
$cshowList :: [DORErrors] -> ShowS
show :: DORErrors -> String
$cshow :: DORErrors -> String
showsPrec :: Int -> DORErrors -> ShowS
$cshowsPrec :: Int -> DORErrors -> ShowS
Show)

-- | ServiceConfiguration: 'S3Configuration'
instance SignQuery DeleteObjects where
    type ServiceConfiguration DeleteObjects = S3Configuration

    signQuery :: forall queryType.
DeleteObjects
-> ServiceConfiguration DeleteObjects queryType
-> SignatureData
-> SignedQuery
signQuery DeleteObjects {Bool
[(Bucket, Maybe Bucket)]
Maybe Bucket
Bucket
dosMultiFactorAuthentication :: Maybe Bucket
dosQuiet :: Bool
dosObjects :: [(Bucket, Maybe Bucket)]
dosBucket :: Bucket
dosMultiFactorAuthentication :: DeleteObjects -> Maybe Bucket
dosQuiet :: DeleteObjects -> Bool
dosObjects :: DeleteObjects -> [(Bucket, Maybe Bucket)]
dosBucket :: DeleteObjects -> Bucket
..} = forall qt.
S3Query -> S3Configuration qt -> SignatureData -> SignedQuery
s3SignQuery S3Query
      {
        s3QMethod :: Method
s3QMethod       = Method
Post
      , s3QBucket :: Maybe ByteString
s3QBucket       = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Bucket -> ByteString
T.encodeUtf8 Bucket
dosBucket
      , s3QSubresources :: [(ByteString, Maybe ByteString)]
s3QSubresources = forall a. QueryLike a => a -> [(ByteString, Maybe ByteString)]
HTTP.toQuery [(ByteString
"delete" :: B.ByteString, forall a. Maybe a
Nothing :: Maybe B.ByteString)]
      , s3QQuery :: [(ByteString, Maybe ByteString)]
s3QQuery        = []
      , s3QContentType :: Maybe ByteString
s3QContentType  = forall a. Maybe a
Nothing
      , s3QContentMd5 :: Maybe (Digest MD5)
s3QContentMd5   = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a. HashAlgorithm a => ByteString -> Digest a
CH.hashlazy ByteString
dosBody
      , s3QObject :: Maybe ByteString
s3QObject       = forall a. Maybe a
Nothing
      , s3QAmzHeaders :: RequestHeaders
s3QAmzHeaders   = forall a. Maybe a -> [a]
maybeToList forall a b. (a -> b) -> a -> b
$ ((HeaderName
"x-amz-mfa", ) forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bucket -> ByteString
T.encodeUtf8) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Bucket
dosMultiFactorAuthentication
      , s3QOtherHeaders :: RequestHeaders
s3QOtherHeaders = []
      , s3QRequestBody :: Maybe RequestBody
s3QRequestBody  = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ ByteString -> RequestBody
HTTP.RequestBodyLBS ByteString
dosBody
      }
        where dosBody :: ByteString
dosBody = RenderSettings -> Document -> ByteString
XML.renderLBS forall a. Default a => a
XML.def XML.Document {
                    documentPrologue :: Prologue
XML.documentPrologue = [Miscellaneous] -> Maybe Doctype -> [Miscellaneous] -> Prologue
XML.Prologue [] forall a. Maybe a
Nothing []
                  , documentRoot :: Element
XML.documentRoot = Element
root
                  , documentEpilogue :: [Miscellaneous]
XML.documentEpilogue = []
                  }
              root :: Element
root = XML.Element {
                    elementName :: Name
XML.elementName = Name
"Delete"
                  , elementAttributes :: Map Name Bucket
XML.elementAttributes = forall k a. Map k a
M.empty
                  , elementNodes :: [Node]
XML.elementNodes = Bool -> Node
quietNode Bool
dosQuiet forall a. a -> [a] -> [a]
: ((Bucket, Maybe Bucket) -> Node
objectNode forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(Bucket, Maybe Bucket)]
dosObjects)
                  }
              objectNode :: (Bucket, Maybe Bucket) -> Node
objectNode (Bucket
obj, Maybe Bucket
mbVersion) = Element -> Node
XML.NodeElement XML.Element {
                    elementName :: Name
XML.elementName = Name
"Object"
                  , elementAttributes :: Map Name Bucket
XML.elementAttributes = forall k a. Map k a
M.empty
                  , elementNodes :: [Node]
XML.elementNodes = Bucket -> Node
keyNode Bucket
obj forall a. a -> [a] -> [a]
: forall a. Maybe a -> [a]
maybeToList (Bucket -> Node
versionNode forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Bucket
mbVersion)
                  }
              versionNode :: Bucket -> Node
versionNode = Name -> Bucket -> Node
toNode Name
"VersionId"
              keyNode :: Bucket -> Node
keyNode     = Name -> Bucket -> Node
toNode Name
"Key"
              quietNode :: Bool -> Node
quietNode Bool
b = Name -> Bucket -> Node
toNode Name
"Quiet" forall a b. (a -> b) -> a -> b
$ if Bool
b then Bucket
"true" else Bucket
"false"
              toNode :: Name -> Bucket -> Node
toNode Name
name Bucket
content = Element -> Node
XML.NodeElement XML.Element {
                    elementName :: Name
XML.elementName = Name
name
                  , elementAttributes :: Map Name Bucket
XML.elementAttributes = forall k a. Map k a
M.empty
                  , elementNodes :: [Node]
XML.elementNodes = [Bucket -> Node
XML.NodeContent Bucket
content]
                  }

instance ResponseConsumer DeleteObjects DeleteObjectsResponse where
    type ResponseMetadata DeleteObjectsResponse = S3Metadata

    responseConsumer :: Request
-> DeleteObjects
-> IORef (ResponseMetadata DeleteObjectsResponse)
-> HTTPResponseConsumer DeleteObjectsResponse
responseConsumer Request
_ DeleteObjects
_ = forall a.
(Cursor -> Response S3Metadata a)
-> IORef S3Metadata -> HTTPResponseConsumer a
s3XmlResponseConsumer forall {m :: * -> *}.
MonadThrow m =>
Cursor -> m DeleteObjectsResponse
parse
        where parse :: Cursor -> m DeleteObjectsResponse
parse Cursor
cursor = do
                  [DORDeleted]
dorDeleted <- forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence forall a b. (a -> b) -> a -> b
$ Cursor
cursor forall node a. Cursor node -> (Cursor node -> [a]) -> [a]
$/ Bucket -> Axis
Cu.laxElement Bucket
"Deleted" forall node a b.
(Cursor node -> [a]) -> (a -> b) -> Cursor node -> [b]
&| forall {m :: * -> *}. MonadThrow m => Cursor -> m DORDeleted
parseDeleted
                  [DORErrors]
dorErrors  <- forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence forall a b. (a -> b) -> a -> b
$ Cursor
cursor forall node a. Cursor node -> (Cursor node -> [a]) -> [a]
$/ Bucket -> Axis
Cu.laxElement Bucket
"Error" forall node a b.
(Cursor node -> [a]) -> (a -> b) -> Cursor node -> [b]
&| forall {m :: * -> *}. MonadThrow m => Cursor -> m DORErrors
parseErrors
                  forall (m :: * -> *) a. Monad m => a -> m a
return DeleteObjectsResponse {[DORErrors]
[DORDeleted]
dorErrors :: [DORErrors]
dorDeleted :: [DORDeleted]
dorErrors :: [DORErrors]
dorDeleted :: [DORDeleted]
..}
              parseDeleted :: Cursor -> m DORDeleted
parseDeleted Cursor
c = do
                  Bucket
ddKey <- forall (m :: * -> *) a. MonadThrow m => String -> [a] -> m a
force String
"Missing Key" forall a b. (a -> b) -> a -> b
$ Cursor
c forall node a. Cursor node -> (Cursor node -> [a]) -> [a]
$/ Bucket -> Cursor -> [Bucket]
elContent Bucket
"Key"
                  let ddVersionId :: Maybe Bucket
ddVersionId = forall a. [a] -> Maybe a
listToMaybe forall a b. (a -> b) -> a -> b
$ Cursor
c forall node a. Cursor node -> (Cursor node -> [a]) -> [a]
$/ Bucket -> Cursor -> [Bucket]
elContent Bucket
"VersionId"
                      ddDeleteMarkerVersionId :: Maybe Bucket
ddDeleteMarkerVersionId = forall a. [a] -> Maybe a
listToMaybe forall a b. (a -> b) -> a -> b
$ Cursor
c forall node a. Cursor node -> (Cursor node -> [a]) -> [a]
$/ Bucket -> Cursor -> [Bucket]
elContent Bucket
"DeleteMarkerVersionId"
                  forall (m :: * -> *) a. Monad m => a -> m a
return DORDeleted {Maybe Bucket
Bucket
ddDeleteMarkerVersionId :: Maybe Bucket
ddVersionId :: Maybe Bucket
ddKey :: Bucket
ddDeleteMarkerVersionId :: Maybe Bucket
ddVersionId :: Maybe Bucket
ddKey :: Bucket
..}
              parseErrors :: Cursor -> m DORErrors
parseErrors Cursor
c = do
                  Bucket
deKey     <- forall (m :: * -> *) a. MonadThrow m => String -> [a] -> m a
force String
"Missing Key" forall a b. (a -> b) -> a -> b
$ Cursor
c forall node a. Cursor node -> (Cursor node -> [a]) -> [a]
$/ Bucket -> Cursor -> [Bucket]
elContent Bucket
"Key"
                  Bucket
deCode    <- forall (m :: * -> *) a. MonadThrow m => String -> [a] -> m a
force String
"Missing Code" forall a b. (a -> b) -> a -> b
$ Cursor
c forall node a. Cursor node -> (Cursor node -> [a]) -> [a]
$/ Bucket -> Cursor -> [Bucket]
elContent Bucket
"Code"
                  Bucket
deMessage <- forall (m :: * -> *) a. MonadThrow m => String -> [a] -> m a
force String
"Missing Message" forall a b. (a -> b) -> a -> b
$ Cursor
c forall node a. Cursor node -> (Cursor node -> [a]) -> [a]
$/ Bucket -> Cursor -> [Bucket]
elContent Bucket
"Message"
                  forall (m :: * -> *) a. Monad m => a -> m a
return DORErrors {Bucket
deMessage :: Bucket
deCode :: Bucket
deKey :: Bucket
deMessage :: Bucket
deCode :: Bucket
deKey :: Bucket
..}

instance Transaction DeleteObjects DeleteObjectsResponse

instance AsMemoryResponse DeleteObjectsResponse where
    type MemoryResponse DeleteObjectsResponse = DeleteObjectsResponse
    loadToMemory :: DeleteObjectsResponse
-> ResourceT IO (MemoryResponse DeleteObjectsResponse)
loadToMemory = forall (m :: * -> *) a. Monad m => a -> m a
return