From 0114fc8ae98f48736350b7e0d200d5f54552d4bc Mon Sep 17 00:00:00 2001 From: nelsonic Date: Wed, 22 Jul 2020 18:59:54 +0100 Subject: [PATCH] create roles schema and resources #27 / #31 --- lib/auth/ctx.ex | 104 ++++++++++++++++++ lib/auth/ctx/role.ex | 19 ++++ lib/auth_web/controllers/role_controller.ex | 62 +++++++++++ lib/auth_web/router.ex | 2 + lib/auth_web/templates/role/edit.html.eex | 5 + lib/auth_web/templates/role/form.html.eex | 19 ++++ lib/auth_web/templates/role/index.html.eex | 28 +++++ lib/auth_web/templates/role/new.html.eex | 5 + lib/auth_web/templates/role/show.html.eex | 18 +++ lib/auth_web/views/role_view.ex | 3 + .../20200722175850_create_roles.exs | 15 +++ test/auth/ctx_test.exs | 66 +++++++++++ .../controllers/role_controller_test.exs | 88 +++++++++++++++ 13 files changed, 434 insertions(+) create mode 100644 lib/auth/ctx.ex create mode 100644 lib/auth/ctx/role.ex create mode 100644 lib/auth_web/controllers/role_controller.ex create mode 100644 lib/auth_web/templates/role/edit.html.eex create mode 100644 lib/auth_web/templates/role/form.html.eex create mode 100644 lib/auth_web/templates/role/index.html.eex create mode 100644 lib/auth_web/templates/role/new.html.eex create mode 100644 lib/auth_web/templates/role/show.html.eex create mode 100644 lib/auth_web/views/role_view.ex create mode 100644 priv/repo/migrations/20200722175850_create_roles.exs create mode 100644 test/auth/ctx_test.exs create mode 100644 test/auth_web/controllers/role_controller_test.exs diff --git a/lib/auth/ctx.ex b/lib/auth/ctx.ex new file mode 100644 index 00000000..2a07041c --- /dev/null +++ b/lib/auth/ctx.ex @@ -0,0 +1,104 @@ +defmodule Auth.Ctx do + @moduledoc """ + The Ctx context. + """ + + import Ecto.Query, warn: false + alias Auth.Repo + + alias Auth.Ctx.Role + + @doc """ + Returns the list of roles. + + ## Examples + + iex> list_roles() + [%Role{}, ...] + + """ + def list_roles do + Repo.all(Role) + end + + @doc """ + Gets a single role. + + Raises `Ecto.NoResultsError` if the Role does not exist. + + ## Examples + + iex> get_role!(123) + %Role{} + + iex> get_role!(456) + ** (Ecto.NoResultsError) + + """ + def get_role!(id), do: Repo.get!(Role, id) + + @doc """ + Creates a role. + + ## Examples + + iex> create_role(%{field: value}) + {:ok, %Role{}} + + iex> create_role(%{field: bad_value}) + {:error, %Ecto.Changeset{}} + + """ + def create_role(attrs \\ %{}) do + %Role{} + |> Role.changeset(attrs) + |> Repo.insert() + end + + @doc """ + Updates a role. + + ## Examples + + iex> update_role(role, %{field: new_value}) + {:ok, %Role{}} + + iex> update_role(role, %{field: bad_value}) + {:error, %Ecto.Changeset{}} + + """ + def update_role(%Role{} = role, attrs) do + role + |> Role.changeset(attrs) + |> Repo.update() + end + + @doc """ + Deletes a role. + + ## Examples + + iex> delete_role(role) + {:ok, %Role{}} + + iex> delete_role(role) + {:error, %Ecto.Changeset{}} + + """ + def delete_role(%Role{} = role) do + Repo.delete(role) + end + + @doc """ + Returns an `%Ecto.Changeset{}` for tracking role changes. + + ## Examples + + iex> change_role(role) + %Ecto.Changeset{data: %Role{}} + + """ + def change_role(%Role{} = role, attrs \\ %{}) do + Role.changeset(role, attrs) + end +end diff --git a/lib/auth/ctx/role.ex b/lib/auth/ctx/role.ex new file mode 100644 index 00000000..e6cd02b0 --- /dev/null +++ b/lib/auth/ctx/role.ex @@ -0,0 +1,19 @@ +defmodule Auth.Ctx.Role do + use Ecto.Schema + import Ecto.Changeset + + schema "roles" do + field :desc, :string + field :name, :string + field :person_id, :id + + timestamps() + end + + @doc false + def changeset(role, attrs) do + role + |> cast(attrs, [:name, :desc]) + |> validate_required([:name, :desc]) + end +end diff --git a/lib/auth_web/controllers/role_controller.ex b/lib/auth_web/controllers/role_controller.ex new file mode 100644 index 00000000..e25c3394 --- /dev/null +++ b/lib/auth_web/controllers/role_controller.ex @@ -0,0 +1,62 @@ +defmodule AuthWeb.RoleController do + use AuthWeb, :controller + + alias Auth.Ctx + alias Auth.Ctx.Role + + def index(conn, _params) do + roles = Ctx.list_roles() + render(conn, "index.html", roles: roles) + end + + def new(conn, _params) do + changeset = Ctx.change_role(%Role{}) + render(conn, "new.html", changeset: changeset) + end + + def create(conn, %{"role" => role_params}) do + case Ctx.create_role(role_params) do + {:ok, role} -> + conn + |> put_flash(:info, "Role created successfully.") + |> redirect(to: Routes.role_path(conn, :show, role)) + + {:error, %Ecto.Changeset{} = changeset} -> + render(conn, "new.html", changeset: changeset) + end + end + + def show(conn, %{"id" => id}) do + role = Ctx.get_role!(id) + render(conn, "show.html", role: role) + end + + def edit(conn, %{"id" => id}) do + role = Ctx.get_role!(id) + changeset = Ctx.change_role(role) + render(conn, "edit.html", role: role, changeset: changeset) + end + + def update(conn, %{"id" => id, "role" => role_params}) do + role = Ctx.get_role!(id) + + case Ctx.update_role(role, role_params) do + {:ok, role} -> + conn + |> put_flash(:info, "Role updated successfully.") + |> redirect(to: Routes.role_path(conn, :show, role)) + + {:error, %Ecto.Changeset{} = changeset} -> + render(conn, "edit.html", role: role, changeset: changeset) + end + end + + def delete(conn, %{"id" => id}) do + role = Ctx.get_role!(id) + {:ok, _role} = Ctx.delete_role(role) + + conn + |> put_flash(:info, "Role deleted successfully.") + |> redirect(to: Routes.role_path(conn, :index)) + end +end diff --git a/lib/auth_web/router.ex b/lib/auth_web/router.ex index 8fb5f35c..298652a2 100644 --- a/lib/auth_web/router.ex +++ b/lib/auth_web/router.ex @@ -38,6 +38,8 @@ defmodule AuthWeb.Router do pipe_through :auth get "/profile", AuthController, :admin + resources "/roles", RoleController + resources "/settings/apikeys", ApikeyController end diff --git a/lib/auth_web/templates/role/edit.html.eex b/lib/auth_web/templates/role/edit.html.eex new file mode 100644 index 00000000..f5527cf7 --- /dev/null +++ b/lib/auth_web/templates/role/edit.html.eex @@ -0,0 +1,5 @@ +

