diff --git a/lib/web/router.ex b/lib/web/router.ex index b2a6f7a..e894858 100644 --- a/lib/web/router.ex +++ b/lib/web/router.ex @@ -3,18 +3,23 @@ defmodule Mebe2.Web.Router do use Raxx.Logger use Mebe2.Web.Middleware.RequestTime use Mebe2.Web.Middleware.Archives + alias Mebe2.Web.Routes use Raxx.Router, [ - {%{method: :GET, path: ["tag", _tag, "p", _page]}, Mebe2.Web.Routes.Tag}, - {%{method: :GET, path: ["tag", _tag]}, Mebe2.Web.Routes.Tag}, - {%{method: :GET, path: ["archive", _year, _month, "p", _page]}, Mebe2.Web.Routes.Month}, - {%{method: :GET, path: ["archive", _year, _month]}, Mebe2.Web.Routes.Month}, - {%{method: :GET, path: ["archive", _year, "p", _page]}, Mebe2.Web.Routes.Year}, - {%{method: :GET, path: ["archive", _year]}, Mebe2.Web.Routes.Year}, - {%{method: :GET, path: ["p", _page]}, Mebe2.Web.Routes.Index}, - {%{method: :GET, path: [_year, _month, _day, _slug]}, Mebe2.Web.Routes.Post}, - {%{method: :GET, path: [_slug]}, Mebe2.Web.Routes.Page}, - {%{method: :GET, path: []}, Mebe2.Web.Routes.Index}, - {_, Mebe2.Web.Routes.NotFound} + {%{method: :GET, path: ["tag", _tag, "p", _page]}, Routes.Tag}, + {%{method: :GET, path: ["tag", _tag, "feed"]}, Routes.Tag}, + {%{method: :GET, path: ["tag", _tag]}, Routes.Tag}, + {%{method: :GET, path: ["archive", _year, _month, "p", _page]}, Routes.Month}, + {%{method: :GET, path: ["archive", _year, _month, "feed"]}, Routes.Month}, + {%{method: :GET, path: ["archive", _year, _month]}, Routes.Month}, + {%{method: :GET, path: ["archive", _year, "p", _page]}, Routes.Year}, + {%{method: :GET, path: ["archive", _year, "feed"]}, Routes.Year}, + {%{method: :GET, path: ["archive", _year]}, Routes.Year}, + {%{method: :GET, path: ["p", _page]}, Routes.Index}, + {%{method: :GET, path: ["feed"]}, Routes.Index}, + {%{method: :GET, path: [_year, _month, _day, _slug]}, Routes.Post}, + {%{method: :GET, path: [_slug]}, Routes.Page}, + {%{method: :GET, path: []}, Routes.Index}, + {_, Routes.NotFound} ] end diff --git a/lib/web/routes/index.ex b/lib/web/routes/index.ex index c216d36..ae9d7ef 100644 --- a/lib/web/routes/index.ex +++ b/lib/web/routes/index.ex @@ -1,15 +1,21 @@ defmodule Mebe2.Web.Routes.Index do use Raxx.Server alias Mebe2.Web.Views.Index + alias Mebe2.Web.Routes.Utils @impl Raxx.Server def handle_request(%Raxx.Request{path: ["p", page]} = _req, _state) do - Mebe2.Web.Routes.Utils.render_posts(page, &post_getter/2, &Index.render/4) + Utils.render_posts(page, &post_getter/2, &Index.render/4) + end + + @impl Raxx.Server + def handle_request(%Raxx.Request{path: ["feed"]} = _req, _state) do + Utils.render_feed(&post_getter/2) end @impl Raxx.Server def handle_request(%Raxx.Request{} = _req, _state) do - Mebe2.Web.Routes.Utils.render_posts(&post_getter/2, &Index.render/4) + Utils.render_posts(&post_getter/2, &Index.render/4) end defp post_getter(first, limit), diff --git a/lib/web/routes/month.ex b/lib/web/routes/month.ex index a516eec..5e53623 100644 --- a/lib/web/routes/month.ex +++ b/lib/web/routes/month.ex @@ -1,5 +1,6 @@ defmodule Mebe2.Web.Routes.Month do use Raxx.Server + alias Mebe2.Web.Routes.Utils @impl Raxx.Server def handle_request( @@ -8,13 +9,23 @@ defmodule Mebe2.Web.Routes.Month do ) do with {year, _} <- Integer.parse(year_str), {month, _} <- Integer.parse(month_str) do - Mebe2.Web.Routes.Utils.render_posts( + Utils.render_posts( page, &post_getter(year, month, &1, &2), &renderer(year, month, &1, &2, &3, &4) ) else - _ -> Mebe2.Web.Routes.Utils.render_404() + _ -> Utils.render_404() + end + end + + @impl Raxx.Server + def handle_request(%Raxx.Request{path: ["archive", year_str, month_str, "feed"]} = _req, _state) do + with {year, _} <- Integer.parse(year_str), + {month, _} <- Integer.parse(month_str) do + Utils.render_feed(&post_getter(year, month, &1, &2)) + else + _ -> Utils.render_404() end end @@ -22,12 +33,12 @@ defmodule Mebe2.Web.Routes.Month do def handle_request(%Raxx.Request{path: ["archive", year_str, month_str]} = _req, _state) do with {year, _} <- Integer.parse(year_str), {month, _} <- Integer.parse(month_str) do - Mebe2.Web.Routes.Utils.render_posts( + Utils.render_posts( &post_getter(year, month, &1, &2), &renderer(year, month, &1, &2, &3, &4) ) else - _ -> Mebe2.Web.Routes.Utils.render_404() + _ -> Utils.render_404() end end diff --git a/lib/web/routes/tag.ex b/lib/web/routes/tag.ex index 1758240..4211e50 100644 --- a/lib/web/routes/tag.ex +++ b/lib/web/routes/tag.ex @@ -1,18 +1,24 @@ defmodule Mebe2.Web.Routes.Tag do use Raxx.Server + alias Mebe2.Web.Routes.Utils @impl Raxx.Server def handle_request(%Raxx.Request{path: ["tag", tag, "p", page]} = _req, _state) do - Mebe2.Web.Routes.Utils.render_posts( + Utils.render_posts( page, &post_getter(tag, &1, &2), &renderer(tag, &1, &2, &3, &4) ) end + @impl Raxx.Server + def handle_request(%Raxx.Request{path: ["tag", tag, "feed"]} = _req, _state) do + Utils.render_feed(&post_getter(tag, &1, &2)) + end + @impl Raxx.Server def handle_request(%Raxx.Request{path: ["tag", tag]} = _req, _state) do - Mebe2.Web.Routes.Utils.render_posts(&post_getter(tag, &1, &2), &renderer(tag, &1, &2, &3, &4)) + Utils.render_posts(&post_getter(tag, &1, &2), &renderer(tag, &1, &2, &3, &4)) end defp post_getter(tag, first, limit), diff --git a/lib/web/routes/utils.ex b/lib/web/routes/utils.ex index 47b79ed..df7e9d0 100644 --- a/lib/web/routes/utils.ex +++ b/lib/web/routes/utils.ex @@ -20,10 +20,11 @@ defmodule Mebe2.Web.Routes.Utils do @doc """ Get post range for the given page, i.e. the starting post and limit to display on that page. + You may optionally give the posts per page limit to use when constructing the range. """ - @spec get_post_range(integer) :: {integer, integer} - def get_post_range(page) when is_integer(page) do - ppp = Mebe2.get_conf(:posts_per_page) + @spec get_post_range(integer, integer | nil) :: {integer, integer} + def get_post_range(page, posts_per_page \\ nil) when is_integer(page) do + ppp = if is_nil(posts_per_page), do: Mebe2.get_conf(:posts_per_page), else: posts_per_page {(page - 1) * ppp, ppp} end @@ -31,7 +32,7 @@ defmodule Mebe2.Web.Routes.Utils do Render a set of posts on the given page. - `page` is a string from the URL path. - - `post_getter` isa function that gets the range of posts to load and returns a tuple where the + - `post_getter` is a function that gets the range of posts to load and returns a tuple where the first element is the list of found posts, and the second element is the amount of all posts that are in the DB with these conditions. - `renderer` is a function that renders the content. Its arguments are the response to use, @@ -53,6 +54,26 @@ defmodule Mebe2.Web.Routes.Utils do end end + @doc """ + Render RSS feed for the given posts. + + `post_getter` is a function that gets the range of posts to load and returns a tuple where the + first element is the list of found posts and the second element can be anything (the structure) + is the same as in `render_posts` so that the post getters can be reused. + """ + @spec render_feed((integer, integer -> {[Post.t()], any})) :: Raxx.Response.t() + def render_feed(post_getter) do + with true <- Mebe2.get_conf(:enable_feeds) do + {first, limit} = get_post_range(1, Mebe2.get_conf(:posts_in_feed)) + {posts, _} = post_getter.(first, limit) + + Raxx.response(200) + |> Mebe2.Web.Views.Feeds.PostList.render(posts) + else + _ -> render_404() + end + end + @doc """ Render a 404 page. """ diff --git a/lib/web/routes/year.ex b/lib/web/routes/year.ex index 5111b6a..90bc4a5 100644 --- a/lib/web/routes/year.ex +++ b/lib/web/routes/year.ex @@ -1,28 +1,38 @@ defmodule Mebe2.Web.Routes.Year do use Raxx.Server + alias Mebe2.Web.Routes.Utils @impl Raxx.Server def handle_request(%Raxx.Request{path: ["archive", year_str, "p", page]} = _req, _state) do with {year, _} <- Integer.parse(year_str) do - Mebe2.Web.Routes.Utils.render_posts( + Utils.render_posts( page, &post_getter(year, &1, &2), &renderer(year, &1, &2, &3, &4) ) else - _ -> Mebe2.Web.Routes.Utils.render_404() + _ -> Utils.render_404() + end + end + + @impl Raxx.Server + def handle_request(%Raxx.Request{path: ["archive", year_str, "feed"]} = _req, _state) do + with {year, _} <- Integer.parse(year_str) do + Utils.render_feed(&post_getter(year, &1, &2)) + else + _ -> Utils.render_404() end end @impl Raxx.Server def handle_request(%Raxx.Request{path: ["archive", year_str]} = _req, _state) do with {year, _} <- Integer.parse(year_str) do - Mebe2.Web.Routes.Utils.render_posts( + Utils.render_posts( &post_getter(year, &1, &2), &renderer(year, &1, &2, &3, &4) ) else - _ -> Mebe2.Web.Routes.Utils.render_404() + _ -> Utils.render_404() end end diff --git a/lib/web/views/base_layout.html.eex b/lib/web/views/base_layout.html.eex index d6edc0c..eb5c8bd 100644 --- a/lib/web/views/base_layout.html.eex +++ b/lib/web/views/base_layout.html.eex @@ -3,6 +3,15 @@ <%= Mebe2.get_conf(:blog_name) %> + + <%= raw(if Mebe2.get_conf(:enable_feeds) do %> + + <% end) %>
diff --git a/lib/web/views/feeds/base_layout.ex b/lib/web/views/feeds/base_layout.ex new file mode 100644 index 0000000..26ce234 --- /dev/null +++ b/lib/web/views/feeds/base_layout.ex @@ -0,0 +1,4 @@ +defmodule Mebe2.Web.Views.Feeds.BaseLayout do + use Raxx.Layout, + layout: "base_layout.xml.eex" +end diff --git a/lib/web/views/feeds/base_layout.xml.eex b/lib/web/views/feeds/base_layout.xml.eex new file mode 100644 index 0000000..03a7860 --- /dev/null +++ b/lib/web/views/feeds/base_layout.xml.eex @@ -0,0 +1,11 @@ + + + <%= Mebe2.get_conf(:blog_name) %> + <%= Mebe2.get_conf(:absolute_url) %>/ + + Mebe2 + © <%= Mebe2.get_conf(:blog_author) %> + + <%= __content__ %> + + diff --git a/lib/web/views/feeds/post_list.ex b/lib/web/views/feeds/post_list.ex new file mode 100644 index 0000000..27b9df9 --- /dev/null +++ b/lib/web/views/feeds/post_list.ex @@ -0,0 +1,13 @@ +defmodule Mebe2.Web.Views.Feeds.PostList do + use Mebe2.Web.Views.Feeds.BaseLayout, + template: "post_list.xml.eex", + arguments: [:posts] + + @doc """ + Format datetime for RSS usage. + """ + @spec format_time(DateTime.t()) :: String.t() + def format_time(datetime) do + Calendar.Strftime.strftime!(datetime, "%a, %d %b %Y %T %z") + end +end diff --git a/lib/web/views/feeds/post_list.xml.eex b/lib/web/views/feeds/post_list.xml.eex new file mode 100644 index 0000000..40b3b0c --- /dev/null +++ b/lib/web/views/feeds/post_list.xml.eex @@ -0,0 +1,28 @@ +<%= raw(for post <- posts do %> + + + <![CDATA[<%= raw(post.title) %>]]> + + + <%= raw(if Mebe2.get_conf(:multi_author_mode) do %> + <%= Mebe2.Engine.Utils.get_author(post) %> + <% end) %> + + <%= Mebe2.get_conf(:absolute_url) %><%= Mebe2.Web.Views.Utils.get_post_path(post) %> + <%= Mebe2.get_conf(:absolute_url) %><%= Mebe2.Web.Views.Utils.get_post_path(post) %> + + + <%= raw(post.content) %> + <% else %> + <%= raw(post.short_content) %> + <% end) %> + + + Read more… + + ]]> + + <%= format_time(post.datetime) %> + +<% end) %>