Item views (#7)
* Add Earmark dependency For markdown to HTML conversion * Display items by slug: articles, pages * Handle 401 Forbidden responses in Directus * Add item controller as pokemon route * Strip out generated layouts * Plan future routes * Look for item in order: article, link, event, album * Add item templates
This commit is contained in:
parent
e907e347c9
commit
8bbe8a1b24
13 changed files with 264 additions and 70 deletions
|
|
@ -7,12 +7,16 @@ defmodule Mse25.Directus do
|
||||||
params =
|
params =
|
||||||
[
|
[
|
||||||
"sort=-pubDate",
|
"sort=-pubDate",
|
||||||
"fields=" <> Enum.join([
|
"fields=" <>
|
||||||
|
Enum.join(
|
||||||
|
[
|
||||||
"slug",
|
"slug",
|
||||||
"title",
|
"title",
|
||||||
"date_updated",
|
"date_updated",
|
||||||
"pubDate"
|
"pubDate"
|
||||||
], ",")
|
],
|
||||||
|
","
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|> query_params_string(options)
|
|> query_params_string(options)
|
||||||
|
|
||||||
|
|
@ -41,8 +45,10 @@ defmodule Mse25.Directus do
|
||||||
params =
|
params =
|
||||||
[
|
[
|
||||||
"sort=-started_at",
|
"sort=-started_at",
|
||||||
#"filter={\"upcoming\":{\"_eq\":true}}",
|
# "filter={\"upcoming\":{\"_eq\":true}}",
|
||||||
"fields=" <> Enum.join([
|
"fields=" <>
|
||||||
|
Enum.join(
|
||||||
|
[
|
||||||
"started_at",
|
"started_at",
|
||||||
"ended_at",
|
"ended_at",
|
||||||
"title",
|
"title",
|
||||||
|
|
@ -52,7 +58,9 @@ defmodule Mse25.Directus do
|
||||||
"poster.height",
|
"poster.height",
|
||||||
"bands.artists_id.name",
|
"bands.artists_id.name",
|
||||||
"mia.artists_id.name"
|
"mia.artists_id.name"
|
||||||
], ",")
|
],
|
||||||
|
","
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|> query_params_string(options)
|
|> query_params_string(options)
|
||||||
|
|
||||||
|
|
@ -67,7 +75,9 @@ defmodule Mse25.Directus do
|
||||||
params =
|
params =
|
||||||
[
|
[
|
||||||
"sort=-pubDate",
|
"sort=-pubDate",
|
||||||
"fields=" <> Enum.join([
|
"fields=" <>
|
||||||
|
Enum.join(
|
||||||
|
[
|
||||||
"slug",
|
"slug",
|
||||||
"title",
|
"title",
|
||||||
"date_updated",
|
"date_updated",
|
||||||
|
|
@ -75,7 +85,9 @@ defmodule Mse25.Directus do
|
||||||
"h1",
|
"h1",
|
||||||
"source",
|
"source",
|
||||||
"contents"
|
"contents"
|
||||||
], ",")
|
],
|
||||||
|
","
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|> query_params_string(options)
|
|> query_params_string(options)
|
||||||
|
|
||||||
|
|
@ -99,11 +111,16 @@ defmodule Mse25.Directus do
|
||||||
[base_url: base_url, token: token] = Application.fetch_env!(:mse25, :directus)
|
[base_url: base_url, token: token] = Application.fetch_env!(:mse25, :directus)
|
||||||
req = Req.new(base_url: base_url <> "/items")
|
req = Req.new(base_url: base_url <> "/items")
|
||||||
|
|
||||||
Req.get!(req, url: resource, auth: {:bearer, token})
|
case Req.get!(req, url: resource, auth: {:bearer, token})
|
||||||
|> payload
|
|> payload do
|
||||||
|
{:ok, payload} -> payload
|
||||||
|
{:forbidden, message} -> message
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp payload(%Req.Response{body: %{"data" => payload}}), do: payload
|
defp payload(%Req.Response{status: 200, body: %{"data" => payload}}), do: {:ok, payload}
|
||||||
|
|
||||||
|
defp payload(%Req.Response{status: 401}), do: {:forbidden, "Invalid Directus credentials"}
|
||||||
|
|
||||||
defp query_params_string(params, options),
|
defp query_params_string(params, options),
|
||||||
do:
|
do:
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,32 @@
|
||||||
<header class="px-4 sm:px-6 lg:px-8">
|
<b>madr</b><br>
|
||||||
<div class="flex items-center justify-between border-b border-zinc-100 py-3 text-sm">
|
|> Hårdrock<br>
|
||||||
<div class="flex items-center gap-4">
|
|> Programmering<br>
|
||||||
<a href="/">
|
|> Ljudteknik<br>
|
||||||
<img src={~p"/images/logo.svg"} width="36" />
|
|> Åsikter
|
||||||
</a>
|
|
||||||
<p class="bg-brand/5 text-brand rounded-full px-2 font-medium leading-6">
|
<nav>
|
||||||
v<%= Application.spec(:phoenix, :vsn) %>
|
<ul>
|
||||||
</p>
|
<li><a href="/om">Om mig</a></li>
|
||||||
</div>
|
<li><a href="/webblogg">Webblogg</a></li>
|
||||||
<div class="flex items-center gap-4 font-semibold leading-6 text-zinc-900">
|
<li><a href="/delningar">Delningar</a></li>
|
||||||
<a href="https://twitter.com/elixirphoenix" class="hover:text-zinc-700">
|
<li><a href="/evenemang">Evenemang</a></li>
|
||||||
@elixirphoenix
|
<li><a href="/vad-jag-gor">Vad jag gör</a></li>
|
||||||
</a>
|
</ul>
|
||||||
<a href="https://github.com/phoenixframework/phoenix" class="hover:text-zinc-700">
|
</nav>
|
||||||
GitHub
|
|
||||||
</a>
|
<form metod="get" action="/search">
|
||||||
<a
|
<label>Search site <input type="search" name="q"></label>
|
||||||
href="https://hexdocs.pm/phoenix/overview.html"
|
</form>
|
||||||
class="rounded-lg bg-zinc-100 px-2 py-1 hover:bg-zinc-200/80"
|
|
||||||
>
|
<ul>
|
||||||
Get Started <span aria-hidden="true">→</span>
|
<li><a href="https://github.com/madr" rel="external">Github</a></li>
|
||||||
</a>
|
<li><a href="https://linkedin.com/anders-ytterstrom" rel="external">LinkedIn</a></li>
|
||||||
</div>
|
<li><a href="https://discogs.com/madr" rel="external">Discogs</a></li>
|
||||||
</div>
|
<li><a href="https://songkick.com/madr" rel="external">Songkick</a></li>
|
||||||
</header>
|
</ul>
|
||||||
<main class="px-4 py-20 sm:px-6 lg:px-8">
|
|
||||||
<div class="mx-auto max-w-2xl">
|
<%= @inner_content %>
|
||||||
<.flash_group flash={@flash} />
|
|
||||||
<%= @inner_content %>
|
<footer>
|
||||||
</div>
|
<p><a href="https://madr.se" rel="home">madr.se</a> av Anders Englöf Ytterström, sedan 2006. <a href="/colophon">Kolofon</a>.</p>
|
||||||
</main>
|
</footer>
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,13 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en" class="[scrollbar-gutter:stable]">
|
<html lang="sv">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="csrf-token" content={get_csrf_token()} />
|
<meta name="csrf-token" content={get_csrf_token()}>
|
||||||
<.live_title suffix=" · Phoenix Framework">
|
<.live_title suffix=" · Phoenix Framework">
|
||||||
<%= assigns[:page_title] || "Mse25" %>
|
<%= assigns[:page_title] || "Mse25" %>
|
||||||
</.live_title>
|
</.live_title>
|
||||||
<link phx-track-static rel="stylesheet" href={~p"/assets/app.css"} />
|
<link rel="stylesheet" href={~p"/assets/app.css"}>
|
||||||
<script defer phx-track-static type="text/javascript" src={~p"/assets/app.js"}>
|
|
||||||
</script>
|
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-white">
|
<body class="bg-white">
|
||||||
<%= @inner_content %>
|
<%= @inner_content %>
|
||||||
|
|
|
||||||
100
lib/mse25_web/controllers/item_controller.ex
Normal file
100
lib/mse25_web/controllers/item_controller.ex
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
defmodule Mse25Web.ItemController do
|
||||||
|
use Mse25Web, :controller
|
||||||
|
alias Mse25.Directus
|
||||||
|
|
||||||
|
def index(conn, _params) do
|
||||||
|
case conn.path_info |> fetch do
|
||||||
|
{:ok, item_type, item_data} ->
|
||||||
|
render(conn, item_type, assigns(item_type, item_data))
|
||||||
|
|
||||||
|
{:not_found, message} ->
|
||||||
|
render(conn, message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp fetch([year, slug], :article) do
|
||||||
|
case Directus.get_article(year <> "/" <> slug) do
|
||||||
|
{:ok, response} -> {:ok, :article, response}
|
||||||
|
_ -> fetch([year, slug], :link)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp fetch([year, slug], :link) do
|
||||||
|
case Directus.get_link(year <> "/" <> slug) do
|
||||||
|
{:ok, response} -> {:ok, :link, response}
|
||||||
|
_ -> fetch([year, slug], :event)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp fetch([year, slug], :event) do
|
||||||
|
case Directus.get_event(year <> "/" <> slug) do
|
||||||
|
{:ok, response} -> {:ok, :event, response}
|
||||||
|
not_found -> not_found
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp fetch([year, slug]) do
|
||||||
|
fetch([year, slug], :article)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp fetch([slug]) do
|
||||||
|
case Directus.get_page(slug) do
|
||||||
|
{:ok, response} -> {:ok, :page, response}
|
||||||
|
not_found -> not_found
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp assigns(:article, %{
|
||||||
|
"title" => heading,
|
||||||
|
"contents" => contents,
|
||||||
|
"pubDate" => published_at,
|
||||||
|
"date_updated" => updated_at
|
||||||
|
}) do
|
||||||
|
[
|
||||||
|
heading: heading,
|
||||||
|
contents: Earmark.as_html!(contents),
|
||||||
|
published_at: published_at,
|
||||||
|
updated_at: updated_at
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
defp assigns(:event, %{
|
||||||
|
"title" => heading,
|
||||||
|
"contents" => contents,
|
||||||
|
"started_at" => published_at
|
||||||
|
}) do
|
||||||
|
[
|
||||||
|
heading: heading,
|
||||||
|
contents: Earmark.as_html!(contents),
|
||||||
|
published_at: published_at
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
defp assigns(:link, %{
|
||||||
|
"title" => heading,
|
||||||
|
"contents" => contents,
|
||||||
|
"pubDate" => published_at,
|
||||||
|
"source" => url,
|
||||||
|
"h1" => title
|
||||||
|
}) do
|
||||||
|
[
|
||||||
|
heading: heading,
|
||||||
|
contents: Earmark.as_html!(contents),
|
||||||
|
published_at: published_at,
|
||||||
|
url: url,
|
||||||
|
title: title
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
defp assigns(:page, %{
|
||||||
|
"title" => heading,
|
||||||
|
"contents" => contents,
|
||||||
|
"date_updated" => updated_at
|
||||||
|
}) do
|
||||||
|
[
|
||||||
|
heading: heading,
|
||||||
|
contents: Earmark.as_html!(contents),
|
||||||
|
updated_at: updated_at
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
5
lib/mse25_web/controllers/item_html.ex
Normal file
5
lib/mse25_web/controllers/item_html.ex
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
defmodule Mse25Web.ItemHTML do
|
||||||
|
use Mse25Web, :html
|
||||||
|
|
||||||
|
embed_templates "item_html/*"
|
||||||
|
end
|
||||||
12
lib/mse25_web/controllers/item_html/article.html.heex
Normal file
12
lib/mse25_web/controllers/item_html/article.html.heex
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
<date><%= @published_at %></date>
|
||||||
|
<h1><%= @heading %></h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<%= raw @contents %>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>Skribent: Anders Englöf Ytterström. Publicerad <%= @published_at %> och senast uppdaterad <%= @updated_at %>.</p>
|
||||||
|
</footer>
|
||||||
|
</article>
|
||||||
9
lib/mse25_web/controllers/item_html/event.html.heex
Normal file
9
lib/mse25_web/controllers/item_html/event.html.heex
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
<date><%= @published_at %></date>
|
||||||
|
<h1><%= @heading %></h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<%= raw @contents %>
|
||||||
|
|
||||||
|
</article>
|
||||||
14
lib/mse25_web/controllers/item_html/link.html.heex
Normal file
14
lib/mse25_web/controllers/item_html/link.html.heex
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
<date><%= @published_at %></date>
|
||||||
|
<h1><%= @heading %></h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<%= raw @contents %>
|
||||||
|
<p>
|
||||||
|
Källa: <a href={@url} rel="external"><%= @title %></a>
|
||||||
|
</p>
|
||||||
|
<footer>
|
||||||
|
<p>Skribent: Anders Englöf Ytterström. Publicerad <%= @published_at %>.</p>
|
||||||
|
</footer>
|
||||||
|
</article>
|
||||||
11
lib/mse25_web/controllers/item_html/page.html.heex
Normal file
11
lib/mse25_web/controllers/item_html/page.html.heex
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
<h1><%= @heading %></h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<%= raw @contents %>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>Skribent: Anders Englöf Ytterström. Senast uppdaterad <%= @updated_at %>.</p>
|
||||||
|
</footer>
|
||||||
|
</article>
|
||||||
12
lib/mse25_web/controllers/item_html/show.html.heex
Normal file
12
lib/mse25_web/controllers/item_html/show.html.heex
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
<date><%= @published_at %></date>
|
||||||
|
<h1><%= @heading %></h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<%= raw @contents %>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>Skribent: Anders Englöf Ytterström. Publicerad <%= @published_at %> och senast uppdaterad <%= @updated_at %>.</p>
|
||||||
|
</footer>
|
||||||
|
</article>
|
||||||
|
|
@ -18,6 +18,20 @@ defmodule Mse25Web.Router do
|
||||||
pipe_through :browser
|
pipe_through :browser
|
||||||
|
|
||||||
get "/", PageController, :home
|
get "/", PageController, :home
|
||||||
|
|
||||||
|
# get "/evenemang", EventController, :index
|
||||||
|
# get "/kommande-evenemang.ics", EventController, :calendar
|
||||||
|
# get "/event-map.js", EventController, :interactive_map
|
||||||
|
|
||||||
|
# get "/webblogg", ArticleController, :index
|
||||||
|
# get "/webblogg/prenumerera.xml", ArticleController, :feed
|
||||||
|
|
||||||
|
# get "/delningar", ShareController, :index
|
||||||
|
# get "/delningar/prenumerera.xml", ShareController, :feed
|
||||||
|
|
||||||
|
# get "/:year", TimelineController, :annual
|
||||||
|
# get "/prenumerera.xml", TimelineController, :feed
|
||||||
|
get "/*path", ItemController, :index
|
||||||
end
|
end
|
||||||
|
|
||||||
# Other scopes may use custom stacks.
|
# Other scopes may use custom stacks.
|
||||||
|
|
|
||||||
3
mix.exs
3
mix.exs
|
|
@ -45,7 +45,8 @@ defmodule Mse25.MixProject do
|
||||||
{:jason, "~> 1.2"},
|
{:jason, "~> 1.2"},
|
||||||
{:dns_cluster, "~> 0.1.1"},
|
{:dns_cluster, "~> 0.1.1"},
|
||||||
{:bandit, "~> 1.5"},
|
{:bandit, "~> 1.5"},
|
||||||
{:req, "~> 0.5.0"}
|
{:req, "~> 0.5.0"},
|
||||||
|
{:earmark, "~> 1.4"}
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
1
mix.lock
1
mix.lock
|
|
@ -2,6 +2,7 @@
|
||||||
"bandit": {:hex, :bandit, "1.5.7", "6856b1e1df4f2b0cb3df1377eab7891bec2da6a7fd69dc78594ad3e152363a50", [:mix], [{:hpax, "~> 1.0.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "f2dd92ae87d2cbea2fa9aa1652db157b6cba6c405cb44d4f6dd87abba41371cd"},
|
"bandit": {:hex, :bandit, "1.5.7", "6856b1e1df4f2b0cb3df1377eab7891bec2da6a7fd69dc78594ad3e152363a50", [:mix], [{:hpax, "~> 1.0.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "f2dd92ae87d2cbea2fa9aa1652db157b6cba6c405cb44d4f6dd87abba41371cd"},
|
||||||
"castore": {:hex, :castore, "1.0.8", "dedcf20ea746694647f883590b82d9e96014057aff1d44d03ec90f36a5c0dc6e", [:mix], [], "hexpm", "0b2b66d2ee742cb1d9cb8c8be3b43c3a70ee8651f37b75a8b982e036752983f1"},
|
"castore": {:hex, :castore, "1.0.8", "dedcf20ea746694647f883590b82d9e96014057aff1d44d03ec90f36a5c0dc6e", [:mix], [], "hexpm", "0b2b66d2ee742cb1d9cb8c8be3b43c3a70ee8651f37b75a8b982e036752983f1"},
|
||||||
"dns_cluster": {:hex, :dns_cluster, "0.1.3", "0bc20a2c88ed6cc494f2964075c359f8c2d00e1bf25518a6a6c7fd277c9b0c66", [:mix], [], "hexpm", "46cb7c4a1b3e52c7ad4cbe33ca5079fbde4840dedeafca2baf77996c2da1bc33"},
|
"dns_cluster": {:hex, :dns_cluster, "0.1.3", "0bc20a2c88ed6cc494f2964075c359f8c2d00e1bf25518a6a6c7fd277c9b0c66", [:mix], [], "hexpm", "46cb7c4a1b3e52c7ad4cbe33ca5079fbde4840dedeafca2baf77996c2da1bc33"},
|
||||||
|
"earmark": {:hex, :earmark, "1.4.47", "7e7596b84fe4ebeb8751e14cbaeaf4d7a0237708f2ce43630cfd9065551f94ca", [:mix], [], "hexpm", "3e96bebea2c2d95f3b346a7ff22285bc68a99fbabdad9b655aa9c6be06c698f8"},
|
||||||
"esbuild": {:hex, :esbuild, "0.8.1", "0cbf919f0eccb136d2eeef0df49c4acf55336de864e63594adcea3814f3edf41", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "25fc876a67c13cb0a776e7b5d7974851556baeda2085296c14ab48555ea7560f"},
|
"esbuild": {:hex, :esbuild, "0.8.1", "0cbf919f0eccb136d2eeef0df49c4acf55336de864e63594adcea3814f3edf41", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "25fc876a67c13cb0a776e7b5d7974851556baeda2085296c14ab48555ea7560f"},
|
||||||
"expo": {:hex, :expo, "1.0.1", "f9e2f984f5b8d195815d52d0ba264798c12c8d2f2606f76fa4c60e8ebe39474d", [:mix], [], "hexpm", "f250b33274e3e56513644858c116f255d35c767c2b8e96a512fe7839ef9306a1"},
|
"expo": {:hex, :expo, "1.0.1", "f9e2f984f5b8d195815d52d0ba264798c12c8d2f2606f76fa4c60e8ebe39474d", [:mix], [], "hexpm", "f250b33274e3e56513644858c116f255d35c767c2b8e96a512fe7839ef9306a1"},
|
||||||
"file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"},
|
"file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"},
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue