Diffuser/lib/diffuser_web/live/prompt_request_live/index.ex

207 lines
6.3 KiB
Elixir

defmodule DiffuserWeb.PromptRequestLive.Index do
use DiffuserWeb, :live_view
alias Diffuser.Generator
alias Diffuser.Generator.PromptRequest
alias Diffuser.Accounts
alias Diffuser.Accounts.User
alias DiffuserWeb.Endpoint
alias Phoenix.Socket.Broadcast
alias Diffuser.Repo
alias Ecto.Association.NotLoaded
@impl true
def mount(params, %{"user" => user, "is_admin" => is_admin}, socket) do
changeset = Accounts.change_user(user)
{:ok,
socket
|> assign(:user, user)
|> assign(:params, params)
|> assign(:is_admin, is_admin)
|> assign(:user_changeset, changeset)}
end
@impl true
def handle_params(params, _url, socket) do
page = list_prompt_requests(params) |> subscribe_to_queued_prompts()
socket =
socket
|> apply_action(socket.assigns.live_action, params)
|> assign(:page, page)
|> assign(:params, params)
{:noreply, socket}
end
defp apply_action(socket, :edit, %{"id" => id}) do
socket
|> assign(:page_title, "Edit Prompt")
|> assign(:prompt_request, Generator.get_prompt_request!(id))
end
defp apply_action(socket, :new, _params) do
socket
|> assign(:page_title, "New Prompt")
|> assign(:prompt_request, %PromptRequest{})
end
defp apply_action(socket, :index, _params) do
socket
|> assign(:page_title, "Listing Prompts")
|> assign(:prompt_request, nil)
end
@impl true
def handle_event("delete", %{"id" => id}, %{assigns: %{params: params}} = socket) do
prompt_request = Generator.get_prompt_request!(id)
{:ok, _} = Generator.delete_prompt_request(prompt_request)
{:noreply, assign(socket, :page, list_prompt_requests(params))}
end
def handle_event("upvote", %{"id" => id}, %{assigns: %{user: user, params: params}} = socket) do
prompt_request = Generator.get_prompt_request!(id)
Diffuser.Accounts.upvote(user, prompt_request)
{:noreply, assign(socket, :page, list_prompt_requests(params))}
end
def handle_event(
"update_user",
%{"user" => params},
%{assigns: %{user: user}} = socket
) do
case Accounts.update_user(user, params) do
{:ok, user} ->
{:noreply, assign(socket, :user, user)}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign(socket, :user_changeset, changeset)}
end
end
def handle_event(
"search",
%{"search" => %{"query" => query}},
%{assigns: %{params: params}} = socket
) do
params = Map.put(params, :query, query)
page = Generator.paginate_prompt_requests(PromptRequest, params)
{:noreply, socket |> assign(:params, params) |> assign(:page, page)}
end
def handle_event("clear", _, socket) do
page = Generator.paginate_prompt_requests(PromptRequest, %{page: 1})
{:noreply, socket |> assign(:params, %{page: 1}) |> assign(:page, page)}
end
def handle_event("order_by", %{"votes" => direction}, %{assigns: %{params: params}} = socket) do
direction = if direction in ["asc", "desc"], do: direction, else: nil
params = Map.put(params, :order_by, direction)
page = Generator.paginate_prompt_requests(PromptRequest, params)
{:noreply, socket |> assign(:params, params) |> assign(:page, page)}
end
def handle_event("go_to" = event, %{"jump" => %{"page" => _page} = result}, socket),
do: handle_event(event, result, socket)
def handle_event("go_to", %{"page" => page}, %{assigns: %{params: params}} = socket) do
params = Map.put(params, :page, page)
page = Generator.paginate_prompt_requests(PromptRequest, params)
{:noreply, socket |> assign(:params, params) |> assign(:page, page)}
end
defp has_voted(nil, _), do: false
defp has_voted(%{id: user_id}, %{votes: prompt_request_votes}) do
prompt_request_votes
|> Enum.any?(fn %{user_id: id} ->
user_id == id
end)
end
defp display_current_filters(params) do
query = Map.get(params, :query, nil)
order_by = Map.get(params, :order_by, nil)
page = Map.get(params, :page, 1)
query_str = if query, do: "Searching for \"#{query}\"", else: "Everything"
order_by_str = if order_by == "desc", do: " with most votes", else: ""
query_str <> order_by_str <> " on page #{page}"
end
defp display_name(%User{username: username}) when not is_nil(username), do: username
defp display_name(%User{id: id}), do: id |> String.slice(0, 8)
defp fake_name(), do: for(_ <- 1..8, into: "", do: <<Enum.random('0123456789abcdef')>>)
defp list_prompt_requests(params) do
Generator.paginate_prompt_requests(PromptRequest, params)
end
defp total_time(%PromptRequest{began_at: began_at, ended_at: ended_at})
when not is_nil(began_at) and not is_nil(ended_at) do
"Processing Time: #{NaiveDateTime.diff(ended_at, began_at, :second)} seconds"
end
defp total_time(_), do: ""
defp owns_prompt_request(user, %{user: %NotLoaded{} = prompt_request}),
do: user |> owns_prompt_request(prompt_request |> Repo.preload(:user))
defp owns_prompt_request(nil, _), do: false
defp owns_prompt_request(_, %{user: nil}), do: false
defp owns_prompt_request(%{ip_address: their_ip_address, id: their_id}, %{
user: %{ip_address: ip_address, id: id}
})
when their_ip_address == ip_address or their_id == id,
do: true
defp owns_prompt_request(_, _), do: false
defp subscribe_to_queued_prompts(%Scrivener.Page{entries: entries} = page) do
entries
|> Enum.each(fn %PromptRequest{id: id, status: status} ->
if status in ["queued", "in_progress"] do
Endpoint.subscribe("request:#{id}")
end
end)
page
end
@impl true
def handle_info(
%Broadcast{
topic: _,
event: event,
payload: %{prompt_request: %PromptRequest{} = prompt_request}
},
socket
)
when event in ["request", "progress"],
do: {:noreply, socket |> update_subscribed_prompt(prompt_request)}
defp update_subscribed_prompt(
%{assigns: %{page: %Scrivener.Page{entries: entries} = page}} = socket,
%PromptRequest{id: id} = prompt_request
) do
entries =
entries
|> Enum.map(
&if &1.id === id, do: prompt_request |> Repo.preload([:votes, :user, :images]), else: &1
)
page = Map.put(page, :entries, entries)
socket
|> assign(:page, page)
end
end