Added deletion to the last models

This commit is contained in:
Kieran Eglin 2024-02-28 08:56:47 -08:00
parent 855f2bb1ef
commit 17a6b6a691
No known key found for this signature in database
GPG key ID: 193984967FCF432D
11 changed files with 226 additions and 50 deletions

View file

@ -4,12 +4,15 @@ defmodule Pinchflat.Profiles do
""" """
import Ecto.Query, warn: false import Ecto.Query, warn: false
alias Pinchflat.Repo
alias Pinchflat.Repo
alias Pinchflat.Sources
alias Pinchflat.Profiles.MediaProfile alias Pinchflat.Profiles.MediaProfile
@doc """ @doc """
Returns the list of media_profiles. Returns [%MediaProfile{}, ...] Returns the list of media_profiles.
Returns [%MediaProfile{}, ...]
""" """
def list_media_profiles do def list_media_profiles do
Repo.all(MediaProfile) Repo.all(MediaProfile)
@ -23,7 +26,9 @@ defmodule Pinchflat.Profiles do
def get_media_profile!(id), do: Repo.get!(MediaProfile, id) def get_media_profile!(id), do: Repo.get!(MediaProfile, id)
@doc """ @doc """
Creates a media_profile. Returns {:ok, %MediaProfile{}} | {:error, %Ecto.Changeset{}} Creates a media_profile.
Returns {:ok, %MediaProfile{}} | {:error, %Ecto.Changeset{}}
""" """
def create_media_profile(attrs) do def create_media_profile(attrs) do
%MediaProfile{} %MediaProfile{}
@ -32,7 +37,9 @@ defmodule Pinchflat.Profiles do
end end
@doc """ @doc """
Updates a media_profile. Returns {:ok, %MediaProfile{}} | {:error, %Ecto.Changeset{}} Updates a media_profile.
Returns {:ok, %MediaProfile{}} | {:error, %Ecto.Changeset{}}
""" """
def update_media_profile(%MediaProfile{} = media_profile, attrs) do def update_media_profile(%MediaProfile{} = media_profile, attrs) do
media_profile media_profile
@ -41,14 +48,25 @@ defmodule Pinchflat.Profiles do
end end
@doc """ @doc """
Deletes a media_profile. Returns {:ok, %MediaProfile{}} | {:error, %Ecto.Changeset{}} Deletes a media_profile, all its sources, and all their media items.
Can optionally delete the media files.
Returns {:ok, %MediaProfile{}} | {:error, %Ecto.Changeset{}}
""" """
def delete_media_profile(%MediaProfile{} = media_profile) do def delete_media_profile(%MediaProfile{} = media_profile, opts \\ []) do
delete_files = Keyword.get(opts, :delete_files, false)
media_profile
|> Sources.list_sources_for()
|> Enum.each(fn source ->
Sources.delete_source(source, delete_files: delete_files)
end)
Repo.delete(media_profile) Repo.delete(media_profile)
end end
@doc """ @doc """
Returns an `%Ecto.Changeset{}` for tracking media_profile changes. Returns `%Ecto.Changeset{}`
""" """
def change_media_profile(%MediaProfile{} = media_profile, attrs \\ %{}) do def change_media_profile(%MediaProfile{} = media_profile, attrs \\ %{}) do
MediaProfile.changeset(media_profile, attrs) MediaProfile.changeset(media_profile, attrs)

View file

@ -8,8 +8,9 @@ defmodule Pinchflat.Sources do
alias Pinchflat.Media alias Pinchflat.Media
alias Pinchflat.Tasks alias Pinchflat.Tasks
alias Pinchflat.Tasks.SourceTasks
alias Pinchflat.Sources.Source alias Pinchflat.Sources.Source
alias Pinchflat.Tasks.SourceTasks
alias Pinchflat.Profiles.MediaProfile
alias Pinchflat.MediaClient.SourceDetails alias Pinchflat.MediaClient.SourceDetails
@doc """ @doc """
@ -19,6 +20,15 @@ defmodule Pinchflat.Sources do
Repo.all(Source) Repo.all(Source)
end end
@doc """
Returns the list of sources for a media_profile.
Returns [%Source{}, ...]
"""
def list_sources_for(%MediaProfile{} = media_profile) do
Repo.all(from s in Source, where: s.media_profile_id == ^media_profile.id)
end
@doc """ @doc """
Gets a single source. Gets a single source.

