Add backlinks
This commit is contained in:
parent
4ba50f9fb5
commit
28cd37966a
|
@ -56,6 +56,19 @@ defmodule Wiki.Content do
|
|||
%Page{}
|
||||
|> Page.changeset(attrs)
|
||||
|> Repo.insert()
|
||||
|> case do
|
||||
{:ok, page} ->
|
||||
content = Map.get(attrs, "content") || Map.get(attrs, :content)
|
||||
|
||||
unless is_nil(content) do
|
||||
Page.update_page_links(%Page{page | content: content})
|
||||
end
|
||||
|
||||
{:ok, page}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, reason}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
|
@ -74,6 +87,19 @@ defmodule Wiki.Content do
|
|||
page
|
||||
|> Page.changeset(attrs)
|
||||
|> Repo.update()
|
||||
|> case do
|
||||
{:ok, page} ->
|
||||
content = Map.get(attrs, "content") || Map.get(attrs, :content)
|
||||
|
||||
unless is_nil(content) do
|
||||
Page.update_page_links(%Page{page | content: content})
|
||||
end
|
||||
|
||||
{:ok, page}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, reason}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
defmodule Wiki.Content.Page do
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
import Ecto.Query
|
||||
alias Wiki.Repo
|
||||
alias Wiki.Content.PageLink
|
||||
|
||||
@type t() :: %__MODULE__{
|
||||
encrypted_content: binary(),
|
||||
|
@ -32,6 +35,14 @@ defmodule Wiki.Content.Page do
|
|||
belongs_to :user, Wiki.Accounts.User
|
||||
has_many :uploads, Wiki.Content.Upload
|
||||
|
||||
# Pages that this page links to
|
||||
has_many :_pages_linked_to, PageLink, foreign_key: :from_id
|
||||
has_many :pages_linked_to, through: [:_pages_linked_to, :to]
|
||||
|
||||
# Pages that link to this page
|
||||
has_many :_pages_linked_from, PageLink, foreign_key: :to_id
|
||||
has_many :pages_linked_from, through: [:_pages_linked_from, :from]
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
|
@ -65,7 +76,7 @@ defmodule Wiki.Content.Page do
|
|||
{encrypted_content, tag, iv} = do_encrypt(content, key)
|
||||
|
||||
user_id = get_field(changeset, :user_id)
|
||||
{html, _linked_pages} = Wiki.Content.Renderer.render(content, user_id)
|
||||
html = Wiki.Content.Renderer.render(content, user_id)
|
||||
{encrypted_html, html_tag, html_iv} = do_encrypt(html, key)
|
||||
|
||||
changeset
|
||||
|
@ -122,4 +133,22 @@ defmodule Wiki.Content.Page do
|
|||
false
|
||||
)
|
||||
end
|
||||
|
||||
@spec update_page_links(page :: __MODULE__.t()) :: :ok
|
||||
def update_page_links(%__MODULE__{content: content, id: id} = page) when is_binary(content) do
|
||||
linked_page_ids = Wiki.Content.Renderer.get_linked_pages(page)
|
||||
|
||||
if length(linked_page_ids) == 0 do
|
||||
Repo.delete_all(from link in PageLink, where: link.from_id == ^id)
|
||||
else
|
||||
Repo.delete_all(
|
||||
from link in PageLink, where: link.from_id == ^id and not (link.to_id in ^linked_page_ids)
|
||||
)
|
||||
|
||||
values = Enum.map(linked_page_ids, fn to_id -> [from_id: id, to_id: to_id] end)
|
||||
Repo.insert_all(PageLink, values, on_conflict: :nothing)
|
||||
end
|
||||
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
defmodule Wiki.Content.PageLink do
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
|
||||
schema "page_links" do
|
||||
belongs_to :from, Wiki.Content.Page
|
||||
belongs_to :to, Wiki.Content.Page
|
||||
end
|
||||
|
||||
@doc false
|
||||
def changeset(page_link, attrs) do
|
||||
page_link
|
||||
|> cast(attrs, [:from_id, :to_id])
|
||||
|> validate_required([:from_id, :to_id])
|
||||
end
|
||||
end
|
|
@ -5,14 +5,18 @@ defmodule Wiki.Content.Renderer do
|
|||
alias WikiWeb.Endpoint
|
||||
import Ecto.Query
|
||||
|
||||
@spec render(String.t(), integer()) :: {String.t(), [integer()]}
|
||||
@spec render(String.t(), integer()) :: String.t()
|
||||
def render(content, user_id) do
|
||||
{content, linked_pages} = replace_page_links(content, user_id)
|
||||
{content, _linked_pages} = replace_page_links(content, user_id)
|
||||
|
||||
{
|
||||
render_markdown(content),
|
||||
Enum.uniq(linked_pages)
|
||||
}
|
||||
content
|
||||
|> render_markdown()
|
||||
end
|
||||
|
||||
@spec get_linked_pages(page :: Page.t()) :: [integer()]
|
||||
def get_linked_pages(%Page{content: content, user_id: user_id}) do
|
||||
{_content, linked_pages} = replace_page_links(content, user_id)
|
||||
Enum.uniq(linked_pages)
|
||||
end
|
||||
|
||||
@page_link_regex ~r/\[\[.*?\]\]/
|
||||
|
|
|
@ -85,7 +85,7 @@ defmodule WikiWeb.PageController do
|
|||
end
|
||||
|
||||
def show(conn, _params) do
|
||||
page = Repo.preload(conn.assigns.page, :uploads)
|
||||
page = Repo.preload(conn.assigns.page, [:uploads, :pages_linked_from])
|
||||
render(conn, "show.html", page: page)
|
||||
end
|
||||
|
||||
|
|
|
@ -20,3 +20,14 @@
|
|||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<h2>Backlinks</h2>
|
||||
<ul>
|
||||
<%= for page <- @page.pages_linked_from do %>
|
||||
<li>
|
||||
<a href="<%= Routes.page_path(@conn, :show, page.id) %>">
|
||||
<%= page.title %>
|
||||
</a>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
defmodule Wiki.Repo.Migrations.CreatePageLinks do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
create table(:page_links) do
|
||||
add :from_id, references(:pages, on_delete: :nothing), primary_key: true
|
||||
add :to_id, references(:pages, on_delete: :nothing), primary_key: true
|
||||
end
|
||||
|
||||
create index(:page_links, [:from_id])
|
||||
create index(:page_links, [:to_id])
|
||||
|
||||
create unique_index(:page_links, [:from_id, :to_id],
|
||||
name: :page_link_from_id_to_id_unique_index
|
||||
)
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue