From 8269dbb52dca1d7c4fc687a717180859af51f68d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rio=20Rodrigues?= Date: Fri, 7 Apr 2023 16:53:23 +0100 Subject: [PATCH 1/3] Allow users to apply for yearbook class --- lib/yearbook/university.ex | 29 +++++++ lib/yearbook/university/class_student.ex | 4 +- .../{admin => }/class_live/form_component.ex | 2 +- .../class_live/form_component.html.heex | 0 .../live/{admin => }/class_live/index.ex | 2 +- .../{admin => }/class_live/index.html.heex | 35 ++++---- .../live/{admin => }/class_live/show.ex | 2 +- .../{admin => }/class_live/show.html.heex | 4 +- lib/yearbook_web/live/yearbook_live/show.ex | 29 +++++++ .../live/yearbook_live/show.html.heex | 85 ++++++++++--------- lib/yearbook_web/router.ex | 15 ++-- .../templates/layout/_auth_menu.html.heex | 2 +- .../templates/layout/_header.html.heex | 2 +- lib/yearbook_web/views/layout_view.ex | 2 +- ...20220708135025_create_classes_students.exs | 2 +- priv/repo/seeds.exs | 2 +- .../live/admin/class_live_test.exs | 12 +-- 17 files changed, 151 insertions(+), 78 deletions(-) rename lib/yearbook_web/live/{admin => }/class_live/form_component.ex (96%) rename lib/yearbook_web/live/{admin => }/class_live/form_component.html.heex (100%) rename lib/yearbook_web/live/{admin => }/class_live/index.ex (95%) rename lib/yearbook_web/live/{admin => }/class_live/index.html.heex (56%) rename lib/yearbook_web/live/{admin => }/class_live/show.ex (90%) rename lib/yearbook_web/live/{admin => }/class_live/show.html.heex (60%) diff --git a/lib/yearbook/university.ex b/lib/yearbook/university.ex index a7d19e6..a947009 100644 --- a/lib/yearbook/university.ex +++ b/lib/yearbook/university.ex @@ -295,4 +295,33 @@ defmodule Yearbook.University do def change_class(%Class{} = class, attrs \\ %{}) do Class.changeset(class, attrs) end + + alias Yearbook.University.ClassStudent + + def create_class_student(attrs \\ %{}) do + aluno = get_all_classes_students(attrs["student_id"], attrs["class_id"]) + + if aluno > 0 do + {:error, %Ecto.Changeset{}} + else + %ClassStudent{} + |> ClassStudent.changeset(attrs) + |> Repo.insert() + end + end + + def get_all_classes_students(student_id, class_id) do + ClassStudent + |> where(student_id: ^student_id) + |> where(class_id: ^class_id) + |> Repo.all() + |> Enum.count() + end + + def get_classes_students(student_id) do + ClassStudent + |> where(student_id: ^student_id) + |> where(accepted: true) + |> Repo.all() + end end diff --git a/lib/yearbook/university/class_student.ex b/lib/yearbook/university/class_student.ex index be51d19..5fe1e3b 100644 --- a/lib/yearbook/university/class_student.ex +++ b/lib/yearbook/university/class_student.ex @@ -11,14 +11,14 @@ defmodule Yearbook.University.ClassStudent do schema "classes_students" do belongs_to :class, University.Class belongs_to :student, Accounts.User - + field :accepted, :boolean, default: false timestamps() end @doc false def changeset(class_student, attrs) do class_student - |> cast(attrs, [:class_id, :student_id]) + |> cast(attrs, [:class_id, :student_id, :accepted]) |> validate_required([:class_id, :student_id]) |> unique_constraint([:class_id, :student_id]) end diff --git a/lib/yearbook_web/live/admin/class_live/form_component.ex b/lib/yearbook_web/live/class_live/form_component.ex similarity index 96% rename from lib/yearbook_web/live/admin/class_live/form_component.ex rename to lib/yearbook_web/live/class_live/form_component.ex index 1285766..0023999 100644 --- a/lib/yearbook_web/live/admin/class_live/form_component.ex +++ b/lib/yearbook_web/live/class_live/form_component.ex @@ -1,4 +1,4 @@ -defmodule YearbookWeb.Admin.ClassLive.FormComponent do +defmodule YearbookWeb.ClassLive.FormComponent do @moduledoc false use YearbookWeb, :live_component diff --git a/lib/yearbook_web/live/admin/class_live/form_component.html.heex b/lib/yearbook_web/live/class_live/form_component.html.heex similarity index 100% rename from lib/yearbook_web/live/admin/class_live/form_component.html.heex rename to lib/yearbook_web/live/class_live/form_component.html.heex diff --git a/lib/yearbook_web/live/admin/class_live/index.ex b/lib/yearbook_web/live/class_live/index.ex similarity index 95% rename from lib/yearbook_web/live/admin/class_live/index.ex rename to lib/yearbook_web/live/class_live/index.ex index 2e6c130..01fb4ca 100644 --- a/lib/yearbook_web/live/admin/class_live/index.ex +++ b/lib/yearbook_web/live/class_live/index.ex @@ -1,4 +1,4 @@ -defmodule YearbookWeb.Admin.ClassLive.Index do +defmodule YearbookWeb.ClassLive.Index do @moduledoc false use YearbookWeb, :live_view diff --git a/lib/yearbook_web/live/admin/class_live/index.html.heex b/lib/yearbook_web/live/class_live/index.html.heex similarity index 56% rename from lib/yearbook_web/live/admin/class_live/index.html.heex rename to lib/yearbook_web/live/class_live/index.html.heex index cba82c9..351d324 100644 --- a/lib/yearbook_web/live/admin/class_live/index.html.heex +++ b/lib/yearbook_web/live/class_live/index.html.heex @@ -3,18 +3,20 @@