View file

@ -12,19 +12,17 @@ defmodule PinchflatWeb.MediaItems.MediaItemController do
def delete(conn, %{"id" => id} = params) do def delete(conn, %{"id" => id} = params) do
delete_files = Map.get(params, "delete_files", false) delete_files = Map.get(params, "delete_files", false)
media_item = Media.get_media_item!(id) media_item = Media.get_media_item!(id)
{:ok, _} = Media.delete_media_item(media_item, delete_files: delete_files)
if delete_files do flash_message =
{:ok, _} = Media.delete_media_item(media_item, delete_files: true) if delete_files do
"Record and files deleted successfully."
else
"Record deleted successfully. Files were not deleted."
end
conn conn
|> put_flash(:info, "Record and files deleted successfully.") |> put_flash(:info, flash_message)
|> redirect(to: ~p"/sources/#{media_item.source_id}") |> redirect(to: ~p"/sources/#{media_item.source_id}")
else
{:ok, _} = Media.delete_media_item(media_item)
conn
|> put_flash(:info, "Record deleted successfully. Files were not deleted.")
|> redirect(to: ~p"/sources/#{media_item.source_id}")
end
end end
end end

View file

@ -46,6 +46,7 @@ defmodule PinchflatWeb.MediaProfiles.MediaProfileController do
def edit(conn, %{"id" => id}) do def edit(conn, %{"id" => id}) do
media_profile = Profiles.get_media_profile!(id) media_profile = Profiles.get_media_profile!(id)
changeset = Profiles.change_media_profile(media_profile) changeset = Profiles.change_media_profile(media_profile)
render(conn, :edit, media_profile: media_profile, changeset: changeset) render(conn, :edit, media_profile: media_profile, changeset: changeset)
end end
@ -63,12 +64,20 @@ defmodule PinchflatWeb.MediaProfiles.MediaProfileController do
end end
end end
def delete(conn, %{"id" => id}) do def delete(conn, %{"id" => id} = params) do
delete_files = Map.get(params, "delete_files", false)
media_profile = Profiles.get_media_profile!(id) media_profile = Profiles.get_media_profile!(id)
{:ok, _media_profile} = Profiles.delete_media_profile(media_profile) {:ok, _media_profile} = Profiles.delete_media_profile(media_profile, delete_files: delete_files)
flash_message =
if delete_files do
"Media profile, its sources, and its files deleted successfully."
else
"Media profile and its sources deleted successfully. Files were not deleted."
end
conn conn
|> put_flash(:info, "Media profile deleted successfully.") |> put_flash(:info, flash_message)
|> redirect(to: ~p"/media_profiles") |> redirect(to: ~p"/media_profiles")
end end
end end

View file

@ -22,5 +22,27 @@
<h3 class="font-bold text-xl">Attributes</h3> <h3 class="font-bold text-xl">Attributes</h3>
<.list_items_from_map map={Map.from_struct(@media_profile)} /> <.list_items_from_map map={Map.from_struct(@media_profile)} />
</div> </div>
<section class="flex flex-col md:flex-row items-center md:justify-around my-10">
<.link
href={~p"/media_profiles/#{@media_profile}"}
method="delete"
data-confirm="Are you sure you want to delete this profile and all its sources (leaving files in place)? This cannot be undone."
>
<.button color="bg-meta-1" rounding="rounded-full">
Delete Profile and its Sources
</.button>
</.link>
<.link
href={~p"/media_profiles/#{@media_profile}?delete_files=true"}
method="delete"
data-confirm="Are you sure you want to delete this profile, all its sources, and its files? This cannot be undone."
class="mt-5 md:mt-0"
>
<.button color="bg-meta-1" rounding="rounded-full">
Delete Profile, Sources and Files
</.button>
</.link>
</section>
</div> </div>
</div> </div>

