{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
module Text.Atom.Conduit.Render
(
renderAtomFeed
, renderAtomEntry
, renderAtomContent
, renderAtomSource
, renderAtomGenerator
, renderAtomLink
, renderAtomCategory
, renderAtomPerson
, renderAtomText
) where
import Text.Atom.Lens
import Text.Atom.Types
import Conduit
import Control.Monad
import Data.Monoid
import Data.Text as Text
import Data.Time.Clock
import Data.Time.LocalTime
import Data.Time.RFC3339
import Data.XML.Types
import Lens.Micro
import Refined
import Text.XML as XML
import Text.XML.Stream.Render
import qualified Text.XML.Unresolved as Unresolved
import URI.ByteString
renderAtomFeed :: (Monad m) => AtomFeed -> ConduitT () Event m ()
renderAtomFeed f = atomTag "feed" (attr "xmlns" "http://www.w3.org/2005/Atom") $ do
forM_ (f^.feedAuthorsL) $ renderAtomPerson "author"
forM_ (f^.feedCategoriesL) renderAtomCategory
forM_ (f^.feedContributorsL) $ renderAtomPerson "contributor"
forM_ (f^.feedEntriesL) renderAtomEntry
forM_ (f^.feedGeneratorL) renderAtomGenerator
forM_ (feedIcon f) $ atomTag "icon" mempty . content . decodeUtf8 . withAtomURI serializeURIRef'
atomTag "id" mempty . content $ f^.feedIdL
forM_ (f^.feedLinksL) renderAtomLink
forM_ (feedLogo f) $ atomTag "logo" mempty . content . decodeUtf8 . withAtomURI serializeURIRef'
forM_ (f^.feedRightsL) $ renderAtomText "rights"
forM_ (f^.feedSubtitleL) $ renderAtomText "subtitle"
renderAtomText "title" $ f^.feedTitleL
dateTag "updated" $ f^.feedUpdatedL
renderAtomEntry :: (Monad m) => AtomEntry -> ConduitT () Event m ()
renderAtomEntry e = atomTag "entry" mempty $ do
forM_ (e^.entryAuthorsL) $ renderAtomPerson "author"
forM_ (e^.entryCategoriesL) renderAtomCategory
forM_ (e^.entryContentL) renderAtomContent
forM_ (e^.entryContributorsL) $ renderAtomPerson "contributor"
atomTag "id" mempty . content $ e^.entryIdL
forM_ (e^.entryLinksL) renderAtomLink
forM_ (e^.entryPublishedL) $ dateTag "published"
forM_ (e^.entryRightsL) $ renderAtomText "rights"
forM_ (e^.entrySourceL) renderAtomSource
forM_ (e^.entrySummaryL) $ renderAtomText "summary"
renderAtomText "title" (e^.entryTitleL)
dateTag "updated" (e^.entryUpdatedL)
renderAtomContent :: (Monad m) => AtomContent -> ConduitT () Event m ()
renderAtomContent (AtomContentInlineXHTML element) = atomTag "content" (attr "type" "xhtml") $ yieldMany $ Unresolved.elementToEvents element
renderAtomContent (AtomContentOutOfLine ctype uri) = atomTag "content" (nonEmptyAttr "type" ctype <> attr "src" (decodeUtf8 $ withAtomURI serializeURIRef' uri)) $ return ()
renderAtomContent (AtomContentInlineText TypeHTML t) = atomTag "content" (attr "type" "html") $ content t
renderAtomContent (AtomContentInlineText TypeText t) = atomTag "content" mempty $ content t
renderAtomContent (AtomContentInlineOther ctype t) = atomTag "content" (attr "type" ctype) $ content t
renderAtomSource :: (Monad m) => AtomSource -> ConduitT () Event m ()
renderAtomSource s = atomTag "source" mempty $ do
forM_ (s^.sourceAuthorsL) $ renderAtomPerson "author"
forM_ (s^.sourceCategoriesL) renderAtomCategory
forM_ (s^.sourceContributorsL) $ renderAtomPerson "contributor"
forM_ (s^.sourceGeneratorL) renderAtomGenerator
forM_ (sourceIcon s) $ atomTag "icon" mempty . content . decodeUtf8 . withAtomURI serializeURIRef'
unless (Text.null $ s^.sourceIdL) . atomTag "id" mempty . content $ s^.sourceIdL
forM_ (s^.sourceLinksL) renderAtomLink
forM_ (sourceLogo s) $ atomTag "logo" mempty . content . decodeUtf8 . withAtomURI serializeURIRef'
forM_ (s^.sourceRightsL) $ renderAtomText "rights"
forM_ (s^.sourceSubtitleL) $ renderAtomText "subtitle"
forM_ (s^.sourceTitleL) $ renderAtomText "title"
forM_ (s^.sourceUpdatedL) $ dateTag "updated"
renderAtomGenerator :: (Monad m) => AtomGenerator -> ConduitT () Event m ()
renderAtomGenerator g = atomTag "generator" attributes . content . unrefine $ g^.generatorContentL
where attributes = optionalAttr "uri" (decodeUtf8 . withAtomURI serializeURIRef' <$> generatorUri g)
<> nonEmptyAttr "version" (g^.generatorVersionL)
renderAtomLink :: (Monad m) => AtomLink -> ConduitT () Event m ()
renderAtomLink l = atomTag "link" linkAttrs $ return ()
where linkAttrs = attr "href" (decodeUtf8 . withAtomURI serializeURIRef' $ linkHref l)
<> nonEmptyAttr "rel" (l^.linkRelL)
<> nonEmptyAttr "type" (l^.linkTypeL)
<> nonEmptyAttr "hreflang" (l^.linkLangL)
<> nonEmptyAttr "title" (l^.linkTitleL)
<> nonEmptyAttr "length" (l^.linkLengthL)
renderAtomCategory :: (Monad m) => AtomCategory -> ConduitT () Event m ()
renderAtomCategory c = atomTag "category" attributes $ return ()
where attributes = attr "term" (unrefine $ c^.categoryTermL)
<> nonEmptyAttr "scheme" (c^.categorySchemeL)
<> nonEmptyAttr "label" (c^.categoryLabelL)
renderAtomPerson :: (Monad m) => Text -> AtomPerson -> ConduitT () Event m ()
renderAtomPerson name p = atomTag name mempty $ do
atomTag "name" mempty . content . unrefine $ p^.personNameL
unless (Text.null $ p^.personEmailL) $ atomTag "email" mempty . content $ p^.personEmailL
forM_ (personUri p) $ atomTag "uri" mempty . content . decodeUtf8 . withAtomURI serializeURIRef'
renderAtomText :: Monad m => Text -> AtomText -> ConduitT () Event m ()
renderAtomText name (AtomXHTMLText element) = atomTag name (attr "type" "xhtml") $ yieldMany $ Unresolved.elementToEvents element
renderAtomText name (AtomPlainText TypeHTML t) = atomTag name (attr "type" "html") $ content t
renderAtomText name (AtomPlainText TypeText t) = atomTag name mempty $ content t
atomTag :: Monad m => Text -> Attributes -> ConduitT () Event m () -> ConduitT () Event m ()
atomTag name = tag (Name name (Just "http://www.w3.org/2005/Atom") (Just "atom"))
dateTag :: (Monad m) => Text -> UTCTime -> ConduitT () Event m ()
dateTag name = atomTag name mempty . content . formatTimeRFC3339 . utcToZonedTime utc
nonEmptyAttr :: Name -> Text -> Attributes
nonEmptyAttr name value
| value == mempty = mempty
| otherwise = attr name value