{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
module Hakyll.Web.Feed
( FeedConfiguration (..)
, renderRss
, renderAtom
, renderRssWithTemplates
, renderAtomWithTemplates
) where
import Hakyll.Core.Compiler
import Hakyll.Core.Item
import Hakyll.Core.Util.String (replaceAll)
import Hakyll.Web.Template
import Hakyll.Web.Template.Context
import Hakyll.Web.Template.List
import Data.FileEmbed (makeRelativeToProject)
import System.FilePath ((</>))
rssTemplate :: Template
rssTemplate =
$(makeRelativeToProject ("data" </> "templates" </> "rss.xml")
>>= embedTemplate)
rssItemTemplate :: Template
rssItemTemplate =
$(makeRelativeToProject ("data" </> "templates" </> "rss-item.xml")
>>= embedTemplate)
atomTemplate :: Template
atomTemplate =
$(makeRelativeToProject ("data" </> "templates" </> "atom.xml")
>>= embedTemplate)
atomItemTemplate :: Template
atomItemTemplate =
$(makeRelativeToProject ("data" </> "templates" </> "atom-item.xml")
>>= embedTemplate)
data FeedConfiguration = FeedConfiguration
{
feedTitle :: String
,
feedDescription :: String
,
feedAuthorName :: String
,
feedAuthorEmail :: String
,
feedRoot :: String
} deriving (Show, Eq)
renderFeed :: Template
-> Template
-> FeedConfiguration
-> Context String
-> [Item String]
-> Compiler (Item String)
renderFeed feedTpl itemTpl config itemContext items = do
protectedItems <- mapM (applyFilter protectCDATA) items
body <- makeItem =<< applyTemplateList itemTpl itemContext' protectedItems
applyTemplate feedTpl feedContext body
where
applyFilter :: (Monad m,Functor f) => (String -> String) -> f String -> m (f String)
applyFilter tr str = return $ fmap tr str
protectCDATA :: String -> String
protectCDATA = replaceAll "]]>" (const "]]>")
itemContext' = mconcat
[ itemContext
, constField "root" (feedRoot config)
, constField "authorName" (feedAuthorName config)
, constField "authorEmail" (feedAuthorEmail config)
]
feedContext = mconcat
[ bodyField "body"
, constField "title" (feedTitle config)
, constField "description" (feedDescription config)
, constField "authorName" (feedAuthorName config)
, constField "authorEmail" (feedAuthorEmail config)
, constField "root" (feedRoot config)
, urlField "url"
, updatedField
, missingField
]
updatedField = field "updated" $ \_ -> case items of
[] -> return "Unknown"
(x : _) -> unContext itemContext' "updated" [] x >>= \cf -> case cf of
StringField s -> return s
_ -> fail "Hakyll.Web.Feed.renderFeed: Internal error"
renderRssWithTemplates ::
Template
-> Template
-> FeedConfiguration
-> Context String
-> [Item String]
-> Compiler (Item String)
renderRssWithTemplates feedTemplate itemTemplate config context = renderFeed
feedTemplate itemTemplate config
(makeItemContext "%a, %d %b %Y %H:%M:%S UT" context)
renderAtomWithTemplates ::
Template
-> Template
-> FeedConfiguration
-> Context String
-> [Item String]
-> Compiler (Item String)
renderAtomWithTemplates feedTemplate itemTemplate config context = renderFeed
feedTemplate itemTemplate config
(makeItemContext "%Y-%m-%dT%H:%M:%SZ" context)
renderRss :: FeedConfiguration
-> Context String
-> [Item String]
-> Compiler (Item String)
renderRss = renderRssWithTemplates rssTemplate rssItemTemplate
renderAtom :: FeedConfiguration
-> Context String
-> [Item String]
-> Compiler (Item String)
renderAtom = renderAtomWithTemplates atomTemplate atomItemTemplate
makeItemContext :: String -> Context a -> Context a
makeItemContext fmt context = mconcat
[context, dateField "published" fmt, dateField "updated" fmt]