From 84d6b005e466d1bb69f2b8ac00a5e99c039a067a Mon Sep 17 00:00:00 2001 From: Roman Cattaneo <> Date: Sun, 28 Jan 2024 21:18:19 +0100 Subject: [PATCH 01/42] Update Readme --- README.md | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index a2d3a82..e7c52ad 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,30 @@ -# cklist +# ✔️ cklist -Awesome checklists are about to come here. Stay tuned. +Awesome :heavy_check_mark: checklists are about to come here. Stay tuned... -## Contributing +## 🤝 Contributing -Contributions are welcome. +We are just getting started. Feel free to reach out if you feel like joining. -- cklists are based on the awesome [Phoenix Framework](https://www.phoenixframework.org/). -- Elixir & Erlang versions are managed with [asdf](https://asdf-vm.com/) in [.tool-versions](.tool-versions). -- We use [PostgreSQL](https://www.postgresql.org/) as database backend. For local development, we assume a user `cklist` exists (see [config/dev.exs](./config/dev.exs)). The authentication system makes use of the `citext` extension of PostgreSQL. If DB migration complains about missing the `citext` extension, try search for and installing the `postgres-contrib` package. +### Setup notes + +#### Framework + +cklists are based on the awesome [Phoenix Framework](https://www.phoenixframework.org/). + +#### Versions + +Elixir, Erlang, and npm versions are managed with [asdf](https://asdf-vm.com/) in [.tool-versions](.tool-versions). + +#### Database + +We use [PostgreSQL](https://www.postgresql.org/) as database backend. Phoenix' authentication system makes use of the `citext` extension of PostgreSQL. If DB migration complains about missing the `citext` extension, try search for and installing the `postgres-contrib` package. + +Database secrets can be stored in `.env`-style configuration. This is useful for both, local development and deployments. To override the database configuration, put the following contents + +```none +DATABASE_URL="ecto://cklist:cklist@localhost/cklist_dev" +TEST_DATABASE_URL="ecto://cklist:cklist@localhost/cklist_test" +``` + +in a file `envs/.env` and adapt the defaults to your liking. From 818f34a33968aa8f556887c06a9f11515eab4c1c Mon Sep 17 00:00:00 2001 From: Roman Cattaneo <> Date: Sun, 28 Jan 2024 20:25:04 +0100 Subject: [PATCH 02/42] Ignore VSCode configuration folder --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 899f4fa..62755bd 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,6 @@ npm-debug.log /assets/node_modules/ .env envs/ + +# VSCode configuration +/.vscode/ From f528a4154def2d4067685ded54dcb7e4c3ccab6f Mon Sep 17 00:00:00 2001 From: Roman Cattaneo <> Date: Sun, 28 Jan 2024 20:57:26 +0100 Subject: [PATCH 03/42] Basic checklist ressource I ran the following `mix` command to auto-generate a `checklist` ressource ``` mix phx.gen.html Checklists Checklist checklists title:string description:string user_id:references:users document:map ``` --- lib/cklist/checklists.ex | 104 ++++++++++++++++++ lib/cklist/checklists/checklist.ex | 20 ++++ .../controllers/checklist_controller.ex | 62 +++++++++++ lib/cklist_web/controllers/checklist_html.ex | 13 +++ .../checklist_html/checklist_form.html.heex | 10 ++ .../controllers/checklist_html/edit.html.heex | 8 ++ .../checklist_html/index.html.heex | 25 +++++ .../controllers/checklist_html/new.html.heex | 8 ++ .../controllers/checklist_html/show.html.heex | 17 +++ lib/cklist_web/router.ex | 2 + .../20240128194147_create_checklists.exs | 16 +++ test/cklist/checklists_test.exs | 63 +++++++++++ .../controllers/checklist_controller_test.exs | 84 ++++++++++++++ test/support/fixtures/checklists_fixtures.ex | 22 ++++ 14 files changed, 454 insertions(+) create mode 100644 lib/cklist/checklists.ex create mode 100644 lib/cklist/checklists/checklist.ex create mode 100644 lib/cklist_web/controllers/checklist_controller.ex create mode 100644 lib/cklist_web/controllers/checklist_html.ex create mode 100644 lib/cklist_web/controllers/checklist_html/checklist_form.html.heex create mode 100644 lib/cklist_web/controllers/checklist_html/edit.html.heex create mode 100644 lib/cklist_web/controllers/checklist_html/index.html.heex create mode 100644 lib/cklist_web/controllers/checklist_html/new.html.heex create mode 100644 lib/cklist_web/controllers/checklist_html/show.html.heex create mode 100644 priv/repo/migrations/20240128194147_create_checklists.exs create mode 100644 test/cklist/checklists_test.exs create mode 100644 test/cklist_web/controllers/checklist_controller_test.exs create mode 100644 test/support/fixtures/checklists_fixtures.ex diff --git a/lib/cklist/checklists.ex b/lib/cklist/checklists.ex new file mode 100644 index 0000000..08d87b0 --- /dev/null +++ b/lib/cklist/checklists.ex @@ -0,0 +1,104 @@ +defmodule Cklist.Checklists do + @moduledoc """ + The Checklists context. + """ + + import Ecto.Query, warn: false + alias Cklist.Repo + + alias Cklist.Checklists.Checklist + + @doc """ + Returns the list of checklists. + + ## Examples + + iex> list_checklists() + [%Checklist{}, ...] + + """ + def list_checklists do + Repo.all(Checklist) + end + + @doc """ + Gets a single checklist. + + Raises `Ecto.NoResultsError` if the Checklist does not exist. + + ## Examples + + iex> get_checklist!(123) + %Checklist{} + + iex> get_checklist!(456) + ** (Ecto.NoResultsError) + + """ + def get_checklist!(id), do: Repo.get!(Checklist, id) + + @doc """ + Creates a checklist. + + ## Examples + + iex> create_checklist(%{field: value}) + {:ok, %Checklist{}} + + iex> create_checklist(%{field: bad_value}) + {:error, %Ecto.Changeset{}} + + """ + def create_checklist(attrs \\ %{}) do + %Checklist{} + |> Checklist.changeset(attrs) + |> Repo.insert() + end + + @doc """ + Updates a checklist. + + ## Examples + + iex> update_checklist(checklist, %{field: new_value}) + {:ok, %Checklist{}} + + iex> update_checklist(checklist, %{field: bad_value}) + {:error, %Ecto.Changeset{}} + + """ + def update_checklist(%Checklist{} = checklist, attrs) do + checklist + |> Checklist.changeset(attrs) + |> Repo.update() + end + + @doc """ + Deletes a checklist. + + ## Examples + + iex> delete_checklist(checklist) + {:ok, %Checklist{}} + + iex> delete_checklist(checklist) + {:error, %Ecto.Changeset{}} + + """ + def delete_checklist(%Checklist{} = checklist) do + Repo.delete(checklist) + end + + @doc """ + Returns an `%Ecto.Changeset{}` for tracking checklist changes. + + ## Examples + + iex> change_checklist(checklist) + %Ecto.Changeset{data: %Checklist{}} + + """ + def change_checklist(%Checklist{} = checklist, attrs \\ %{}) do + Checklist.changeset(checklist, attrs) + end +end diff --git a/lib/cklist/checklists/checklist.ex b/lib/cklist/checklists/checklist.ex new file mode 100644 index 0000000..f371a43 --- /dev/null +++ b/lib/cklist/checklists/checklist.ex @@ -0,0 +1,20 @@ +defmodule Cklist.Checklists.Checklist do + use Ecto.Schema + import Ecto.Changeset + + schema "checklists" do + field :description, :string + field :title, :string + field :document, :map + field :user_id, :id + + timestamps(type: :utc_datetime) + end + + @doc false + def changeset(checklist, attrs) do + checklist + |> cast(attrs, [:title, :description, :document]) + |> validate_required([:title, :description]) + end +end diff --git a/lib/cklist_web/controllers/checklist_controller.ex b/lib/cklist_web/controllers/checklist_controller.ex new file mode 100644 index 0000000..4fff10b --- /dev/null +++ b/lib/cklist_web/controllers/checklist_controller.ex @@ -0,0 +1,62 @@ +defmodule CklistWeb.ChecklistController do + use CklistWeb, :controller + + alias Cklist.Checklists + alias Cklist.Checklists.Checklist + + def index(conn, _params) do + checklists = Checklists.list_checklists() + render(conn, :index, checklists: checklists) + end + + def new(conn, _params) do + changeset = Checklists.change_checklist(%Checklist{}) + render(conn, :new, changeset: changeset) + end + + def create(conn, %{"checklist" => checklist_params}) do + case Checklists.create_checklist(checklist_params) do + {:ok, checklist} -> + conn + |> put_flash(:info, "Checklist created successfully.") + |> redirect(to: ~p"/checklists/#{checklist}") + + {:error, %Ecto.Changeset{} = changeset} -> + render(conn, :new, changeset: changeset) + end + end + + def show(conn, %{"id" => id}) do + checklist = Checklists.get_checklist!(id) + render(conn, :show, checklist: checklist) + end + + def edit(conn, %{"id" => id}) do + checklist = Checklists.get_checklist!(id) + changeset = Checklists.change_checklist(checklist) + render(conn, :edit, checklist: checklist, changeset: changeset) + end + + def update(conn, %{"id" => id, "checklist" => checklist_params}) do + checklist = Checklists.get_checklist!(id) + + case Checklists.update_checklist(checklist, checklist_params) do + {:ok, checklist} -> + conn + |> put_flash(:info, "Checklist updated successfully.") + |> redirect(to: ~p"/checklists/#{checklist}") + + {:error, %Ecto.Changeset{} = changeset} -> + render(conn, :edit, checklist: checklist, changeset: changeset) + end + end + + def delete(conn, %{"id" => id}) do + checklist = Checklists.get_checklist!(id) + {:ok, _checklist} = Checklists.delete_checklist(checklist) + + conn + |> put_flash(:info, "Checklist deleted successfully.") + |> redirect(to: ~p"/checklists") + end +end diff --git a/lib/cklist_web/controllers/checklist_html.ex b/lib/cklist_web/controllers/checklist_html.ex new file mode 100644 index 0000000..21a0cbf --- /dev/null +++ b/lib/cklist_web/controllers/checklist_html.ex @@ -0,0 +1,13 @@ +defmodule CklistWeb.ChecklistHTML do + use CklistWeb, :html + + embed_templates "checklist_html/*" + + @doc """ + Renders a checklist form. + """ + attr :changeset, Ecto.Changeset, required: true + attr :action, :string, required: true + + def checklist_form(assigns) +end diff --git a/lib/cklist_web/controllers/checklist_html/checklist_form.html.heex b/lib/cklist_web/controllers/checklist_html/checklist_form.html.heex new file mode 100644 index 0000000..8e878a4 --- /dev/null +++ b/lib/cklist_web/controllers/checklist_html/checklist_form.html.heex @@ -0,0 +1,10 @@ +<.simple_form :let={f} for={@changeset} action={@action}> + <.error :if={@changeset.action}> + Oops, something went wrong! Please check the errors below. + + <.input field={f[:title]} type="text" label="Title" /> + <.input field={f[:description]} type="text" label="Description" /> + <:actions> + <.button>Save Checklist + + diff --git a/lib/cklist_web/controllers/checklist_html/edit.html.heex b/lib/cklist_web/controllers/checklist_html/edit.html.heex new file mode 100644 index 0000000..46187dc --- /dev/null +++ b/lib/cklist_web/controllers/checklist_html/edit.html.heex @@ -0,0 +1,8 @@ +<.header> + Edit Checklist <%= @checklist.id %> + <:subtitle>Use this form to manage checklist records in your database. + + +<.checklist_form changeset={@changeset} action={~p"/checklists/#{@checklist}"} /> + +<.back navigate={~p"/checklists"}>Back to checklists diff --git a/lib/cklist_web/controllers/checklist_html/index.html.heex b/lib/cklist_web/controllers/checklist_html/index.html.heex new file mode 100644 index 0000000..aaf88c0 --- /dev/null +++ b/lib/cklist_web/controllers/checklist_html/index.html.heex @@ -0,0 +1,25 @@ +<.header> + Listing Checklists + <:actions> + <.link href={~p"/checklists/new"}> + <.button>New Checklist + + + + +<.table id="checklists" rows={@checklists} row_click={&JS.navigate(~p"/checklists/#{&1}")}> + <:col :let={checklist} label="Title"><%= checklist.title %> + <:col :let={checklist} label="Description"><%= checklist.description %> + <:col :let={checklist} label="Document"><%= checklist.document %> + <:action :let={checklist}> +
+ <%= @current_users.email %> +
+ <.link + href={~p"/users/settings"} + class="hover:text-zinc-700" + > + Settings + + <.link + href={~p"/users/log_out"} + method="delete" + class="hover:text-zinc-700" + > + Log out + + <% else %> + <.link + href={~p"/users/register"} + class="hover:text-zinc-700" + > + Register + + <.link + href={~p"/users/log_in"} + class="hover:text-zinc-700" + > + Log in + + <% end %> + +