From 9ee12c3751c8ad34c7140bafab74c48939a6b2d9 Mon Sep 17 00:00:00 2001 From: Filip Gralinski Date: Tue, 3 May 2016 22:14:55 +0200 Subject: [PATCH] add RSS for a challenge timeline --- Foundation.hs | 1 + Handler/Discussion.hs | 48 ++++++++++++++++++++++++-- config/routes | 1 + gonito.cabal | 1 + static/images/rss-icon.jpg | Bin 0 -> 1430 bytes templates/challenge-discussion.hamlet | 4 +++ templates/timeline-item.hamlet | 3 +- 7 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 static/images/rss-icon.jpg diff --git a/Foundation.hs b/Foundation.hs index f0ef0e5..859a688 100644 --- a/Foundation.hs +++ b/Foundation.hs @@ -114,6 +114,7 @@ instance Yesod App where isAuthorized (ChallengeAllSubmissionsR _) _ = return Authorized isAuthorized (ChallengeGraphDataR _) _ = return Authorized isAuthorized (ChallengeDiscussionR _) _ = return Authorized + isAuthorized (ChallengeDiscussionFeedR _) _ = return Authorized isAuthorized (AvatarR _) _ = return Authorized diff --git a/Handler/Discussion.hs b/Handler/Discussion.hs index 7743ff1..f4e481e 100644 --- a/Handler/Discussion.hs +++ b/Handler/Discussion.hs @@ -10,12 +10,18 @@ import Text.Blaze.Html4.Strict (i) import Handler.ShowChallenge import Yesod.Form.Bootstrap3 +import Yesod.RssFeed -data TimelineItem = TimelineItem UTCTime (Entity User) Markup +import Data.Text as T (pack) +import Database.Persist.Sql -getTime (TimelineItem stamp _ _) = stamp +data TimelineItem = TimelineItem Text UTCTime (Entity User) Markup + +getTime (TimelineItem _ stamp _ _) = stamp class ToTimelineItem a where + getTimelineItemId :: a -> Text + timelineWhen :: a -> UTCTime timelineWhoId :: a -> UserId @@ -29,17 +35,20 @@ class ToTimelineItem a where toTimelineItem :: a -> Handler TimelineItem toTimelineItem sItem = do + let itemIdentifier = getTimelineItemId sItem let when = timelineWhen sItem who <- timelineWho sItem what <- timelineWhat sItem - return $ TimelineItem when who what + return $ TimelineItem itemIdentifier when who what instance ToTimelineItem (Entity Comment) where + getTimelineItemId (Entity commentId comment) = "comment-" ++ (T.pack $ show $ fromSqlKey $ commentId) timelineWhoId (Entity _ comment) = commentAuthor comment timelineWhen (Entity _ comment) = commentPosted comment timelineWhat (Entity _ comment) = return $ toMarkup $ commentText comment instance ToTimelineItem (Entity Submission) where + getTimelineItemId (Entity commentId comment) = "submission-" ++ (T.pack $ show $ fromSqlKey $ commentId) timelineWhoId (Entity _ submission) = submissionSubmitter submission timelineWhen (Entity _ submission) = submissionStamp submission timelineWhat (Entity _ submission) = return $ i $ toMarkup ( @@ -88,3 +97,36 @@ commentForm :: Key Challenge -> AForm Handler (ChallengeId, Textarea) commentForm challengeId = (,) <$> pure challengeId <*> areq textareaField (bfs MsgCommentText) Nothing + + +numberOfItemsInFeed :: Int +numberOfItemsInFeed = 20 + + +getChallengeDiscussionFeedR :: Text -> Handler RepRss +getChallengeDiscussionFeedR name = do + (Entity challengeId challenge) <- runDB $ getBy404 $ UniqueName name + items <- getTimelineItems challengeId + now <- liftIO getCurrentTime + render <- getUrlRender + rssFeedText Feed { + feedTitle = "gonito.net / " ++ (challengeTitle challenge), + feedLinkSelf = render HomeR, + feedLinkHome = render (ChallengeDiscussionFeedR name), + feedAuthor = "gonito.net", + feedDescription = toMarkup $ "Comments and submission for a gonito.net challenge — " ++ (challengeTitle challenge), + feedLanguage = "en", + feedUpdated = case items of + (latestItem : _) -> getTime latestItem + _ -> now, + feedLogo = Nothing, + feedEntries = map (getFeedEntry render challenge) (take numberOfItemsInFeed items) } + + +getFeedEntry :: (Route App -> Text) -> Challenge -> TimelineItem -> FeedEntry Text +getFeedEntry render challenge (TimelineItem identifier stamp (Entity userId user) contents) = FeedEntry { + feedEntryLink = (render (ChallengeDiscussionR (challengeName challenge))) <> "#" <> identifier, + feedEntryUpdated = stamp, + feedEntryTitle = (challengeTitle challenge) ++ " / " ++ (formatSubmitter user), + feedEntryContent = contents, + feedEntryEnclosure = Nothing } diff --git a/config/routes b/config/routes index c0cdf12..aa6d5b4 100644 --- a/config/routes +++ b/config/routes @@ -19,6 +19,7 @@ /challenge-how-to/#Text ChallengeHowToR GET /challenge-graph-data/#Text ChallengeGraphDataR GET /challenge-discussion/#Text ChallengeDiscussionR GET POST +/challenge-discussion-rss/#Text ChallengeDiscussionFeedR GET /q QueryFormR GET POST /q/#Text QueryResultsR GET diff --git a/gonito.cabal b/gonito.cabal index 4237345..74fcc71 100644 --- a/gonito.cabal +++ b/gonito.cabal @@ -125,6 +125,7 @@ library , blaze-html , conduit-extra , resourcet + , yesod-newsfeed executable gonito if flag(library-only) diff --git a/static/images/rss-icon.jpg b/static/images/rss-icon.jpg new file mode 100644 index 0000000000000000000000000000000000000000..51aff81126b1b1395ee4304d531924e89e786752 GIT binary patch literal 1430 zcma)$eKga19LK-E&1@c0v#E<^mT5CnVOvAjL!}VOkal%b7&$K87EAY-6D4*pYSg*i zQ;3Oqei%s)BI|~Uo99_eid0G{ySSI#b#ABr?e#t1bH3;OI-l?RqaId218cl?dF}!b z41jRW0qVB^y)!;6`V@eG7Wfnb^)xVW3qKah0pTs01X3%&Spa=Iu&=-?_~5Dc!RjRa^zj2lYx`6nQ_*5~0*5}~b;NP-&%YwKrcL0pScj{tqRrUDH| z0~hdG;aR9B1Yv%nd*9WVBjuEX8MQssxU@b&AG>a$+?_5k#l{2%gyAOC0L?Gk`o8}` z@9!3TX9RrL2s_uUQ|QHnjo4~tLVrog1h ziY@piT*!n|HF@NcD|27T2u(_H_VTBTJD_FT^(M{U!60 zo;d%ZBc?fB_3}4?@!b++Y!$5sM^!$s-a!-H9IM6Id0Iw=FB>}PU?jY2YqhuuPhWT3 zf{J>=8EyKPv#+OM-`E*q|Eko@Rs+)@H#WiR`i^<)@BRO_w4&N(25`$X{nY(0Dqg-@ zG1&BkJ3?Ux6^GFMA0L%b1X#W|=QQ4>gm80dtHSKweKn|gx3Gsct7qp3OWt=mSmHCn)`y6AhMDfqqztJ=UC3mg4E+3X%ROS>bj* zpGjKmKVe+H#a}wu)0Z7JDco?5Jjk&jX152Tv569U1bjR%tZQLYPVTFOa>XgekE6~j z$Er<}Q;q|P(TpO6%@GF}3??4(Izvg5p9?)Nj!+zYEOD6aFsTq&3-k5zMORB1hZS9q zX(X?fqT{+M6a2cY))b@HB;P5|C-{10`R15$o?-LiR7~1XQ<teu zes;q`aNMrQ+1wi|-j+9tQ$EITuXB7)mAmg<9GYn#=m9Og(F6BdSP3th$JBwY(y(hBJRvT-Ws6?zoJ8 zC#%uuAKQGXprl>WS+9Sx&;xm;9XrI78T5^E_pxj5dgS>!la>DR*r6^wq8kI}a{CLk zNtGe8$)85~ihV=tj661Ol!Z5W1?lzY^U`+IoTFr6;kX5E*mHzIjXj(20K39*ua+f@-~c1vpS)OpFN*r1rA?X;+> nJ97_xuH6#gGcsEDw(_qmPQG7_VLog in to write a comment +

+ + +