diff --git a/lib/todo_test/account.ex b/lib/todo_test/account.ex new file mode 100644 index 0000000..a754c6b --- /dev/null +++ b/lib/todo_test/account.ex @@ -0,0 +1,104 @@ +defmodule TodoTest.Account do + @moduledoc """ + The Account context. + """ + + import Ecto.Query, warn: false + alias TodoTest.Repo + + alias TodoTest.Account.User + + @doc """ + Returns the list of users. + + ## Examples + + iex> list_users() + [%User{}, ...] + + """ + def list_users do + Repo.all(User) + end + + @doc """ + Gets a single user. + + Raises `Ecto.NoResultsError` if the User does not exist. + + ## Examples + + iex> get_user!(123) + %User{} + + iex> get_user!(456) + ** (Ecto.NoResultsError) + + """ + def get_user!(id), do: Repo.get!(User, id) + + @doc """ + Creates a user. + + ## Examples + + iex> create_user(%{field: value}) + {:ok, %User{}} + + iex> create_user(%{field: bad_value}) + {:error, %Ecto.Changeset{}} + + """ + def create_user(attrs \\ %{}) do + %User{} + |> User.changeset(attrs) + |> Repo.insert() + end + + @doc """ + Updates a user. + + ## Examples + + iex> update_user(user, %{field: new_value}) + {:ok, %User{}} + + iex> update_user(user, %{field: bad_value}) + {:error, %Ecto.Changeset{}} + + """ + def update_user(%User{} = user, attrs) do + user + |> User.changeset(attrs) + |> Repo.update() + end + + @doc """ + Deletes a user. + + ## Examples + + iex> delete_user(user) + {:ok, %User{}} + + iex> delete_user(user) + {:error, %Ecto.Changeset{}} + + """ + def delete_user(%User{} = user) do + Repo.delete(user) + end + + @doc """ + Returns an `%Ecto.Changeset{}` for tracking user changes. + + ## Examples + + iex> change_user(user) + %Ecto.Changeset{data: %User{}} + + """ + def change_user(%User{} = user, attrs \\ %{}) do + User.changeset(user, attrs) + end +end diff --git a/lib/todo_test/account/user.ex b/lib/todo_test/account/user.ex new file mode 100644 index 0000000..3d54b69 --- /dev/null +++ b/lib/todo_test/account/user.ex @@ -0,0 +1,19 @@ +defmodule TodoTest.Account.User do + use Ecto.Schema + import Ecto.Changeset + + schema "users" do + field :email, :string + field :name, :string + field :password, :string + + timestamps() + end + + @doc false + def changeset(user, attrs) do + user + |> cast(attrs, [:name, :email, :password]) + |> validate_required([:name, :email, :password]) + end +end diff --git a/lib/todo_test_web/controllers/user_controller.ex b/lib/todo_test_web/controllers/user_controller.ex new file mode 100644 index 0000000..abf0126 --- /dev/null +++ b/lib/todo_test_web/controllers/user_controller.ex @@ -0,0 +1,64 @@ +defmodule TodoTestWeb.UserController do + use TodoTestWeb, :controller + + alias TodoTest.Account + alias TodoTest.Account.User + + def index(conn, _params) do + users = Account.list_users() + + IO.inspect(users, label: "Look rut!") + render(conn, "index.html", users: users) + end + + def new(conn, _params) do + changeset = Account.change_user(%User{}) + render(conn, "new.html", changeset: changeset) + end + + def create(conn, %{"user" => user_params}) do + case Account.create_user(user_params) do + {:ok, user} -> + conn + |> put_flash(:info, "User created successfully.") + |> redirect(to: Routes.user_path(conn, :show, user)) + + {:error, %Ecto.Changeset{} = changeset} -> + render(conn, "new.html", changeset: changeset) + end + end + + def show(conn, %{"id" => id}) do + user = Account.get_user!(id) + render(conn, "show.html", user: user) + end + + def edit(conn, %{"id" => id}) do + user = Account.get_user!(id) + changeset = Account.change_user(user) + render(conn, "edit.html", user: user, changeset: changeset) + end + + def update(conn, %{"id" => id, "user" => user_params}) do + user = Account.get_user!(id) + + case Account.update_user(user, user_params) do + {:ok, user} -> + conn + |> put_flash(:info, "User updated successfully.") + |> redirect(to: Routes.user_path(conn, :show, user)) + + {:error, %Ecto.Changeset{} = changeset} -> + render(conn, "edit.html", user: user, changeset: changeset) + end + end + + def delete(conn, %{"id" => id}) do + user = Account.get_user!(id) + {:ok, _user} = Account.delete_user(user) + + conn + |> put_flash(:info, "User deleted successfully.") + |> redirect(to: Routes.user_path(conn, :index)) + end +end diff --git a/lib/todo_test_web/router.ex b/lib/todo_test_web/router.ex index 041ced8..7707369 100644 --- a/lib/todo_test_web/router.ex +++ b/lib/todo_test_web/router.ex @@ -28,6 +28,7 @@ defmodule TodoTestWeb.Router do get "/price", PageController, :price + resources "/users", UserController end # Other scopes may use custom stacks. diff --git a/lib/todo_test_web/templates/user/edit.html.heex b/lib/todo_test_web/templates/user/edit.html.heex new file mode 100644 index 0000000..85e1404 --- /dev/null +++ b/lib/todo_test_web/templates/user/edit.html.heex @@ -0,0 +1,5 @@ +