View file

@ -90,20 +90,18 @@ defmodule PinchflatWeb.Sources.SourceController do
def delete(conn, %{"id" => id} = params) do def delete(conn, %{"id" => id} = params) do
delete_files = Map.get(params, "delete_files", false) delete_files = Map.get(params, "delete_files", false)
source = Sources.get_source!(id) source = Sources.get_source!(id)
{:ok, _source} = Sources.delete_source(source, delete_files: delete_files)
if delete_files do flash_message =
{:ok, _source} = Sources.delete_source(source, delete_files: true) if delete_files do
"Source and files deleted successfully."
else
"Source deleted successfully. Files were not deleted."
end
conn conn
|> put_flash(:info, "Source and files deleted successfully.") |> put_flash(:info, flash_message)
|> redirect(to: ~p"/sources") |> redirect(to: ~p"/sources")
else
{:ok, _source} = Sources.delete_source(source)
conn
|> put_flash(:info, "Source deleted successfully. Files were not deleted.")
|> redirect(to: ~p"/sources")
end
end end
defp media_profiles do defp media_profiles do

View file

@ -75,7 +75,7 @@
<section class="flex flex-col md:flex-row items-center md:justify-around mt-10"> <section class="flex flex-col md:flex-row items-center md:justify-around mt-10">
<.link <.link
href={~p"/sources/#{@source.id}"} href={~p"/sources/#{@source}"}
method="delete" method="delete"
data-confirm="Are you sure you want to delete this source (leaving files in place)? This cannot be undone." data-confirm="Are you sure you want to delete this source (leaving files in place)? This cannot be undone."
> >
@ -84,9 +84,9 @@
</.button> </.button>
</.link> </.link>
<.link <.link
href={~p"/sources/#{@source.id}?delete_files=true"} href={~p"/sources/#{@source}?delete_files=true"}
method="delete" method="delete"
data-confirm="Are you sure you want to delete this source AND it's associated files? This cannot be undone." data-confirm="Are you sure you want to delete this source AND it's files? This cannot be undone."
class="mt-5 md:mt-0" class="mt-5 md:mt-0"
> >
<.button color="bg-meta-1" rounding="rounded-full"> <.button color="bg-meta-1" rounding="rounded-full">

View file

@ -340,7 +340,7 @@ defmodule Pinchflat.MediaTest do
end end
end end
describe "delete_media_item/1" do describe "delete_media_item/2" do
test "deletion deletes the media_item" do test "deletion deletes the media_item" do
media_item = media_item_fixture() media_item = media_item_fixture()
assert {:ok, %MediaItem{}} = Media.delete_media_item(media_item) assert {:ok, %MediaItem{}} = Media.delete_media_item(media_item)
@ -363,7 +363,7 @@ defmodule Pinchflat.MediaTest do
end end
end end
describe "delete_media_item/1 when testing file deletion" do describe "delete_media_item/2 when testing file deletion" do
test "deletes the media item's files" do test "deletes the media item's files" do
media_item = media_item_with_attachments() media_item = media_item_with_attachments()

View file