Edit Role

+ +<%= render "form.html", Map.put(assigns, :action, Routes.role_path(@conn, :update, @role)) %> + +<%= link "Back", to: Routes.role_path(@conn, :index) %> diff --git a/lib/auth_web/templates/role/form.html.eex b/lib/auth_web/templates/role/form.html.eex new file mode 100644 index 00000000..1339ceb1 --- /dev/null +++ b/lib/auth_web/templates/role/form.html.eex @@ -0,0 +1,19 @@ +<%= form_for @changeset, @action, fn f -> %> + <%= if @changeset.action do %> +
+

Oops, something went wrong! Please check the errors below.

+
+ <% end %> + + <%= label f, :name %> + <%= text_input f, :name %> + <%= error_tag f, :name %> + + <%= label f, :desc %> + <%= text_input f, :desc %> + <%= error_tag f, :desc %> + +
+ <%= submit "Save" %> +
+<% end %> diff --git a/lib/auth_web/templates/role/index.html.eex b/lib/auth_web/templates/role/index.html.eex new file mode 100644 index 00000000..4920d942 --- /dev/null +++ b/lib/auth_web/templates/role/index.html.eex @@ -0,0 +1,28 @@ +

Listing Roles

+ + + + + + + + + + + +<%= for role <- @roles do %> + + + + + + +<% end %> + +
NameDesc
<%= role.name %><%= role.desc %> + <%= link "Show", to: Routes.role_path(@conn, :show, role) %> + <%= link "Edit", to: Routes.role_path(@conn, :edit, role) %> + <%= link "Delete", to: Routes.role_path(@conn, :delete, role), method: :delete, data: [confirm: "Are you sure?"] %> +
+ +<%= link "New Role", to: Routes.role_path(@conn, :new) %> diff --git a/lib/auth_web/templates/role/new.html.eex b/lib/auth_web/templates/role/new.html.eex new file mode 100644 index 00000000..79e26f37 --- /dev/null +++ b/lib/auth_web/templates/role/new.html.eex @@ -0,0 +1,5 @@ +

