Skip to content

Commit

Permalink
Merge pull request #582 from podlove/feature/edit-show
Browse files Browse the repository at this point in the history
feature: editing existing shows
  • Loading branch information
electronicbites authored Oct 12, 2024
2 parents d3087c5 + f7a366c commit c870d9e
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 21 deletions.
87 changes: 84 additions & 3 deletions lib/radiator/podcast.ex
Original file line number Diff line number Diff line change
Expand Up @@ -212,14 +212,77 @@ defmodule Radiator.Podcast do
end)
end

# Fills the list of associate hosts of a show by adding users to hosts list.
# Suggested to run inside a transaction.
defp associate_hosts(show, hosts) do
Enum.each(hosts, fn host ->
%ShowHosts{}
|> ShowHosts.changeset(%{show_id: show.id, user_id: host.id})
|> Repo.insert!()
create_showhosts!(%{show_id: show.id, user_id: host.id})
end)
end

@doc """
Updates a show with hosts.
## Examples
iex> update_show(show, %{field: new_value}, [%User{}])
{:ok, %Show{}}
iex> update_show(show, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_show(%Show{} = show, attrs, hosts) do
Repo.transaction(fn ->
case update_show(show, attrs) do
{:ok, show} ->
update_associate_hosts(show, hosts)
show

{:error, changeset} ->
Repo.rollback(changeset)
end
end)
end

# Updates the list of associate hosts of a show by adding or removing users to hosts list.
# Suggested to run inside a transaction.
defp update_associate_hosts(show, hosts) do
show = Repo.preload(show, :hosts)

# intersection contains unchanged hosts -> ignore them
remove_hosts = show.hosts -- hosts
add_hosts = hosts -- show.hosts

# Add users to hosts
Enum.each(add_hosts, fn host ->
create_showhosts!(%{show_id: show.id, user_id: host.id})
end)

# Remove users from hosts
remove_host_ids = Enum.map(remove_hosts, fn host -> host.id end)

if !Enum.empty?(remove_host_ids) do
count_removable_hosts = length(remove_host_ids)

from(s in ShowHosts,
where:
s.show_id == ^show.id and
s.user_id in ^remove_host_ids
)
|> Repo.delete_all()
|> case do
{^count_removable_hosts, nil} ->
:ok

{count_removed, _} ->
Repo.rollback(
"Couldn't remove all hosts (expect: #{count_removable_hosts} vs. #{count_removed})."
)
end
end
end

@doc """
Updates a show.
Expand Down Expand Up @@ -284,6 +347,24 @@ defmodule Radiator.Podcast do
Repo.preload(show, fields_or_query, force: true)
end

@doc """
Creates ShowHosts, the association be show and user
## Examples
iex> create_showhosts(%{field: value})
%ShowHosts{}
iex> create_showhosts(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_showhosts!(attrs \\ %{}) do
%ShowHosts{}
|> ShowHosts.changeset(attrs)
|> Repo.insert!()
end

@doc """
Returns the query for list of episodes exluding the once that are marked as deleted.
Expand Down
51 changes: 44 additions & 7 deletions lib/radiator_web/live/admin_live/index.ex
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@ defmodule RadiatorWeb.AdminLive.Index do
|> reply(:noreply)
end

def handle_event("edit_show", %{"show_id" => show_id}, socket) do
show = Podcast.get_show!(show_id, preload: [:hosts])
changeset = Podcast.change_show(show, %{})

socket
|> assign(:action, :edit_show)
|> assign(:show, show)
|> assign(:host_suggestions, [])
|> assign(:selected_hosts, show.hosts)
|> assign(:host_email, "")
|> assign(:form, to_form(changeset))
|> reply(:noreply)
end

def handle_event("cancel", _params, socket) do
socket
|> assign(:action, nil)
Expand Down Expand Up @@ -125,6 +139,19 @@ defmodule RadiatorWeb.AdminLive.Index do
end

def handle_event("save", %{"show" => params}, socket) do
save_show(socket, socket.assigns.action, params)
end

def handle_event("delete", %{"id" => id}, socket) do
network = Podcast.get_network!(id)
{:ok, _} = Podcast.delete_network(network)

socket
|> assign(:networks, Podcast.list_networks(preload: :shows))
|> reply(:noreply)
end

defp save_show(socket, :new_show, params) do
case Podcast.create_show(params, socket.assigns.selected_hosts) do
{:ok, _show} ->
socket
Expand All @@ -144,14 +171,24 @@ defmodule RadiatorWeb.AdminLive.Index do
end
end