Edit User

+ +<%= render "form.html", Map.put(assigns, :action, Routes.user_path(@conn, :update, @user)) %> + +<%= link "Back", to: Routes.user_path(@conn, :index) %> diff --git a/lib/todo_test_web/templates/user/form.html.heex b/lib/todo_test_web/templates/user/form.html.heex new file mode 100644 index 0000000..f5fdc50 --- /dev/null +++ b/lib/todo_test_web/templates/user/form.html.heex @@ -0,0 +1,23 @@ +<.form let={f} for={@changeset} action={@action}> + <%= 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, :email %> + <%= text_input f, :email %> + <%= error_tag f, :email %> + + <%= label f, :password %> + <%= text_input f, :password %> + <%= error_tag f, :password %> + +
+ <%= submit "Save" %> +
+ diff --git a/lib/todo_test_web/templates/user/index.html.heex b/lib/todo_test_web/templates/user/index.html.heex new file mode 100644 index 0000000..5787c34 --- /dev/null +++ b/lib/todo_test_web/templates/user/index.html.heex @@ -0,0 +1,30 @@ +

Listing Users

+ + + + + + + + + + + + +<%= for user <- @users do %> + + + + + + + +<% end %> + +
NameEmailPassword
<%= user.name %><%= user.email %><%= user.password %> + <%= link "Show", to: Routes.user_path(@conn, :show, user) %> + <%= link "Edit", to: Routes.user_path(@conn, :edit, user) %> + <%= link "Delete", to: Routes.user_path(@conn, :delete, user), method: :delete, data: [confirm: "Are you sure?"] %> +
+ +<%= link "New User", to: Routes.user_path(@conn, :new) %> diff --git a/lib/todo_test_web/templates/user/new.html.heex b/lib/todo_test_web/templates/user/new.html.heex new file mode 100644 index 0000000..a89ca9a --- /dev/null +++ b/lib/todo_test_web/templates/user/new.html.heex @@ -0,0 +1,5 @@ +

New User

+ +<%= render "form.html", Map.put(assigns, :action, Routes.user_path(@conn, :create)) %> + +<%= link "Back", to: Routes.user_path(@conn, :index) %> diff --git a/lib/todo_test_web/templates/user/show.html.heex b/lib/todo_test_web/templates/user/show.html.heex new file mode 100644 index 0000000..85ae4e4 --- /dev/null +++ b/lib/todo_test_web/templates/user/show.html.heex @@ -0,0 +1,23 @@ +

Show User

