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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user