Lista de Turmas

-
- <%= live_patch to: Routes.admin_class_index_path(@socket, :new) do %> - - <% end %> -
+ <%= if assigns[:current_user] && (@current_user.permissions == [:admin, :sysadmin] || @current_user.permissions == [:admin] || @current_user.permissions == [:sysadmin]) do %> +
+ <%= live_patch to: Routes.admin_class_index_path(@socket, :new) do %> + + <% end %> +
+ <% end %> <%= if @live_action in [:new, :edit] do %> - <.modal return_to={Routes.admin_class_index_path(@socket, :index)}> - <.live_component module={YearbookWeb.Admin.ClassLive.FormComponent} id={@class.id || :new} title={@page_title} action={@live_action} class={@class} return_to={Routes.admin_class_index_path(@socket, :index)} /> + <.modal return_to={Routes.class_index_path(@socket, :index)}> + <.live_component module={YearbookWeb.ClassLive.FormComponent} id={@class.id || :new} title={@page_title} action={@live_action} class={@class} return_to={Routes.class_index_path(@socket, :index)} /> <% end %> @@ -46,15 +48,16 @@ <%= live_redirect to: Routes.yearbook_show_path(@socket, :show, class), class: "text-orange-600 hover:text-orange-900" do %> - Show - <% end %> - - <%= live_patch to: Routes.admin_class_index_path(@socket, :edit, class), class: "text-orange-600 hover:text-orange-900" do %> - Edit + Ver <% end %> + <%= if assigns[:current_user] && (@current_user.permissions == [:admin, :sysadmin] || @current_user.permissions == [:admin] || @current_user.permissions == [:sysadmin]) do %> + <%= live_patch to: Routes.admin_class_index_path(@socket, :edit, class), class: "text-orange-600 hover:text-orange-900" do %> + Edit + <% end %> - <%= link to: "#", phx_click: "delete", phx_value_id: class.id, data: [confirm: "Are you sure?"], class: "text-orange-600 hover:text-orange-900" do %> - DeleteDelete + <%= link to: "#", phx_click: "delete", phx_value_id: class.id, data: [confirm: "Are you sure?"], class: "text-orange-600 hover:text-orange-900" do %> + DeleteDelete + <% end %> <% end %> diff --git a/lib/yearbook_web/live/admin/class_live/show.ex b/lib/yearbook_web/live/class_live/show.ex similarity index 90% rename from lib/yearbook_web/live/admin/class_live/show.ex rename to lib/yearbook_web/live/class_live/show.ex index 8295a2f..1267954 100644 --- a/lib/yearbook_web/live/admin/class_live/show.ex +++ b/lib/yearbook_web/live/class_live/show.ex @@ -1,4 +1,4 @@ -defmodule YearbookWeb.Admin.ClassLive.Show do +defmodule YearbookWeb.ClassLive.Show do @moduledoc false use YearbookWeb, :live_view diff --git a/lib/yearbook_web/live/admin/class_live/show.html.heex b/lib/yearbook_web/live/class_live/show.html.heex similarity index 60% rename from lib/yearbook_web/live/admin/class_live/show.html.heex rename to lib/yearbook_web/live/class_live/show.html.heex index bf28104..a82cc7a 100644 --- a/lib/yearbook_web/live/admin/class_live/show.html.heex +++ b/lib/yearbook_web/live/class_live/show.html.heex @@ -3,7 +3,7 @@ <%= if @live_action in [:edit] do %> <.modal return_to={Routes.admin_class_show_path(@socket, :show, @class)}> - <.live_component module={YearbookWeb.Admin.ClassLive.FormComponent} id={@class.id} title={@page_title} action={@live_action} class={@class} return_to={Routes.admin_class_show_path(@socket, :show, @class)} /> + <.live_component module={YearbookWeb.ClassLive.FormComponent} id={@class.id} title={@page_title} action={@live_action} class={@class} return_to={Routes.admin_class_show_path(@socket, :show, @class)} /> <% end %> @@ -14,5 +14,5 @@ - <%= live_patch("Edit", to: Routes.admin_class_show_path(@socket, :edit, @class), class: "button") %> | <%= live_redirect("Back", to: Routes.admin_class_index_path(@socket, :index)) %> + <%= live_patch("Edit", to: Routes.admin_class_show_path(@socket, :edit, @class), class: "button") %> | <%= live_redirect("Back", to: Routes.class_index_path(@socket, :index)) %> diff --git a/lib/yearbook_web/live/yearbook_live/show.ex b/lib/yearbook_web/live/yearbook_live/show.ex index 69f8464..fd83c25 100644 --- a/lib/yearbook_web/live/yearbook_live/show.ex +++ b/lib/yearbook_web/live/yearbook_live/show.ex @@ -10,6 +10,29 @@ defmodule YearbookWeb.YearbookLive.Show do {:ok, socket} end + @impl true + def handle_event("apply", _payload, socket) do + attrs = %{ + "class_id" => socket.assigns.class.id, + "student_id" => socket.assigns.current_user.id, + "accepted" => false + } + + case University.create_class_student(attrs) do + {:ok, _class_student} -> + {:noreply, + socket + |> put_flash(:info, "Applied to class successfully") + |> push_redirect(to: Routes.class_index_path(socket, :index))} + + {:error, %Ecto.Changeset{} = changeset} -> + {:noreply, + assign(socket, :changeset, changeset) + |> put_flash(:error, "You have already applied to this class") + |> push_redirect(to: Routes.class_index_path(socket, :index))} + end + end + @impl true def handle_params(%{"class_id" => id}, _, socket) do class = University.get_class!(id, [:students, :degree, :academic_year]) @@ -19,4 +42,10 @@ defmodule YearbookWeb.YearbookLive.Show do |> assign(:page_title, class.degree.name) |> assign(:class, class)} end + + def is_accepted?(student, class) do + classes = University.get_classes_students(student) + + Enum.any?(classes, fn cs -> cs.accepted == true && cs.class_id == class end) + end end diff --git a/lib/yearbook_web/live/yearbook_live/show.html.heex b/lib/yearbook_web/live/yearbook_live/show.html.heex index e2e302e..eacbb41 100644 --- a/lib/yearbook_web/live/yearbook_live/show.html.heex +++ b/lib/yearbook_web/live/yearbook_live/show.html.heex @@ -10,48 +10,57 @@
+ <%= if @current_user && Yearbook.University.get_classes_students(@current_user.id) == [] && (@current_user.permissions != [:admin, :sysadmin] || @current_user.permissions != [:admin] || @current_user.permissions != [:sysadmin]) do %> +
+ +
+ <% end %>
    <%= for student <- @class.students do %> -
  • -
    - <%= if is_nil(student.avatar) do %> -
    - - <%= extract_initials(student.name) %> - + <%= if is_accepted?(student.id, @class.id) do %> +
  • +
    + <%= if is_nil(student.avatar) do %> +
    + + <%= extract_initials(student.name) %> + +
    + <% else %> + + <% end %> +
    +
    +

    <%= student.name %>

    +
    +
    - <% else %> - - <% end %> -
    -
    -

    <%= student.name %>

    -
    -
    -
    -
  • + + <% end %> <% end %>
