defmodule PinchflatWeb.Api.V1.ApiSourceController do @moduledoc """ JSON API controller for Sources. """ use PinchflatWeb, :controller action_fallback PinchflatWeb.Api.V1.FallbackController alias Pinchflat.Repo alias Pinchflat.Sources alias Pinchflat.Sources.Source alias Pinchflat.Tasks alias Pinchflat.Downloading.DownloadingHelpers alias Pinchflat.SlowIndexing.SlowIndexingHelpers alias Pinchflat.Metadata.SourceMetadataStorageWorker alias Pinchflat.Media.FileSyncingWorker alias Pinchflat.Sources.SourceDeletionWorker def index(conn, _params) do sources = Sources.list_sources() |> Repo.preload(:media_profile) json(conn, %{data: sources}) end def show(conn, %{"id" => id}) do case Sources.get_source(id) do nil -> {:error, :not_found} source -> source = Repo.preload(source, [:media_profile, :media_items]) pending_tasks = source |> Tasks.list_tasks_for(nil, [:executing, :available, :scheduled, :retryable]) |> Repo.preload(:job) json(conn, %{data: source, pending_tasks: pending_tasks}) end end def create(conn, %{"source" => source_params}) do case Sources.create_source(source_params) do {:ok, source} -> source = Repo.preload(source, :media_profile) conn |> put_status(:created) |> json(%{data: source}) {:error, %Ecto.Changeset{} = changeset} -> conn |> put_status(:unprocessable_entity) |> json(%{errors: format_changeset_errors(changeset)}) end end def update(conn, %{"id" => id, "source" => source_params}) do source = Sources.get_source!(id) case Sources.update_source(source, source_params) do {:ok, source} -> source = Repo.preload(source, :media_profile) json(conn, %{data: source}) {:error, %Ecto.Changeset{} = changeset} -> conn |> put_status(:unprocessable_entity) |> json(%{errors: format_changeset_errors(changeset)}) end end def delete(conn, %{"id" => id} = params) do delete_files = Map.get(params, "delete_files", "false") == "true" source = Sources.get_source!(id) {:ok, _} = Sources.update_source(source, %{marked_for_deletion_at: DateTime.utc_now()}) SourceDeletionWorker.kickoff(source, %{delete_files: delete_files}) conn |> put_status(:ok) |> json(%{data: %{id: source.id, message: "Source deletion started."}}) end def force_download_pending(conn, %{"source_id" => id}) do source = Sources.get_source!(id) DownloadingHelpers.enqueue_pending_download_tasks(source) json(conn, %{data: %{message: "Forcing download of pending media items."}}) end def force_redownload(conn, %{"source_id" => id}) do source = Sources.get_source!(id) DownloadingHelpers.kickoff_redownload_for_existing_media(source) json(conn, %{data: %{message: "Forcing re-download of downloaded media items."}}) end def force_index(conn, %{"source_id" => id}) do source = Sources.get_source!(id) SlowIndexingHelpers.kickoff_indexing_task(source, %{force: true}) json(conn, %{data: %{message: "Index enqueued."}}) end def force_metadata_refresh(conn, %{"source_id" => id}) do source = Sources.get_source!(id) SourceMetadataStorageWorker.kickoff_with_task(source) json(conn, %{data: %{message: "Metadata refresh enqueued."}}) end def sync_files_on_disk(conn, %{"source_id" => id}) do source = Sources.get_source!(id) FileSyncingWorker.kickoff_with_task(source) json(conn, %{data: %{message: "File sync enqueued."}}) end defp format_changeset_errors(changeset) do Ecto.Changeset.traverse_errors(changeset, fn {msg, opts} -> Enum.reduce(opts, msg, fn {key, value}, acc -> String.replace(acc, "%{#{key}}", to_string(value)) end) end) end end