Add RSS feed support for index and tag feeds

This commit is contained in:
Mikko Ahlroth 2015-08-05 23:43:00 +03:00
parent cd0d2ddf5b
commit c81a9a430a
10 changed files with 145 additions and 22 deletions

View file

@ -25,9 +25,4 @@ defmodule MebeEngine.Models do
title: nil,
content: nil
end
defmodule Archive do
defstruct key: nil,
posts: nil
end
end

View file

@ -17,8 +17,11 @@ config :mebe_web, MebeWeb.Endpoint,
config :blog_config,
blog_name: "My awesome blog",
blog_author: "Author McAuthor",
absolute_url: "http://localhost:4000", # Absolute URL to the site without trailing slash, including protocol
enable_feeds: false, # Set to true to enable RSS feeds
posts_per_page: 10,
posts_in_feed: 20,
# Disqus comments
disqus_comments: false, # Use Disqus comments

View file

@ -0,0 +1,40 @@
defmodule MebeWeb.ControllerUtils do
use MebeWeb.Web, :controller
@moduledoc """
This module contains the common functions for all controllers.
"""
@blog_name Application.get_env(:blog_config, :blog_name)
@blog_author Application.get_env(:blog_config, :blog_author)
@absolute_url Application.get_env(:blog_config, :absolute_url)
@posts_per_page Application.get_env(:blog_config, :posts_per_page)
@disqus_comments Application.get_env(:blog_config, :disqus_comments)
@page_commenting Application.get_env(:blog_config, :page_commenting)
@disqus_shortname Application.get_env(:blog_config, :disqus_shortname)
@doc """
Render a list of posts with the given template and params. The posts
and generic configuration settings are assigned to the connection.
"""
def render_posts(conn, posts, template, _params) do
conn
|> insert_config
|> assign(:posts, posts)
|> render(template)
end
@doc """
Insert common config variables to the assigns table for the connection
"""
def insert_config(conn) do
conn
|> assign(:blog_name, @blog_name)
|> assign(:blog_author, @blog_author)
|> assign(:absolute_url, @absolute_url)
|> assign(:posts_per_page, @posts_per_page)
|> assign(:disqus_comments, @disqus_comments)
|> assign(:page_commenting, @page_commenting)
|> assign(:disqus_shortname, @disqus_shortname)
end
end

View file

@ -0,0 +1,35 @@
defmodule MebeWeb.FeedController do
use MebeWeb.Web, :controller
alias MebeEngine.DB
import MebeWeb.ControllerUtils, only: [render_posts: 4]
plug :put_resp_content_type, "application/rss+xml"
plug :put_layout_formats, ["xml"]
plug :put_layout, "feed.xml"
@posts_in_feed Application.get_env(:blog_config, :posts_in_feed)
def index(conn, params) do
posts = DB.get_reg_posts 0, @posts_in_feed
conn
|> render_posts(posts, "postlist.xml", params)
end
def tag(conn, params) do
%{"tag" => tag} = params
posts = DB.get_tag_posts tag, 0, @posts_in_feed
conn
|> assign(:tag, tag)
|> render_posts(posts, "postlist.xml", params)
end
defp put_headers(conn, key_values) do
Enum.reduce key_values, conn, fn {k, v}, conn ->
Plug.Conn.put_resp_header(conn, k, v)
end
end
end

View file

@ -2,6 +2,7 @@ defmodule MebeWeb.PageController do
use MebeWeb.Web, :controller
alias MebeEngine.DB
import MebeWeb.ControllerUtils, only: [render_posts: 4, insert_config: 1]
@posts_per_page Application.get_env(:blog_config, :posts_per_page)
@ -119,7 +120,6 @@ defmodule MebeWeb.PageController do
end
end
# Render a list page (a list of posts) or 404 if no posts could be found.
# The postgetter should be an anonymous function which returns a list of
# posts when called, or an empty list if none are found. The function gets
@ -134,13 +134,11 @@ defmodule MebeWeb.PageController do
posts ->
conn
|> insert_config
|> assign(:posts, posts)
|> assign(:total_count, total_count)
|> assign(:current_page, page)
|> assign(:page_type, page_type)
|> assign(:page_args, page_args)
|> render(template)
|> render_posts(posts, template, params)
end
end
@ -167,15 +165,4 @@ defmodule MebeWeb.PageController do
|> put_status(:not_found)
|> render(MebeWeb.ErrorView, :"404")
end
# Insert config variables to the assigns table for the connection
defp insert_config(conn) do
conn
|> assign(:blog_name, Application.get_env(:blog_config, :blog_name))
|> assign(:blog_author, Application.get_env(:blog_config, :blog_author))
|> assign(:posts_per_page, @posts_per_page)
|> assign(:disqus_comments, Application.get_env(:blog_config, :disqus_comments))
|> assign(:page_commenting, Application.get_env(:blog_config, :page_commenting))
|> assign(:disqus_shortname, Application.get_env(:blog_config, :disqus_shortname))
end
end