@ -1,9 +1,12 @@
defmodule Pinchflat.ProfilesTest do defmodule Pinchflat.ProfilesTest do
use Pinchflat.DataCase use Pinchflat.DataCase
import Pinchflat.MediaFixtures
import Pinchflat.SourcesFixtures
import Pinchflat.ProfilesFixtures
alias Pinchflat.Profiles alias Pinchflat.Profiles
alias Pinchflat.Profiles.MediaProfile alias Pinchflat.Profiles.MediaProfile
import Pinchflat.ProfilesFixtures
@invalid_attrs %{name: nil, output_path_template: nil} @invalid_attrs %{name: nil, output_path_template: nil}
@ -61,11 +64,66 @@ defmodule Pinchflat.ProfilesTest do
end end
end end
describe "delete_media_profile/1" do describe "delete_media_profile/2" do
test "deletion deletes the media_profile" do test "deletion deletes the media_profile" do
media_profile = media_profile_fixture() media_profile = media_profile_fixture()
assert {:ok, %MediaProfile{}} = Profiles.delete_media_profile(media_profile) assert {:ok, %MediaProfile{}} = Profiles.delete_media_profile(media_profile)
assert_raise Ecto.NoResultsError, fn -> Profiles.get_media_profile!(media_profile.id) end
assert_raise Ecto.NoResultsError, fn -> Repo.reload!(media_profile) end
end
test "deletion deletes all sources" do
media_profile = media_profile_fixture()
source = source_fixture(media_profile_id: media_profile.id)
assert {:ok, %MediaProfile{}} = Profiles.delete_media_profile(media_profile)
assert_raise Ecto.NoResultsError, fn -> Repo.reload!(source) end
end
test "deletion deletes all media items" do
media_profile = media_profile_fixture()
source = source_fixture(media_profile_id: media_profile.id)
media_item = media_item_fixture(source_id: source.id)
assert {:ok, %MediaProfile{}} = Profiles.delete_media_profile(media_profile)
assert_raise Ecto.NoResultsError, fn -> Repo.reload!(media_item) end
end
test "deletion does not delete files by default" do
media_profile = media_profile_fixture()
source = source_fixture(media_profile_id: media_profile.id)
media_item = media_item_with_attachments(%{source_id: source.id})
assert {:ok, %MediaProfile{}} = Profiles.delete_media_profile(media_profile)
assert File.exists?(media_item.media_filepath)
end
end
describe "delete_media_profile/2 when deleting files" do
test "still deletes all the needful records" do
media_profile = media_profile_fixture()
source = source_fixture(media_profile_id: media_profile.id)
media_item = media_item_fixture(source_id: source.id)
assert {:ok, %MediaProfile{}} = Profiles.delete_media_profile(media_profile, delete_files: true)
assert_raise Ecto.NoResultsError, fn -> Repo.reload!(media_profile) end
assert_raise Ecto.NoResultsError, fn -> Repo.reload!(source) end
assert_raise Ecto.NoResultsError, fn -> Repo.reload!(media_item) end
end
test "deletes files" do
media_profile = media_profile_fixture()
source = source_fixture(media_profile_id: media_profile.id)
media_item = media_item_with_attachments(%{source_id: source.id})
assert {:ok, %MediaProfile{}} = Profiles.delete_media_profile(media_profile, delete_files: true)
refute File.exists?(media_item.media_filepath)
end end
end end

View file

@ -23,6 +23,15 @@ defmodule Pinchflat.SourcesTest do
end end
end end
describe "list_sources_for/1" do
test "returns all sources for a given media profile" do
media_profile = media_profile_fixture()
source = source_fixture(media_profile_id: media_profile.id)
assert Sources.list_sources_for(media_profile) == [source]
end
end
describe "get_source!/1" do describe "get_source!/1" do
test "it returns the source with given id" do test "it returns the source with given id" do
source = source_fixture() source = source_fixture()
@ -285,7 +294,7 @@ defmodule Pinchflat.SourcesTest do
end end
end end
describe "delete_source/1" do describe "delete_source/2" do
test "it deletes the source" do test "it deletes the source" do
source = source_fixture() source = source_fixture()
assert {:ok, %Source{}} = Sources.delete_source(source) assert {:ok, %Source{}} = Sources.delete_source(source)
@ -322,7 +331,7 @@ defmodule Pinchflat.SourcesTest do
end end
end end
describe "delete_source/1 when deleting files" do describe "delete_source/2 when deleting files" do
test "deletes source and media_items" do test "deletes source and media_items" do
source = source_fixture() source = source_fixture()
media_item = media_item_with_attachments(%{source_id: source.id}) media_item = media_item_with_attachments(%{source_id: source.id})

