Markdown
This commit is contained in:
parent
9d3f45997a
commit
8715db806a
|
@ -2,6 +2,14 @@ defmodule Wiki.Accounts.User do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
@type t() :: %__MODULE__{
|
||||||
|
email: String.t(),
|
||||||
|
password: String.t() | nil,
|
||||||
|
hashed_password: String.t(),
|
||||||
|
confirmed_at: NaiveDateTime.t(),
|
||||||
|
content_encryption_key_salt: String.t()
|
||||||
|
}
|
||||||
|
|
||||||
@derive {Inspect, except: [:password]}
|
@derive {Inspect, except: [:password]}
|
||||||
schema "users" do
|
schema "users" do
|
||||||
field :email, :string
|
field :email, :string
|
||||||
|
|
|
@ -100,7 +100,7 @@ defmodule Wiki.Content do
|
||||||
%Ecto.Changeset{data: %Page{}}
|
%Ecto.Changeset{data: %Page{}}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def change_page(%Page{} = page, attrs \\ %{}) do
|
def change_page(%Page{} = page, attrs \\ %{}, options \\ []) do
|
||||||
Page.changeset(page, attrs)
|
Page.changeset(page, attrs, options)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,12 +2,24 @@ defmodule Wiki.Content.Page do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
@type t() :: %__MODULE__{
|
||||||
|
encrypted_content: binary(),
|
||||||
|
encrypted_content_iv: binary(),
|
||||||
|
encrypted_content_tag: binary(),
|
||||||
|
content: String.t() | nil,
|
||||||
|
content_encryption_key: String.t() | nil,
|
||||||
|
html: String.t() | nil,
|
||||||
|
title: String.t(),
|
||||||
|
user: Wiki.Accounts.User.t()
|
||||||
|
}
|
||||||
|
|
||||||
schema "pages" do
|
schema "pages" do
|
||||||
field :encrypted_content, :binary
|
field :encrypted_content, :binary
|
||||||
field :encrypted_content_iv, :binary
|
field :encrypted_content_iv, :binary
|
||||||
field :encrypted_content_tag, :binary
|
field :encrypted_content_tag, :binary
|
||||||
field :content, :string, virtual: true
|
field :content, :string, virtual: true
|
||||||
field :content_encryption_key, :string, virtual: true
|
field :content_encryption_key, :string, virtual: true
|
||||||
|
field :html, :string, virtual: true
|
||||||
field :title, :string
|
field :title, :string
|
||||||
|
|
||||||
belongs_to :user, Wiki.Accounts.User
|
belongs_to :user, Wiki.Accounts.User
|
||||||
|
@ -16,7 +28,8 @@ defmodule Wiki.Content.Page do
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc false
|
@doc false
|
||||||
def changeset(page, attrs) do
|
def changeset(page, attrs, options \\ []) do
|
||||||
|
changeset =
|
||||||
page
|
page
|
||||||
|> cast(attrs, [
|
|> cast(attrs, [
|
||||||
:title,
|
:title,
|
||||||
|
@ -24,7 +37,12 @@ defmodule Wiki.Content.Page do
|
||||||
:content_encryption_key,
|
:content_encryption_key,
|
||||||
:user_id
|
:user_id
|
||||||
])
|
])
|
||||||
|> encrypt_changeset()
|
|
||||||
|
if Keyword.get(options, :encrypt, true) do
|
||||||
|
encrypt_changeset(changeset)
|
||||||
|
else
|
||||||
|
changeset
|
||||||
|
end
|
||||||
|> validate_required([
|
|> validate_required([
|
||||||
:title,
|
:title,
|
||||||
:encrypted_content,
|
:encrypted_content,
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
defmodule Wiki.Content.Renderer do
|
||||||
|
alias Wiki.Repo
|
||||||
|
alias Wiki.Content.Page
|
||||||
|
alias WikiWeb.Router.Helpers, as: Routes
|
||||||
|
alias WikiWeb.Endpoint
|
||||||
|
import Ecto.Query
|
||||||
|
|
||||||
|
@spec render(Page.t()) :: String.t()
|
||||||
|
def render(page) do
|
||||||
|
page.content
|
||||||
|
|> replace_page_links(page)
|
||||||
|
|> render_markdown()
|
||||||
|
end
|
||||||
|
|
||||||
|
@page_link_regex ~r/\[\[.*?\]\]/
|
||||||
|
|
||||||
|
@spec replace_page_links(content :: String.t(), root_page :: Page.t()) :: String.t()
|
||||||
|
defp replace_page_links(content, root_page) do
|
||||||
|
String.replace(content, @page_link_regex, fn match ->
|
||||||
|
title = String.slice(match, 2..-3)
|
||||||
|
lower_title = String.downcase(title)
|
||||||
|
|
||||||
|
path =
|
||||||
|
from(p in Page)
|
||||||
|
|> where([p], p.user_id == ^root_page.user_id)
|
||||||
|
|> where([p], fragment("lower(?)", p.title) == ^lower_title)
|
||||||
|
|> select([p], p.id)
|
||||||
|
|> Repo.one()
|
||||||
|
|> case do
|
||||||
|
nil ->
|
||||||
|
Routes.page_path(Endpoint, :new, title: title)
|
||||||
|
|
||||||
|
linked_page_id ->
|
||||||
|
Routes.page_path(Endpoint, :show, linked_page_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
# convert link to markdown, because [[title]] -> link transformation happens before markdown parsing
|
||||||
|
"[#{title}](#{path})"
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec render_markdown(content :: String.t()) :: String.t()
|
||||||
|
defp render_markdown(content) do
|
||||||
|
{:ok, html, _errors} = Earmark.as_html(content)
|
||||||
|
html
|
||||||
|
end
|
||||||
|
end
|
|
@ -34,8 +34,8 @@ defmodule WikiWeb.PageController do
|
||||||
render(conn, "index.html", pages: pages)
|
render(conn, "index.html", pages: pages)
|
||||||
end
|
end
|
||||||
|
|
||||||
def new(conn, _params) do
|
def new(conn, params) do
|
||||||
changeset = Content.change_page(%Page{})
|
changeset = Content.change_page(%Page{}, params, encrypt: false)
|
||||||
render(conn, "new.html", changeset: changeset)
|
render(conn, "new.html", changeset: changeset)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -59,7 +59,8 @@ defmodule WikiWeb.PageController do
|
||||||
end
|
end
|
||||||
|
|
||||||
def show(conn, _params) do
|
def show(conn, _params) do
|
||||||
render(conn, "show.html", page: conn.assigns.page)
|
rendered_content = Content.Renderer.render(conn.assigns.page)
|
||||||
|
render(conn, "show.html", page: conn.assigns.page, content: rendered_content)
|
||||||
end
|
end
|
||||||
|
|
||||||
def edit(conn, _params) do
|
def edit(conn, _params) do
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<strong>Content:</strong>
|
<strong>Content:</strong>
|
||||||
<%= @page.content %>
|
<%= raw(@content) %>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -13,5 +13,6 @@ defmodule Wiki.Repo.Migrations.CreatePages do
|
||||||
end
|
end
|
||||||
|
|
||||||
create index(:pages, [:user_id])
|
create index(:pages, [:user_id])
|
||||||
|
create index(:pages, ["(lower(title))"], name: :pages_lowercase_title_index)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue