mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-24 04:27:59 +01:00
tag aliasing and image editing
This commit is contained in:
parent
b7c8b95003
commit
482f1dfe5e
14 changed files with 196 additions and 21 deletions
|
@ -174,9 +174,9 @@ defmodule Philomena.Tags do
|
||||||
def alias_tag(%Tag{} = tag, attrs) do
|
def alias_tag(%Tag{} = tag, attrs) do
|
||||||
target_tag = Repo.get_by!(Tag, name: attrs["target_tag"])
|
target_tag = Repo.get_by!(Tag, name: attrs["target_tag"])
|
||||||
|
|
||||||
filters_hidden = where(Filter, [f], fragment("? @> ARRAY[?]", f.hidden_tag_ids, ^tag.id))
|
filters_hidden = where(Filter, [f], fragment("? @> ARRAY[?]::integer[]", f.hidden_tag_ids, ^tag.id))
|
||||||
filters_spoilered = where(Filter, [f], fragment("? @> ARRAY[?]", f.spoilered_tag_ids, ^tag.id))
|
filters_spoilered = where(Filter, [f], fragment("? @> ARRAY[?]::integer[]", f.spoilered_tag_ids, ^tag.id))
|
||||||
users_watching = where(User, [u], fragment("? @> ARRAY[?]", u.watched_tag_ids, ^tag.id))
|
users_watching = where(User, [u], fragment("? @> ARRAY[?]::integer[]", u.watched_tag_ids, ^tag.id))
|
||||||
|
|
||||||
array_replace(filters_hidden, :hidden_tag_ids, tag.id, target_tag.id)
|
array_replace(filters_hidden, :hidden_tag_ids, tag.id, target_tag.id)
|
||||||
array_replace(filters_spoilered, :spoilered_tag_ids, tag.id, target_tag.id)
|
array_replace(filters_spoilered, :spoilered_tag_ids, tag.id, target_tag.id)
|
||||||
|
@ -186,7 +186,7 @@ defmodule Philomena.Tags do
|
||||||
Repo.query!(
|
Repo.query!(
|
||||||
"INSERT INTO image_taggings (image_id, tag_id) " <>
|
"INSERT INTO image_taggings (image_id, tag_id) " <>
|
||||||
"SELECT i.id, #{target_tag.id} FROM images i " <>
|
"SELECT i.id, #{target_tag.id} FROM images i " <>
|
||||||
"INNER JOIN image_tagging it on it.image_id = i.id " <>
|
"INNER JOIN image_taggings it on it.image_id = i.id " <>
|
||||||
"WHERE it.tag_id = #{tag.id} " <>
|
"WHERE it.tag_id = #{tag.id} " <>
|
||||||
"ON CONFLICT DO NOTHING"
|
"ON CONFLICT DO NOTHING"
|
||||||
)
|
)
|
||||||
|
@ -228,6 +228,12 @@ defmodule Philomena.Tags do
|
||||||
|> Image.reindex()
|
|> Image.reindex()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def unalias_tag(%Tag{} = tag) do
|
||||||
|
tag
|
||||||
|
|> Tag.unalias_changeset()
|
||||||
|
|> Repo.update()
|
||||||
|
end
|
||||||
|
|
||||||
defp array_replace(queryable, column, old_value, new_value) do
|
defp array_replace(queryable, column, old_value, new_value) do
|
||||||
queryable
|
queryable
|
||||||
|> update(
|
|> update(
|
||||||
|
|
|
@ -95,7 +95,7 @@ defmodule Philomena.Tags.Tag do
|
||||||
tag
|
tag
|
||||||
|> cast(attrs, [:image, :image_format, :image_mime_type, :uploaded_image])
|
|> cast(attrs, [:image, :image_format, :image_mime_type, :uploaded_image])
|
||||||
|> validate_required([:image, :image_format, :image_mime_type])
|
|> validate_required([:image, :image_format, :image_mime_type])
|
||||||
|> validate_inclusion(:image_mime_type, ~W(image/gif image/jpeg image/png))
|
|> validate_inclusion(:image_mime_type, ~W(image/gif image/jpeg image/png image/svg+xml))
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove_image_changeset(tag) do
|
def remove_image_changeset(tag) do
|
||||||
|
@ -104,6 +104,10 @@ defmodule Philomena.Tags.Tag do
|
||||||
|> put_change(:image, nil)
|
|> put_change(:image, nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def unalias_changeset(tag) do
|
||||||
|
change(tag, aliased_tag_id: nil)
|
||||||
|
end
|
||||||
|
|
||||||
def creation_changeset(tag, attrs) do
|
def creation_changeset(tag, attrs) do
|
||||||
tag
|
tag
|
||||||
|> cast(attrs, [:name])
|
|> cast(attrs, [:name])
|
||||||
|
|
|
@ -88,8 +88,9 @@ defimpl Canada.Can, for: [Atom, Philomena.Users.User] do
|
||||||
def can?(%User{role: "moderator"}, :show, %Topic{}), do: true
|
def can?(%User{role: "moderator"}, :show, %Topic{}), do: true
|
||||||
def can?(%User{role: "moderator"}, :hide, %Topic{}), do: true
|
def can?(%User{role: "moderator"}, :hide, %Topic{}), do: true
|
||||||
|
|
||||||
# Edit tags
|
# Edit and alias tags
|
||||||
def can?(%User{role: "moderator"}, :edit, %Tag{}), do: true
|
def can?(%User{role: "moderator"}, :edit, %Tag{}), do: true
|
||||||
|
def can?(%User{role: "moderator"}, :alias, %Tag{}), do: true
|
||||||
|
|
||||||
#
|
#
|
||||||
# Assistants can...
|
# Assistants can...
|
||||||
|
|
32
lib/philomena_web/controllers/tag/alias_controller.ex
Normal file
32
lib/philomena_web/controllers/tag/alias_controller.ex
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
defmodule PhilomenaWeb.Tag.AliasController do
|
||||||
|
use PhilomenaWeb, :controller
|
||||||
|
|
||||||
|
alias Philomena.Tags.Tag
|
||||||
|
alias Philomena.Tags
|
||||||
|
|
||||||
|
plug PhilomenaWeb.CanaryMapPlug, edit: :alias, update: :alias, delete: :alias
|
||||||
|
plug :load_and_authorize_resource, model: Tag, id_name: "tag_id", id_field: "slug", preload: [:implied_tags, :aliased_tag], persisted: true
|
||||||
|
|
||||||
|
def edit(conn, _params) do
|
||||||
|
changeset = Tags.change_tag(conn.assigns.tag)
|
||||||
|
render(conn, "edit.html", changeset: changeset)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update(conn, %{"tag" => tag_params}) do
|
||||||
|
spawn fn ->
|
||||||
|
Tags.alias_tag(conn.assigns.tag, tag_params)
|
||||||
|
end
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> put_flash(:info, "Tag alias queued.")
|
||||||
|
|> redirect(to: Routes.tag_path(conn, :show, conn.assigns.tag))
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete(conn, _params) do
|
||||||
|
{:ok, _tag} = Tags.unalias_tag(conn.assigns.tag)
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> put_flash(:info, "Tag alias removed.")
|
||||||
|
|> redirect(to: Routes.tag_path(conn, :show, conn.assigns.tag))
|
||||||
|
end
|
||||||
|
end
|
35
lib/philomena_web/controllers/tag/image_controller.ex
Normal file
35
lib/philomena_web/controllers/tag/image_controller.ex
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
defmodule PhilomenaWeb.Tag.ImageController do
|
||||||
|
use PhilomenaWeb, :controller
|
||||||
|
|
||||||
|
alias Philomena.Tags.Tag
|
||||||
|
alias Philomena.Tags
|
||||||
|
import Ecto.Query
|
||||||
|
|
||||||
|
plug PhilomenaWeb.CanaryMapPlug, update: :edit, delete: :edit
|
||||||
|
plug :load_and_authorize_resource, model: Tag, id_name: "tag_id", id_field: "slug", preload: [:implied_tags], persisted: true
|
||||||
|
|
||||||
|
def edit(conn, _params) do
|
||||||
|
changeset = Tags.change_tag(conn.assigns.tag)
|
||||||
|
render(conn, "edit.html", changeset: changeset)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update(conn, %{"tag" => tag_params}) do
|
||||||
|
case Tags.update_tag_image(conn.assigns.tag, tag_params) do
|
||||||
|
{:ok, %{tag: tag}} ->
|
||||||
|
conn
|
||||||
|
|> put_flash(:info, "Tag image successfully updated.")
|
||||||
|
|> redirect(to: Routes.tag_path(conn, :show, tag))
|
||||||
|
|
||||||
|
{:error, :tag, changeset, _changes} ->
|
||||||
|
render(conn, "edit.html", changeset: changeset)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete(conn, _params) do
|
||||||
|
{:ok, _tag} = Tags.remove_tag_image(conn.assigns.tag)
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> put_flash(:info, "Tag image successfully removed.")
|
||||||
|
|> redirect(to: Routes.tag_path(conn, :show, conn.assigns.tag))
|
||||||
|
end
|
||||||
|
end
|
|
@ -8,7 +8,8 @@ defmodule PhilomenaWeb.TagController do
|
||||||
|
|
||||||
plug PhilomenaWeb.RecodeParameterPlug, [name: "id"] when action in [:show]
|
plug PhilomenaWeb.RecodeParameterPlug, [name: "id"] when action in [:show]
|
||||||
plug PhilomenaWeb.CanaryMapPlug, update: :edit
|
plug PhilomenaWeb.CanaryMapPlug, update: :edit
|
||||||
plug :load_and_authorize_resource, model: Tag, id_field: "slug", only: [:show, :edit, :update, :delete], preload: [:aliases, :implied_tags, :implied_by_tags, :dnp_entries, public_links: :user]
|
plug :load_and_authorize_resource, model: Tag, id_field: "slug", only: [:show, :edit, :update, :delete], preload: [:aliases, :aliased_tag, :implied_tags, :implied_by_tags, :dnp_entries, public_links: :user]
|
||||||
|
plug :redirect_alias
|
||||||
|
|
||||||
def index(conn, params) do
|
def index(conn, params) do
|
||||||
query_string = params["tq"] || "*"
|
query_string = params["tq"] || "*"
|
||||||
|
@ -128,4 +129,16 @@ defmodule PhilomenaWeb.TagController do
|
||||||
|> String.replace("\"", "\\\"")
|
|> String.replace("\"", "\\\"")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp redirect_alias(conn, _opts) do
|
||||||
|
case conn.assigns.tag do
|
||||||
|
%{aliased_tag: nil} ->
|
||||||
|
conn
|
||||||
|
|
||||||
|
%{aliased_tag: tag} ->
|
||||||
|
conn
|
||||||
|
|> put_flash(:info, "This tag (`#{conn.assigns.tag.name}') has been aliased into the tag `#{tag.name}'.")
|
||||||
|
|> redirect(to: Routes.tag_path(conn, :show, tag))
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -209,7 +209,10 @@ defmodule PhilomenaWeb.Router do
|
||||||
resources "/claim", DuplicateReport.ClaimController, only: [:create, :delete], singleton: true
|
resources "/claim", DuplicateReport.ClaimController, only: [:create, :delete], singleton: true
|
||||||
end
|
end
|
||||||
|
|
||||||
resources "/tags", TagController, only: [:edit, :update, :delete]
|
resources "/tags", TagController, only: [:edit, :update, :delete] do
|
||||||
|
resources "/image", Tag.ImageController, only: [:edit, :update, :delete], singleton: true
|
||||||
|
resources "/alias", Tag.AliasController, only: [:edit, :update, :delete], singleton: true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/", PhilomenaWeb do
|
scope "/", PhilomenaWeb do
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
.block__content.js-imagelist-info.flex
|
.block__content.js-imagelist-info.flex class=tags_row_class(@conn)
|
||||||
.flex__fixed.tag-info__image.thumb-tiny-container.spacing-right
|
.flex__fixed.tag-info__image.thumb-tiny-container.spacing-right
|
||||||
= if @tag.image do
|
= if @tag.image do
|
||||||
img src=tag_image(@tag) alt="spoiler image"
|
img src=tag_image(@tag) alt="spoiler image"
|
||||||
|
@ -18,21 +18,29 @@
|
||||||
= @tag.short_description
|
= @tag.short_description
|
||||||
br
|
br
|
||||||
|
|
||||||
|
= if manages_tags?(@conn) and present?(@tag.mod_notes) do
|
||||||
|
strong.comment_deleted> Mod notes:
|
||||||
|
= @tag.mod_notes
|
||||||
|
br
|
||||||
|
|
||||||
= if Enum.any?(@tag.aliases) do
|
= if Enum.any?(@tag.aliases) do
|
||||||
strong> Aliases:
|
strong> Aliases:
|
||||||
= Enum.map_join(@tag.aliases, ", ", & &1.name)
|
= if aliases_tags?(@conn) do
|
||||||
|
= map_join(@tag.aliases, ", ", &link(&1.name, to: Routes.tag_alias_path(@conn, :edit, &1)))
|
||||||
|
- else
|
||||||
|
= map_join(@tag.aliases, ", ", & &1.name)
|
||||||
br
|
br
|
||||||
|
|
||||||
= if Enum.any?(@tag.implied_tags) do
|
= if Enum.any?(@tag.implied_tags) do
|
||||||
strong> Implies:
|
strong> Implies:
|
||||||
= Enum.map_join(@tag.implied_tags, ", ", & &1.name)
|
= map_join(@tag.implied_tags, ", ", &link(&1.name, to: Routes.tag_path(@conn, :show, &1)))
|
||||||
br
|
br
|
||||||
|
|
||||||
= if present?(@tag.public_links) or present?(@tag.implied_by_tags) or present?(@tag.description) do
|
= if present?(@tag.public_links) or present?(@tag.implied_by_tags) or present?(@tag.description) do
|
||||||
br
|
br
|
||||||
= link "Toggle detailed information", to: "#", data: [click_toggle: ".tag-info__more"]
|
= link "Toggle detailed information", to: "#", data: [click_toggle: ".tag-info__more"]
|
||||||
|
|
||||||
.tag-info__more
|
.tag-info__more.hidden
|
||||||
hr
|
hr
|
||||||
|
|
||||||
= if Enum.any?(@tag.public_links) do
|
= if Enum.any?(@tag.public_links) do
|
||||||
|
@ -53,7 +61,7 @@
|
||||||
br
|
br
|
||||||
|
|
||||||
= if Enum.any?(@tag.implied_by_tags) do
|
= if Enum.any?(@tag.implied_by_tags) do
|
||||||
input.toggle-box id="implied_by" type="checkbox" checked="false"
|
input.toggle-box id="implied_by" type="checkbox"
|
||||||
label for="implied_by"
|
label for="implied_by"
|
||||||
' Implied by (warning: unfiltered)
|
' Implied by (warning: unfiltered)
|
||||||
|
|
||||||
|
@ -83,5 +91,5 @@
|
||||||
==> body
|
==> body
|
||||||
|
|
||||||
| (
|
| (
|
||||||
= link "more info", to: "#"
|
= link "more info", to: Routes.dnp_entry_path(@conn, :show, entry)
|
||||||
| )
|
| )
|
||||||
|
|
21
lib/philomena_web/templates/tag/alias/edit.html.slime
Normal file
21
lib/philomena_web/templates/tag/alias/edit.html.slime
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
h1
|
||||||
|
' Aliasing tag
|
||||||
|
= @tag.name
|
||||||
|
|
||||||
|
= form_for @changeset, Routes.tag_alias_path(@conn, :update, @tag), [method: "put"], fn f ->
|
||||||
|
= if @changeset.action do
|
||||||
|
.alert.alert-danger
|
||||||
|
p Oops, something went wrong! Please check the errors below.
|
||||||
|
|
||||||
|
.field
|
||||||
|
=> label f, "Alias target:"
|
||||||
|
= text_input f, :target_tag, value: alias_target(@tag), class: "input"
|
||||||
|
|
||||||
|
.field
|
||||||
|
=> submit "Alias tag", class: "button"
|
||||||
|
|
||||||
|
br
|
||||||
|
= button_to "Remove tag alias", Routes.tag_alias_path(@conn, :delete, @tag), method: "delete", class: "button", data: [confirm: "Are you really, really sure?"]
|
||||||
|
|
||||||
|
br
|
||||||
|
= link "Back", to: Routes.tag_path(@conn, :show, @tag)
|
|
@ -1,5 +1,8 @@
|
||||||
h1 Editing Tag
|
h1 Editing Tag
|
||||||
|
|
||||||
|
p = link "Edit image", to: Routes.tag_image_path(@conn, :edit, @tag)
|
||||||
|
p = link "Edit aliases", to: Routes.tag_alias_path(@conn, :edit, @tag)
|
||||||
|
|
||||||
= form_for @changeset, Routes.tag_path(@conn, :update, @tag), [class: "form"], fn f ->
|
= form_for @changeset, Routes.tag_path(@conn, :update, @tag), [class: "form"], fn f ->
|
||||||
= if @changeset.action do
|
= if @changeset.action do
|
||||||
.alert.alert-danger
|
.alert.alert-danger
|
||||||
|
@ -30,13 +33,6 @@ h1 Editing Tag
|
||||||
.field
|
.field
|
||||||
= render PhilomenaWeb.TagView, "_tag_editor.html", f: f, name: :implied_tag_list, type: :edit, conn: @conn
|
= render PhilomenaWeb.TagView, "_tag_editor.html", f: f, name: :implied_tag_list, type: :edit, conn: @conn
|
||||||
|
|
||||||
/- if can? :manage, Tag
|
|
||||||
h4 Tag Merging (Aliasing)
|
|
||||||
.fieldlabel Merge with target tag for searches, user links, filters, etc.; soft keeps the tag around for redirection purposes as an "alias"
|
|
||||||
.field
|
|
||||||
= select_tag :merge_mode, options_for_select({ Soft: :alias, Hard: :hard_merge }, :alias), class: "input"
|
|
||||||
= text_input f, :target_tag_name, class: "input", placeholder: "Target tag name", autocapitalize: "none", value: @tag.aliased_tag_name
|
|
||||||
|
|
||||||
br
|
br
|
||||||
= submit "Save Tag", class: "button button--state-primary"
|
= submit "Save Tag", class: "button button--state-primary"
|
||||||
|
|
||||||
|
|
41
lib/philomena_web/templates/tag/image/edit.html.slime
Normal file
41
lib/philomena_web/templates/tag/image/edit.html.slime
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
|
||||||
|
|
||||||
|
.profile-top
|
||||||
|
.profile-top__avatar
|
||||||
|
.tag-info__image.thumb-tiny-container
|
||||||
|
= if @tag.image do
|
||||||
|
img src=tag_image(@tag) alt="spoiler image" width=50 height=50
|
||||||
|
- else
|
||||||
|
| no spoiler image
|
||||||
|
|
||||||
|
.profile-top__name-and-links
|
||||||
|
div
|
||||||
|
h1 Tag image
|
||||||
|
|
||||||
|
p Add a new image or remove the existing one here.
|
||||||
|
p SVG is preferred.
|
||||||
|
|
||||||
|
= form_for @changeset, Routes.tag_image_path(@conn, :update, @tag), [method: "put", multipart: true], fn f ->
|
||||||
|
= if @changeset.action do
|
||||||
|
.alert.alert-danger
|
||||||
|
p Oops, something went wrong! Please check the errors below.
|
||||||
|
|
||||||
|
h4 Select an image
|
||||||
|
.image-other
|
||||||
|
#js-image-upload-previews
|
||||||
|
p Upload a file from your computer
|
||||||
|
.field
|
||||||
|
= file_input f, :image, class: "input js-scraper"
|
||||||
|
= error_tag f, :image_mime_type
|
||||||
|
|
||||||
|
.field-error-js.hidden.js-scraper
|
||||||
|
|
||||||
|
br
|
||||||
|
|
||||||
|
=> submit "Update tag image", class: "button"
|
||||||
|
|
||||||
|
br
|
||||||
|
= button_to "Remove tag image", Routes.tag_image_path(@conn, :delete, @tag), method: "delete", class: "button", data: [confirm: "Are you really, really sure?"]
|
||||||
|
|
||||||
|
br
|
||||||
|
= link "Back", to: Routes.tag_path(@conn, :show, @tag)
|
6
lib/philomena_web/views/tag/alias_view.ex
Normal file
6
lib/philomena_web/views/tag/alias_view.ex
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
defmodule PhilomenaWeb.Tag.AliasView do
|
||||||
|
use PhilomenaWeb, :view
|
||||||
|
|
||||||
|
def alias_target(%{aliased_tag: nil}), do: ""
|
||||||
|
def alias_target(%{aliased_tag: tag}), do: tag.name
|
||||||
|
end
|
5
lib/philomena_web/views/tag/image_view.ex
Normal file
5
lib/philomena_web/views/tag/image_view.ex
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
defmodule PhilomenaWeb.Tag.ImageView do
|
||||||
|
use PhilomenaWeb, :view
|
||||||
|
|
||||||
|
import PhilomenaWeb.TagView, only: [tag_image: 1]
|
||||||
|
end
|
|
@ -14,6 +14,10 @@ defmodule PhilomenaWeb.TagView do
|
||||||
can?(conn, :edit, %Tag{})
|
can?(conn, :edit, %Tag{})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def aliases_tags?(conn) do
|
||||||
|
can?(conn, :alias, %Tag{})
|
||||||
|
end
|
||||||
|
|
||||||
def tag_image(%{image: image}) do
|
def tag_image(%{image: image}) do
|
||||||
tag_url_root() <> "/" <> image
|
tag_url_root() <> "/" <> image
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue