defmodule Localiser.Web.Controllers.UserController do use Phoenix.Controller, formats: [:json] use OpenApiSpex.ControllerSpecs alias Localiser.Domain.Users alias Localiser.Web.Schemas tags ["Users"] security [%{"bearerAuth" => []}] operation :me, summary: "Get own profile", responses: [ ok: {"Current user", "application/json", Schemas.User}, unauthorized: {"Unauthorized", "application/json", Schemas.Error} ] operation :index, summary: "List all users (admin)", responses: [ ok: {"User list", "application/json", %OpenApiSpex.Schema{type: :array, items: Schemas.User}}, unauthorized: {"Unauthorized", "application/json", Schemas.Error}, forbidden: {"Forbidden", "application/json", Schemas.Error} ] operation :show, summary: "Get a user (admin)", parameters: [id: [in: :path, type: :integer, required: true]], responses: [ ok: {"User", "application/json", Schemas.User}, unauthorized: {"Unauthorized", "application/json", Schemas.Error}, forbidden: {"Forbidden", "application/json", Schemas.Error} ] operation :create, summary: "Create a user (admin)", request_body: {"User params", "application/json", Schemas.UserCreateParams, required: true}, responses: [ created: {"Created user", "application/json", Schemas.User}, unauthorized: {"Unauthorized", "application/json", Schemas.Error}, forbidden: {"Forbidden", "application/json", Schemas.Error}, unprocessable_entity: {"Validation errors", "application/json", Schemas.ValidationErrors} ] operation :update, summary: "Update a user (admin)", parameters: [id: [in: :path, type: :integer, required: true]], request_body: {"User params", "application/json", Schemas.UserUpdateParams}, responses: [ ok: {"Updated user", "application/json", Schemas.User}, unauthorized: {"Unauthorized", "application/json", Schemas.Error}, forbidden: {"Forbidden", "application/json", Schemas.Error}, unprocessable_entity: {"Validation errors", "application/json", Schemas.ValidationErrors} ] operation :delete, summary: "Delete a user (admin)", parameters: [id: [in: :path, type: :integer, required: true]], responses: [ no_content: "Deleted", unauthorized: {"Unauthorized", "application/json", Schemas.Error}, forbidden: {"Forbidden", "application/json", Schemas.Error} ] operation :promote, summary: "Promote a user to admin", parameters: [id: [in: :path, type: :integer, required: true]], responses: [ ok: {"Updated user", "application/json", Schemas.User}, unauthorized: {"Unauthorized", "application/json", Schemas.Error}, forbidden: {"Forbidden", "application/json", Schemas.Error} ] def me(conn, _params) do json(conn, render_user(conn.assigns.current_user)) end def index(conn, _params) do json(conn, Enum.map(Users.list_users(), &render_user/1)) end def show(conn, %{"id" => id}) do user = Users.get_user!(id) json(conn, render_user(user)) end def create(conn, params) do case Users.create_user(params) do {:ok, user} -> conn |> put_status(:created) |> json(render_user(user)) {:error, changeset} -> conn |> put_status(:unprocessable_entity) |> json(%{errors: format_errors(changeset)}) end end def update(conn, %{"id" => id} = params) do user = Users.get_user!(id) attrs = Map.drop(params, ["id"]) case Users.update_user(user, attrs) do {:ok, updated} -> json(conn, render_user(updated)) {:error, changeset} -> conn |> put_status(:unprocessable_entity) |> json(%{errors: format_errors(changeset)}) end end def delete(conn, %{"id" => id}) do user = Users.get_user!(id) {:ok, _} = Users.delete_user(user) send_resp(conn, :no_content, "") end def promote(conn, %{"id" => id}) do user = Users.get_user!(id) case Users.promote_to_admin(user) do {:ok, updated} -> json(conn, render_user(updated)) {:error, changeset} -> conn |> put_status(:unprocessable_entity) |> json(%{errors: format_errors(changeset)}) end end defp render_user(user) do %{id: user.id, username: user.username, is_admin: user.is_admin} end defp format_errors(changeset) do Ecto.Changeset.traverse_errors(changeset, fn {msg, opts} -> Enum.reduce(opts, msg, fn {key, val}, acc -> String.replace(acc, "%{#{key}}", to_string(val)) end) end) end end