View file

@ -1,8 +1,12 @@
defmodule PinchflatWeb.MediaProfileControllerTest do defmodule PinchflatWeb.MediaProfileControllerTest do
use PinchflatWeb.ConnCase use PinchflatWeb.ConnCase
import Pinchflat.MediaFixtures
import Pinchflat.SourcesFixtures
import Pinchflat.ProfilesFixtures import Pinchflat.ProfilesFixtures
alias Pinchflat.Repo
@create_attrs %{name: "some name", output_path_template: "some output_path_template"} @create_attrs %{name: "some name", output_path_template: "some output_path_template"}
@update_attrs %{ @update_attrs %{
name: "some updated name", name: "some updated name",
@ -97,21 +101,71 @@ defmodule PinchflatWeb.MediaProfileControllerTest do
end end
end end
describe "delete media_profile" do describe "delete media_profile when just deleting the records" do
setup [:create_media_profile] setup [:create_media_profile]
test "deletes chosen media_profile", %{conn: conn, media_profile: media_profile} do test "deletes chosen media_profile and its associations", %{conn: conn, media_profile: media_profile} do
source = source_fixture(media_profile_id: media_profile.id)
media_item = media_item_with_attachments(%{source_id: source.id})
conn = delete(conn, ~p"/media_profiles/#{media_profile}") conn = delete(conn, ~p"/media_profiles/#{media_profile}")
assert redirected_to(conn) == ~p"/media_profiles" assert redirected_to(conn) == ~p"/media_profiles"
assert_error_sent 404, fn -> assert_raise Ecto.NoResultsError, fn -> Repo.reload!(media_profile) end
get(conn, ~p"/media_profiles/#{media_profile}") assert_raise Ecto.NoResultsError, fn -> Repo.reload!(source) end
end assert_raise Ecto.NoResultsError, fn -> Repo.reload!(media_item) end
end
test "redirects to the media_profiles page", %{conn: conn, media_profile: media_profile} do
conn = delete(conn, ~p"/media_profiles/#{media_profile}")
assert redirected_to(conn) == ~p"/media_profiles"
end
test "doesn't delete any files", %{conn: conn, media_profile: media_profile} do
source = source_fixture(media_profile_id: media_profile.id)
media_item = media_item_with_attachments(%{source_id: source.id})
delete(conn, ~p"/media_profiles/#{media_profile}")
assert File.exists?(media_item.media_filepath)
end
end
describe "delete media_profile when deleting the records and files" do
setup [:create_media_profile]
test "deletes chosen media_profile and its associations", %{conn: conn, media_profile: media_profile} do
source = source_fixture(media_profile_id: media_profile.id)
media_item = media_item_with_attachments(%{source_id: source.id})
conn = delete(conn, ~p"/media_profiles/#{media_profile}?delete_files=true")
assert redirected_to(conn) == ~p"/media_profiles"
assert_raise Ecto.NoResultsError, fn -> Repo.reload!(media_profile) end
assert_raise Ecto.NoResultsError, fn -> Repo.reload!(source) end
assert_raise Ecto.NoResultsError, fn -> Repo.reload!(media_item) end
end
test "redirects to the media_profiles page", %{conn: conn, media_profile: media_profile} do
conn = delete(conn, ~p"/media_profiles/#{media_profile}?delete_files=true")
assert redirected_to(conn) == ~p"/media_profiles"
end
test "deletes the files", %{conn: conn, media_profile: media_profile} do
source = source_fixture(media_profile_id: media_profile.id)
media_item = media_item_with_attachments(%{source_id: source.id})
delete(conn, ~p"/media_profiles/#{media_profile}?delete_files=true")
refute File.exists?(media_item.media_filepath)
end end
end end
defp create_media_profile(_) do defp create_media_profile(_) do
media_profile = media_profile_fixture() media_profile = media_profile_fixture()
%{media_profile: media_profile} %{media_profile: media_profile}
end end
end end