mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-27 13:47:58 +01:00
Tag locking (#102)
This commit is contained in:
parent
7030b02183
commit
f112f7928b
14 changed files with 162 additions and 20 deletions
|
@ -265,15 +265,25 @@ defmodule Philomena.Images do
|
|||
|> Repo.transaction()
|
||||
end
|
||||
|
||||
def update_locked_tags(%Image{} = image, attrs) do
|
||||
new_tags = Tags.get_or_create_tags(attrs["tag_input"])
|
||||
|
||||
image
|
||||
|> Repo.preload(:locked_tags)
|
||||
|> Image.locked_tags_changeset(attrs, new_tags)
|
||||
|> Repo.update()
|
||||
end
|
||||
|
||||
def update_tags(%Image{} = image, attribution, attrs) do
|
||||
old_tags = Tags.get_or_create_tags(attrs["old_tag_input"])
|
||||
new_tags = Tags.get_or_create_tags(attrs["tag_input"])
|
||||
|
||||
Multi.new()
|
||||
|> Multi.run(:image, fn repo, _chg ->
|
||||
image = repo.preload(image, [:tags, :locked_tags])
|
||||
|
||||
image
|
||||
|> repo.preload(:tags)
|
||||
|> Image.tag_changeset(%{}, old_tags, new_tags)
|
||||
|> Image.tag_changeset(%{}, old_tags, new_tags, image.locked_tags)
|
||||
|> repo.update()
|
||||
|> case do
|
||||
{:ok, image} ->
|
||||
|
|
|
@ -38,6 +38,7 @@ defmodule Philomena.Images.Image do
|
|||
has_many :favers, through: [:faves, :user]
|
||||
has_many :hiders, through: [:hides, :user]
|
||||
many_to_many :tags, Tag, join_through: "image_taggings", on_replace: :delete
|
||||
many_to_many :locked_tags, Tag, join_through: "image_tag_locks", on_replace: :delete
|
||||
has_one :intensity, ImageIntensity
|
||||
has_many :galleries, through: [:gallery_interactions, :image]
|
||||
|
||||
|
@ -179,14 +180,20 @@ defmodule Philomena.Images.Image do
|
|||
|> validate_format(:source_url, ~r/\Ahttps?:\/\//)
|
||||
end
|
||||
|
||||
def tag_changeset(image, attrs, old_tags, new_tags) do
|
||||
def tag_changeset(image, attrs, old_tags, new_tags, excluded_tags \\ []) do
|
||||
image
|
||||
|> cast(attrs, [])
|
||||
|> TagDiffer.diff_input(old_tags, new_tags)
|
||||
|> TagDiffer.diff_input(old_tags, new_tags, excluded_tags)
|
||||
|> TagValidator.validate_tags()
|
||||
|> cache_changeset()
|
||||
end
|
||||
|
||||
def locked_tags_changeset(image, attrs, locked_tags) do
|
||||
image
|
||||
|> cast(attrs, [])
|
||||
|> put_assoc(:locked_tags, locked_tags)
|
||||
end
|
||||
|
||||
def dnp_changeset(image, user) do
|
||||
image
|
||||
|> change()
|
||||
|
|
|
@ -5,13 +5,15 @@ defmodule Philomena.Images.TagDiffer do
|
|||
alias Philomena.Tags.Tag
|
||||
alias Philomena.Repo
|
||||
|
||||
def diff_input(changeset, old_tags, new_tags) do
|
||||
def diff_input(changeset, old_tags, new_tags, excluded_tags) do
|
||||
excluded_ids = Enum.map(excluded_tags, & &1.id)
|
||||
|
||||
old_set = to_set(old_tags)
|
||||
new_set = to_set(new_tags)
|
||||
|
||||
tags = changeset |> get_field(:tags)
|
||||
added_tags = added_set(old_set, new_set)
|
||||
removed_tags = removed_set(old_set, new_set)
|
||||
added_tags = added_set(old_set, new_set, excluded_ids)
|
||||
removed_tags = removed_set(old_set, new_set, excluded_ids)
|
||||
|
||||
{tags, actually_added, actually_removed} = apply_changes(tags, added_tags, removed_tags)
|
||||
|
||||
|
@ -21,7 +23,7 @@ defmodule Philomena.Images.TagDiffer do
|
|||
|> put_assoc(:tags, tags)
|
||||
end
|
||||
|
||||
defp added_set(old_set, new_set) do
|
||||
defp added_set(old_set, new_set, excluded_ids) do
|
||||
# new_tags - old_tags
|
||||
added_set =
|
||||
new_set
|
||||
|
@ -40,12 +42,16 @@ defmodule Philomena.Images.TagDiffer do
|
|||
|> Enum.filter(fn {_k, v} -> v.namespace == "oc" end)
|
||||
|> get_oc_tag()
|
||||
|
||||
Map.merge(added_and_implied_set, oc_set)
|
||||
added_and_implied_set
|
||||
|> Map.merge(oc_set)
|
||||
|> Map.drop(excluded_ids)
|
||||
end
|
||||
|
||||
defp removed_set(old_set, new_set) do
|
||||
defp removed_set(old_set, new_set, excluded_ids) do
|
||||
# old_tags - new_tags
|
||||
old_set |> Map.drop(Map.keys(new_set))
|
||||
old_set
|
||||
|> Map.drop(Map.keys(new_set))
|
||||
|> Map.drop(excluded_ids)
|
||||
end
|
||||
|
||||
defp get_oc_tag([]), do: Map.new()
|
||||
|
|
21
lib/philomena/images/tag_lock.ex
Normal file
21
lib/philomena/images/tag_lock.ex
Normal file
|
@ -0,0 +1,21 @@
|
|||
defmodule Philomena.Images.TagLock do
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
|
||||
alias Philomena.Images.Image
|
||||
alias Philomena.Tags.Tag
|
||||
|
||||
@primary_key false
|
||||
|
||||
schema "image_tag_locks" do
|
||||
belongs_to :image, Image, primary_key: true
|
||||
belongs_to :tag, Tag, primary_key: true
|
||||
end
|
||||
|
||||
@doc false
|
||||
def changeset(tag_lock, attrs) do
|
||||
tag_lock
|
||||
|> cast(attrs, [])
|
||||
|> validate_required([])
|
||||
end
|
||||
end
|
|
@ -23,7 +23,7 @@ defmodule PhilomenaWeb.Image.TagController do
|
|||
plug :load_and_authorize_resource,
|
||||
model: Image,
|
||||
id_name: "image_id",
|
||||
preload: [:user, tags: :aliases]
|
||||
preload: [:user, :locked_tags, tags: :aliases]
|
||||
|
||||
def update(conn, %{"image" => image_params}) do
|
||||
attributes = conn.assigns.attributes
|
||||
|
|
|
@ -4,8 +4,27 @@ defmodule PhilomenaWeb.Image.TagLockController do
|
|||
alias Philomena.Images.Image
|
||||
alias Philomena.Images
|
||||
|
||||
plug PhilomenaWeb.CanaryMapPlug, create: :hide, delete: :hide
|
||||
plug :load_and_authorize_resource, model: Image, id_name: "image_id", persisted: true
|
||||
plug PhilomenaWeb.CanaryMapPlug, show: :hide, update: :hide, create: :hide, delete: :hide
|
||||
|
||||
plug :load_and_authorize_resource,
|
||||
model: Image,
|
||||
id_name: "image_id",
|
||||
persisted: true,
|
||||
preload: [:locked_tags]
|
||||
|
||||
def show(conn, _params) do
|
||||
changeset = Images.change_image(conn.assigns.image)
|
||||
|
||||
render(conn, "show.html", title: "Locking image tags", changeset: changeset)
|
||||
end
|
||||
|
||||
def update(conn, %{"image" => image_attrs}) do
|
||||
{:ok, image} = Images.update_locked_tags(conn.assigns.image, image_attrs)
|
||||
|
||||
conn
|
||||
|> put_flash(:info, "Successfully updated list of locked tags.")
|
||||
|> redirect(to: Routes.image_path(conn, :show, image))
|
||||
end
|
||||
|
||||
def create(conn, _params) do
|
||||
{:ok, image} = Images.lock_tags(conn.assigns.image, true)
|
||||
|
|
|
@ -181,7 +181,7 @@ defmodule PhilomenaWeb.ImageController do
|
|||
[i, _],
|
||||
_ in fragment("SELECT COUNT(*) FROM source_changes s WHERE s.image_id = ?", i.id)
|
||||
)
|
||||
|> preload([:deleter, user: [awards: :badge], tags: :aliases])
|
||||
|> preload([:deleter, :locked_tags, user: [awards: :badge], tags: :aliases])
|
||||
|> select([i, t, s], {i, t.count, s.count})
|
||||
|> Repo.one()
|
||||
|> case do
|
||||
|
|
|
@ -212,7 +212,9 @@ defmodule PhilomenaWeb.Router do
|
|||
only: [:create, :delete],
|
||||
singleton: true
|
||||
|
||||
resources "/tag_lock", Image.TagLockController, only: [:create, :delete], singleton: true
|
||||
resources "/tag_lock", Image.TagLockController,
|
||||
only: [:show, :update, :create, :delete],
|
||||
singleton: true
|
||||
end
|
||||
|
||||
resources "/forums", ForumController, only: [] do
|
||||
|
|
|
@ -142,7 +142,8 @@
|
|||
- else
|
||||
= button_to "Unlock tag editing", Routes.image_tag_lock_path(@conn, :delete, @image), method: "delete", class: "button"
|
||||
|
||||
= if @image.hidden_from_users and can?(@conn, :destroy, @image) do
|
||||
br
|
||||
.flex.flex--spaced-out
|
||||
= link "Lock specific tags", to: Routes.image_tag_lock_path(@conn, :show, @image), class: "button"
|
||||
= if @image.hidden_from_users and can?(@conn, :destroy, @image) do
|
||||
= button_to "Destroy image", Routes.image_destroy_path(@conn, :create, @image), method: "post", class: "button button--state-danger", data: [confirm: "This action is IRREVERSIBLE. Are you sure?"]
|
||||
|
|
|
@ -6,6 +6,12 @@
|
|||
.js-imageform class=form_class
|
||||
= if can?(@conn, :edit_metadata, @image) and !@conn.assigns.current_ban do
|
||||
|
||||
= if Enum.any?(@image.locked_tags) do
|
||||
.block.block--fixed.block--warning
|
||||
i.fa.fa-lock>
|
||||
' The following tags have been restricted on this image:
|
||||
code= Enum.map_join(@image.locked_tags, ", ", & &1.name)
|
||||
|
||||
= form_for @changeset, Routes.image_tag_path(@conn, :update, @image), [id: "tags-form", method: "put", data: [remote: true]], fn f ->
|
||||
= if @changeset.action do
|
||||
.alert.alert-danger
|
||||
|
|
13
lib/philomena_web/templates/image/tag_lock/show.html.slime
Normal file
13
lib/philomena_web/templates/image/tag_lock/show.html.slime
Normal file
|
@ -0,0 +1,13 @@
|
|||
- tag_input = Enum.map_join(@image.locked_tags, ", ", & &1.name)
|
||||
|
||||
h1
|
||||
| Editing locked tags on image #
|
||||
= @image.id
|
||||
|
||||
= form_for @changeset, Routes.image_tag_lock_path(@conn, :update, @image), fn f ->
|
||||
.field
|
||||
= render PhilomenaWeb.TagView, "_tag_editor.html", f: f, name: :tag_input, type: :edit, extra: [value: tag_input]
|
||||
= error_tag f, :tag_input
|
||||
|
||||
.actions
|
||||
= submit "Update", class: "button", autocomplete: "off", data: [disable_with: "Please wait..."]
|
3
lib/philomena_web/views/image/tag_lock_view.ex
Normal file
3
lib/philomena_web/views/image/tag_lock_view.ex
Normal file
|
@ -0,0 +1,3 @@
|
|||
defmodule PhilomenaWeb.Image.TagLockView do
|
||||
use PhilomenaWeb, :view
|
||||
end
|
13
priv/repo/migrations/20210301012137_add_tag_locks.exs
Normal file
13
priv/repo/migrations/20210301012137_add_tag_locks.exs
Normal file
|
@ -0,0 +1,13 @@
|
|||
defmodule Philomena.Repo.Migrations.AddTagLocks do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
create table("image_tag_locks", primary_key: false) do
|
||||
add :image_id, references(:images, on_delete: :delete_all), null: false
|
||||
add :tag_id, references(:tags, on_delete: :delete_all), null: false
|
||||
end
|
||||
|
||||
create index("image_tag_locks", [:image_id, :tag_id], unique: true)
|
||||
create index("image_tag_locks", [:tag_id])
|
||||
end
|
||||
end
|
|
@ -858,6 +858,16 @@ CREATE TABLE public.image_subscriptions (
|
|||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: image_tag_locks; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.image_tag_locks (
|
||||
image_id bigint NOT NULL,
|
||||
tag_id bigint NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: image_taggings; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -2796,6 +2806,20 @@ CREATE INDEX image_intensities_index ON public.image_intensities USING btree (nw
|
|||
CREATE UNIQUE INDEX image_sources_image_id_source_index ON public.image_sources USING btree (image_id, source);
|
||||
|
||||
|
||||
--
|
||||
-- Name: image_tag_locks_image_id_tag_id_index; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE UNIQUE INDEX image_tag_locks_image_id_tag_id_index ON public.image_tag_locks USING btree (image_id, tag_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: image_tag_locks_tag_id_index; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX image_tag_locks_tag_id_index ON public.image_tag_locks USING btree (tag_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_adverts_on_restrictions; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -4772,6 +4796,22 @@ ALTER TABLE ONLY public.image_sources
|
|||
ADD CONSTRAINT image_sources_image_id_fkey FOREIGN KEY (image_id) REFERENCES public.images(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: image_tag_locks image_tag_locks_image_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.image_tag_locks
|
||||
ADD CONSTRAINT image_tag_locks_image_id_fkey FOREIGN KEY (image_id) REFERENCES public.images(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: image_tag_locks image_tag_locks_tag_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.image_tag_locks
|
||||
ADD CONSTRAINT image_tag_locks_tag_id_fkey FOREIGN KEY (tag_id) REFERENCES public.tags(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: user_tokens user_tokens_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -4802,3 +4842,4 @@ INSERT INTO public."schema_migrations" (version) VALUES (20200817213256);
|
|||
INSERT INTO public."schema_migrations" (version) VALUES (20200905214139);
|
||||
INSERT INTO public."schema_migrations" (version) VALUES (20201124224116);
|
||||
INSERT INTO public."schema_migrations" (version) VALUES (20210121200815);
|
||||
INSERT INTO public."schema_migrations" (version) VALUES (20210301012137);
|
||||
|
|
Loading…
Reference in a new issue