List all items annually (#18)

* Add year filter to Directus client

* Add Timeline module to combine several streams

* Fetch annual view by pokemon route

* Add annual view

* Remove scaffold route
This commit is contained in:
Anders Englöf Ytterström 2024-10-04 13:09:50 +02:00 committed by GitHub
parent a6d34d17fc
commit 794752592e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 255 additions and 4 deletions

View file

@ -20,6 +20,7 @@ defmodule Mse25.Directus do
","
)
]
|> annual?(:articles, options)
|> query_params_string(options, :articles)
get("/articles?" <> params)
@ -105,12 +106,15 @@ defmodule Mse25.Directus do
"slug",
"poster",
"category",
"started_at",
"ended_at",
"bands.artists_id.name",
"mia.artists_id.name"
],
","
)
]
|> annual?(:events, options)
|> query_params_string(options, :events)
get("/events?" <> params)
@ -138,6 +142,7 @@ defmodule Mse25.Directus do
","
)
]
|> annual?(:links, options)
|> query_params_string(options, :links)
get("/links?" <> params)
@ -215,4 +220,42 @@ defmodule Mse25.Directus do
pg -> ["filter[title][_icontains]=" <> String.replace(to_string(pg), " ", "%20") | params]
end
end
defp annual?(params, type, opts) do
case opts[:year] do
nil ->
params
year ->
year_filter(type, year, params)
end
end
defp year_filter(:albums, year, params),
do: [
"filter[purchased_at][_gte]=" <> to_string(year) <> "-01-01",
"filter[purchased_at][_lte]=" <> to_string(year) <> "-12-31"
| params
]
defp year_filter(:articles, year, params),
do: [
"filter[pubDate][_gte]=" <> to_string(year) <> "-01-01",
"filter[pubDate][_lte]=" <> to_string(year) <> "-12-31"
| params
]
defp year_filter(:events, year, params),
do: [
"filter[started_at][_gte]=" <> to_string(year) <> "-01-01",
"filter[ended_at][_lte]=" <> to_string(year) <> "-12-31"
| params
]
defp year_filter(:links, year, params),
do: [
"filter[pubDate][_gte]=" <> to_string(year) <> "-01-01",
"filter[pubDate][_lte]=" <> to_string(year) <> "-12-31"
| params
]
end

61
lib/mse25/timeline.ex Normal file
View file

@ -0,0 +1,61 @@
defmodule Mse25.Timeline do
alias Mse25.Directus
def archive() do
items =
Task.await_many([
Task.async(fn -> Directus.get_albums!() end),
Task.async(fn -> Directus.get_articles!(limit: 9999) end),
Task.async(fn -> Directus.get_links!(limit: 9999) end),
Task.async(fn -> Directus.get_events!(limit: 9999) end)
])
end
def annual(year) do
items =
Task.await_many([
Task.async(fn -> Directus.get_albums!(limit: 9999, year: year) end),
Task.async(fn -> Directus.get_articles!(limit: 9999, year: year) end),
Task.async(fn -> Directus.get_links!(limit: 9999, year: year) end),
Task.async(fn -> Directus.get_events!(limit: 9999, year: year) end)
])
counts =
items
|> Enum.reject(&Enum.empty?/1)
|> Enum.map(fn [item | l] -> {item_key(item), Enum.count(l) + 1} end)
|> Map.new()
timeline =
items
|> List.flatten()
|> Enum.sort_by(&sort_key/1)
|> Enum.map(&categorize/1)
|> Enum.group_by(fn item -> sort_key(item) |> String.slice(5..6) end)
|> Enum.reverse()
{:ok, %{year: year, timeline: timeline, counts: counts}}
end
def search(query) do
items =
Task.await_many([
Task.async(fn -> Directus.get_articles!(limit: 9999, query: query) end),
Task.async(fn -> Directus.get_links!(limit: 9999, query: query) end),
Task.async(fn -> Directus.get_events!(limit: 9999, query: query) end)
])
end
defp sort_key(%{"pubDate" => date}), do: date
defp sort_key(%{"started_at" => date}), do: date
defp sort_key(%{"purchased_at" => date}), do: date
defp item_key(%{"source" => _s, "pubDate" => _}), do: :links
defp item_key(%{"pubDate" => _}), do: :articles
defp item_key(%{"started_at" => _}), do: :events
defp item_key(%{"purchased_at" => _}), do: :albums
defp categorize(item) do
Map.put(item, :t, item_key(item))
end
end

View file