View file

@ -1,10 +1,11 @@
defmodule MebeWeb.Router do
use Phoenix.Router
@enable_feeds Application.get_env(:blog_config, :enable_feeds)
pipeline :browser do
plug MebeWeb.RequestStartTimePlug
plug :accepts, ["html"]
plug :accepts, ["html", "xml"]
plug :fetch_session
plug :fetch_flash
end
@ -14,9 +15,11 @@ defmodule MebeWeb.Router do
get "/p/:page", PageController, :index
get "/", PageController, :index
if @enable_feeds, do: (get "/feed", FeedController, :index)
get "/tag/:tag/p/:page", PageController, :tag
get "/tag/:tag", PageController, :tag
if @enable_feeds, do: (get "/tag/:tag/feed", FeedController, :tag)
get "/archive/:year/p/:page", PageController, :year
get "/archive/:year", PageController, :year

View file

@ -0,0 +1,41 @@
<%= for post <- @posts do %>
<% {year, month, day} = post.date %>
<%
# Justified versions of the month and day
{j_month, j_day} = {
String.rjust(Integer.to_string(month), 2, ?0),
String.rjust(Integer.to_string(day), 2, ?0)
}
%>
<%
# Quick and dirty RFC 822 month converter
rfc_month = Enum.at(["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], month - 1)
data = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4]
dow_year = if month < 3, do: year - 1, else: year
dow = rem(dow_year + div(dow_year, 4) - div(dow_year, 100) + div(dow_year, 400) + Enum.at(data, month - 1) + day, 7)
dow_str = Enum.at(["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], dow - 1)
%>
<item>
<title>
<![CDATA[<%= post.title %>]]>
</title>
<link><%= @absolute_url %><%= page_path @conn, :post, year, j_month, j_day, post.slug %></link>
<guid><%= @absolute_url %><%= page_path @conn, :post, year, j_month, j_day, post.slug %></guid>
<description>
<![CDATA[
<%= post.short_content %>
<a href="<%= @absolute_url %><%= page_path @conn, :post, year, j_month, j_day, post.slug %>">
Read more
</a>
]]>
</description>
<pubDate><%= dow_str %>, <%= day %> <%= rfc_month %> <%= year %> 00:00:00 UT</pubDate>
</item>
<% end %>

View file

@ -8,13 +8,19 @@
<title><%= title @conn %></title>
<link rel="stylesheet" href="<%= static_path(@conn, "/css/app.css") %>">
<%= if assigns[:page_type] == :tag do %>
<link href="<%= @absolute_url %><%= feed_path @conn, :tag, @tag %>" rel="alternate" type="application/rss+xml" title="RSS feed for tag <%= @tag %>" />
<% else %>
<link href="<%= @absolute_url %><%= feed_path @conn, :index %>" rel="alternate" type="application/rss+xml" title="RSS feed" />
<% end %>
</head>
<body>
<div class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a href="<%= page_path @conn, :index, 1 %>" class="navbar-brand">
<a href="<%= @absolute_url %>" class="navbar-brand">
<%= Application.get_env :blog_config, :blog_name %>
</a>
</div>

View file

@ -0,0 +1,10 @@
<rss version="2.0">
<channel>
<title><%= title @conn %></title>
<link><%= @absolute_url %></link>
<description></description>
<generator>Mebe</generator>
<%= @inner %>
</channel>
</rss>

View file

@ -0,0 +1,3 @@
defmodule MebeWeb.FeedView do
use MebeWeb.Web, :view
end