module Network.Gitit.Feed (FeedConfig(..), filestoreToXmlFeed) where
import Control.Monad
import Data.DateTime
import Data.List (intercalate, sortBy)
import Data.Maybe
import Data.Ord (comparing)
import Network.URI (isAllowedInURI, escapeURIString)
import System.FilePath
import Data.FileStore.Types
import Text.Atom.Feed
import Text.Atom.Feed.Export
import Text.XML.Light
data FeedConfig = FeedConfig {
fcTitle :: String
, fcBaseUrl :: String
, fcFeedDays :: Integer
} deriving (Show, Read)
filestoreToXmlFeed :: FeedConfig -> FileStore -> (Maybe FilePath) -> IO String
filestoreToXmlFeed cfg f mbPath = filestoreToFeed cfg f mbPath >>= return . ppTopElement . xmlFeed
filestoreToFeed :: FeedConfig -> FileStore -> (Maybe FilePath) -> IO Feed
filestoreToFeed cfg a mbPath = do
let path' = maybe "" id mbPath
when (null $ fcBaseUrl cfg) $ error "base-url in the config file is null."
rs <- changeLog cfg a mbPath
let rsShifted = case rs of
[] -> []
(x:_) -> x : init rs
now <- liftM formatFeedTime getCurrentTime
return $ Feed { feedId = fcBaseUrl cfg ++ "/" ++ escape path'
, feedTitle = TextString $ fcTitle cfg
, feedUpdated = now
, feedAuthors = []
, feedCategories = []
, feedContributors = []
, feedGenerator = Just Generator{ genURI = Just "http://github.com/jgm/gitit"
, genVersion = Nothing
, genText = "gitit" }
, feedIcon = Nothing
, feedLinks = [ (nullLink (fcBaseUrl cfg ++ "/_feed/" ++ escape path')) {linkRel = Just (Left "self")} ]
, feedLogo = Nothing
, feedRights = Nothing
, feedSubtitle = Nothing
, feedAttrs = []
, feedOther = []
, feedEntries = reverse $ zipWith (revToEntry cfg path') rs rsShifted }
changeLog :: FeedConfig -> FileStore -> (Maybe FilePath) -> IO [Revision]
changeLog cfg a mbPath = do
let files = maybe [] (\f -> [f, f <.> "page"]) mbPath
now <- getCurrentTime
let startTime = addMinutes (60 * 24 * fcFeedDays cfg) now
rs <- history a files TimeRange{timeFrom = Just startTime, timeTo = Just now}
return $ sortBy (comparing revDateTime) rs
revToEntry :: FeedConfig -> String -> Revision -> Revision -> Entry
revToEntry cfg path' Revision{
revId = rid,
revDateTime = rdt,
revAuthor = ra,
revDescription = rd,
revChanges = rv } prevRevision =
baseEntry{ entrySummary = Just $ TextString rd
, entryAuthors = [Person { personName = authorName ra
, personURI = Nothing
, personEmail = Nothing
, personOther = [] }]
, entryLinks = [diffLink]
}
where diffLink = Link{ linkHref = fcBaseUrl cfg ++ "/_diff/" ++ escape firstpath ++ "?to=" ++ rid ++ fromrev
, linkRel = Just (Left "alternate")
, linkType = Nothing
, linkHrefLang = Nothing
, linkTitle = Nothing
, linkLength = Nothing
, linkAttrs = []
, linkOther = [] }
(firstpath, fromrev) =
if null path'
then case rv of
[] -> error "revToEntry, null rv"
(rev:_) -> case rev of
Modified f -> (dePage f, "&from=" ++ revId prevRevision)
Added f -> (dePage f, "")
Deleted f -> (dePage f, "&from=" ++ revId prevRevision)
else (path',"")
baseEntry = nullEntry (fcBaseUrl cfg ++ "/" ++ escape path' ++ "?revision=" ++ rid)
(TextString (intercalate ", " $ map showRev rv)) (formatFeedTime rdt)
showRev (Modified f) = dePage f
showRev (Added f) = "added " ++ dePage f
showRev (Deleted f) = "deleted " ++ dePage f
dePage f = if takeExtension f == ".page"
then dropExtension f
else f
escape :: String -> String
escape = escapeURIString isAllowedInURI
formatFeedTime :: DateTime -> String
formatFeedTime = formatDateTime "%Y-%m%--%dT%TZ"