From c81a9a430a881a66e4f4e07babf40605e9cd3eae Mon Sep 17 00:00:00 2001 From: Mikko Ahlroth Date: Wed, 5 Aug 2015 23:43:00 +0300 Subject: [PATCH] Add RSS feed support for index and tag feeds --- apps/mebe_engine/lib/models.ex | 5 --- apps/mebe_web/config/config.exs.dist | 3 ++ .../web/controllers/controller_utils.ex | 40 ++++++++++++++++++ .../web/controllers/feed_controller.ex | 35 ++++++++++++++++ .../web/controllers/page_controller.ex | 17 +------- apps/mebe_web/web/router.ex | 5 ++- .../web/templates/feed/postlist.xml.eex | 41 +++++++++++++++++++ .../web/templates/layout/app.html.eex | 8 +++- .../web/templates/layout/feed.xml.eex | 10 +++++ apps/mebe_web/web/views/feed_view.ex | 3 ++ 10 files changed, 145 insertions(+), 22 deletions(-) create mode 100644 apps/mebe_web/web/controllers/controller_utils.ex create mode 100644 apps/mebe_web/web/controllers/feed_controller.ex create mode 100644 apps/mebe_web/web/templates/feed/postlist.xml.eex create mode 100644 apps/mebe_web/web/templates/layout/feed.xml.eex create mode 100644 apps/mebe_web/web/views/feed_view.ex diff --git a/apps/mebe_engine/lib/models.ex b/apps/mebe_engine/lib/models.ex index 7378d2a..e6406b9 100644 --- a/apps/mebe_engine/lib/models.ex +++ b/apps/mebe_engine/lib/models.ex @@ -25,9 +25,4 @@ defmodule MebeEngine.Models do title: nil, content: nil end - - defmodule Archive do - defstruct key: nil, - posts: nil - end end \ No newline at end of file diff --git a/apps/mebe_web/config/config.exs.dist b/apps/mebe_web/config/config.exs.dist index 885b32b..cf4dfee 100644 --- a/apps/mebe_web/config/config.exs.dist +++ b/apps/mebe_web/config/config.exs.dist @@ -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 diff --git a/apps/mebe_web/web/controllers/controller_utils.ex b/apps/mebe_web/web/controllers/controller_utils.ex new file mode 100644 index 0000000..c3828de --- /dev/null +++ b/apps/mebe_web/web/controllers/controller_utils.ex @@ -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 diff --git a/apps/mebe_web/web/controllers/feed_controller.ex b/apps/mebe_web/web/controllers/feed_controller.ex new file mode 100644 index 0000000..e4a861c --- /dev/null +++ b/apps/mebe_web/web/controllers/feed_controller.ex @@ -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 diff --git a/apps/mebe_web/web/controllers/page_controller.ex b/apps/mebe_web/web/controllers/page_controller.ex index c7787e4..dbe3657 100644 --- a/apps/mebe_web/web/controllers/page_controller.ex +++ b/apps/mebe_web/web/controllers/page_controller.ex @@ -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 diff --git a/apps/mebe_web/web/router.ex b/apps/mebe_web/web/router.ex index 17dc812..836e571 100644 --- a/apps/mebe_web/web/router.ex +++ b/apps/mebe_web/web/router.ex @@ -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 diff --git a/apps/mebe_web/web/templates/feed/postlist.xml.eex b/apps/mebe_web/web/templates/feed/postlist.xml.eex new file mode 100644 index 0000000..7980bf1 --- /dev/null +++ b/apps/mebe_web/web/templates/feed/postlist.xml.eex @@ -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) + %> + + + + <![CDATA[<%= post.title %>]]> + + <%= @absolute_url %><%= page_path @conn, :post, year, j_month, j_day, post.slug %> + <%= @absolute_url %><%= page_path @conn, :post, year, j_month, j_day, post.slug %> + + + + + Read moreā€¦ + + + ]]> + + <%= dow_str %>, <%= day %> <%= rfc_month %> <%= year %> 00:00:00 UT + +<% end %> diff --git a/apps/mebe_web/web/templates/layout/app.html.eex b/apps/mebe_web/web/templates/layout/app.html.eex index ffba180..1f77468 100644 --- a/apps/mebe_web/web/templates/layout/app.html.eex +++ b/apps/mebe_web/web/templates/layout/app.html.eex @@ -8,13 +8,19 @@ <%= title @conn %> "> + + <%= if assigns[:page_type] == :tag do %> + + <% else %> + + <% end %>