mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-27 13:47:58 +01:00
add irreversible admin-only action to permanently delete an image file
This commit is contained in:
parent
90a16b3317
commit
3ba38edf0b
7 changed files with 74 additions and 0 deletions
|
@ -138,6 +138,20 @@ defmodule Philomena.Images do
|
||||||
|> Repo.isolated_transaction(:serializable)
|
|> Repo.isolated_transaction(:serializable)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def destroy_image(%Image{} = image) do
|
||||||
|
changeset = Image.remove_image_changeset(image)
|
||||||
|
|
||||||
|
Multi.new()
|
||||||
|
|> Multi.update(:image, changeset)
|
||||||
|
|> Multi.run(:remove_file, fn _repo, %{image: image} ->
|
||||||
|
Uploader.unpersist_old_upload(image)
|
||||||
|
Hider.destroy_thumbnails(image)
|
||||||
|
|
||||||
|
{:ok, nil}
|
||||||
|
end)
|
||||||
|
|> Repo.isolated_transaction(:serializable)
|
||||||
|
end
|
||||||
|
|
||||||
def lock_comments(%Image{} = image, locked) do
|
def lock_comments(%Image{} = image, locked) do
|
||||||
image
|
image
|
||||||
|> Image.lock_comments_changeset(locked)
|
|> Image.lock_comments_changeset(locked)
|
||||||
|
|
|
@ -21,6 +21,14 @@ defmodule Philomena.Images.Hider do
|
||||||
File.rename(source, target)
|
File.rename(source, target)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def destroy_thumbnails(image) do
|
||||||
|
hidden = image_thumb_dir(image, image.hidden_image_key)
|
||||||
|
normal = image_thumb_dir(image)
|
||||||
|
|
||||||
|
File.rm_rf(hidden)
|
||||||
|
File.rm_rf(normal)
|
||||||
|
end
|
||||||
|
|
||||||
# fixme: these are copied from the thumbnailer
|
# fixme: these are copied from the thumbnailer
|
||||||
defp image_thumb_dir(%Image{created_at: created_at, id: id}),
|
defp image_thumb_dir(%Image{created_at: created_at, id: id}),
|
||||||
do: Path.join([image_thumbnail_root(), time_identifier(created_at), to_string(id)])
|
do: Path.join([image_thumbnail_root(), time_identifier(created_at), to_string(id)])
|
||||||
|
|
|
@ -166,6 +166,12 @@ defmodule Philomena.Images.Image do
|
||||||
|> unsafe_validate_unique([:image_orig_sha512_hash], Repo)
|
|> unsafe_validate_unique([:image_orig_sha512_hash], Repo)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def remove_image_changeset(image) do
|
||||||
|
image
|
||||||
|
|> change(removed_image: image.image)
|
||||||
|
|> change(image: nil)
|
||||||
|
end
|
||||||
|
|
||||||
def source_changeset(image, attrs) do
|
def source_changeset(image, attrs) do
|
||||||
image
|
image
|
||||||
|> cast(attrs, [:source_url])
|
|> cast(attrs, [:source_url])
|
||||||
|
|
|
@ -45,6 +45,7 @@ defimpl Canada.Can, for: [Atom, Philomena.Users.User] do
|
||||||
def can?(%User{role: "moderator"}, :show, %Filter{}), do: true
|
def can?(%User{role: "moderator"}, :show, %Filter{}), do: true
|
||||||
|
|
||||||
# Manage images
|
# Manage images
|
||||||
|
def can?(%User{role: "moderator"}, :destroy, %Image{}), do: false
|
||||||
def can?(%User{role: "moderator"}, _action, Image), do: true
|
def can?(%User{role: "moderator"}, _action, Image), do: true
|
||||||
def can?(%User{role: "moderator"}, _action, %Image{}), do: true
|
def can?(%User{role: "moderator"}, _action, %Image{}), do: true
|
||||||
|
|
||||||
|
|
39
lib/philomena_web/controllers/image/destroy_controller.ex
Normal file
39
lib/philomena_web/controllers/image/destroy_controller.ex
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
defmodule PhilomenaWeb.Image.DestroyController do
|
||||||
|
use PhilomenaWeb, :controller
|
||||||
|
|
||||||
|
alias Philomena.Images.Image
|
||||||
|
alias Philomena.Images
|
||||||
|
|
||||||
|
plug PhilomenaWeb.CanaryMapPlug, create: :destroy
|
||||||
|
plug :load_and_authorize_resource, model: Image, id_name: "image_id", persisted: true
|
||||||
|
plug :verify_deleted when action in [:create]
|
||||||
|
|
||||||
|
def create(conn, _params) do
|
||||||
|
image = conn.assigns.image
|
||||||
|
|
||||||
|
case Images.destroy_image(image) do
|
||||||
|
{:ok, %{image: image}} ->
|
||||||
|
conn
|
||||||
|
|> put_flash(:info, "Image contents destroyed.")
|
||||||
|
|> redirect(to: Routes.image_path(conn, :show, image))
|
||||||
|
|
||||||
|
_error ->
|
||||||
|
conn
|
||||||
|
|> put_flash(:error, "Failed to destroy image.")
|
||||||
|
|> redirect(to: Routes.image_path(conn, :show, image))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp verify_deleted(conn, _opts) do
|
||||||
|
case conn.assigns.image.hidden_from_users do
|
||||||
|
true ->
|
||||||
|
conn
|
||||||
|
|
||||||
|
_false ->
|
||||||
|
conn
|
||||||
|
|> put_flash(:error, "Cannot destroy a non-hidden image!")
|
||||||
|
|> redirect(to: Routes.image_path(conn, :show, conn.assigns.image))
|
||||||
|
|> halt()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -201,6 +201,7 @@ defmodule PhilomenaWeb.Router do
|
||||||
resources "/scratchpad", Image.ScratchpadController, only: [:edit, :update], singleton: true
|
resources "/scratchpad", Image.ScratchpadController, only: [:edit, :update], singleton: true
|
||||||
resources "/uploader", Image.UploaderController, only: [:update], singleton: true
|
resources "/uploader", Image.UploaderController, only: [:update], singleton: true
|
||||||
resources "/anonymous", Image.AnonymousController, only: [:create, :delete], singleton: true
|
resources "/anonymous", Image.AnonymousController, only: [:create, :delete], singleton: true
|
||||||
|
resources "/destroy", Image.DestroyController, only: [:create], singleton: true
|
||||||
|
|
||||||
resources "/comment_lock", Image.CommentLockController,
|
resources "/comment_lock", Image.CommentLockController,
|
||||||
only: [:create, :delete],
|
only: [:create, :delete],
|
||||||
|
|
|
@ -141,3 +141,8 @@
|
||||||
= button_to "Lock tag editing", Routes.image_tag_lock_path(@conn, :create, @image), method: "post", class: "button"
|
= button_to "Lock tag editing", Routes.image_tag_lock_path(@conn, :create, @image), method: "post", class: "button"
|
||||||
- else
|
- else
|
||||||
= button_to "Unlock tag editing", Routes.image_tag_lock_path(@conn, :delete, @image), method: "delete", class: "button"
|
= 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
|
||||||
|
= 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?"]
|
||||||
|
|
Loading…
Reference in a new issue