Mostly get db-based posts up and running.
This commit is contained in:
parent
7210b38757
commit
3378bc6065
|
@ -1,5 +1,7 @@
|
|||
defmodule JOL.Blog do
|
||||
alias JOL.Blog.Post
|
||||
alias JOL.Blog.{Post, Tag}
|
||||
alias JOL.Repo
|
||||
import Ecto.Query
|
||||
|
||||
defmodule NotFoundError do
|
||||
defexception [:message, plug_status: 404]
|
||||
|
@ -10,17 +12,40 @@ defmodule JOL.Blog do
|
|||
end
|
||||
|
||||
def unique_tag_list do
|
||||
[]
|
||||
Repo.all(Tag, order_by: :name)
|
||||
end
|
||||
|
||||
def recent_posts(num \\ 10) do
|
||||
[]
|
||||
Repo.all(
|
||||
from p in Post,
|
||||
limit: ^num,
|
||||
order_by: {:desc, :published_at}
|
||||
)
|
||||
end
|
||||
|
||||
def get_post_by_slug!(slug) do
|
||||
Repo.one(
|
||||
from p in Post,
|
||||
where: [slug: ^slug],
|
||||
preload: [:tags]
|
||||
)
|
||||
end
|
||||
|
||||
def get_posts_by_tag!(tag) do
|
||||
Repo.all(
|
||||
from p in Post,
|
||||
join: t in assoc(p, :tags),
|
||||
preload: [tags: t],
|
||||
where: t.name == ^tag
|
||||
)
|
||||
end
|
||||
|
||||
def get_tag_by_id!(id) do
|
||||
Repo.one(
|
||||
from t in Tag,
|
||||
where: t.id == ^id,
|
||||
preload: [:posts]
|
||||
)
|
||||
end
|
||||
|
||||
def format_date(date) do
|
||||
|
|
|
@ -7,6 +7,7 @@ defmodule JOL.Blog.Post do
|
|||
field :body, :string
|
||||
field :published_at, :naive_datetime
|
||||
field :slug, :string
|
||||
many_to_many :tags, JOL.Blog.Tag, join_through: "post_tags"
|
||||
|
||||
timestamps(type: :utc_datetime)
|
||||
end
|
||||
|
@ -15,6 +16,7 @@ defmodule JOL.Blog.Post do
|
|||
def changeset(post, attrs) do
|
||||
post
|
||||
|> cast(attrs, [:title, :body, :published_at, :slug])
|
||||
|> validate_required([:title, :body, :published_at, :slug])
|
||||
|> validate_required([:title, :body, :slug])
|
||||
|> cast_assoc(:tags)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
defmodule JOL.Blog.Tags do
|
||||
defmodule JOL.Blog.Tag do
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
|
||||
schema "tags" do
|
||||
field :name, :string
|
||||
many_to_many :posts, JOL.Blog.Post, join_through: "post_tags"
|
||||
|
||||
timestamps(type: :utc_datetime)
|
||||
end
|
||||
|
@ -13,5 +14,6 @@ defmodule JOL.Blog.Tags do
|
|||
tags
|
||||
|> cast(attrs, [:name])
|
||||
|> validate_required([:name])
|
||||
|> unique_constraint([:name])
|
||||
end
|
||||
end
|
|
@ -3,11 +3,11 @@
|
|||
<h1><%= @post.title %></h1>
|
||||
|
||||
<p>
|
||||
<date><%= JOL.Blog.format_date(@post.date) %></date>
|
||||
<date><%= JOL.Blog.format_date(@post.published_at) %></date>
|
||||
</p>
|
||||
|
||||
<%= raw @post.body %>
|
||||
|
||||
<p class="post-tags">
|
||||
Filed under: <%= Enum.join(@post.tags, ", ") %>
|
||||
Filed under: <%= @post.tags |> Enum.map(& &1.name) |> Enum.join(", ") %>
|
||||
</p>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<ul class="recent-posts">
|
||||
<%= for post <- @posts do %>
|
||||
<li>
|
||||
<date><%= JOL.Blog.format_date(post.date) %></date>
|
||||
<date><%= JOL.Blog.format_date(post.published_at) %></date>
|
||||
<.link href={~p"/blog/#{post.slug}"}><%= post.title %> </.link>
|
||||
</li>
|
||||
<% end %>
|
||||
|
|
|
@ -8,11 +8,13 @@ defmodule JOLWeb.TagController do
|
|||
tags: JOL.Blog.unique_tag_list)
|
||||
end
|
||||
|
||||
def tag(conn, %{"tag" => tag}) do
|
||||
def tag(conn, %{"id" => id}) do
|
||||
tag = JOL.Blog.get_tag_by_id!(id)
|
||||
|
||||
conn
|
||||
|> render(:tag,
|
||||
tag: tag,
|
||||
page_title: "Posts Filed Under #{tag}",
|
||||
posts: JOL.Blog.get_posts_by_tag!(tag))
|
||||
tag: tag.name,
|
||||
page_title: "Filed Under #{tag.name}",
|
||||
posts: tag.posts)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<ul>
|
||||
<%= for tag <- @tags do %>
|
||||
<li class="tag-list">
|
||||
<a href={~p"/tags/#{tag}"}><%= tag %></a>
|
||||
<a href={~p"/tags/#{tag.id}"}><%= tag.name %></a>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<%= for post <- @posts do %>
|
||||
<div class="post-summary">
|
||||
<p class="post-date"><date><%= post.date %></date></p>
|
||||
<p class="post-date"><date><%= post.published_at %></date></p>
|
||||
<h3> <.link href={~p"/blog/#{post.slug}"}><%= post.title %> </.link> </h3>
|
||||
<p><%= raw post.lede %></p>
|
||||
</div>
|
||||
|
|
|
@ -28,7 +28,7 @@ defmodule JOLWeb.Router do
|
|||
get "/colophon", PageController, :colophon
|
||||
|
||||
get "/tags", TagController, :index
|
||||
get "/tags/:tag", TagController, :tag
|
||||
get "/tags/:id", TagController, :tag
|
||||
|
||||
get "/blog", BlogController, :index
|
||||
get "/blog/:slug", BlogController, :show
|
||||
|
|
3
mix.exs
3
mix.exs
|
@ -59,7 +59,8 @@ defmodule JOL.MixProject do
|
|||
{:dns_cluster, "~> 0.1.1"},
|
||||
{:bandit, "~> 1.2"},
|
||||
{:atomex, "~> 0.3.0"},
|
||||
{:tz, "~> 0.27"}
|
||||
{:tz, "~> 0.27"},
|
||||
{:toml, "~> 0.7"}
|
||||
]
|
||||
end
|
||||
|
||||
|
|
26
priv/migrate_posts.exs
Normal file
26
priv/migrate_posts.exs
Normal file
|
@ -0,0 +1,26 @@
|
|||
alias JOL.Blog.{Parser,Post,Tag}
|
||||
alias JOL.Repo
|
||||
import Ecto.Query
|
||||
|
||||
post_dir = Application.app_dir(:jol, "priv/posts/blog/")
|
||||
|
||||
Path.wildcard("#{post_dir}/**/*.md")
|
||||
|> Enum.each(fn path ->
|
||||
{attrs, body} = Parser.parse(path, File.read!(path))
|
||||
for tag <- attrs.tags do
|
||||
Repo.insert!(%Tag{name: tag}, on_conflict: :nothing, conflict_target: [:name])
|
||||
end
|
||||
|
||||
post_attrs = %{title: attrs.title,
|
||||
published_at: attrs.date,
|
||||
slug: attrs.slug,
|
||||
body: body,
|
||||
tags: Repo.all(from t in Tag, where: t.name in ^attrs.tags)
|
||||
}
|
||||
|
||||
%Post{}
|
||||
|> Repo.preload(:tags)
|
||||
|> Ecto.Changeset.cast(post_attrs, [:published_at, :slug, :body, :title])
|
||||
|> Ecto.Changeset.put_assoc(:tags, post_attrs.tags)
|
||||
|> Repo.insert!()
|
||||
end)
|
10
priv/repo/migrations/20240924153630_join_posts_and_tags.exs
Normal file
10
priv/repo/migrations/20240924153630_join_posts_and_tags.exs
Normal file
|
@ -0,0 +1,10 @@
|
|||
defmodule JOL.Repo.Migrations.JoinPostsAndTags do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
create table(:post_tags) do
|
||||
add :post_id, references(:posts)
|
||||
add :tag_id, references(:tags)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,8 @@
|
|||
defmodule JOL.Repo.Migrations.MakeTagNameUnique do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
create unique_index(:tags, ["name"])
|
||||
create unique_index(:post_tags, ["post_id", "tag_id"])
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue