Add backlinks

This commit is contained in:
Shadowfacts 2020-08-02 16:12:38 -04:00
parent 4ba50f9fb5
commit 28cd37966a
Signed by: shadowfacts
GPG Key ID: 94A5AB95422746E5
7 changed files with 111 additions and 8 deletions

View File

@ -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 """

View File

@ -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

View File

@ -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

View File

@ -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),
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/\[\[.*?\]\]/

View File

@ -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

View File

@ -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>

View File

@ -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