RSS
Added first cut of RSS feed; added links to head of default theme's layout template
This commit is contained in:
parent
d3712dc562
commit
7538b9ef26
@ -138,6 +138,24 @@ let tryFindPostByPriorPermalink conn (webLogId : string) (permalink : string) =
|
|||||||
|> await
|
|> await
|
||||||
|> Seq.tryHead
|
|> Seq.tryHead
|
||||||
|
|
||||||
|
/// Get a set of posts for RSS
|
||||||
|
let findFeedPosts conn webLogId nbr : (Post * User option) list =
|
||||||
|
findPageOfPublishedPosts conn webLogId 1 nbr
|
||||||
|
|> List.map (fun post -> { post with categories = r.Table(Table.Category)
|
||||||
|
.GetAll(post.categoryIds |> List.toArray)
|
||||||
|
.OrderBy("name")
|
||||||
|
.Pluck("id", "name")
|
||||||
|
.RunListAsync<Category>(conn)
|
||||||
|
|> await
|
||||||
|
|> Seq.toList },
|
||||||
|
(match r.Table(Table.User)
|
||||||
|
.Get(post.authorId)
|
||||||
|
.RunAtomAsync<User>(conn)
|
||||||
|
|> await
|
||||||
|
|> box with
|
||||||
|
| null -> None
|
||||||
|
| user -> Some <| unbox user))
|
||||||
|
|
||||||
/// Save a post
|
/// Save a post
|
||||||
let savePost conn post =
|
let savePost conn post =
|
||||||
match post.id with
|
match post.id with
|
||||||
|
@ -11,8 +11,10 @@ open Nancy.Security
|
|||||||
open Nancy.Session.Persistable
|
open Nancy.Session.Persistable
|
||||||
open NodaTime
|
open NodaTime
|
||||||
open RethinkDb.Driver.Net
|
open RethinkDb.Driver.Net
|
||||||
|
open System
|
||||||
|
open System.ServiceModel.Syndication
|
||||||
|
|
||||||
/// Routes dealing with posts (including the home page, /tag, /category, and catch-all routes)
|
/// Routes dealing with posts (including the home page, /tag, /category, RSS, and catch-all routes)
|
||||||
type PostModule(conn : IConnection, clock : IClock) as this =
|
type PostModule(conn : IConnection, clock : IClock) as this =
|
||||||
inherit NancyModule()
|
inherit NancyModule()
|
||||||
|
|
||||||
@ -31,6 +33,7 @@ type PostModule(conn : IConnection, clock : IClock) as this =
|
|||||||
this.Get .["/category/{slug}/page/{page:int}"] <- fun parms -> this.CategorizedPosts (downcast parms)
|
this.Get .["/category/{slug}/page/{page:int}"] <- fun parms -> this.CategorizedPosts (downcast parms)
|
||||||
this.Get .["/tag/{tag}" ] <- fun parms -> this.TaggedPosts (downcast parms)
|
this.Get .["/tag/{tag}" ] <- fun parms -> this.TaggedPosts (downcast parms)
|
||||||
this.Get .["/tag/{tag}/page/{page:int}" ] <- fun parms -> this.TaggedPosts (downcast parms)
|
this.Get .["/tag/{tag}/page/{page:int}" ] <- fun parms -> this.TaggedPosts (downcast parms)
|
||||||
|
this.Get .["/feed" ] <- fun parms -> this.GenerateFeed (downcast parms)
|
||||||
this.Get .["/posts/list" ] <- fun _ -> this.PostList 1
|
this.Get .["/posts/list" ] <- fun _ -> this.PostList 1
|
||||||
this.Get .["/posts/list/page/{page:int}" ] <- fun parms -> this.PostList (getPage <| downcast parms)
|
this.Get .["/posts/list/page/{page:int}" ] <- fun parms -> this.PostList (getPage <| downcast parms)
|
||||||
this.Get .["/post/{postId}/edit" ] <- fun parms -> this.EditPost (downcast parms)
|
this.Get .["/post/{postId}/edit" ] <- fun parms -> this.EditPost (downcast parms)
|
||||||
@ -133,6 +136,39 @@ type PostModule(conn : IConnection, clock : IClock) as this =
|
|||||||
model.subtitle <- Some <| sprintf "Posts tagged \"%s\"" tag
|
model.subtitle <- Some <| sprintf "Posts tagged \"%s\"" tag
|
||||||
this.ThemedView "index" model
|
this.ThemedView "index" model
|
||||||
|
|
||||||
|
/// Generate an RSS feed
|
||||||
|
member this.GenerateFeed (parameters : DynamicDictionary) =
|
||||||
|
let format = match parameters.ContainsKey "format" with // FIXME: format not coming through on query string
|
||||||
|
| true -> parameters.["format"].ToString ()
|
||||||
|
| _ -> "rss"
|
||||||
|
let posts = findFeedPosts conn this.WebLog.id 10
|
||||||
|
let feed =
|
||||||
|
SyndicationFeed(
|
||||||
|
this.WebLog.name, defaultArg this.WebLog.subtitle null,
|
||||||
|
Uri(sprintf "%s://%s" this.Request.Url.Scheme this.WebLog.urlBase), null,
|
||||||
|
(match posts |> List.tryHead with
|
||||||
|
| Some (post, _) -> Instant(post.updatedOn).ToDateTimeOffset ()
|
||||||
|
| _ -> System.DateTimeOffset(System.DateTime.MinValue)),
|
||||||
|
posts
|
||||||
|
|> List.map (fun (post, user) ->
|
||||||
|
let item =
|
||||||
|
SyndicationItem(
|
||||||
|
BaseUri = Uri(sprintf "%s://%s/%s" this.Request.Url.Scheme this.WebLog.urlBase post.permalink),
|
||||||
|
PublishDate = Instant(post.publishedOn).ToDateTimeOffset (),
|
||||||
|
LastUpdatedTime = Instant(post.updatedOn).ToDateTimeOffset (),
|
||||||
|
Title = TextSyndicationContent(post.title),
|
||||||
|
Content = TextSyndicationContent(post.text, TextSyndicationContentKind.Html))
|
||||||
|
user
|
||||||
|
|> Option.iter (fun u -> item.Authors.Add
|
||||||
|
(SyndicationPerson(u.userName, u.preferredName, defaultArg u.url null)))
|
||||||
|
post.categories
|
||||||
|
|> List.iter (fun c -> item.Categories.Add(SyndicationCategory(c.name)))
|
||||||
|
item))
|
||||||
|
let stream = new IO.MemoryStream()
|
||||||
|
Xml.XmlWriter.Create(stream)
|
||||||
|
|> match format with | "atom" -> feed.SaveAsAtom10 | _ -> feed.SaveAsRss20
|
||||||
|
stream.Position <- int64 0
|
||||||
|
upcast this.Response.FromStream(stream, sprintf "application/%s+xml" format)
|
||||||
|
|
||||||
// ---- Administer posts ----
|
// ---- Administer posts ----
|
||||||
|
|
||||||
|
@ -148,6 +148,7 @@
|
|||||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="System.Numerics" />
|
<Reference Include="System.Numerics" />
|
||||||
|
<Reference Include="System.ServiceModel" />
|
||||||
<Reference Include="System.Web.Razor">
|
<Reference Include="System.Web.Razor">
|
||||||
<HintPath>..\packages\FSharp.Formatting.2.14.4\lib\net40\System.Web.Razor.dll</HintPath>
|
<HintPath>..\packages\FSharp.Formatting.2.14.4\lib\net40\System.Web.Razor.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
<link rel="stylesheet" type="text/css" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" />
|
<link rel="stylesheet" type="text/css" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="/default/bootstrap-theme.min.css" />
|
<link rel="stylesheet" type="text/css" href="/default/bootstrap-theme.min.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" />
|
<link rel="stylesheet" type="text/css" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" />
|
||||||
|
<link rel="alternate" type="application/atom+xml" href="//@Model.webLog.urlBase/feed?format=atom" />
|
||||||
|
<link rel="alternate" type="application/rss+xml" href="//@Model.webLog.urlBase/feed" />
|
||||||
@Section['Head'];
|
@Section['Head'];
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
Loading…
Reference in New Issue
Block a user