add slugs for note and channel

This commit is contained in:
Inhji 2023-04-02 23:46:49 +02:00
parent eba003b3b5
commit 64cc1a7e55
16 changed files with 34 additions and 16 deletions

View file

@ -1,12 +1,13 @@
defmodule Chiya.Channels.Channel do
use Ecto.Schema
import Ecto.Changeset
alias Chiya.Channels.ChannelSlug
@derive {Jason.Encoder, only: [:id, :name, :content, :slug, :visibility]}
schema "channels" do
field :content, :string
field :name, :string
field :slug, :string
field :slug, ChannelSlug.Type
field :visibility, Ecto.Enum, values: [:public, :private, :unlisted]
many_to_many :notes, Chiya.Notes.Note,
@ -20,8 +21,9 @@ defmodule Chiya.Channels.Channel do
def changeset(channel, attrs) do
channel
|> cast(attrs, [:name, :content, :visibility, :slug])
|> ChannelSlug.maybe_generate_slug()
|> ChannelSlug.unique_constraint()
|> validate_required([:name, :content, :visibility, :slug])
|> validate_exclusion(:slug, ~w(admin user dev))
|> unique_constraint(:slug)
end
end

View file

@ -0,0 +1,3 @@
defmodule Chiya.Channels.ChannelSlug do
use EctoAutoslugField.Slug, from: :name, to: :slug
end

View file

@ -1,6 +1,9 @@
defmodule Chiya.Notes.Note do
use Ecto.Schema
import Ecto.Changeset
alias Chiya.Notes.NoteSlug
@reserved_slugs []
@derive {Jason.Encoder, only: [:id, :name, :content, :slug, :channels]}
schema "notes" do
@ -8,7 +11,7 @@ defmodule Chiya.Notes.Note do
field :kind, Ecto.Enum, values: [:post, :bookmark], default: :post
field :name, :string
field :published_at, :naive_datetime
field :slug, :string
field :slug, NoteSlug.Type
field :url, :string
many_to_many :channels, Chiya.Channels.Channel,
@ -27,7 +30,9 @@ defmodule Chiya.Notes.Note do
|> Chiya.Notes.preload_note()
|> cast(attrs, [:name, :content, :slug, :published_at, :kind, :url])
|> put_assoc(:channels, attrs["channels"] || [])
|> NoteSlug.maybe_generate_slug()
|> NoteSlug.unique_constraint()
|> validate_required([:name, :content, :slug, :kind])
|> unique_constraint(:slug)
|> validate_exclusion(:slug, @reserved_slugs)
end
end

View file

@ -0,0 +1,3 @@
defmodule Chiya.Notes.NoteSlug do
use EctoAutoslugField.Slug, from: :name, to: :slug
end

View file

@ -3,7 +3,7 @@
<div class="flex items-center gap-4">
<%= for channel <- @channels do %>
<.link
href={~p"/#{channel.slug}"}
href={~p"/c/#{channel.slug}"}
class="text-xs font-semibold leading-6 text-theme-base hover:text-theme-base/75"
>
<%= channel.name %>

View file

@ -13,7 +13,7 @@
</section>
<section class="mt-4 flex gap-4">
<a href="/admin/notes/new" class="p-4 rounded bg-gray-100 shadow border border-gray-300 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-200">
<a href="/admin/notes/new" class="p-4 rounded text-gray-700 bg-gray-100 shadow border border-gray-300 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-200 hover:text-gray-700/80 dark:hover:text-gray-200/80 transition hover:shadow-none">
<.icon name="hero-document-plus" /> New Note
</a>
</section>

View file

@ -5,6 +5,9 @@
<.link href={~p"/admin/channels/#{@channel}/edit"}>
<.button>Edit channel</.button>
</.link>
<.link href={~p"/c/#{@channel.slug}"}>
<.button>Preview</.button>
</.link>
</:actions>
</.header>

View file

@ -10,7 +10,7 @@
<div class="w-full mt-6 sm:w-auto flex flex-col gap-1.5">
<%= for note <- @channel.notes do %>
<a
href={~p"/n/#{note.slug}"}
href={~p"/#{note.slug}"}
class="rounded -mx-2 -my-0.5 px-2 py-0.5 hover:bg-theme-primary/10 transition"
>
<span class="text-theme-heading text-lg font-semibold leading-8"><%= note.name %></span>

View file

@ -27,7 +27,7 @@
<div class="w-full mt-6 sm:w-auto flex flex-col gap-1.5">
<%= for note <- @channel.notes do %>
<a
href={~p"/n/#{note.slug}"}
href={~p"/#{note.slug}"}
class="rounded -mx-2 -my-0.5 px-2 py-0.5 hover:bg-theme-primary/10 transition"
>
<span class="text-theme-heading text-lg font-semibold leading-8">

View file

@ -17,7 +17,7 @@ defmodule ChiyaWeb.NoteShowLive do
<.link href={~p"/admin/notes/#{@note}/edit"}>
<.button>Edit note</.button>
</.link>
<.link href={~p"/n/#{@note.slug}"}>
<.link href={~p"/#{@note.slug}"}>
<.button>Preview</.button>
</.link>
<.link href={~p"/admin/notes/#{@note}/raw"}>

View file

@ -2,7 +2,8 @@ defmodule ChiyaWeb.Markdown do
@options [
footnotes: true,
breaks: true,
escape: true
escape: true,
wikilinks: true
]
def render(markdown) do

View file

