diff --git a/lib/changelog_web/controllers/feed_controller.ex b/lib/changelog_web/controllers/feed_controller.ex index 154537a700..b232721785 100644 --- a/lib/changelog_web/controllers/feed_controller.ex +++ b/lib/changelog_web/controllers/feed_controller.ex @@ -190,5 +190,80 @@ defmodule ChangelogWeb.FeedController do |> render("sitemap.xml") end + @doc "A topic's news and podcasts feed" + def topic(conn, %{"slug" => slug}) do + topic = Repo.get_by!(Topic, slug: slug) + + items = + topic + |> filter_items_by_topic(:all) + |> fetch_items_by_topic() + + render_topic(conn, slug, items) + end + + @doc "A topic's news feed" + def topic_news(conn, %{"slug" => slug}) do + topic = Repo.get_by!(Topic, slug: slug) + + news_items = + topic + |> filter_items_by_topic(:news) + |> fetch_items_by_topic() + + render_topic(conn, topic, news_items) + end + + @doc "A topic's podcasts feed" + def topic_podcasts(conn, %{"slug" => slug}) do + topic = Repo.get_by!(Topic, slug: slug) + + podcasts = + topic + |> filter_items_by_topic(:podcasts) + |> fetch_items_by_topic() + + render_topic(conn, topic, podcasts) + end + + defp filter_items_by_topic(topic, :all) do + NewsItem + |> NewsItem.with_topic(topic) + end + + defp filter_items_by_topic(topic, :news) do + NewsItem + |> NewsItem.with_topic(topic) + |> NewsItem.non_audio() + end + + defp filter_items_by_topic(topic, :podcasts) do + NewsItem + |> NewsItem.with_topic(topic) + |> NewsItem.audio() + end + + defp fetch_items_by_topic(query) do + query + |> NewsItem.published() + |> NewsItem.newest_first() + |> NewsItem.preload_all() + |> Repo.all() + end + + defp render_topic(conn, topic, items) do + IO.inspect(topic, label: "TOPIC") + IO.inspect(items, label: "ITEMS") + + conn + |> put_layout(false) + |> put_resp_content_type("application/xml") + |> assign(:topic_name, topic.name) + |> assign(:topic_description, topic.description) + |> assign(:items, items) + |> ResponseCache.cache_public(cache_duration()) + |> render("topic.xml") + end + defp cache_duration, do: 2..10 |> Enum.random() |> :timer.minutes() end diff --git a/lib/changelog_web/router.ex b/lib/changelog_web/router.ex index bfded8d8be..2a64787492 100644 --- a/lib/changelog_web/router.ex +++ b/lib/changelog_web/router.ex @@ -103,7 +103,10 @@ defmodule ChangelogWeb.Router do post "/episodes/:id/transcript", EpisodeController, :transcript, as: :episode resources "/episode_requests", EpisodeRequestController - put "/episode_requests/:id/decline", EpisodeRequestController, :decline, as: :episode_request + + put "/episode_requests/:id/decline", EpisodeRequestController, :decline, + as: :episode_request + put "/episode_requests/:id/fail", EpisodeRequestController, :fail, as: :episode_request put "/episode_requests/:id/pend", EpisodeRequestController, :pend, as: :episode_request @@ -141,11 +144,18 @@ defmodule ChangelogWeb.Router do scope "/", ChangelogWeb do pipe_through [:feed] + get "/sitemap.xml", FeedController, :sitemap + get "/feed", FeedController, :news get "/feed/titles", FeedController, :news_titles + + get "/topic/:slug/feed", FeedController, :topic_show + get "/topic/:slug/news/feed", FeedController, :topic_news + get "/topic/:slug/podcasts/feed", FeedController, :topic_podcasts + get "/posts/feed", FeedController, :posts - get "/sitemap.xml", FeedController, :sitemap get "/:slug/feed", FeedController, :podcast + get "/plusplus/:slug/feed", FeedController, :plusplus get "/metacast/:slug/feed", FeedController, :metacast end diff --git a/lib/changelog_web/templates/feed/topic.xml.eex b/lib/changelog_web/templates/feed/topic.xml.eex new file mode 100644 index 0000000000..22553d75dd --- /dev/null +++ b/lib/changelog_web/templates/feed/topic.xml.eex @@ -0,0 +1,17 @@ + + + + Changelog: <%= @topic_name %> + All rights reserved + <%= Routes.root_url(@conn, :index) %> + + + en-us + <%= @topic_description %> + <%= for item <- @items do %> + + <%= render_item(item, assigns) %> + + <% end %> + + diff --git a/test/changelog_web/controllers/feed_controller_test.exs b/test/changelog_web/controllers/feed_controller_test.exs index 2430e8989e..fe8303a46d 100644 --- a/test/changelog_web/controllers/feed_controller_test.exs +++ b/test/changelog_web/controllers/feed_controller_test.exs @@ -140,4 +140,93 @@ defmodule ChangelogWeb.FeedControllerTest do refute conn.resp_body =~ p2.title assert conn.resp_body =~ p3.title end + + describe "Topic feed" do + setup [:setup_topic_feed_tests] + + test "the topic feed", %{ + conn: conn, + topics: topics, + news_items_with_topics: news_items_with_topics, + posts_with_topics: posts_with_topics, + podcast_episodes_with_topics: podcast_episodes_with_topics + } do + topic_slug = "rust" + conn = get(conn, Routes.feed_path(conn, :topic, topic_slug)) + + assert conn.status == 200 + assert valid_xml(conn) + end + + test "the topic's news feed", %{ + conn: conn, + topics: topics, + news_items_with_topics: news_items_with_topics, + posts_with_topics: posts_with_topics, + podcast_episodes_with_topics: podcast_episodes_with_topics + } do + topic_slug = "rust" + conn = get(conn, Routes.feed_path(conn, :topic_news, topic_slug)) + + assert conn.status == 200 + assert valid_xml(conn) + end + + test "the topic's podcasts feed", %{ + conn: conn, + topics: topics, + news_items_with_topics: news_items_with_topics, + posts_with_topics: posts_with_topics, + podcast_episodes_with_topics: podcast_episodes_with_topics + } do + topic_slug = "rust" + conn = get(conn, Routes.feed_path(conn, :topic_podcasts, topic_slug)) + + assert conn.status == 200 + assert valid_xml(conn) + + topic = topics[topic_slug] + assert conn.resp_body =~ topic.name + assert conn.resp_body =~ topic.description + + Enum.each(posts_with_topics, fn post_with_topic -> + assert conn.resp_body =~ post_with_topic.post.title + assert conn.resp_body =~ post_with_topic.post.body + end) + + Enum.each(podcast_episodes_with_topics, fn podcast_episode_with_topic -> + assert conn.resp_body =~ podcast_episode_with_topic.episode.title + assert conn.resp_body =~ podcast_episode_with_topic.episode.summary + end) + end + end + + defp setup_topic_feed_tests(context) do + # Add some topics + t1 = insert(:topic, slug: "rust", name: "Rust", description: "Rust is a systems programming language created by Mozilla.") + # Create some news items + ni1 = insert(:published_news_item, headline: "Rust is pretty cool", story: "Use it or lose it") + # Associate those news items with topics + nit1 = insert(:news_item_topic, topic: t1, news_item: ni1) + + # Add a post + post1 = insert(:published_post, body: "Can you believe this Rust thing?!") + pt1 = insert(:post_topic, post: post1, topic: t1) + + # Add a podcast + pod1 = insert(:podcast, name: "Rust Crust", slug: "rustcrust", description: "Rust is neat") + # Add a podcast episode + e1 = insert(:published_episode, podcast: pod1) + # Associate that episode with a topic + et1 = insert(:episode_topic, episode: e1, topic: t1) + + %{ + topics: %{ + "rust" => t1 + }, + news_items_with_topics: [nit1], + posts_with_topics: [pt1], + podcast_episodes_with_topics: [et1] + } + end end