1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
-- | A Module that allows easy rendering of RSS feeds. If you use this module,
-- you must make sure you set the `absoluteUrl` field in the main Hakyll
-- configuration.
--
-- Apart from that, the main rendering functions (@renderRss@, @renderAtom@)
-- all assume that you pass the list of items so that the most recent entry
-- in the feed is the first item in the list.
--
-- Also note that the @Context@s should have (at least) the following
-- fields to produce a correct feed:
--
-- - @$title@: Title of the item.
--
-- - @$description@: Description to appear in the feed.
--
-- - @$url@: URL to the item - this is usually set automatically.
--
-- Furthermore, the feed will be generated, but will be incorrect (it won't
-- validate) if an empty list is passed.
module Text.Hakyll.Feed
( FeedConfiguration (..)
, renderRss
, renderAtom
) where
import Control.Arrow ((>>>), second)
import Control.Monad.Reader (liftIO)
import Data.Maybe (fromMaybe)
import qualified Data.Map as M
import Text.Hakyll.Context (Context (..))
import Text.Hakyll.CreateContext (createListing)
import Text.Hakyll.ContextManipulations (renderDate)
import Text.Hakyll.HakyllMonad (Hakyll)
import Text.Hakyll.Render (render, renderChain)
import Text.Hakyll.HakyllAction
import Paths_hakyll
-- | This is a data structure to keep the configuration of a feed.
data FeedConfiguration = FeedConfiguration
{ -- | Url of the feed (relative to site root). For example, @rss.xml@.
feedUrl :: String
, -- | Title of the feed.
feedTitle :: String
, -- | Description of the feed.
feedDescription :: String
, -- | Name of the feed author.
feedAuthorName :: String
}
-- | This is an auxiliary function to create a listing that is, in fact, a feed.
-- The items should be sorted on date.
createFeed :: FeedConfiguration -- ^ Feed configuration.
-> [HakyllAction () Context] -- ^ Items to include.
-> FilePath -- ^ Feed template.
-> FilePath -- ^ Item template.
-> HakyllAction () Context
createFeed configuration renderables template itemTemplate =
listing >>> render template
where
listing = createListing (feedUrl configuration)
[itemTemplate] renderables additional
additional = map (second $ Left . ($ configuration))
[ ("title", feedTitle)
, ("description", feedDescription)
, ("authorName", feedAuthorName)
] ++ updated
-- Take the first timestamp, which should be the most recent.
updated = let action = createHakyllAction $ return . fromMaybe "foo"
. M.lookup "timestamp" . unContext
toTuple r = ("timestamp", Right $ r >>> action)
in map toTuple $ take 1 renderables
-- | Abstract function to render any feed.
renderFeed :: FeedConfiguration -- ^ Feed configuration.
-> [HakyllAction () Context] -- ^ Items to include in the feed.
-> FilePath -- ^ Feed template.
-> FilePath -- ^ Item template.
-> Hakyll ()
renderFeed configuration renderables template itemTemplate = do
template' <- liftIO $ getDataFileName template
itemTemplate' <- liftIO $ getDataFileName itemTemplate
let renderFeed' = createFeed configuration renderables
template' itemTemplate'
renderChain [] renderFeed'
-- | Render an RSS feed with a number of items.
renderRss :: FeedConfiguration -- ^ Feed configuration.
-> [HakyllAction () Context] -- ^ Items to include in the feed.
-> Hakyll ()
renderRss configuration renderables =
renderFeed configuration (map (>>> renderRssDate) renderables)
"templates/rss.xml" "templates/rss-item.xml"
where
renderRssDate = renderDate "timestamp" "%a, %d %b %Y %H:%M:%S UT"
"No date found."
-- | Render an Atom feed with a number of items.
renderAtom :: FeedConfiguration -- ^ Feed configuration.
-> [HakyllAction () Context] -- ^ Items to include in the feed.
-> Hakyll ()
renderAtom configuration renderables =
renderFeed configuration (map (>>> renderAtomDate) renderables)
"templates/atom.xml" "templates/atom-item.xml"
where
renderAtomDate = renderDate "timestamp" "%Y-%m-%dT%H:%M:%SZ"
"No date found."
|