def handle_event("delete", %{"id" => id}, socket) do
network = Podcast.get_network!(id)
{:ok, _} = Podcast.delete_network(network)
defp save_show(socket, :edit_show, params) do
case Podcast.update_show(socket.assigns.show, params, socket.assigns.selected_hosts) do
{:ok, _show} ->
socket
|> assign(:action, nil)
|> assign(:networks, Podcast.list_networks(preload: :shows))
|> assign(selected_hosts: [])
|> assign(host_suggestions: [])
|> assign(host_email: "")
|> put_flash(:info, "Show updated successfully")
|> reply(:noreply)

socket
|> assign(:networks, Podcast.list_networks(preload: :shows))
# |> stream_delete(:networks, network)}
|> reply(:noreply)
{:error, %Ecto.Changeset{} = changeset} ->
socket
|> assign(:form, to_form(changeset))
|> put_flash(:info, "Show could not be updated")
|> reply(:noreply)
end
end

defp get_bookmarklet(api_uri, socket) do
Expand Down
19 changes: 10 additions & 9 deletions lib/radiator_web/live/admin_live/index.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@
</button>
</h2>
<div class="grid grid-cols-3 gap-6 sm:grid-cols-6">
<.link
:for={{show, i} <- Enum.with_index(network.shows)}
href={~p"/admin/podcast/#{show}"}
class="bg-[#f0f4f4] aspect-square rounded"
>
<img src={"/images/pic1#{i}.jpg"} alt="" />
<div class="p-2 text-center"><%= show.title %></div>
</.link>
<div :for={{show, i} <- Enum.with_index(network.shows)}>
<.link href={~p"/admin/podcast/#{show}"} class="bg-[#f0f4f4] aspect-square rounded">
<img src={"/images/pic1#{i}.jpg"} alt="" />
<div class="p-2 text-center"><%= show.title %></div>
</.link>
<button :if={@action != :edit_show} phx-click="edit_show" phx-value-show_id={show.id}>
<.icon name="hero-pencil-square" class="w-5 h-5" />
</button>
</div>
<button
:if={@action != :new_show}
class="bg-[#df7366] text-white rounded"
Expand Down Expand Up @@ -49,7 +50,7 @@
</.form>
</div>

<div :if={@action == :new_show} class="p-4 my-4 bg-[#f0f4f4]">
<div :if={@action in [:new_show, :edit_show]} class="p-4 my-4 bg-[#f0f4f4]">
<h3 class="text-xl">Create Show</h3>
<.form :let={f} for={@form} id="show-form" phx-change="validate" phx-submit="save">
<.input field={f[:title]} type="text" label="Title" />
Expand Down
37 changes: 37 additions & 0 deletions test/radiator/podcast_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,43 @@ defmodule Radiator.PodcastTest do
assert show == Podcast.get_show!(show.id)
end

test "update_show/2 with valid data updates the show by removing hosts" do
init_hosts = [
user_fixture(%{email: "bob@example.com"}),
user_fixture(%{email: "jim@example.com"})
]

show = show_fixture(%{}, init_hosts)

assert {:ok, %Show{} = show} = Podcast.update_show(show, %{}, [])
show = Podcast.reload_assoc(show, [:hosts])
assert show.hosts == []
end

test "update_show/2 with valid data updates the show by adding hosts" do
updated_hosts = [
user_fixture(%{email: "bob@example.com"}),
user_fixture(%{email: "jim@example.com"})
]

show = show_fixture(%{}, [])

assert {:ok, %Show{} = show} = Podcast.update_show(show, %{}, updated_hosts)
show = Podcast.reload_assoc(show, [:hosts])
assert show.hosts == updated_hosts
end

test "update_show/2 with valid data updates the show by adding and removing hosts" do
init_hosts = [user_fixture(%{email: "bob@example.com"})]
updated_hosts = [user_fixture(%{email: "jim@example.com"})]

show = show_fixture(%{}, init_hosts)

assert {:ok, %Show{} = show} = Podcast.update_show(show, %{}, updated_hosts)
show = Podcast.reload_assoc(show, [:hosts])
assert show.hosts == updated_hosts
end

test "delete_show/1 deletes the show" do
show = show_fixture()
assert {:ok, %Show{}} = Podcast.delete_show(show)
Expand Down
4 changes: 2 additions & 2 deletions test/support/fixtures/podcast_fixtures.ex
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ defmodule Radiator.PodcastFixtures do
@doc """
Generate a show.
"""
def show_fixture(attrs \\ %{}) do
def show_fixture(attrs \\ %{}, hosts \\ []) do
network = get_network(attrs)

{:ok, show} =
Expand All @@ -31,7 +31,7 @@ defmodule Radiator.PodcastFixtures do
title: "some title",
network_id: network.id
})
|> Podcast.create_show()
|> Podcast.create_show(hosts)

show
end
Expand Down

0 comments on commit c870d9e

Please sign in to comment.