defmodule WorkloadServiceWeb.TaskController do use WorkloadServiceWeb, :controller use OpenApiSpex.ControllerSpecs alias WorkloadService.CommandedApp alias WorkloadService.Workload.Queries alias WorkloadServiceWeb.Schemas.Task, as: S tags(["Tasks"]) operation(:list, summary: "List tasks", parameters: [ page: [in: :query, type: :integer, required: false, example: 1], page_size: [in: :query, type: :integer, required: false, example: 20], status: [in: :query, type: :string, required: false], policy_type: [in: :query, type: :string, required: false], org_id: [in: :query, type: :string, required: false], application_id: [in: :query, type: :string, required: false], provider_id: [in: :query, type: :string, required: false] ], responses: [ ok: {"Task list", "application/json", S.TaskListResponse}, bad_request: {"Invalid params", "application/json", S.ErrorResponse} ] ) def list(conn, params) do case Queries.list_tasks(params) do {:ok, {tasks, meta}} -> conn |> put_status(:ok) |> json(%{ data: Enum.map(tasks, &task_summary/1), meta: meta_json(meta) }) {:error, _} -> conn |> put_status(:bad_request) |> json(%{error: "invalid parameters"}) end end operation(:show, summary: "Get task by ID", parameters: [ id: [in: :path, type: :string, required: true] ], responses: [ ok: {"Task detail", "application/json", S.TaskDetailResponse}, not_found: {"Not found", "application/json", S.ErrorResponse} ] ) def show(conn, %{"id" => id}) do case Queries.get_task_by_id(id) do {:error, :not_found} -> conn |> put_status(:not_found) |> json(%{error: "task not found"}) {:ok, task} -> conn |> put_status(:ok) |> json(%{data: task_detail(task)}) end end operation(:respond_to_quote, summary: "Record quote response", parameters: [ id: [in: :path, type: :string, required: true] ], request_body: {"Quote response", "application/json", S.QuoteResponseRequest, required: true}, responses: [ ok: {"Quote response recorded", "application/json", S.TaskDetailResponse}, not_found: {"Not found", "application/json", S.ErrorResponse}, unprocessable_entity: {"Error", "application/json", S.ErrorResponse} ] ) def respond_to_quote(conn, %{"id" => id} = params) do case Queries.get_task_by_id(id) do {:error, :not_found} -> conn |> put_status(:not_found) |> json(%{error: "task not found"}) {:ok, %{status: "created"} = _task} -> command = %WorkloadService.Commands.QuoteTask.SubmitResponse{ id: id, submission: %{ "quote_id" => params["quote_id"], "plans" => params["plans"], "valid_until" => params["valid_until"], "responded_by" => params["responded_by"], "document_data" => params["document_data"] }, attachments: [params["document_url"]] |> Enum.filter(& &1) } case CommandedApp.dispatch(command) do :ok -> {:ok, task} = Queries.get_task_by_id(id) conn |> put_status(:ok) |> json(%{data: task_detail(task)}) {:error, reason} -> conn |> put_status(:unprocessable_entity) |> json(%{error: inspect(reason)}) end {:ok, %{status: "draft"} = _task} -> command = %WorkloadService.Commands.QuoteTask.ApproveSubmission{ id: id } case CommandedApp.dispatch(command) do :ok -> {:ok, task} = Queries.get_task_by_id(id) conn |> put_status(:ok) |> json(%{data: task_detail(task)}) {:error, reason} -> conn |> put_status(:unprocessable_entity) |> json(%{error: inspect(reason)}) end {:ok, %{status: "approved"} = _task} -> command = %WorkloadService.Commands.QuoteTask.CompleteTask{ id: id, completed_by: params["completed_by"] || "system" } case CommandedApp.dispatch(command) do :ok -> {:ok, task} = Queries.get_task_by_id(id) conn |> put_status(:ok) |> json(%{data: task_detail(task)}) {:error, reason} -> conn |> put_status(:unprocessable_entity) |> json(%{error: inspect(reason)}) end {:ok, _task} -> conn |> put_status(:unprocessable_entity) |> json(%{error: "invalid state"}) end end operation(:confirm_delivery, summary: "Confirm solicitation delivery", parameters: [ id: [in: :path, type: :string, required: true] ], request_body: {"Delivery confirmation", "application/json", S.ConfirmDeliveryRequest, required: false}, responses: [ ok: {"Delivery confirmed", "application/json", S.TaskDetailResponse}, not_found: {"Not found", "application/json", S.ErrorResponse}, unprocessable_entity: {"Error", "application/json", S.ErrorResponse} ] ) def confirm_delivery(conn, %{"id" => id} = params) do case Queries.get_task_by_id(id) do {:error, :not_found} -> conn |> put_status(:not_found) |> json(%{error: "task not found"}) {:ok, %{status: "created"} = _task} -> command = %WorkloadService.Commands.SolicitationTask.SubmitResponse{ id: id, submission: %{ "delivery_confirmed_by" => params["delivery_confirmed_by"] || "system" }, attachments: [] } case CommandedApp.dispatch(command) do :ok -> {:ok, task} = Queries.get_task_by_id(id) conn |> put_status(:ok) |> json(%{data: task_detail(task)}) {:error, reason} -> conn |> put_status(:unprocessable_entity) |> json(%{error: inspect(reason)}) end {:ok, %{status: "draft"} = _task} -> command = %WorkloadService.Commands.SolicitationTask.ApproveSubmission{ id: id } case CommandedApp.dispatch(command) do :ok -> {:ok, task} = Queries.get_task_by_id(id) conn |> put_status(:ok) |> json(%{data: task_detail(task)}) {:error, reason} -> conn |> put_status(:unprocessable_entity) |> json(%{error: inspect(reason)}) end {:ok, %{status: "approved"} = _task} -> command = %WorkloadService.Commands.SolicitationTask.CompleteTask{ id: id, completed_by: params["completed_by"] || "system" } case CommandedApp.dispatch(command) do :ok -> {:ok, task} = Queries.get_task_by_id(id) conn |> put_status(:ok) |> json(%{data: task_detail(task)}) {:error, reason} -> conn |> put_status(:unprocessable_entity) |> json(%{error: inspect(reason)}) end {:ok, _task} -> conn |> put_status(:unprocessable_entity) |> json(%{error: "invalid state"}) end end defp task_summary(t) do %{ id: t.id, org_id: t.org_id, application_id: t.application_id, provider_id: t.provider_id, provider_name: t.provider_name, task_info: t.task_info, status: t.status, created_at: t.inserted_at } end defp task_detail(t) do %{ id: t.id, org_id: t.org_id, application_id: t.application_id, provider_id: t.provider_id, provider_name: t.provider_name, task_info: t.task_info, submission: t.submission, attachments: t.attachments, status: t.status, version: t.version, created_at: t.inserted_at, updated_at: t.updated_at } end defp meta_json(meta) do %{ total_count: meta.total_count, total_pages: meta.total_pages, current_page: meta.current_page, page_size: meta.page_size, has_next: meta.has_next_page?, has_prev: meta.has_previous_page? } end end