+ + + +<%= link "Edit", to: Routes.user_path(@conn, :edit, @user) %> | +<%= link "Back", to: Routes.user_path(@conn, :index) %> diff --git a/lib/todo_test_web/views/user_view.ex b/lib/todo_test_web/views/user_view.ex new file mode 100644 index 0000000..9a5324f --- /dev/null +++ b/lib/todo_test_web/views/user_view.ex @@ -0,0 +1,3 @@ +defmodule TodoTestWeb.UserView do + use TodoTestWeb, :view +end diff --git a/priv/repo/migrations/20211230151820_create_users.exs b/priv/repo/migrations/20211230151820_create_users.exs new file mode 100644 index 0000000..fa42812 --- /dev/null +++ b/priv/repo/migrations/20211230151820_create_users.exs @@ -0,0 +1,13 @@ +defmodule TodoTest.Repo.Migrations.CreateUsers do + use Ecto.Migration + + def change do + create table(:users) do + add :name, :string + add :email, :string + add :password, :string + + timestamps() + end + end +end diff --git a/test/support/fixtures/account_fixtures.ex b/test/support/fixtures/account_fixtures.ex new file mode 100644 index 0000000..5a5861c --- /dev/null +++ b/test/support/fixtures/account_fixtures.ex @@ -0,0 +1,22 @@ +defmodule TodoTest.AccountFixtures do + @moduledoc """ + This module defines test helpers for creating + entities via the `TodoTest.Account` context. + """ + + @doc """ + Generate a user. + """ + def user_fixture(attrs \\ %{}) do + {:ok, user} = + attrs + |> Enum.into(%{ + email: "some email", + name: "some name", + password: "some password" + }) + |> TodoTest.Account.create_user() + + user + end +end diff --git a/test/todo_test/account_test.exs b/test/todo_test/account_test.exs new file mode 100644 index 0000000..67b31a1 --- /dev/null +++ b/test/todo_test/account_test.exs @@ -0,0 +1,63 @@ +defmodule TodoTest.AccountTest do + use TodoTest.DataCase + + alias TodoTest.Account + + describe "users" do + alias TodoTest.Account.User + + import TodoTest.AccountFixtures + + @invalid_attrs %{email: nil, name: nil, password: nil} + + test "list_users/0 returns all users" do + user = user_fixture() + assert Account.list_users() == [user] + end + + test "get_user!/1 returns the user with given id" do + user = user_fixture() + assert Account.get_user!(user.id) == user + end + + test "create_user/1 with valid data creates a user" do + valid_attrs = %{email: "some email", name: "some name", password: "some password"} + + assert {:ok, %User{} = user} = Account.create_user(valid_attrs) + assert user.email == "some email" + assert user.name == "some name" + assert user.password == "some password" + end + + test "create_user/1 with invalid data returns error changeset" do + assert {:error, %Ecto.Changeset{}} = Account.create_user(@invalid_attrs) + end + + test "update_user/2 with valid data updates the user" do + user = user_fixture() + update_attrs = %{email: "some updated email", name: "some updated name", password: "some updated password"} + + assert {:ok, %User{} = user} = Account.update_user(user, update_attrs) + assert user.email == "some updated email" + assert user.name == "some updated name" + assert user.password == "some updated password" + end + + test "update_user/2 with invalid data returns error changeset" do + user = user_fixture() + assert {:error, %Ecto.Changeset{}} = Account.update_user(user, @invalid_attrs) + assert user == Account.get_user!(user.id) + end + + test "delete_user/1 deletes the user" do + user = user_fixture() + assert {:ok, %User{}} = Account.delete_user(user) + assert_raise Ecto.NoResultsError, fn -> Account.get_user!(user.id) end + end + + test "change_user/1 returns a user changeset" do + user = user_fixture() + assert %Ecto.Changeset{} = Account.change_user(user) + end + end +end diff --git a/test/todo_test_web/controllers/user_controller_test.exs b/test/todo_test_web/controllers/user_controller_test.exs new file mode 100644 index 0000000..12dfba7 --- /dev/null +++ b/test/todo_test_web/controllers/user_controller_test.exs @@ -0,0 +1,84 @@ +defmodule TodoTestWeb.UserControllerTest do + use TodoTestWeb.ConnCase + + import TodoTest.AccountFixtures + + @create_attrs %{email: "some email", name: "some name", password: "some password"} + @update_attrs %{email: "some updated email", name: "some updated name", password: "some updated password"} + @invalid_attrs %{email: nil, name: nil, password: nil} + + describe "index" do + test "lists all users", %{conn: conn} do + conn = get(conn, Routes.user_path(conn, :index)) + assert html_response(conn, 200) =~ "Listing Users" + end + end + + describe "new user" do + test "renders form", %{conn: conn} do + conn = get(conn, Routes.user_path(conn, :new)) + assert html_response(conn, 200) =~ "New User" + end + end + + describe "create user" do + test "redirects to show when data is valid", %{conn: conn} do + conn = post(conn, Routes.user_path(conn, :create), user: @create_attrs) + + assert %{id: id} = redirected_params(conn) + assert redirected_to(conn) == Routes.user_path(conn, :show, id) + + conn = get(conn, Routes.user_path(conn, :show, id)) + assert html_response(conn, 200) =~ "Show User" + end + + test "renders errors when data is invalid", %{conn: conn} do + conn = post(conn, Routes.user_path(conn, :create), user: @invalid_attrs) + assert html_response(conn, 200) =~ "New User" + end + end + + describe "edit user" do + setup [:create_user] + + test "renders form for editing chosen user", %{conn: conn, user: user} do + conn = get(conn, Routes.user_path(conn, :edit, user)) + assert html_response(conn, 200) =~ "Edit User" + end + end + + describe "update user" do + setup [:create_user] + + test "redirects when data is valid", %{conn: conn, user: user} do + conn = put(conn, Routes.user_path(conn, :update, user), user: @update_attrs) + assert redirected_to(conn) == Routes.user_path(conn, :show, user) + + conn = get(conn, Routes.user_path(conn, :show, user)) + assert html_response(conn, 200) =~ "some updated email" + end + + test "renders errors when data is invalid", %{conn: conn, user: user} do + conn = put(conn, Routes.user_path(conn, :update, user), user: @invalid_attrs) + assert html_response(conn, 200) =~ "Edit User" + end + end + + describe "delete user" do + setup [:create_user] + + test "deletes chosen user", %{conn: conn, user: user} do + conn = delete(conn, Routes.user_path(conn, :delete, user)) + assert redirected_to(conn) == Routes.user_path(conn, :index) + + assert_error_sent 404, fn -> + get(conn, Routes.user_path(conn, :show, user)) + end + end + end + + defp create_user(_) do + user = user_fixture() + %{user: user} + end +end