New Role

+ +<%= render "form.html", Map.put(assigns, :action, Routes.role_path(@conn, :create)) %> + +<%= link "Back", to: Routes.role_path(@conn, :index) %> diff --git a/lib/auth_web/templates/role/show.html.eex b/lib/auth_web/templates/role/show.html.eex new file mode 100644 index 00000000..98f82c6e --- /dev/null +++ b/lib/auth_web/templates/role/show.html.eex @@ -0,0 +1,18 @@ +

Show Role

+ + + +<%= link "Edit", to: Routes.role_path(@conn, :edit, @role) %> +<%= link "Back", to: Routes.role_path(@conn, :index) %> diff --git a/lib/auth_web/views/role_view.ex b/lib/auth_web/views/role_view.ex new file mode 100644 index 00000000..1aff1f86 --- /dev/null +++ b/lib/auth_web/views/role_view.ex @@ -0,0 +1,3 @@ +defmodule AuthWeb.RoleView do + use AuthWeb, :view +end diff --git a/priv/repo/migrations/20200722175850_create_roles.exs b/priv/repo/migrations/20200722175850_create_roles.exs new file mode 100644 index 00000000..c393b64d --- /dev/null +++ b/priv/repo/migrations/20200722175850_create_roles.exs @@ -0,0 +1,15 @@ +defmodule Auth.Repo.Migrations.CreateRoles do + use Ecto.Migration + + def change do + create table(:roles) do + add :name, :string + add :desc, :string + add :person_id, references(:people, on_delete: :nothing) + + timestamps() + end + + create index(:roles, [:person_id]) + end +end diff --git a/test/auth/ctx_test.exs b/test/auth/ctx_test.exs new file mode 100644 index 00000000..b09034f3 --- /dev/null +++ b/test/auth/ctx_test.exs @@ -0,0 +1,66 @@ +defmodule Auth.CtxTest do + use Auth.DataCase + + alias Auth.Ctx + + describe "roles" do + alias Auth.Ctx.Role + + @valid_attrs %{desc: "some desc", name: "some name"} + @update_attrs %{desc: "some updated desc", name: "some updated name"} + @invalid_attrs %{desc: nil, name: nil} + + def role_fixture(attrs \\ %{}) do + {:ok, role} = + attrs + |> Enum.into(@valid_attrs) + |> Ctx.create_role() + + role + end + + test "list_roles/0 returns all roles" do + role = role_fixture() + assert Ctx.list_roles() == [role] + end + + test "get_role!/1 returns the role with given id" do + role = role_fixture() + assert Ctx.get_role!(role.id) == role + end + + test "create_role/1 with valid data creates a role" do + assert {:ok, %Role{} = role} = Ctx.create_role(@valid_attrs) + assert role.desc == "some desc" + assert role.name == "some name" + end + + test "create_role/1 with invalid data returns error changeset" do + assert {:error, %Ecto.Changeset{}} = Ctx.create_role(@invalid_attrs) + end + + test "update_role/2 with valid data updates the role" do + role = role_fixture() + assert {:ok, %Role{} = role} = Ctx.update_role(role, @update_attrs) + assert role.desc == "some updated desc" + assert role.name == "some updated name" + end + + test "update_role/2 with invalid data returns error changeset" do + role = role_fixture() + assert {:error, %Ecto.Changeset{}} = Ctx.update_role(role, @invalid_attrs) + assert role == Ctx.get_role!(role.id) + end + + test "delete_role/1 deletes the role" do + role = role_fixture() + assert {:ok, %Role{}} = Ctx.delete_role(role) + assert_raise Ecto.NoResultsError, fn -> Ctx.get_role!(role.id) end + end + + test "change_role/1 returns a role changeset" do + role = role_fixture() + assert %Ecto.Changeset{} = Ctx.change_role(role) + end + end +end diff --git a/test/auth_web/controllers/role_controller_test.exs b/test/auth_web/controllers/role_controller_test.exs new file mode 100644 index 00000000..97fe5a18 --- /dev/null +++ b/test/auth_web/controllers/role_controller_test.exs @@ -0,0 +1,88 @@ +defmodule AuthWeb.RoleControllerTest do + use AuthWeb.ConnCase + + alias Auth.Ctx + + @create_attrs %{desc: "some desc", name: "some name"} + @update_attrs %{desc: "some updated desc", name: "some updated name"} + @invalid_attrs %{desc: nil, name: nil} + + def fixture(:role) do + {:ok, role} = Ctx.create_role(@create_attrs) + role + end + + describe "index" do + test "lists all roles", %{conn: conn} do + conn = get(conn, Routes.role_path(conn, :index)) + assert html_response(conn, 200) =~ "Listing Roles" + end + end + + describe "new role" do + test "renders form", %{conn: conn} do + conn = get(conn, Routes.role_path(conn, :new)) + assert html_response(conn, 200) =~ "New Role" + end + end + + describe "create role" do + test "redirects to show when data is valid", %{conn: conn} do + conn = post(conn, Routes.role_path(conn, :create), role: @create_attrs) + + assert %{id: id} = redirected_params(conn) + assert redirected_to(conn) == Routes.role_path(conn, :show, id) + + conn = get(conn, Routes.role_path(conn, :show, id)) + assert html_response(conn, 200) =~ "Show Role" + end + + test "renders errors when data is invalid", %{conn: conn} do + conn = post(conn, Routes.role_path(conn, :create), role: @invalid_attrs) + assert html_response(conn, 200) =~ "New Role" + end + end + + describe "edit role" do + setup [:create_role] + + test "renders form for editing chosen role", %{conn: conn, role: role} do + conn = get(conn, Routes.role_path(conn, :edit, role)) + assert html_response(conn, 200) =~ "Edit Role" + end + end + + describe "update role" do + setup [:create_role] + + test "redirects when data is valid", %{conn: conn, role: role} do + conn = put(conn, Routes.role_path(conn, :update, role), role: @update_attrs) + assert redirected_to(conn) == Routes.role_path(conn, :show, role) + + conn = get(conn, Routes.role_path(conn, :show, role)) + assert html_response(conn, 200) =~ "some updated desc" + end + + test "renders errors when data is invalid", %{conn: conn, role: role} do + conn = put(conn, Routes.role_path(conn, :update, role), role: @invalid_attrs) + assert html_response(conn, 200) =~ "Edit Role" + end + end + + describe "delete role" do + setup [:create_role] + + test "deletes chosen role", %{conn: conn, role: role} do + conn = delete(conn, Routes.role_path(conn, :delete, role)) + assert redirected_to(conn) == Routes.role_path(conn, :index) + assert_error_sent 404, fn -> + get(conn, Routes.role_path(conn, :show, role)) + end + end + end + + defp create_role(_) do + role = fixture(:role) + %{role: role} + end +end