2.9 KiB · text History c5a2f92
defmodule WaxxWeb.Api.V1.BoardController do
  @moduledoc """
  Read-only board endpoints (Phase 2).

      GET /api/v1/boards                  — list of boards the caller has access to
      GET /api/v1/boards/:id              — board metadata + members
      GET /api/v1/boards/:id/workflow     — stages + transitions + labels +
                                            fields + subboards (static
                                            structure, refreshed on
                                            :workflow_changed)
      GET /api/v1/boards/:id/cards        — cards with assignees/labels/
                                            field values (refreshed on
                                            :cards_changed)
      GET /api/v1/boards/:id/history      — paginated activity log

  Membership is required on every board endpoint — `Kanban.get_board_for_user/2`
  returns nil when the caller isn't a member, which the controller turns
  into a `:not_found` (we don't leak the existence of boards the user
  can't see).
  """

  use WaxxWeb, :controller

  alias Waxx.Kanban
  alias Waxx.Repo
  alias WaxxWeb.Api.V1.BoardJSON

  action_fallback WaxxWeb.Api.FallbackController

  def index(conn, _params) do
    user = conn.assigns.current_scope.user

    boards_with_roles =
      user
      |> Kanban.list_boards_for()
      |> Enum.map(fn b -> {b, Kanban.role_for(b.id, user)} end)

    json(conn, BoardJSON.boards_list(boards_with_roles))
  end

  def show(conn, %{"id" => id}) do
    user = conn.assigns.current_scope.user

    with {:ok, board} <- fetch_board(id, user) do
      role = Kanban.role_for(board.id, user)
      members = Kanban.list_members(board.id)
      json(conn, BoardJSON.board(board, role, members))
    end
  end

  def workflow(conn, %{"board_id" => id}) do
    user = conn.assigns.current_scope.user

    with {:ok, _board} <- fetch_board(id, user) do
      board = Kanban.get_board_with_workflow!(id, user)
      json(conn, BoardJSON.workflow(board))
    end
  end

  def cards(conn, %{"board_id" => id}) do
    user = conn.assigns.current_scope.user

    with {:ok, _} <- fetch_board(id, user) do
      board = Kanban.get_board_with_workflow!(id, user)
      cards = Kanban.list_cards(board)
      json(conn, BoardJSON.cards(cards))
    end
  end

  def history(conn, %{"board_id" => id} = params) do
    user = conn.assigns.current_scope.user

    with {:ok, board} <- fetch_board(id, user) do
      limit = parse_limit(params["limit"])
      activities = Kanban.list_activities(board, limit: limit)
      json(conn, BoardJSON.activities(activities))
    end
  end

  defp fetch_board(id, user) do
    case Kanban.get_board_for_user(id, user) do
      nil -> {:error, :not_found}
      board -> {:ok, Repo.preload(board, [])}
    end
  end

  defp parse_limit(nil), do: 200

  defp parse_limit(s) when is_binary(s) do
    case Integer.parse(s) do
      {n, _} when n > 0 and n <= 500 -> n
      _ -> 200
    end
  end

  defp parse_limit(_), do: 200
end