@ -109,8 +109,8 @@ defmodule ChiyaWeb.Router do
scope "/", ChiyaWeb do
pipe_through [:browser, :public]
get "/n/:slug", PageController, :note
get "/:slug", PageController, :channel
get "/:slug", PageController, :note
get "/c/:slug", PageController, :channel
get "/", PageController, :home
end
end

View file

@ -36,6 +36,7 @@ defmodule Chiya.MixProject do
{:phoenix, "~> 1.7.1"},
{:phoenix_ecto, "~> 4.4"},
{:ecto_sql, "~> 3.6"},
{:ecto_autoslug_field, "~> 3.0"},
{:postgrex, ">= 0.0.0"},
{:phoenix_html, "~> 3.3"},
{:phoenix_live_reload, "~> 1.2", only: :dev},

View file

@ -12,6 +12,7 @@
"earmark": {:hex, :earmark, "1.4.37", "56ce845c543393aa3f9b294c818c3d783452a4a67e4ab18c4303a954a8b59363", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "d86d5e12868db86d5321b00e62a4bbcb4150346e4acc9a90a041fb188a5cb106"},
"earmark_parser": {:hex, :earmark_parser, "1.4.31", "a93921cdc6b9b869f519213d5bc79d9e218ba768d7270d46fdcf1c01bacff9e2", [:mix], [], "hexpm", "317d367ee0335ef037a87e46c91a2269fef6306413f731e8ec11fc45a7efd059"},
"ecto": {:hex, :ecto, "3.9.4", "3ee68e25dbe0c36f980f1ba5dd41ee0d3eb0873bccae8aeaf1a2647242bffa35", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "de5f988c142a3aa4ec18b85a4ec34a2390b65b24f02385c1144252ff6ff8ee75"},
"ecto_autoslug_field": {:hex, :ecto_autoslug_field, "3.0.0", "37fbc2f07e6691136afff246f2cf5b159ad395b665a55d06db918975fd2397db", [:mix], [{:ecto, ">= 3.7.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:slugger, ">= 0.3.0", [hex: :slugger, repo: "hexpm", optional: false]}], "hexpm", "8ec252c7cf85f13132062f56a484d6a0ef1f981f7be9ce4ad7e9546dd8c0cc0f"},
"ecto_sql": {:hex, :ecto_sql, "3.9.2", "34227501abe92dba10d9c3495ab6770e75e79b836d114c41108a4bf2ce200ad5", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1eb5eeb4358fdbcd42eac11c1fbd87e3affd7904e639d77903c1358b2abd3f70"},
"elixir_make": {:hex, :elixir_make, "0.7.5", "784cc00f5fa24239067cc04d449437dcc5f59353c44eb08f188b2b146568738a", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "c3d63e8d5c92fa3880d89ecd41de59473fa2e83eeb68148155e25e8b95aa2887"},
"esbuild": {:hex, :esbuild, "0.7.0", "ce3afb13cd2c5fd63e13c0e2d0e0831487a97a7696cfa563707342bb825d122a", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "4ae9f4f237c5ebcb001390b8ada65a12fb2bb04f3fe3d1f1692b7a06fbfe8752"},
@ -45,6 +46,7 @@
"plug_crypto": {:hex, :plug_crypto, "1.2.3", "8f77d13aeb32bfd9e654cb68f0af517b371fb34c56c9f2b58fe3df1235c1251a", [:mix], [], "hexpm", "b5672099c6ad5c202c45f5a403f21a3411247f164e4a8fab056e5cd8a290f4a2"},
"postgrex": {:hex, :postgrex, "0.16.5", "fcc4035cc90e23933c5d69a9cd686e329469446ef7abba2cf70f08e2c4b69810", [:mix], [{:connection, "~> 1.1", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "edead639dc6e882618c01d8fc891214c481ab9a3788dfe38dd5e37fd1d5fb2e8"},
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
"slugger": {:hex, :slugger, "0.3.0", "efc667ab99eee19a48913ccf3d038b1fb9f165fa4fbf093be898b8099e61b6ed", [:mix], [], "hexpm", "20d0ded0e712605d1eae6c5b4889581c3460d92623a930ddda91e0e609b5afba"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
"swoosh": {:hex, :swoosh, "1.9.1", "0a5d7bf9954eb41d7e55525bc0940379982b090abbaef67cd8e1fd2ed7f8ca1a", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "76dffff3ffcab80f249d5937a592eaef7cc49ac6f4cdd27e622868326ed6371e"},
"tailwind": {:hex, :tailwind, "0.2.0", "95f9e4a32020c5bec480f1d6a43a49ac8030b13183127b577605f506d6e13a66", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "385e939fcd7fe4654be5130b187e358aaabade385513f9d200ffecdbb9552a9e"},

View file

@ -23,14 +23,13 @@ defmodule Chiya.ChannelsTest do
valid_attrs = %{
content: "some content",
name: "some name",
slug: "some slug",
visibility: :public
}
assert {:ok, %Channel{} = channel} = Channels.create_channel(valid_attrs)
assert channel.content == "some content"
assert channel.name == "some name"
assert channel.slug == "some slug"
assert channel.slug == "some-name"
assert channel.visibility == :public
end

View file

@ -25,7 +25,6 @@ defmodule Chiya.NotesTest do
kind: "post",
name: "some name",
published_at: ~N[2023-03-04 16:22:00],
slug: "some slug",
url: "some url"
}
@ -34,7 +33,7 @@ defmodule Chiya.NotesTest do
assert note.kind == :post
assert note.name == "some name"
assert note.published_at == ~N[2023-03-04 16:22:00]
assert note.slug == "some slug"
assert note.slug == "some-name"
assert note.url == "some url"
end