diff --git a/lib/yearbook_web/router.ex b/lib/yearbook_web/router.ex index 4cbb963..140140c 100644 --- a/lib/yearbook_web/router.ex +++ b/lib/yearbook_web/router.ex @@ -23,7 +23,6 @@ defmodule YearbookWeb.Router do scope "/", YearbookWeb do pipe_through :browser - get "/", PageController, :index get "/contacts", PageController, :contacts get "/terms", PageController, :terms @@ -59,6 +58,15 @@ defmodule YearbookWeb.Router do live_session :logged_in, on_mount: [{YearbookWeb.Hooks, :current_user}] do live "/yearbook/:class_id", YearbookLive.Show, :show + live "/classes", ClassLive.Index, :index + + scope "/admin", as: :admin do + pipe_through :require_admin_user + + live "/classes/new", ClassLive.Index, :new + live "/classes/:id/edit", ClassLive.Index, :edit + live "/classes/:id/show/edit", ClassLive.Show, :edit + end scope "/admin", Admin, as: :admin do pipe_through :require_admin_user @@ -74,11 +82,6 @@ defmodule YearbookWeb.Router do live "/degrees/:id/edit", DegreeLive.Index, :edit live "/degrees/:id", DegreeLive.Show, :show live "/degrees/:id/show/edit", DegreeLive.Show, :edit - - live "/classes", ClassLive.Index, :index - live "/classes/new", ClassLive.Index, :new - live "/classes/:id/edit", ClassLive.Index, :edit - live "/classes/:id/show/edit", ClassLive.Show, :edit end end end diff --git a/lib/yearbook_web/templates/layout/_auth_menu.html.heex b/lib/yearbook_web/templates/layout/_auth_menu.html.heex index 8ff549f..3a34929 100644 --- a/lib/yearbook_web/templates/layout/_auth_menu.html.heex +++ b/lib/yearbook_web/templates/layout/_auth_menu.html.heex @@ -1,4 +1,4 @@ -<%= if @current_user do %> +<%= if assigns[:current_user] do %>
<%= if is_nil(@current_user.avatar) do %> diff --git a/lib/yearbook_web/templates/layout/_header.html.heex b/lib/yearbook_web/templates/layout/_header.html.heex index 1b6c5a5..50a6aad 100644 --- a/lib/yearbook_web/templates/layout/_header.html.heex +++ b/lib/yearbook_web/templates/layout/_header.html.heex @@ -4,7 +4,7 @@
CeSIUM - <%= if @current_user do %> + <%= if assigns[:current_user] do %> CeSIUM's Logo <% else %> CeSIUM's Logo diff --git a/lib/yearbook_web/views/layout_view.ex b/lib/yearbook_web/views/layout_view.ex index cb3aebe..412d62c 100644 --- a/lib/yearbook_web/views/layout_view.ex +++ b/lib/yearbook_web/views/layout_view.ex @@ -25,7 +25,7 @@ defmodule YearbookWeb.LayoutView do }, %{ title: "Turmas", - path: Routes.admin_class_index_path(@conn, :index) + path: Routes.class_index_path(@conn, :index) } ] end diff --git a/priv/repo/migrations/20220708135025_create_classes_students.exs b/priv/repo/migrations/20220708135025_create_classes_students.exs index 980937a..2e97917 100644 --- a/priv/repo/migrations/20220708135025_create_classes_students.exs +++ b/priv/repo/migrations/20220708135025_create_classes_students.exs @@ -6,7 +6,7 @@ defmodule Yearbook.Repo.Migrations.CreateClassesStudents do add :id, :binary_id, primary_key: true add :class_id, references(:classes, on_delete: :nothing, type: :binary_id) add :student_id, references(:users, on_delete: :nothing, type: :binary_id) - + add :accepted, :boolean, default: false timestamps() end diff --git a/priv/repo/seeds.exs b/priv/repo/seeds.exs index d19956c..18cfd0b 100644 --- a/priv/repo/seeds.exs +++ b/priv/repo/seeds.exs @@ -136,7 +136,7 @@ for degree <- [lei, mei, miei, dei], |> Repo.update!() %ClassStudent{} - |> ClassStudent.changeset(%{student_id: student.id, class_id: class.id}) + |> ClassStudent.changeset(%{student_id: student.id, class_id: class.id, accepted: true}) |> Repo.insert!() end) end diff --git a/test/yearbook_web/live/admin/class_live_test.exs b/test/yearbook_web/live/admin/class_live_test.exs index f8b8c19..95e8728 100644 --- a/test/yearbook_web/live/admin/class_live_test.exs +++ b/test/yearbook_web/live/admin/class_live_test.exs @@ -26,13 +26,13 @@ defmodule YearbookWeb.Admin.ClassLiveTest do setup [:register_and_log_in_admin_user, :create_class, :create_degree, :create_academic_year] test "lists all classes", %{conn: conn} do - {:ok, _index_live, html} = live(conn, Routes.admin_class_index_path(conn, :index)) + {:ok, _index_live, html} = live(conn, Routes.class_index_path(conn, :index)) assert html =~ "Listing Classes" end test "saves new class", %{conn: conn, degree: degree, academic_year: academic_year} do - {:ok, index_live, _html} = live(conn, Routes.admin_class_index_path(conn, :index)) + {:ok, index_live, _html} = live(conn, Routes.class_index_path(conn, :index)) assert index_live |> element("a", "Nova Turma") |> render_click() =~ "Nova Turma" @@ -49,13 +49,13 @@ defmodule YearbookWeb.Admin.ClassLiveTest do class: %{year: 1, degree_id: degree.id, academic_year_id: academic_year.id} ) |> render_submit() - |> follow_redirect(conn, Routes.admin_class_index_path(conn, :index)) + |> follow_redirect(conn, Routes.class_index_path(conn, :index)) assert html =~ "Class created successfully" end test "updates class in listing", %{conn: conn, class: class} do - {:ok, index_live, _html} = live(conn, Routes.admin_class_index_path(conn, :index)) + {:ok, index_live, _html} = live(conn, Routes.class_index_path(conn, :index)) assert index_live |> element("#class-#{class.id} a", "Edit") |> render_click() =~ "Edit Class" @@ -70,13 +70,13 @@ defmodule YearbookWeb.Admin.ClassLiveTest do index_live |> form("#class-form", class: @update_attrs) |> render_submit() - |> follow_redirect(conn, Routes.admin_class_index_path(conn, :index)) + |> follow_redirect(conn, Routes.class_index_path(conn, :index)) assert html =~ "Class updated successfully" end test "deletes class in listing", %{conn: conn, class: class} do - {:ok, index_live, _html} = live(conn, Routes.admin_class_index_path(conn, :index)) + {:ok, index_live, _html} = live(conn, Routes.class_index_path(conn, :index)) assert index_live |> element("#class-#{class.id} a", "Delete") |> render_click() refute has_element?(index_live, "#class-#{class.id}") From 96e48e4c6419b8bfe01af46826e5335a484fc107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rio=20Rodrigues?= Date: Fri, 7 Apr 2023 22:17:57 +0100 Subject: [PATCH 2/3] Implement suggestions --- lib/yearbook/university.ex | 8 ++++---- lib/yearbook_web/live/yearbook_live/show.ex | 4 ++-- lib/yearbook_web/live/yearbook_live/show.html.heex | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/yearbook/university.ex b/lib/yearbook/university.ex index a947009..aff2d6c 100644 --- a/lib/yearbook/university.ex +++ b/lib/yearbook/university.ex @@ -299,9 +299,9 @@ defmodule Yearbook.University do alias Yearbook.University.ClassStudent def create_class_student(attrs \\ %{}) do - aluno = get_all_classes_students(attrs["student_id"], attrs["class_id"]) + student = list_classes_student(attrs["student_id"], attrs["class_id"]) - if aluno > 0 do + if student > 0 do {:error, %Ecto.Changeset{}} else %ClassStudent{} @@ -310,7 +310,7 @@ defmodule Yearbook.University do end end - def get_all_classes_students(student_id, class_id) do + def list_classes_student(student_id, class_id) do ClassStudent |> where(student_id: ^student_id) |> where(class_id: ^class_id) @@ -318,7 +318,7 @@ defmodule Yearbook.University do |> Enum.count() end - def get_classes_students(student_id) do + def list_student_classes(student_id) do ClassStudent |> where(student_id: ^student_id) |> where(accepted: true) diff --git a/lib/yearbook_web/live/yearbook_live/show.ex b/lib/yearbook_web/live/yearbook_live/show.ex index fd83c25..5ead27e 100644 --- a/lib/yearbook_web/live/yearbook_live/show.ex +++ b/lib/yearbook_web/live/yearbook_live/show.ex @@ -43,8 +43,8 @@ defmodule YearbookWeb.YearbookLive.Show do |> assign(:class, class)} end - def is_accepted?(student, class) do - classes = University.get_classes_students(student) + defp is_accepted?(student, class) do + classes = University.list_student_classes(student) Enum.any?(classes, fn cs -> cs.accepted == true && cs.class_id == class end) end diff --git a/lib/yearbook_web/live/yearbook_live/show.html.heex b/lib/yearbook_web/live/yearbook_live/show.html.heex index eacbb41..8dc5c15 100644 --- a/lib/yearbook_web/live/yearbook_live/show.html.heex +++ b/lib/yearbook_web/live/yearbook_live/show.html.heex @@ -10,7 +10,7 @@
- <%= if @current_user && Yearbook.University.get_classes_students(@current_user.id) == [] && (@current_user.permissions != [:admin, :sysadmin] || @current_user.permissions != [:admin] || @current_user.permissions != [:sysadmin]) do %> + <%= if @current_user && Yearbook.University.list_student_classes(@current_user.id) == [] && (@current_user.permissions != [:admin, :sysadmin] || @current_user.permissions != [:admin] || @current_user.permissions != [:sysadmin]) do %>