@ -1,6 +1,7 @@
defmodule Mse25Web.ItemController do
use Mse25Web, :controller
alias Mse25.Directus
alias Mse25.Timeline
def index(conn, _params) do
case conn.path_info |> fetch do
@ -38,12 +39,36 @@ defmodule Mse25Web.ItemController do
end
defp fetch([slug]) do
case Directus.get_page(slug) do
{:ok, response} -> {:ok, :page, response}
not_found -> not_found
case Integer.parse(slug) do
{:error} ->
case Directus.get_page(slug) do
{:ok, response} -> {:ok, :page, response}
error -> error
end
{year, _} ->
case Timeline.annual(year) do
{:ok, response} -> {:ok, :annual, response}
error -> error
end
end
end
defp assigns(:annual, %{
timeline: timeline,
year: year,
counts: counts
}),
do: [
year: year,
page_title: "Innehåll från " <> to_string(year),
timeline: timeline,
brutal_legends_count: Map.get(counts, :albums, 0),
article_count: Map.get(counts, :articles, 0),
event_count: Map.get(counts, :events, 0),
link_count: Map.get(counts, :links, 0)
]
defp assigns(:article, %{
"title" => heading,
"contents" => contents,

View file

@ -3,4 +3,23 @@ defmodule Mse25Web.ItemHTML do
import Mse25.EventHelpers
embed_templates "item_html/*"
def month_name("01"), do: "Januari"
def month_name("02"), do: "Februari"
def month_name("03"), do: "Mars"
def month_name("04"), do: "April"
def month_name("05"), do: "Maj"
def month_name("06"), do: "Juni"
def month_name("07"), do: "Juli"
def month_name("08"), do: "Augusti"
def month_name("09"), do: "September"
def month_name("10"), do: "Oktober"
def month_name("11"), do: "November"
def month_name("12"), do: "December"
def csl(items) do
items
|> Enum.join(", ")
|> String.replace(~r/, ([^,]+?)$/, " och \\1")
end
end

View file

@ -0,0 +1,104 @@
<header>
<ol class="breadcrumbs" itemscope itemtype="https://schema.org/BreadcrumbList">
<li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
<a href="/" rel="home">
<span itemprop="name">madr.se</span>
</a>
<meta itemprop="position" content="1" />
</li>
</ol>
<h1><%= @page_title %></h1>
<ul>
<li><a href={"/" <> to_string(@year - 1)}>Tillbaka till <%= @year - 1 %></a></li>
<li><a href={"/" <> to_string(@year + 1)}>Framåt till <%= @year + 1 %></a></li>
</ul>
<ul>
<%= if @link_count > 0 do %>
<li><%= @link_count %> länkar värda att uppmärksamma och kommentera</li>
<% end %>
<%= if @article_count > 0 do %>
<li><%= @article_count %> inlägg i webbloggen</li>
<% end %>
<%= if @event_count > 0 do %>
<li><%= @event_count %> besökta evenemang</li>
<% end %>
<%= if @brutal_legends_count > 0 do %>
<li>
<%= @brutal_legends_count %>
<%= if @brutal_legends_count == 1 do %>
köpt vinylskiva
<% else %>
köpta vinylskivor
<% end %>
till Brütal Legend-samlingen
</li>
<% end %>
</ul>
<%= for {month, items} <- @timeline do %>
<section id={"m" <> month}>
<h2><%= month_name(month) <> ", " <> to_string(@year) %></h2>
<%= for item = %{t: t} <- items do %>
<article>
<%= if t == :articles do %>
<h3>
<a href={"/" <> item["slug"]}>
<%= item["title"] %>
</a>
</h3>
<% end %>
<%= if t == :events do %>
<h3>
<a href={"/" <> item["slug"]}>
<%= item["title"] %>
</a>
</h3>
<p><%= item["lead"] %></p>
<img
src={ "https://n.madr.se/assets/" <> item["poster"] <> "?key=poster"}
loading="lazy"
alt="Affisch"
width="200"
/>
<% end %>
<%= if t == :links do %>
<h3>
<%= item["title"] %>
</h3>
<p><%= raw(Earmark.as_html!(item["contents"])) %></p>
Källa:
<a href={"/" <> item["source"]}>
<%= item["h1"] %>
</a>
<% end %>
<%= if t == :albums do %>
<h3>
<%= item["artist"] <>
" - " <> item["album"] <> " (" <> to_string(item["year"]) <> ")" %>
<a
class="permalink"
href={"/" <> to_string(@year) <> "/brutal-legend-" <> item["externalId"]}
>
#
</a>
</h3>
<%= if item["contents"] do %>
<p><%= raw(Earmark.as_html!(item["contents"])) %></p>
<% end %>
<ul>
<%= for song <- item["songs"] do %>
<li><%= song["artist"]["name"] <> " - " <> song["title"] %></li>
<% end %>
</ul>
<img
src={"https://n.madr.se/assets/" <> item["cover"] <> "?key=rectangular"}
alt="Skivomslag"
loading="lazy"
height="75"
width="75"
/>
<% end %>
</article>
<% end %>
</section>
<% end %>
</header>

View file

@ -25,7 +25,6 @@ defmodule Mse25Web.Router do
# get "/kommande-evenemang.ics", EventController, :calendar
# get "/event-map.js", EventController, :interactive_map
# get "/:year", TimelineController, :annual
# get "/prenumerera.xml", TimelineController, :feed
get "/*path", ItemController, :index