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: <>) 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