From 6e6b893df37beb2b680f6a59cdd5b1f69620a146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lobo?= Date: Wed, 5 Jul 2023 15:59:30 +0100 Subject: [PATCH 01/42] Initial role based routing --- lib/atomic_web/allowed_roles.ex | 18 ++++++++++++++++++ lib/atomic_web/router.ex | 10 +++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 lib/atomic_web/allowed_roles.ex diff --git a/lib/atomic_web/allowed_roles.ex b/lib/atomic_web/allowed_roles.ex new file mode 100644 index 000000000..702d53b68 --- /dev/null +++ b/lib/atomic_web/allowed_roles.ex @@ -0,0 +1,18 @@ +defmodule AtomicWeb.Auth.AllowedRoles do + @moduledoc false + import Plug.Conn + + def init(opts), do: opts + + def call(conn, opts) do + + if conn.assigns.current_user.role in opts do + conn + else + conn + |> send_resp(:not_found, "") + |> halt() + end + end + +end diff --git a/lib/atomic_web/router.ex b/lib/atomic_web/router.ex index 2885a0993..de9c0ed92 100644 --- a/lib/atomic_web/router.ex +++ b/lib/atomic_web/router.ex @@ -17,6 +17,14 @@ defmodule AtomicWeb.Router do plug :accepts, ["json"] end + pipeline :admin do + plug AtomicWeb.Auth.AllowedRoles, [:admin] + end + + pipeline :staff do + plug AtomicWeb.Auth.AllowedRoles, [:staff, :admin] + end + scope "/", AtomicWeb do pipe_through :browser @@ -24,7 +32,7 @@ defmodule AtomicWeb.Router do end scope "/", AtomicWeb do - pipe_through [:browser, :require_authenticated_user] + pipe_through [:browser, :require_authenticated_user, :admin] live_session :logged_in, on_mount: [{AtomicWeb.Hooks, :current_user}] do live "/scanner", ScannerLive.Index, :index From 582f36e2fa9c4e0c5613b8e5eda64ba44bace7c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lobo?= Date: Thu, 6 Jul 2023 01:54:11 +0100 Subject: [PATCH 02/42] Add membership status to conn assigns to retrieve role and protect routes --- lib/atomic/accounts.ex | 1 + lib/atomic/organizations.ex | 20 ++++++++++++++++++++ lib/atomic_web/allowed_roles.ex | 2 +- lib/atomic_web/controllers/user_auth.ex | 14 +++++++++++++- lib/atomic_web/router.ex | 10 +++++----- 5 files changed, 40 insertions(+), 7 deletions(-) diff --git a/lib/atomic/accounts.ex b/lib/atomic/accounts.ex index 0fd35f28e..22f9b7e14 100644 --- a/lib/atomic/accounts.ex +++ b/lib/atomic/accounts.ex @@ -267,6 +267,7 @@ defmodule Atomic.Accounts do def get_user_by_session_token(token) do {:ok, query} = UserToken.verify_session_token_query(token) Repo.one(query) + |> Repo.preload(:organizations) end @doc """ diff --git a/lib/atomic/organizations.ex b/lib/atomic/organizations.ex index 26bb50761..8eb1de7db 100644 --- a/lib/atomic/organizations.ex +++ b/lib/atomic/organizations.ex @@ -188,6 +188,26 @@ defmodule Atomic.Organizations do |> Repo.preload(preloads) end + @doc """ + Gets a membership between a user and an organization. + + Raises `Ecto.NoResultsError` if the membership does not exist. + + ## Examples + + iex> get_membership_by_organization_user!(%User{}, %Organization{}) + %membership{} + + iex> get_membership_by_organization_user!(%User{}, %Organization{}) + ** (Ecto.NoResultsError) + + """ + def get_membership_by_organization_user!(%User{} = user, %Organization{} = organization) do + Membership + |> where([m], m.user_id == ^user.id and m.organization_id == ^organization.id) + |> Repo.one() + end + @doc """ Updates an membership. diff --git a/lib/atomic_web/allowed_roles.ex b/lib/atomic_web/allowed_roles.ex index 702d53b68..3de386b47 100644 --- a/lib/atomic_web/allowed_roles.ex +++ b/lib/atomic_web/allowed_roles.ex @@ -6,7 +6,7 @@ defmodule AtomicWeb.Auth.AllowedRoles do def call(conn, opts) do - if conn.assigns.current_user.role in opts do + if conn.assigns.current_membership[:role] in opts do conn else conn diff --git a/lib/atomic_web/controllers/user_auth.ex b/lib/atomic_web/controllers/user_auth.ex index 134b17634..ad0234c72 100644 --- a/lib/atomic_web/controllers/user_auth.ex +++ b/lib/atomic_web/controllers/user_auth.ex @@ -6,6 +6,7 @@ defmodule AtomicWeb.UserAuth do import Phoenix.Controller alias Atomic.Accounts + alias Atomic.Organizations alias AtomicWeb.Router.Helpers, as: Routes # Make the remember me cookie valid for 60 days. @@ -94,7 +95,10 @@ defmodule AtomicWeb.UserAuth do def fetch_current_user(conn, _opts) do {user_token, conn} = ensure_user_token(conn) user = user_token && Accounts.get_user_by_session_token(user_token) - assign(conn, :current_user, user) + membership = get_default_membership(user) + conn + |> assign(:current_user, user) + |> assign(:current_membership, membership) end defp ensure_user_token(conn) do @@ -111,6 +115,14 @@ defmodule AtomicWeb.UserAuth do end end + defp get_default_membership(user) do + organization = List.first(user.organizations) + + role = Organizations.get_membership_by_organization_user!(user, organization).role + + %{organization: organization, role: role} + end + @doc """ Used for routes that require the user to not be authenticated. """ diff --git a/lib/atomic_web/router.ex b/lib/atomic_web/router.ex index de9c0ed92..bccfcded3 100644 --- a/lib/atomic_web/router.ex +++ b/lib/atomic_web/router.ex @@ -17,12 +17,12 @@ defmodule AtomicWeb.Router do plug :accepts, ["json"] end - pipeline :admin do - plug AtomicWeb.Auth.AllowedRoles, [:admin] + pipeline :organization_owner do + plug AtomicWeb.Auth.AllowedRoles, [:owner] end - pipeline :staff do - plug AtomicWeb.Auth.AllowedRoles, [:staff, :admin] + pipeline :organization_admin do + plug AtomicWeb.Auth.AllowedRoles, [:admin, :owner] end scope "/", AtomicWeb do @@ -32,7 +32,7 @@ defmodule AtomicWeb.Router do end scope "/", AtomicWeb do - pipe_through [:browser, :require_authenticated_user, :admin] + pipe_through [:browser, :require_authenticated_user, :organization_admin] live_session :logged_in, on_mount: [{AtomicWeb.Hooks, :current_user}] do live "/scanner", ScannerLive.Index, :index From 80b03ce6b3db8912f9e65ccc4d301d26a7b7b7ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lobo?= Date: Sat, 8 Jul 2023 22:59:53 +0100 Subject: [PATCH 03/42] Add organization parameter to department routes --- lib/atomic/departments.ex | 13 ++++++++++++ lib/atomic/organizations.ex | 20 ------------------- lib/atomic_web/allowed_roles.ex | 18 ----------------- lib/atomic_web/controllers/user_auth.ex | 20 +++++++++---------- lib/atomic_web/live/department_live/index.ex | 12 +++++------ .../live/department_live/index.html.heex | 12 +++++------ .../live/department_live/show.html.heex | 8 ++++---- lib/atomic_web/live/hooks.ex | 8 +++++++- lib/atomic_web/router.ex | 20 ++++++------------- .../templates/layout/root.html.heex | 14 +++++++------ 10 files changed, 59 insertions(+), 86 deletions(-) delete mode 100644 lib/atomic_web/allowed_roles.ex diff --git a/lib/atomic/departments.ex b/lib/atomic/departments.ex index 74237c80c..024435cb4 100644 --- a/lib/atomic/departments.ex +++ b/lib/atomic/departments.ex @@ -21,6 +21,19 @@ defmodule Atomic.Departments do Repo.all(Department) end + @doc """ + Returns the list of departments belonging to an organization. + + ## Examples + + iex> list_departments_by_organization_id(99d7c9e5-4212-4f59-a097-28aaa33c2621) + [%Department{}, ...] + + """ + def list_departments_by_organization_id(id) do + Repo.all(from d in Department, where: d.organization_id == ^id) + end + def get_departments(nil), do: [] def get_departments(ids) do diff --git a/lib/atomic/organizations.ex b/lib/atomic/organizations.ex index 8eb1de7db..26bb50761 100644 --- a/lib/atomic/organizations.ex +++ b/lib/atomic/organizations.ex @@ -188,26 +188,6 @@ defmodule Atomic.Organizations do |> Repo.preload(preloads) end - @doc """ - Gets a membership between a user and an organization. - - Raises `Ecto.NoResultsError` if the membership does not exist. - - ## Examples - - iex> get_membership_by_organization_user!(%User{}, %Organization{}) - %membership{} - - iex> get_membership_by_organization_user!(%User{}, %Organization{}) - ** (Ecto.NoResultsError) - - """ - def get_membership_by_organization_user!(%User{} = user, %Organization{} = organization) do - Membership - |> where([m], m.user_id == ^user.id and m.organization_id == ^organization.id) - |> Repo.one() - end - @doc """ Updates an membership. diff --git a/lib/atomic_web/allowed_roles.ex b/lib/atomic_web/allowed_roles.ex deleted file mode 100644 index 3de386b47..000000000 --- a/lib/atomic_web/allowed_roles.ex +++ /dev/null @@ -1,18 +0,0 @@ -defmodule AtomicWeb.Auth.AllowedRoles do - @moduledoc false - import Plug.Conn - - def init(opts), do: opts - - def call(conn, opts) do - - if conn.assigns.current_membership[:role] in opts do - conn - else - conn - |> send_resp(:not_found, "") - |> halt() - end - end - -end diff --git a/lib/atomic_web/controllers/user_auth.ex b/lib/atomic_web/controllers/user_auth.ex index ad0234c72..bec487771 100644 --- a/lib/atomic_web/controllers/user_auth.ex +++ b/lib/atomic_web/controllers/user_auth.ex @@ -6,7 +6,6 @@ defmodule AtomicWeb.UserAuth do import Phoenix.Controller alias Atomic.Accounts - alias Atomic.Organizations alias AtomicWeb.Router.Helpers, as: Routes # Make the remember me cookie valid for 60 days. @@ -95,10 +94,17 @@ defmodule AtomicWeb.UserAuth do def fetch_current_user(conn, _opts) do {user_token, conn} = ensure_user_token(conn) user = user_token && Accounts.get_user_by_session_token(user_token) - membership = get_default_membership(user) conn |> assign(:current_user, user) - |> assign(:current_membership, membership) + |> assign(:current_organization, get_default_organization(user)) + end + + defp get_default_organization(user) do + if user do + List.first(user.organizations) + else + nil + end end defp ensure_user_token(conn) do @@ -115,14 +121,6 @@ defmodule AtomicWeb.UserAuth do end end - defp get_default_membership(user) do - organization = List.first(user.organizations) - - role = Organizations.get_membership_by_organization_user!(user, organization).role - - %{organization: organization, role: role} - end - @doc """ Used for routes that require the user to not be authenticated. """ diff --git a/lib/atomic_web/live/department_live/index.ex b/lib/atomic_web/live/department_live/index.ex index 448207478..2bfe7b5d8 100644 --- a/lib/atomic_web/live/department_live/index.ex +++ b/lib/atomic_web/live/department_live/index.ex @@ -5,8 +5,8 @@ defmodule AtomicWeb.DepartmentLive.Index do alias Atomic.Departments.Department @impl true - def mount(_params, _session, socket) do - {:ok, assign(socket, :departments, list_departments())} + def mount(params, _session, socket) do + {:ok, assign(socket, :departments, list_departments(params["organization_id"]))} end @impl true @@ -33,14 +33,14 @@ defmodule AtomicWeb.DepartmentLive.Index do end @impl true - def handle_event("delete", %{"id" => id}, socket) do + def handle_event("delete", %{"id" => id, "organization_id" => organization_id}, socket) do department = Departments.get_department!(id) {:ok, _} = Departments.delete_department(department) - {:noreply, assign(socket, :departments, list_departments())} + {:noreply, assign(socket, :departments, list_departments(organization_id))} end - defp list_departments do - Departments.list_departments() + defp list_departments(id) do + Departments.list_departments_by_organization_id(id) end end diff --git a/lib/atomic_web/live/department_live/index.html.heex b/lib/atomic_web/live/department_live/index.html.heex index 475faa969..7f3b1a383 100644 --- a/lib/atomic_web/live/department_live/index.html.heex +++ b/lib/atomic_web/live/department_live/index.html.heex @@ -1,8 +1,8 @@

Listing Departments

<%= if @live_action in [:new, :edit] do %> - <.modal return_to={Routes.department_index_path(@socket, :index)}> - <.live_component module={AtomicWeb.DepartmentLive.FormComponent} id={@department.id || :new} title={@page_title} action={@live_action} department={@department} return_to={Routes.department_index_path(@socket, :index)} /> + <.modal return_to={Routes.department_index_path(@socket, :index, @current_organization)}> + <.live_component module={AtomicWeb.DepartmentLive.FormComponent} id={@department.id || :new} title={@page_title} action={@live_action} department={@department} return_to={Routes.department_index_path(@socket, :index, @current_organization)} /> <% end %> @@ -20,13 +20,13 @@ <%= department.name %> - <%= live_redirect("Show", to: Routes.department_show_path(@socket, :show, department)) %> - <%= live_patch("Edit", to: Routes.department_index_path(@socket, :edit, department)) %> - <%= link("Delete", to: "#", phx_click: "delete", phx_value_id: department.id, data: [confirm: "Are you sure?"]) %> + <%= live_redirect("Show", to: Routes.department_show_path(@socket, :show, @current_organization, department)) %> + <%= live_patch("Edit", to: Routes.department_index_path(@socket, :edit, @current_organization, department)) %> + <%= link("Delete", to: "#", phx_click: "delete", phx_value_id: department.id, phx_value_organization_id: @current_organization.id, data: [confirm: "Are you sure?"]) %> <% end %> -<%= live_patch("New Department", to: Routes.department_index_path(@socket, :new)) %> +<%= live_patch("New Department", to: Routes.department_index_path(@socket, :new, @current_organization)) %> diff --git a/lib/atomic_web/live/department_live/show.html.heex b/lib/atomic_web/live/department_live/show.html.heex index 43b0aba44..241fd62c6 100644 --- a/lib/atomic_web/live/department_live/show.html.heex +++ b/lib/atomic_web/live/department_live/show.html.heex @@ -1,8 +1,8 @@

Show Department

<%= if @live_action in [:edit] do %> - <.modal return_to={Routes.department_show_path(@socket, :show, @department)}> - <.live_component module={AtomicWeb.DepartmentLive.FormComponent} id={@department.id} title={@page_title} action={@live_action} department={@department} return_to={Routes.department_show_path(@socket, :show, @department)} /> + <.modal return_to={Routes.department_show_path(@socket, :show, @current_organization, @department)}> + <.live_component module={AtomicWeb.DepartmentLive.FormComponent} id={@department.id} title={@page_title} action={@live_action} department={@department} return_to={Routes.department_show_path(@socket, :show, @current_organization, @department)} /> <% end %> @@ -24,5 +24,5 @@ -<%= live_patch("Edit", to: Routes.department_show_path(@socket, :edit, @department), class: "button") %> | -<%= live_redirect("Back", to: Routes.department_index_path(@socket, :index)) %> +<%= live_patch("Edit", to: Routes.department_show_path(@socket, :edit, @current_organization, @department), class: "button") %> | +<%= live_redirect("Back", to: Routes.department_index_path(@socket, :index, @current_organization)) %> diff --git a/lib/atomic_web/live/hooks.ex b/lib/atomic_web/live/hooks.ex index b9add6517..e895bccf4 100644 --- a/lib/atomic_web/live/hooks.ex +++ b/lib/atomic_web/live/hooks.ex @@ -12,8 +12,14 @@ defmodule AtomicWeb.Hooks do def on_mount(:current_user, _params, %{"user_token" => user_token}, socket) do current_user = Accounts.get_user_by_session_token(user_token) + current_organization = List.first(current_user.organizations) - {:cont, assign(socket, current_user: current_user)} + socket = + socket + |> assign(:current_user, current_user) + |> assign(:current_organization, current_organization) + + {:cont, socket} end def on_mount(:current_user, _params, _session, socket) do diff --git a/lib/atomic_web/router.ex b/lib/atomic_web/router.ex index bccfcded3..25840cdf8 100644 --- a/lib/atomic_web/router.ex +++ b/lib/atomic_web/router.ex @@ -17,14 +17,6 @@ defmodule AtomicWeb.Router do plug :accepts, ["json"] end - pipeline :organization_owner do - plug AtomicWeb.Auth.AllowedRoles, [:owner] - end - - pipeline :organization_admin do - plug AtomicWeb.Auth.AllowedRoles, [:admin, :owner] - end - scope "/", AtomicWeb do pipe_through :browser @@ -32,7 +24,7 @@ defmodule AtomicWeb.Router do end scope "/", AtomicWeb do - pipe_through [:browser, :require_authenticated_user, :organization_admin] + pipe_through [:browser, :require_authenticated_user] live_session :logged_in, on_mount: [{AtomicWeb.Hooks, :current_user}] do live "/scanner", ScannerLive.Index, :index @@ -42,11 +34,11 @@ defmodule AtomicWeb.Router do live "/activities/:id/edit", ActivityLive.Edit, :edit live "/activities/:id", ActivityLive.Show, :show - live "/departments", DepartmentLive.Index, :index - live "/departments/new", DepartmentLive.Index, :new - live "/departments/:id/edit", DepartmentLive.Index, :edit - live "/departments/:id", DepartmentLive.Show, :show - live "/departments/:id/show/edit", DepartmentLive.Show, :edit + live "/organizations/:organization_id/departments", DepartmentLive.Index, :index + live "/organizations/:organization_id/departments/new", DepartmentLive.Index, :new + live "/organizations/:organization_id/departments/:id/edit", DepartmentLive.Index, :edit + live "/organizations/:organization_id/departments/:id", DepartmentLive.Show, :show + live "/organizations/:organization_id/departments/:id/show/edit", DepartmentLive.Show, :edit live "/partners", PartnerLive.Index, :index live "/partners/new", PartnerLive.Index, :new diff --git a/lib/atomic_web/templates/layout/root.html.heex b/lib/atomic_web/templates/layout/root.html.heex index 6c32d70ed..ea955f775 100644 --- a/lib/atomic_web/templates/layout/root.html.heex +++ b/lib/atomic_web/templates/layout/root.html.heex @@ -15,12 +15,14 @@
From 75bafaeec5006613db3ed6a8f14fb37e36d821b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lobo?= Date: Wed, 5 Jul 2023 15:59:30 +0100 Subject: [PATCH 04/42] Initial role based routing --- lib/atomic_web/allowed_roles.ex | 18 ++++++++++++++++++ lib/atomic_web/router.ex | 10 +++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 lib/atomic_web/allowed_roles.ex diff --git a/lib/atomic_web/allowed_roles.ex b/lib/atomic_web/allowed_roles.ex new file mode 100644 index 000000000..702d53b68 --- /dev/null +++ b/lib/atomic_web/allowed_roles.ex @@ -0,0 +1,18 @@ +defmodule AtomicWeb.Auth.AllowedRoles do + @moduledoc false + import Plug.Conn + + def init(opts), do: opts + + def call(conn, opts) do + + if conn.assigns.current_user.role in opts do + conn + else + conn + |> send_resp(:not_found, "") + |> halt() + end + end + +end diff --git a/lib/atomic_web/router.ex b/lib/atomic_web/router.ex index 5313a2eb0..33634cc80 100644 --- a/lib/atomic_web/router.ex +++ b/lib/atomic_web/router.ex @@ -17,6 +17,14 @@ defmodule AtomicWeb.Router do plug :accepts, ["json"] end + pipeline :admin do + plug AtomicWeb.Auth.AllowedRoles, [:admin] + end + + pipeline :staff do + plug AtomicWeb.Auth.AllowedRoles, [:staff, :admin] + end + scope "/", AtomicWeb do pipe_through :browser @@ -24,7 +32,7 @@ defmodule AtomicWeb.Router do end scope "/", AtomicWeb do - pipe_through [:browser, :require_authenticated_user] + pipe_through [:browser, :require_authenticated_user, :admin] live_session :logged_in, on_mount: [{AtomicWeb.Hooks, :current_user}] do live "/scanner", ScannerLive.Index, :index From feebe5a43bb0d45d9f24cbfada01bec2a8ecb034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lobo?= Date: Thu, 6 Jul 2023 01:54:11 +0100 Subject: [PATCH 05/42] Add membership status to conn assigns to retrieve role and protect routes --- lib/atomic/accounts.ex | 1 + lib/atomic/organizations.ex | 20 ++++++++++++++++++++ lib/atomic_web/allowed_roles.ex | 2 +- lib/atomic_web/controllers/user_auth.ex | 14 +++++++++++++- lib/atomic_web/router.ex | 10 +++++----- 5 files changed, 40 insertions(+), 7 deletions(-) diff --git a/lib/atomic/accounts.ex b/lib/atomic/accounts.ex index 0fd35f28e..22f9b7e14 100644 --- a/lib/atomic/accounts.ex +++ b/lib/atomic/accounts.ex @@ -267,6 +267,7 @@ defmodule Atomic.Accounts do def get_user_by_session_token(token) do {:ok, query} = UserToken.verify_session_token_query(token) Repo.one(query) + |> Repo.preload(:organizations) end @doc """ diff --git a/lib/atomic/organizations.ex b/lib/atomic/organizations.ex index 26bb50761..8eb1de7db 100644 --- a/lib/atomic/organizations.ex +++ b/lib/atomic/organizations.ex @@ -188,6 +188,26 @@ defmodule Atomic.Organizations do |> Repo.preload(preloads) end + @doc """ + Gets a membership between a user and an organization. + + Raises `Ecto.NoResultsError` if the membership does not exist. + + ## Examples + + iex> get_membership_by_organization_user!(%User{}, %Organization{}) + %membership{} + + iex> get_membership_by_organization_user!(%User{}, %Organization{}) + ** (Ecto.NoResultsError) + + """ + def get_membership_by_organization_user!(%User{} = user, %Organization{} = organization) do + Membership + |> where([m], m.user_id == ^user.id and m.organization_id == ^organization.id) + |> Repo.one() + end + @doc """ Updates an membership. diff --git a/lib/atomic_web/allowed_roles.ex b/lib/atomic_web/allowed_roles.ex index 702d53b68..3de386b47 100644 --- a/lib/atomic_web/allowed_roles.ex +++ b/lib/atomic_web/allowed_roles.ex @@ -6,7 +6,7 @@ defmodule AtomicWeb.Auth.AllowedRoles do def call(conn, opts) do - if conn.assigns.current_user.role in opts do + if conn.assigns.current_membership[:role] in opts do conn else conn diff --git a/lib/atomic_web/controllers/user_auth.ex b/lib/atomic_web/controllers/user_auth.ex index 134b17634..ad0234c72 100644 --- a/lib/atomic_web/controllers/user_auth.ex +++ b/lib/atomic_web/controllers/user_auth.ex @@ -6,6 +6,7 @@ defmodule AtomicWeb.UserAuth do import Phoenix.Controller alias Atomic.Accounts + alias Atomic.Organizations alias AtomicWeb.Router.Helpers, as: Routes # Make the remember me cookie valid for 60 days. @@ -94,7 +95,10 @@ defmodule AtomicWeb.UserAuth do def fetch_current_user(conn, _opts) do {user_token, conn} = ensure_user_token(conn) user = user_token && Accounts.get_user_by_session_token(user_token) - assign(conn, :current_user, user) + membership = get_default_membership(user) + conn + |> assign(:current_user, user) + |> assign(:current_membership, membership) end defp ensure_user_token(conn) do @@ -111,6 +115,14 @@ defmodule AtomicWeb.UserAuth do end end + defp get_default_membership(user) do + organization = List.first(user.organizations) + + role = Organizations.get_membership_by_organization_user!(user, organization).role + + %{organization: organization, role: role} + end + @doc """ Used for routes that require the user to not be authenticated. """ diff --git a/lib/atomic_web/router.ex b/lib/atomic_web/router.ex index 33634cc80..8afe9c267 100644 --- a/lib/atomic_web/router.ex +++ b/lib/atomic_web/router.ex @@ -17,12 +17,12 @@ defmodule AtomicWeb.Router do plug :accepts, ["json"] end - pipeline :admin do - plug AtomicWeb.Auth.AllowedRoles, [:admin] + pipeline :organization_owner do + plug AtomicWeb.Auth.AllowedRoles, [:owner] end - pipeline :staff do - plug AtomicWeb.Auth.AllowedRoles, [:staff, :admin] + pipeline :organization_admin do + plug AtomicWeb.Auth.AllowedRoles, [:admin, :owner] end scope "/", AtomicWeb do @@ -32,7 +32,7 @@ defmodule AtomicWeb.Router do end scope "/", AtomicWeb do - pipe_through [:browser, :require_authenticated_user, :admin] + pipe_through [:browser, :require_authenticated_user, :organization_admin] live_session :logged_in, on_mount: [{AtomicWeb.Hooks, :current_user}] do live "/scanner", ScannerLive.Index, :index From 237d1ab4eb8c571fff02d9e34f614dd9a3b2ac5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lobo?= Date: Sat, 8 Jul 2023 22:59:53 +0100 Subject: [PATCH 06/42] Add organization parameter to department routes --- lib/atomic/departments.ex | 13 ++++++++++++ lib/atomic/organizations.ex | 20 ------------------- lib/atomic_web/allowed_roles.ex | 18 ----------------- lib/atomic_web/controllers/user_auth.ex | 20 +++++++++---------- lib/atomic_web/live/department_live/index.ex | 12 +++++------ .../live/department_live/index.html.heex | 10 +++++----- .../live/department_live/show.html.heex | 8 ++++---- lib/atomic_web/live/hooks.ex | 8 +++++++- lib/atomic_web/router.ex | 20 ++++++------------- .../templates/layout/root.html.heex | 13 +++++++----- 10 files changed, 58 insertions(+), 84 deletions(-) delete mode 100644 lib/atomic_web/allowed_roles.ex diff --git a/lib/atomic/departments.ex b/lib/atomic/departments.ex index 74237c80c..024435cb4 100644 --- a/lib/atomic/departments.ex +++ b/lib/atomic/departments.ex @@ -21,6 +21,19 @@ defmodule Atomic.Departments do Repo.all(Department) end + @doc """ + Returns the list of departments belonging to an organization. + + ## Examples + + iex> list_departments_by_organization_id(99d7c9e5-4212-4f59-a097-28aaa33c2621) + [%Department{}, ...] + + """ + def list_departments_by_organization_id(id) do + Repo.all(from d in Department, where: d.organization_id == ^id) + end + def get_departments(nil), do: [] def get_departments(ids) do diff --git a/lib/atomic/organizations.ex b/lib/atomic/organizations.ex index 8eb1de7db..26bb50761 100644 --- a/lib/atomic/organizations.ex +++ b/lib/atomic/organizations.ex @@ -188,26 +188,6 @@ defmodule Atomic.Organizations do |> Repo.preload(preloads) end - @doc """ - Gets a membership between a user and an organization. - - Raises `Ecto.NoResultsError` if the membership does not exist. - - ## Examples - - iex> get_membership_by_organization_user!(%User{}, %Organization{}) - %membership{} - - iex> get_membership_by_organization_user!(%User{}, %Organization{}) - ** (Ecto.NoResultsError) - - """ - def get_membership_by_organization_user!(%User{} = user, %Organization{} = organization) do - Membership - |> where([m], m.user_id == ^user.id and m.organization_id == ^organization.id) - |> Repo.one() - end - @doc """ Updates an membership. diff --git a/lib/atomic_web/allowed_roles.ex b/lib/atomic_web/allowed_roles.ex deleted file mode 100644 index 3de386b47..000000000 --- a/lib/atomic_web/allowed_roles.ex +++ /dev/null @@ -1,18 +0,0 @@ -defmodule AtomicWeb.Auth.AllowedRoles do - @moduledoc false - import Plug.Conn - - def init(opts), do: opts - - def call(conn, opts) do - - if conn.assigns.current_membership[:role] in opts do - conn - else - conn - |> send_resp(:not_found, "") - |> halt() - end - end - -end diff --git a/lib/atomic_web/controllers/user_auth.ex b/lib/atomic_web/controllers/user_auth.ex index ad0234c72..bec487771 100644 --- a/lib/atomic_web/controllers/user_auth.ex +++ b/lib/atomic_web/controllers/user_auth.ex @@ -6,7 +6,6 @@ defmodule AtomicWeb.UserAuth do import Phoenix.Controller alias Atomic.Accounts - alias Atomic.Organizations alias AtomicWeb.Router.Helpers, as: Routes # Make the remember me cookie valid for 60 days. @@ -95,10 +94,17 @@ defmodule AtomicWeb.UserAuth do def fetch_current_user(conn, _opts) do {user_token, conn} = ensure_user_token(conn) user = user_token && Accounts.get_user_by_session_token(user_token) - membership = get_default_membership(user) conn |> assign(:current_user, user) - |> assign(:current_membership, membership) + |> assign(:current_organization, get_default_organization(user)) + end + + defp get_default_organization(user) do + if user do + List.first(user.organizations) + else + nil + end end defp ensure_user_token(conn) do @@ -115,14 +121,6 @@ defmodule AtomicWeb.UserAuth do end end - defp get_default_membership(user) do - organization = List.first(user.organizations) - - role = Organizations.get_membership_by_organization_user!(user, organization).role - - %{organization: organization, role: role} - end - @doc """ Used for routes that require the user to not be authenticated. """ diff --git a/lib/atomic_web/live/department_live/index.ex b/lib/atomic_web/live/department_live/index.ex index c95dcbdaf..f5e6b000f 100644 --- a/lib/atomic_web/live/department_live/index.ex +++ b/lib/atomic_web/live/department_live/index.ex @@ -6,8 +6,8 @@ defmodule AtomicWeb.DepartmentLive.Index do alias Atomic.Organizations @impl true - def mount(_params, _session, socket) do - {:ok, assign(socket, :departments, list_departments())} + def mount(params, _session, socket) do + {:ok, assign(socket, :departments, list_departments(params["organization_id"]))} end @impl true @@ -36,14 +36,14 @@ defmodule AtomicWeb.DepartmentLive.Index do end @impl true - def handle_event("delete", %{"id" => id}, socket) do + def handle_event("delete", %{"id" => id, "organization_id" => organization_id}, socket) do department = Departments.get_department!(id) {:ok, _} = Departments.delete_department(department) - {:noreply, assign(socket, :departments, list_departments())} + {:noreply, assign(socket, :departments, list_departments(organization_id))} end - defp list_departments do - Departments.list_departments() + defp list_departments(id) do + Departments.list_departments_by_organization_id(id) end end diff --git a/lib/atomic_web/live/department_live/index.html.heex b/lib/atomic_web/live/department_live/index.html.heex index abc44402d..246bd8501 100644 --- a/lib/atomic_web/live/department_live/index.html.heex +++ b/lib/atomic_web/live/department_live/index.html.heex @@ -1,8 +1,8 @@

Listing Departments

<%= if @live_action in [:new, :edit] do %> - <.modal return_to={Routes.department_index_path(@socket, :index, @organization)}> - <.live_component module={AtomicWeb.DepartmentLive.FormComponent} organization={@organization} id={@department.id || :new} title={@page_title} action={@live_action} department={@department} return_to={Routes.department_index_path(@socket, :index, @organization)} /> + <.modal return_to={Routes.department_index_path(@socket, :index, @current_organization)}> + <.live_component module={AtomicWeb.DepartmentLive.FormComponent} id={@department.id || :new} title={@page_title} action={@live_action} department={@department} return_to={Routes.department_index_path(@socket, :index, @current_organization)} /> <% end %> @@ -20,8 +20,8 @@ <%= department.name %> - <%= live_redirect("Show", to: Routes.department_show_path(@socket, :show, department.organization_id, department)) %> - <%= live_patch("Edit", to: Routes.department_index_path(@socket, :edit, department.organization_id, department)) %> + <%= live_redirect("Show", to: Routes.department_show_path(@socket, :show, @current_organization, department)) %> + <%= live_patch("Edit", to: Routes.department_index_path(@socket, :edit, @current_organization, department)) %> <%= link("Delete", to: "#", phx_click: "delete", phx_value_id: department.id, data: [confirm: "Are you sure?"]) %> @@ -29,4 +29,4 @@ -<%= live_patch("New Department", to: Routes.department_index_path(@socket, :new, @organization)) %> +<%= live_patch("New Department", to: Routes.department_index_path(@socket, :new, @current_organization)) %> diff --git a/lib/atomic_web/live/department_live/show.html.heex b/lib/atomic_web/live/department_live/show.html.heex index 430a0c233..241fd62c6 100644 --- a/lib/atomic_web/live/department_live/show.html.heex +++ b/lib/atomic_web/live/department_live/show.html.heex @@ -1,8 +1,8 @@

Show Department

<%= if @live_action in [:edit] do %> - <.modal return_to={Routes.department_show_path(@socket, :show, @organization, @department)}> - <.live_component module={AtomicWeb.DepartmentLive.FormComponent} id={@department.id} title={@page_title} action={@live_action} department={@department} return_to={Routes.department_show_path(@socket, :show, @organization, @department)} /> + <.modal return_to={Routes.department_show_path(@socket, :show, @current_organization, @department)}> + <.live_component module={AtomicWeb.DepartmentLive.FormComponent} id={@department.id} title={@page_title} action={@live_action} department={@department} return_to={Routes.department_show_path(@socket, :show, @current_organization, @department)} /> <% end %> @@ -24,5 +24,5 @@ -<%= live_patch("Edit", to: Routes.department_show_path(@socket, :edit, @organization, @department), class: "button") %> | -<%= live_redirect("Back", to: Routes.department_index_path(@socket, :index, @organization)) %> +<%= live_patch("Edit", to: Routes.department_show_path(@socket, :edit, @current_organization, @department), class: "button") %> | +<%= live_redirect("Back", to: Routes.department_index_path(@socket, :index, @current_organization)) %> diff --git a/lib/atomic_web/live/hooks.ex b/lib/atomic_web/live/hooks.ex index b9add6517..e895bccf4 100644 --- a/lib/atomic_web/live/hooks.ex +++ b/lib/atomic_web/live/hooks.ex @@ -12,8 +12,14 @@ defmodule AtomicWeb.Hooks do def on_mount(:current_user, _params, %{"user_token" => user_token}, socket) do current_user = Accounts.get_user_by_session_token(user_token) + current_organization = List.first(current_user.organizations) - {:cont, assign(socket, current_user: current_user)} + socket = + socket + |> assign(:current_user, current_user) + |> assign(:current_organization, current_organization) + + {:cont, socket} end def on_mount(:current_user, _params, _session, socket) do diff --git a/lib/atomic_web/router.ex b/lib/atomic_web/router.ex index 8afe9c267..25840cdf8 100644 --- a/lib/atomic_web/router.ex +++ b/lib/atomic_web/router.ex @@ -17,14 +17,6 @@ defmodule AtomicWeb.Router do plug :accepts, ["json"] end - pipeline :organization_owner do - plug AtomicWeb.Auth.AllowedRoles, [:owner] - end - - pipeline :organization_admin do - plug AtomicWeb.Auth.AllowedRoles, [:admin, :owner] - end - scope "/", AtomicWeb do pipe_through :browser @@ -32,7 +24,7 @@ defmodule AtomicWeb.Router do end scope "/", AtomicWeb do - pipe_through [:browser, :require_authenticated_user, :organization_admin] + pipe_through [:browser, :require_authenticated_user] live_session :logged_in, on_mount: [{AtomicWeb.Hooks, :current_user}] do live "/scanner", ScannerLive.Index, :index @@ -42,11 +34,11 @@ defmodule AtomicWeb.Router do live "/activities/:id/edit", ActivityLive.Edit, :edit live "/activities/:id", ActivityLive.Show, :show - live "/departments/:org", DepartmentLive.Index, :index - live "/departments/:org/new", DepartmentLive.Index, :new - live "/departments/:org/:id/edit", DepartmentLive.Index, :edit - live "/departments/:org/:id", DepartmentLive.Show, :show - live "/departments/:org/:id/show/edit", DepartmentLive.Show, :edit + live "/organizations/:organization_id/departments", DepartmentLive.Index, :index + live "/organizations/:organization_id/departments/new", DepartmentLive.Index, :new + live "/organizations/:organization_id/departments/:id/edit", DepartmentLive.Index, :edit + live "/organizations/:organization_id/departments/:id", DepartmentLive.Show, :show + live "/organizations/:organization_id/departments/:id/show/edit", DepartmentLive.Show, :edit live "/partners", PartnerLive.Index, :index live "/partners/new", PartnerLive.Index, :new diff --git a/lib/atomic_web/templates/layout/root.html.heex b/lib/atomic_web/templates/layout/root.html.heex index c03c73b66..ea955f775 100644 --- a/lib/atomic_web/templates/layout/root.html.heex +++ b/lib/atomic_web/templates/layout/root.html.heex @@ -15,11 +15,14 @@
From a849e37df29a4a127e1764276a375278da537620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lobo?= Date: Sun, 9 Jul 2023 18:55:26 +0100 Subject: [PATCH 07/42] Fix issues regarding previous rebase --- lib/atomic_web/live/department_live/index.ex | 13 +++++-------- lib/atomic_web/live/department_live/index.html.heex | 6 +++--- lib/atomic_web/live/department_live/show.ex | 4 +--- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/lib/atomic_web/live/department_live/index.ex b/lib/atomic_web/live/department_live/index.ex index f5e6b000f..525f0dbb3 100644 --- a/lib/atomic_web/live/department_live/index.ex +++ b/lib/atomic_web/live/department_live/index.ex @@ -3,7 +3,6 @@ defmodule AtomicWeb.DepartmentLive.Index do alias Atomic.Departments alias Atomic.Departments.Department - alias Atomic.Organizations @impl true def mount(params, _session, socket) do @@ -11,7 +10,7 @@ defmodule AtomicWeb.DepartmentLive.Index do end @impl true - def handle_params(%{"org" => _id} = params, _url, socket) do + def handle_params(params, _url, socket) do {:noreply, apply_action(socket, socket.assigns.live_action, params)} end @@ -21,26 +20,24 @@ defmodule AtomicWeb.DepartmentLive.Index do |> assign(:department, Departments.get_department!(id)) end - defp apply_action(socket, :new, %{"org" => id}) do + defp apply_action(socket, :new, _params) do socket |> assign(:page_title, "New Department") - |> assign(:organization, Organizations.get_organization!(id)) |> assign(:department, %Department{}) end - defp apply_action(socket, :index, %{"org" => id}) do + defp apply_action(socket, :index, _params) do socket |> assign(:page_title, "Listing Departments") - |> assign(:organization, Organizations.get_organization!(id)) |> assign(:department, nil) end @impl true - def handle_event("delete", %{"id" => id, "organization_id" => organization_id}, socket) do + def handle_event("delete", %{"id" => id}, socket) do department = Departments.get_department!(id) {:ok, _} = Departments.delete_department(department) - {:noreply, assign(socket, :departments, list_departments(organization_id))} + {:noreply, assign(socket, :departments, list_departments(socket.assigns.current_organization.id))} end defp list_departments(id) do diff --git a/lib/atomic_web/live/department_live/index.html.heex b/lib/atomic_web/live/department_live/index.html.heex index 7f3b1a383..a967ee2f0 100644 --- a/lib/atomic_web/live/department_live/index.html.heex +++ b/lib/atomic_web/live/department_live/index.html.heex @@ -2,7 +2,7 @@ <%= if @live_action in [:new, :edit] do %> <.modal return_to={Routes.department_index_path(@socket, :index, @current_organization)}> - <.live_component module={AtomicWeb.DepartmentLive.FormComponent} id={@department.id || :new} title={@page_title} action={@live_action} department={@department} return_to={Routes.department_index_path(@socket, :index, @current_organization)} /> + <.live_component module={AtomicWeb.DepartmentLive.FormComponent} id={@department.id || :new} organization={@current_organization} title={@page_title} action={@live_action} department={@department} return_to={Routes.department_index_path(@socket, :index, @current_organization)} /> <% end %> @@ -22,11 +22,11 @@ <%= live_redirect("Show", to: Routes.department_show_path(@socket, :show, @current_organization, department)) %> <%= live_patch("Edit", to: Routes.department_index_path(@socket, :edit, @current_organization, department)) %> - <%= link("Delete", to: "#", phx_click: "delete", phx_value_id: department.id, phx_value_organization_id: @current_organization.id, data: [confirm: "Are you sure?"]) %> + <%= link("Delete", to: "#", phx_click: "delete", phx_value_id: department.id, data: [confirm: "Are you sure?"]) %> <% end %> -<%= live_patch("New Department", to: Routes.department_index_path(@socket, :new, @current_organization)) %> +<%= live_patch("New Department", to: Routes.department_index_path(@socket, :new, @current_organization)) %> \ No newline at end of file diff --git a/lib/atomic_web/live/department_live/show.ex b/lib/atomic_web/live/department_live/show.ex index e8ff68123..632373aa3 100644 --- a/lib/atomic_web/live/department_live/show.ex +++ b/lib/atomic_web/live/department_live/show.ex @@ -2,7 +2,6 @@ defmodule AtomicWeb.DepartmentLive.Show do use AtomicWeb, :live_view alias Atomic.Departments - alias Atomic.Organizations @impl true def mount(_params, _session, socket) do @@ -10,11 +9,10 @@ defmodule AtomicWeb.DepartmentLive.Show do end @impl true - def handle_params(%{"org" => org, "id" => id}, _, socket) do + def handle_params(%{"id" => id}, _, socket) do {:noreply, socket |> assign(:page_title, page_title(socket.assigns.live_action)) - |> assign(:organization, Organizations.get_organization!(org)) |> assign(:department, Departments.get_department!(id, preloads: :activities))} end From 3a558fb785f126e67d07bb3126f0aea12de449fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lobo?= Date: Sun, 9 Jul 2023 20:49:03 +0100 Subject: [PATCH 08/42] Check for parameters mismatch and trigger 404 --- lib/atomic_web/exceptions.ex | 3 +++ lib/atomic_web/live/department_live/index.ex | 13 +++++++++---- lib/atomic_web/live/department_live/show.ex | 15 ++++++++++----- 3 files changed, 22 insertions(+), 9 deletions(-) create mode 100644 lib/atomic_web/exceptions.ex diff --git a/lib/atomic_web/exceptions.ex b/lib/atomic_web/exceptions.ex new file mode 100644 index 000000000..daeb87bcd --- /dev/null +++ b/lib/atomic_web/exceptions.ex @@ -0,0 +1,3 @@ +defmodule AtomicWeb.MismatchError do + defexception message: "The provided parameters have no relation in the database.", plug_status: 404 +end diff --git a/lib/atomic_web/live/department_live/index.ex b/lib/atomic_web/live/department_live/index.ex index 525f0dbb3..8794972d1 100644 --- a/lib/atomic_web/live/department_live/index.ex +++ b/lib/atomic_web/live/department_live/index.ex @@ -14,10 +14,15 @@ defmodule AtomicWeb.DepartmentLive.Index do {:noreply, apply_action(socket, socket.assigns.live_action, params)} end - defp apply_action(socket, :edit, %{"id" => id}) do - socket - |> assign(:page_title, "Edit Department") - |> assign(:department, Departments.get_department!(id)) + defp apply_action(socket, :edit, %{"organization_id" => organization_id, "id" => id}) do + department = Departments.get_department!(id, preloads: [:organization]) + if department.organization.id != organization_id do + raise AtomicWeb.MismatchError + else + socket + |> assign(:page_title, "Edit Department") + |> assign(:department, Departments.get_department!(id)) + end end defp apply_action(socket, :new, _params) do diff --git a/lib/atomic_web/live/department_live/show.ex b/lib/atomic_web/live/department_live/show.ex index 632373aa3..958050baf 100644 --- a/lib/atomic_web/live/department_live/show.ex +++ b/lib/atomic_web/live/department_live/show.ex @@ -9,11 +9,16 @@ defmodule AtomicWeb.DepartmentLive.Show do end @impl true - def handle_params(%{"id" => id}, _, socket) do - {:noreply, - socket - |> assign(:page_title, page_title(socket.assigns.live_action)) - |> assign(:department, Departments.get_department!(id, preloads: :activities))} + def handle_params(%{"organization_id" => organization_id, "id" => id}, _, socket) do + department = Departments.get_department!(id, preloads: [:activities, :organization]) + if department.organization.id != organization_id do + raise AtomicWeb.MismatchError + else + {:noreply, + socket + |> assign(:page_title, page_title(socket.assigns.live_action)) + |> assign(:department, department)} + end end defp page_title(:show), do: "Show Department" From 075b5c0dd32637dfeec04c1968b2efcea4d2bc1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lobo?= Date: Mon, 10 Jul 2023 23:58:10 +0100 Subject: [PATCH 09/42] Add organization parameter to partnership routes --- lib/atomic/partnerships.ex | 13 +++++++++++ lib/atomic/partnerships/partner.ex | 2 +- lib/atomic_web/live/department_live/index.ex | 12 +++++----- lib/atomic_web/live/department_live/show.ex | 8 +++---- .../live/partner_live/form_component.ex | 2 ++ .../partner_live/form_component.html.heex | 2 +- lib/atomic_web/live/partner_live/index.ex | 23 +++++++++++-------- .../live/partner_live/index.html.heex | 10 ++++---- lib/atomic_web/live/partner_live/show.ex | 15 ++++++++---- .../live/partner_live/show.html.heex | 8 +++---- lib/atomic_web/router.ex | 10 ++++---- .../templates/layout/root.html.heex | 2 +- 12 files changed, 66 insertions(+), 41 deletions(-) diff --git a/lib/atomic/partnerships.ex b/lib/atomic/partnerships.ex index 0f66f4738..0b9521db6 100644 --- a/lib/atomic/partnerships.ex +++ b/lib/atomic/partnerships.ex @@ -21,6 +21,19 @@ defmodule Atomic.Partnerships do Repo.all(Partner) end + @doc """ + Returns the list of partnerships belonging to an organization. + + ## Examples + + iex> list_partnerships_by_organization_id(99d7c9e5-4212-4f59-a097-28aaa33c2621) + [%Partner{}, ...] + + """ + def list_partnerships_by_organization_id(id) do + Repo.all(from p in Partner, where: p.organization_id == ^id) + end + @doc """ Gets a single partner. diff --git a/lib/atomic/partnerships/partner.ex b/lib/atomic/partnerships/partner.ex index 4c5b8be49..e907f6858 100644 --- a/lib/atomic/partnerships/partner.ex +++ b/lib/atomic/partnerships/partner.ex @@ -7,7 +7,7 @@ defmodule Atomic.Partnerships.Partner do alias Atomic.Organizations.Organization alias Atomic.Uploaders - @required_fields ~w(name description)a + @required_fields ~w(name description organization_id)a @optional_fields [] diff --git a/lib/atomic_web/live/department_live/index.ex b/lib/atomic_web/live/department_live/index.ex index 8794972d1..20db9459e 100644 --- a/lib/atomic_web/live/department_live/index.ex +++ b/lib/atomic_web/live/department_live/index.ex @@ -5,8 +5,8 @@ defmodule AtomicWeb.DepartmentLive.Index do alias Atomic.Departments.Department @impl true - def mount(params, _session, socket) do - {:ok, assign(socket, :departments, list_departments(params["organization_id"]))} + def mount(%{"organization_id" => organization_id}, _session, socket) do + {:ok, assign(socket, :departments, list_departments(organization_id))} end @impl true @@ -15,13 +15,13 @@ defmodule AtomicWeb.DepartmentLive.Index do end defp apply_action(socket, :edit, %{"organization_id" => organization_id, "id" => id}) do - department = Departments.get_department!(id, preloads: [:organization]) - if department.organization.id != organization_id do - raise AtomicWeb.MismatchError - else + department = Departments.get_department!(id) + if department.organization_id == organization_id do socket |> assign(:page_title, "Edit Department") |> assign(:department, Departments.get_department!(id)) + else + raise AtomicWeb.MismatchError end end diff --git a/lib/atomic_web/live/department_live/show.ex b/lib/atomic_web/live/department_live/show.ex index 958050baf..03d970f13 100644 --- a/lib/atomic_web/live/department_live/show.ex +++ b/lib/atomic_web/live/department_live/show.ex @@ -10,14 +10,14 @@ defmodule AtomicWeb.DepartmentLive.Show do @impl true def handle_params(%{"organization_id" => organization_id, "id" => id}, _, socket) do - department = Departments.get_department!(id, preloads: [:activities, :organization]) - if department.organization.id != organization_id do - raise AtomicWeb.MismatchError - else + department = Departments.get_department!(id, preloads: [:activities]) + if department.organization_id == organization_id do {:noreply, socket |> assign(:page_title, page_title(socket.assigns.live_action)) |> assign(:department, department)} + else + raise AtomicWeb.MismatchError end end diff --git a/lib/atomic_web/live/partner_live/form_component.ex b/lib/atomic_web/live/partner_live/form_component.ex index 64fb33643..f34a63e2b 100644 --- a/lib/atomic_web/live/partner_live/form_component.ex +++ b/lib/atomic_web/live/partner_live/form_component.ex @@ -57,6 +57,8 @@ defmodule AtomicWeb.PartnerLive.FormComponent do end defp save_partner(socket, :new, partner_params) do + partner_params = + Map.put(partner_params, "organization_id", socket.assigns.organization.id) case Partnerships.create_partner(partner_params, &consume_image_data(socket, &1)) do {:ok, _partner} -> {:noreply, diff --git a/lib/atomic_web/live/partner_live/form_component.html.heex b/lib/atomic_web/live/partner_live/form_component.html.heex index 26d70a1d7..731c5b1fe 100644 --- a/lib/atomic_web/live/partner_live/form_component.html.heex +++ b/lib/atomic_web/live/partner_live/form_component.html.heex @@ -72,7 +72,7 @@ <%= submit do %> -
+
Save
<% end %> diff --git a/lib/atomic_web/live/partner_live/index.ex b/lib/atomic_web/live/partner_live/index.ex index 01b517731..e8f671450 100644 --- a/lib/atomic_web/live/partner_live/index.ex +++ b/lib/atomic_web/live/partner_live/index.ex @@ -5,8 +5,8 @@ defmodule AtomicWeb.PartnerLive.Index do alias Atomic.Partnerships.Partner @impl true - def mount(_params, _session, socket) do - {:ok, assign(socket, :partnerships, list_partnerships())} + def mount(%{"organization_id" => organization_id}, _session, socket) do + {:ok, assign(socket, :partnerships, list_partnerships(organization_id))} end @impl true @@ -14,10 +14,15 @@ defmodule AtomicWeb.PartnerLive.Index do {:noreply, apply_action(socket, socket.assigns.live_action, params)} end - defp apply_action(socket, :edit, %{"id" => id}) do - socket - |> assign(:page_title, "Edit Partner") - |> assign(:partner, Partnerships.get_partner!(id)) + defp apply_action(socket, :edit, %{"organization_id" => organization_id, "id" => id}) do + partner = Partnerships.get_partner!(id) + if partner.organization_id == organization_id do + socket + |> assign(:page_title, "Edit Partner") + |> assign(:partner, Partnerships.get_partner!(id)) + else + raise AtomicWeb.MismatchError + end end defp apply_action(socket, :new, _params) do @@ -37,10 +42,10 @@ defmodule AtomicWeb.PartnerLive.Index do partner = Partnerships.get_partner!(id) {:ok, _} = Partnerships.delete_partner(partner) - {:noreply, assign(socket, :partnerships, list_partnerships())} + {:noreply, assign(socket, :partnerships, list_partnerships(socket.assigns.current_organization.id))} end - defp list_partnerships do - Partnerships.list_partnerships() + defp list_partnerships(id) do + Partnerships.list_partnerships_by_organization_id(id) end end diff --git a/lib/atomic_web/live/partner_live/index.html.heex b/lib/atomic_web/live/partner_live/index.html.heex index 7ab2cf743..7f892ded7 100644 --- a/lib/atomic_web/live/partner_live/index.html.heex +++ b/lib/atomic_web/live/partner_live/index.html.heex @@ -1,8 +1,8 @@

Listing Partnerships

<%= if @live_action in [:new, :edit] do %> - <.modal return_to={Routes.partner_index_path(@socket, :index)}> - <.live_component module={AtomicWeb.PartnerLive.FormComponent} id={@partner.id || :new} title={@page_title} action={@live_action} partner={@partner} return_to={Routes.partner_index_path(@socket, :index)} /> + <.modal return_to={Routes.partner_index_path(@socket, :index, @current_organization)}> + <.live_component module={AtomicWeb.PartnerLive.FormComponent} id={@partner.id || :new} organization={@current_organization} title={@page_title} action={@live_action} partner={@partner} return_to={Routes.partner_index_path(@socket, :index, @current_organization)} /> <% end %> @@ -22,8 +22,8 @@ <%= partner.description %> - <%= live_redirect("Show", to: Routes.partner_show_path(@socket, :show, partner)) %> - <%= live_patch("Edit", to: Routes.partner_index_path(@socket, :edit, partner)) %> + <%= live_redirect("Show", to: Routes.partner_show_path(@socket, :show, @current_organization, partner)) %> + <%= live_patch("Edit", to: Routes.partner_index_path(@socket, :edit, @current_organization, partner)) %> <%= link("Delete", to: "#", phx_click: "delete", phx_value_id: partner.id, data: [confirm: "Are you sure?"]) %> @@ -31,4 +31,4 @@ -<%= live_patch("New Partner", to: Routes.partner_index_path(@socket, :new)) %> +<%= live_patch("New Partner", to: Routes.partner_index_path(@socket, :new, @current_organization)) %> diff --git a/lib/atomic_web/live/partner_live/show.ex b/lib/atomic_web/live/partner_live/show.ex index 182ad97b5..7be5e9f7f 100644 --- a/lib/atomic_web/live/partner_live/show.ex +++ b/lib/atomic_web/live/partner_live/show.ex @@ -10,11 +10,16 @@ defmodule AtomicWeb.PartnerLive.Show do end @impl true - def handle_params(%{"id" => id}, _, socket) do - {:noreply, - socket - |> assign(:page_title, page_title(socket.assigns.live_action)) - |> assign(:partner, Partnerships.get_partner!(id))} + def handle_params(%{"organization_id" => organization_id, "id" => id}, _, socket) do + partner = Partnerships.get_partner!(id) + if partner.organization_id == organization_id do + {:noreply, + socket + |> assign(:page_title, page_title(socket.assigns.live_action)) + |> assign(:partner, partner)} + else + raise AtomicWeb.MismatchError + end end defp page_title(:show), do: "Show Partner" diff --git a/lib/atomic_web/live/partner_live/show.html.heex b/lib/atomic_web/live/partner_live/show.html.heex index 4f5f51268..daff0ce2e 100644 --- a/lib/atomic_web/live/partner_live/show.html.heex +++ b/lib/atomic_web/live/partner_live/show.html.heex @@ -1,8 +1,8 @@

Show Partner

<%= if @live_action in [:edit] do %> - <.modal return_to={Routes.partner_show_path(@socket, :show, @partner)}> - <.live_component module={AtomicWeb.PartnerLive.FormComponent} id={@partner.id} title={@page_title} action={@live_action} partner={@partner} return_to={Routes.partner_show_path(@socket, :show, @partner)} /> + <.modal return_to={Routes.partner_show_path(@socket, :show, @current_organization, @partner)}> + <.live_component module={AtomicWeb.PartnerLive.FormComponent} id={@partner.id} title={@page_title} action={@live_action} partner={@partner} return_to={Routes.partner_show_path(@socket, :show, @current_organization, @partner)} /> <% end %> @@ -24,5 +24,5 @@ <% end %> -<%= live_patch("Edit", to: Routes.partner_show_path(@socket, :edit, @partner), class: "button") %> | -<%= live_redirect("Back", to: Routes.partner_index_path(@socket, :index)) %> +<%= live_patch("Edit", to: Routes.partner_show_path(@socket, :edit, @current_organization, @partner), class: "button") %> | +<%= live_redirect("Back", to: Routes.partner_index_path(@socket, :index, @current_organization)) %> diff --git a/lib/atomic_web/router.ex b/lib/atomic_web/router.ex index 25840cdf8..f133426a6 100644 --- a/lib/atomic_web/router.ex +++ b/lib/atomic_web/router.ex @@ -40,11 +40,11 @@ defmodule AtomicWeb.Router do live "/organizations/:organization_id/departments/:id", DepartmentLive.Show, :show live "/organizations/:organization_id/departments/:id/show/edit", DepartmentLive.Show, :edit - live "/partners", PartnerLive.Index, :index - live "/partners/new", PartnerLive.Index, :new - live "/partners/:id/edit", PartnerLive.Index, :edit - live "/partners/:id", PartnerLive.Show, :show - live "/partners/:id/show/edit", PartnerLive.Show, :edit + live "/organizations/:organization_id/partners", PartnerLive.Index, :index + live "/organizations/:organization_id/partners/new", PartnerLive.Index, :new + live "/organizations/:organization_id/partners/:id/edit", PartnerLive.Index, :edit + live "/organizations/:organization_id/partners/:id", PartnerLive.Show, :show + live "/organizations/:organization_id/partners/:id/show/edit", PartnerLive.Show, :edit live "/speakers", SpeakerLive.Index, :index live "/speakers/new", SpeakerLive.Index, :new diff --git a/lib/atomic_web/templates/layout/root.html.heex b/lib/atomic_web/templates/layout/root.html.heex index ea955f775..8578d431b 100644 --- a/lib/atomic_web/templates/layout/root.html.heex +++ b/lib/atomic_web/templates/layout/root.html.heex @@ -18,7 +18,7 @@ <%= if @current_user do %>
  • <%= live_redirect("Activities", to: Routes.activity_index_path(@conn, :index)) %>
  • <%= live_redirect("Departments", to: Routes.department_index_path(@conn, :index, @current_organization)) %>
  • -
  • <%= live_redirect("Partners", to: Routes.partner_index_path(@conn, :index)) %>
  • +
  • <%= live_redirect("Partners", to: Routes.partner_index_path(@conn, :index, @current_organization)) %>
  • <%= live_redirect("Speakers", to: Routes.speaker_index_path(@conn, :index)) %>
  • <%= live_redirect("Organizations", to: Routes.organization_index_path(@conn, :index)) %>
  • <%= live_redirect("Scanner", to: Routes.scanner_index_path(@conn, :index)) %>
  • From f07ca2b41947bd7f569421d5bbc6cb71d4f079c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lobo?= Date: Tue, 11 Jul 2023 00:12:02 +0100 Subject: [PATCH 10/42] Change organization routes id parameter's name --- lib/atomic_web/live/organization_live/index.ex | 4 ++-- lib/atomic_web/live/organization_live/show.ex | 2 +- lib/atomic_web/router.ex | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/atomic_web/live/organization_live/index.ex b/lib/atomic_web/live/organization_live/index.ex index 8ecb9635f..48b342d1c 100644 --- a/lib/atomic_web/live/organization_live/index.ex +++ b/lib/atomic_web/live/organization_live/index.ex @@ -14,7 +14,7 @@ defmodule AtomicWeb.OrganizationLive.Index do {:noreply, apply_action(socket, socket.assigns.live_action, params)} end - defp apply_action(socket, :edit, %{"id" => id}) do + defp apply_action(socket, :edit, %{"organization_id" => id}) do socket |> assign(:page_title, "Edit Organization") |> assign(:organization, Organizations.get_organization!(id)) @@ -33,7 +33,7 @@ defmodule AtomicWeb.OrganizationLive.Index do end @impl true - def handle_event("delete", %{"id" => id}, socket) do + def handle_event("delete", %{"organization_id" => id}, socket) do organization = Organizations.get_organization!(id) {:ok, _} = Organizations.delete_organization(organization) diff --git a/lib/atomic_web/live/organization_live/show.ex b/lib/atomic_web/live/organization_live/show.ex index 4b5122e24..00cbd169d 100644 --- a/lib/atomic_web/live/organization_live/show.ex +++ b/lib/atomic_web/live/organization_live/show.ex @@ -9,7 +9,7 @@ defmodule AtomicWeb.OrganizationLive.Show do end @impl true - def handle_params(%{"id" => id}, _, socket) do + def handle_params(%{"organization_id" => id}, _, socket) do org = Organizations.get_organization!(id, [:departments]) {:noreply, diff --git a/lib/atomic_web/router.ex b/lib/atomic_web/router.ex index f133426a6..759ed1727 100644 --- a/lib/atomic_web/router.ex +++ b/lib/atomic_web/router.ex @@ -54,9 +54,9 @@ defmodule AtomicWeb.Router do live "/organizations", OrganizationLive.Index, :index live "/organizations/new", OrganizationLive.Index, :new - live "/organizations/:id/edit", OrganizationLive.Index, :edit - live "/organizations/:id", OrganizationLive.Show, :show - live "/organizations/:id/show/edit", OrganizationLive.Show, :edit + live "/organizations/:organization_id/edit", OrganizationLive.Index, :edit + live "/organizations/:organization_id", OrganizationLive.Show, :show + live "/organizations/:organization_id/show/edit", OrganizationLive.Show, :edit live "/membership/:org", MembershipLive.Index, :index live "/membership/:org/new", MembershipLive.New, :new From 495611359ec966238e07349087106b09cb6dc111 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lobo?= Date: Tue, 11 Jul 2023 01:17:19 +0100 Subject: [PATCH 11/42] Change membership routes and detect id mismatches --- lib/atomic_web/live/membership_live/edit.ex | 26 +++++++++++--------- lib/atomic_web/live/membership_live/index.ex | 2 +- lib/atomic_web/live/membership_live/new.ex | 4 +-- lib/atomic_web/live/membership_live/show.ex | 15 ++++++----- lib/atomic_web/router.ex | 8 +++--- 5 files changed, 31 insertions(+), 24 deletions(-) diff --git a/lib/atomic_web/live/membership_live/edit.ex b/lib/atomic_web/live/membership_live/edit.ex index b12c0edf0..bb418b48e 100644 --- a/lib/atomic_web/live/membership_live/edit.ex +++ b/lib/atomic_web/live/membership_live/edit.ex @@ -9,19 +9,23 @@ defmodule AtomicWeb.MembershipLive.Edit do end @impl true - def handle_params(%{"org" => org, "id" => id}, _, socket) do + def handle_params(%{"organization_id" => organization_id, "id" => id}, _, socket) do membership = Organizations.get_membership!(id, [:user, :organization, :created_by]) - {:noreply, - socket - |> assign(:page_title, page_title(socket.assigns.live_action)) - |> assign(:organization, org) - |> assign(:membership, membership) - |> assign(:current_user, socket.assigns.current_user) - |> assign( - :allowed_roles, - Organizations.roles_less_than_or_equal(socket.assigns.current_user.role) - )} + if membership.organization_id == organization_id do + {:noreply, + socket + |> assign(:page_title, page_title(socket.assigns.live_action)) + |> assign(:organization, organization_id) + |> assign(:membership, membership) + |> assign(:current_user, socket.assigns.current_user) + |> assign( + :allowed_roles, + Organizations.roles_less_than_or_equal(socket.assigns.current_user.role) + )} + else + raise AtomicWeb.MismatchError + end end defp page_title(:index), do: "List memberships" diff --git a/lib/atomic_web/live/membership_live/index.ex b/lib/atomic_web/live/membership_live/index.ex index 454c68208..b745058e3 100644 --- a/lib/atomic_web/live/membership_live/index.ex +++ b/lib/atomic_web/live/membership_live/index.ex @@ -9,7 +9,7 @@ defmodule AtomicWeb.MembershipLive.Index do end @impl true - def handle_params(%{"org" => id}, _, socket) do + def handle_params(%{"organization_id" => id}, _, socket) do memberships = Organizations.list_memberships(%{"organization_id" => id}, [:user]) |> Enum.filter(fn m -> m.role != :follower end) diff --git a/lib/atomic_web/live/membership_live/new.ex b/lib/atomic_web/live/membership_live/new.ex index 020fe7df3..bbe906dd5 100644 --- a/lib/atomic_web/live/membership_live/new.ex +++ b/lib/atomic_web/live/membership_live/new.ex @@ -12,12 +12,12 @@ defmodule AtomicWeb.MembershipLive.New do end @impl true - def handle_params(%{"org" => org_id}, _url, socket) do + def handle_params(%{"organization_id" => organization_id}, _url, socket) do {:noreply, socket |> assign(:page_title, gettext("New Membership")) |> assign(:membership, %Membership{ - organization_id: org_id + organization_id: organization_id }) |> assign(:users, Enum.map(Accounts.list_users(), fn u -> [key: u.email, value: u.id] end)) |> assign( diff --git a/lib/atomic_web/live/membership_live/show.ex b/lib/atomic_web/live/membership_live/show.ex index fab8a6238..f75cba21a 100644 --- a/lib/atomic_web/live/membership_live/show.ex +++ b/lib/atomic_web/live/membership_live/show.ex @@ -9,13 +9,16 @@ defmodule AtomicWeb.MembershipLive.Show do end @impl true - def handle_params(%{"org" => _org, "id" => id}, _, socket) do + def handle_params(%{"organization_id" => organization_id, "id" => id}, _, socket) do membership = Organizations.get_membership!(id, [:user, :organization, :created_by]) - - {:noreply, - socket - |> assign(:page_title, page_title(socket.assigns.live_action)) - |> assign(:membership, membership)} + if membership.organization_id == organization_id do + {:noreply, + socket + |> assign(:page_title, page_title(socket.assigns.live_action)) + |> assign(:membership, membership)} + else + raise AtomicWeb.MismatchError + end end defp page_title(:index), do: "List memberships" diff --git a/lib/atomic_web/router.ex b/lib/atomic_web/router.ex index 759ed1727..a8a86fc6e 100644 --- a/lib/atomic_web/router.ex +++ b/lib/atomic_web/router.ex @@ -58,10 +58,10 @@ defmodule AtomicWeb.Router do live "/organizations/:organization_id", OrganizationLive.Show, :show live "/organizations/:organization_id/show/edit", OrganizationLive.Show, :edit - live "/membership/:org", MembershipLive.Index, :index - live "/membership/:org/new", MembershipLive.New, :new - live "/membership/:org/:id", MembershipLive.Show, :show - live "/membership/:org/:id/edit", MembershipLive.Edit, :edit + live "/organizations/:organization_id/memberships", MembershipLive.Index, :index + live "/organizations/:organization_id/memberships/new", MembershipLive.New, :new + live "/organizations/:organization_id/memberships/:id", MembershipLive.Show, :show + live "/organizations/:organization_id/memberships/:id/edit", MembershipLive.Edit, :edit live "/card/:membership_id", CardLive.Show, :show From 9c439724cd25b7c15caa5a1370843a90d40556e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lobo?= Date: Tue, 11 Jul 2023 01:19:59 +0100 Subject: [PATCH 12/42] Remove duplicate routes --- lib/atomic_web/router.ex | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/atomic_web/router.ex b/lib/atomic_web/router.ex index a8a86fc6e..932504fd7 100644 --- a/lib/atomic_web/router.ex +++ b/lib/atomic_web/router.ex @@ -69,10 +69,6 @@ defmodule AtomicWeb.Router do live "/board/:org/new", BoardLive.New, :new live "/board/:org/:id", BoardLive.Show, :show live "/board/:org/:id/edit", BoardLive.Edit, :edit - live "/memberships/:org", MembershipLive.Index, :index - live "/memberships/:org/new", MembershipLive.New, :new - live "/memberships/:org/:id", MembershipLive.Show, :show - live "/memberships/:org/:id/edit", MembershipLive.Edit, :edit live "/user/edit", UserLive.Edit, :edit end From 756263e13bbcef22a030d78841fe5ec4c86e480a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lobo?= Date: Fri, 14 Jul 2023 18:14:30 +0100 Subject: [PATCH 13/42] Add organization_id param to activity routes --- lib/atomic_web/live/activity_live/edit.ex | 23 ++++++++++++------- .../live/activity_live/edit.html.heex | 2 +- .../live/activity_live/form_component.ex | 13 +++++++++-- .../live/activity_live/index.html.heex | 4 ++-- .../live/activity_live/new.html.heex | 2 +- lib/atomic_web/live/activity_live/show.ex | 20 +++++++++++----- .../live/activity_live/show.html.heex | 6 ++--- .../live/department_live/show.html.heex | 2 +- lib/atomic_web/live/home_live/index.ex | 16 +++++++++++++ lib/atomic_web/live/home_live/index.html.heex | 3 +++ lib/atomic_web/router.ex | 10 ++++---- .../templates/layout/root.html.heex | 3 ++- 12 files changed, 74 insertions(+), 30 deletions(-) create mode 100644 lib/atomic_web/live/home_live/index.ex create mode 100644 lib/atomic_web/live/home_live/index.html.heex diff --git a/lib/atomic_web/live/activity_live/edit.ex b/lib/atomic_web/live/activity_live/edit.ex index 8f63b4003..810fc6ef0 100644 --- a/lib/atomic_web/live/activity_live/edit.ex +++ b/lib/atomic_web/live/activity_live/edit.ex @@ -10,13 +10,20 @@ defmodule AtomicWeb.ActivityLive.Edit do end @impl true - def handle_params(%{"id" => id} = _params, _url, socket) do - {:noreply, - socket - |> assign(:page_title, gettext("Edit Activity")) - |> assign( - :activity, - Activities.get_activity!(id, [:activity_sessions, :speakers, :departments]) - )} + def handle_params(%{"organization_id" => organization_id, "id" => id} = _params, _url, socket) do + activity = Activities.get_activity!(id, [:activity_sessions, :speakers, :departments]) + + organizations = Enum.map(activity.departments, fn department -> + department.organization_id + end) + + if organization_id in organizations do + {:noreply, + socket + |> assign(:page_title, gettext("Edit Activity")) + |> assign(:activity, activity)} + else + raise AtomicWeb.MismatchError + end end end diff --git a/lib/atomic_web/live/activity_live/edit.html.heex b/lib/atomic_web/live/activity_live/edit.html.heex index 76dc631a2..598333bc2 100644 --- a/lib/atomic_web/live/activity_live/edit.html.heex +++ b/lib/atomic_web/live/activity_live/edit.html.heex @@ -1,3 +1,3 @@
    - <.live_component module={AtomicWeb.ActivityLive.FormComponent} id={@activity.id} title={@page_title} action={@live_action} activity={@activity} return_to={Routes.activity_show_path(@socket, :show, @activity)} /> + <.live_component module={AtomicWeb.ActivityLive.FormComponent} id={@activity.id} organization={@current_organization} title={@page_title} action={@live_action} activity={@activity} return_to={Routes.activity_show_path(@socket, :show, @current_organization, @activity)} />
    diff --git a/lib/atomic_web/live/activity_live/form_component.ex b/lib/atomic_web/live/activity_live/form_component.ex index 2c246194b..36df61df7 100644 --- a/lib/atomic_web/live/activity_live/form_component.ex +++ b/lib/atomic_web/live/activity_live/form_component.ex @@ -7,25 +7,34 @@ defmodule AtomicWeb.ActivityLive.FormComponent do @impl true def mount(socket) do - departments = Departments.list_departments() speakers = Activities.list_speakers() {:ok, socket - |> assign(:departments, departments) + |> assign(:departments, []) |> assign(:speakers, speakers)} end @impl true def update(%{activity: activity} = assigns, socket) do + departments = Departments.list_departments_by_organization_id(assigns.organization.id) changeset = Activities.change_activity(activity) {:ok, socket |> assign(assigns) + |> assign(:departments, departments) |> assign(:changeset, changeset)} end + @impl true + def update(%{"organization_id" => organization_id}, socket) do + departments = Departments.list_departments_by_organization_id(organization_id) + {:ok, + socket + |> assign(:departments, departments)} + end + @impl true def handle_event("validate", %{"activity" => activity_params}, socket) do changeset = diff --git a/lib/atomic_web/live/activity_live/index.html.heex b/lib/atomic_web/live/activity_live/index.html.heex index 2b959a11f..6cdc03b3f 100644 --- a/lib/atomic_web/live/activity_live/index.html.heex +++ b/lib/atomic_web/live/activity_live/index.html.heex @@ -22,11 +22,11 @@ <%= activity.maximum_entries %> - <%= live_redirect("Show", to: Routes.activity_show_path(@socket, :show, activity)) %> + <%= live_redirect("Show", to: Routes.activity_show_path(@socket, :show, @current_organization, activity)) %> <% end %> -<%= live_patch("New Activity", to: Routes.activity_new_path(@socket, :new)) %> +<%= live_patch("New Activity", to: Routes.activity_new_path(@socket, :new, @current_organization)) %> diff --git a/lib/atomic_web/live/activity_live/new.html.heex b/lib/atomic_web/live/activity_live/new.html.heex index b6676be95..0cd31fb2a 100644 --- a/lib/atomic_web/live/activity_live/new.html.heex +++ b/lib/atomic_web/live/activity_live/new.html.heex @@ -1,3 +1,3 @@
    - <.live_component module={AtomicWeb.ActivityLive.FormComponent} id={:new} title={@page_title} action={@live_action} activity={@activity} return_to={Routes.activity_index_path(@socket, :index)} /> + <.live_component module={AtomicWeb.ActivityLive.FormComponent} id={:new} organization={@current_organization} title={@page_title} action={@live_action} activity={@activity} return_to={Routes.activity_index_path(@socket, :index, @current_organization)} />
    diff --git a/lib/atomic_web/live/activity_live/show.ex b/lib/atomic_web/live/activity_live/show.ex index 7f2b21ccc..a8b2787e3 100644 --- a/lib/atomic_web/live/activity_live/show.ex +++ b/lib/atomic_web/live/activity_live/show.ex @@ -14,14 +14,22 @@ defmodule AtomicWeb.ActivityLive.Show do end @impl true - def handle_params(%{"id" => id}, _, socket) do + def handle_params(%{"organization_id" => organization_id, "id" => id}, _, socket) do activity = Activities.get_activity!(id, [:activity_sessions, :departments, :speakers]) - {:noreply, - socket - |> assign(:enrolled?, Activities.is_user_enrolled?(activity, socket.assigns.current_user)) - |> assign(:page_title, page_title(socket.assigns.live_action)) - |> assign(:activity, %{activity | enrolled: Activities.get_total_enrolled(activity)})} + organizations = Enum.map(activity.departments, fn department -> + department.organization_id + end) + + if organization_id in organizations do + {:noreply, + socket + |> assign(:enrolled?, Activities.is_user_enrolled?(activity, socket.assigns.current_user)) + |> assign(:page_title, page_title(socket.assigns.live_action)) + |> assign(:activity, %{activity | enrolled: Activities.get_total_enrolled(activity)})} + else + raise AtomicWeb.MismatchError + end end @impl true diff --git a/lib/atomic_web/live/activity_live/show.html.heex b/lib/atomic_web/live/activity_live/show.html.heex index fa94dcc61..c56fb19df 100644 --- a/lib/atomic_web/live/activity_live/show.html.heex +++ b/lib/atomic_web/live/activity_live/show.html.heex @@ -2,7 +2,7 @@ <%= if @live_action in [:edit] do %> <.modal return_to={Routes.activity_show_path(@socket, :show, @activity)}> - <.live_component module={AtomicWeb.ActivityLive.FormComponent} id={@activity.id} title={@page_title} action={@live_action} activity={@activity} return_to={Routes.activity_show_path(@socket, :show, @activity)} /> + <.live_component module={AtomicWeb.ActivityLive.FormComponent} id={@activity.id} organization={@current_organization} title={@page_title} action={@live_action} activity={@activity} return_to={Routes.activity_show_path(@socket, :show, @current_organization, @activity)} /> <% end %> @@ -94,6 +94,6 @@ <% end %> <%= if @current_user.role in [:admin, :staff] do %> - <%= live_patch("Edit", to: Routes.activity_edit_path(@socket, :edit, @activity), class: "button") %> | <%= link("Delete", to: "#", phx_click: "delete", phx_value_id: @activity.id, data: [confirm: "Are you sure?"]) %> | - <%= live_redirect("Back", to: Routes.activity_index_path(@socket, :index)) %> + <%= live_patch("Edit", to: Routes.activity_edit_path(@socket, :edit, @current_organization, @activity), class: "button") %> | <%= link("Delete", to: "#", phx_click: "delete", phx_value_id: @activity.id, data: [confirm: "Are you sure?"]) %> | + <%= live_redirect("Back", to: Routes.activity_index_path(@socket, :index, @current_organization)) %> <% end %> diff --git a/lib/atomic_web/live/department_live/show.html.heex b/lib/atomic_web/live/department_live/show.html.heex index 241fd62c6..a48601716 100644 --- a/lib/atomic_web/live/department_live/show.html.heex +++ b/lib/atomic_web/live/department_live/show.html.heex @@ -17,7 +17,7 @@
      <%= for activity <- @department.activities do %>
    • - <%= live_redirect(activity.title, to: Routes.activity_show_path(@socket, :show, activity)) %> + <%= live_redirect(activity.title, to: Routes.activity_show_path(@socket, :show, @current_organization, activity)) %>
    • <% end %>
    diff --git a/lib/atomic_web/live/home_live/index.ex b/lib/atomic_web/live/home_live/index.ex new file mode 100644 index 000000000..f0551b825 --- /dev/null +++ b/lib/atomic_web/live/home_live/index.ex @@ -0,0 +1,16 @@ +defmodule AtomicWeb.HomeLive.Index do + @moduledoc false + use AtomicWeb, :live_view + + @impl true + def mount(_params, _session, socket) do + {:ok, socket} + end + + @impl true + def handle_params(_params, _url, socket) do + {:noreply, + socket + |> assign(:page_title, "Home")} + end +end diff --git a/lib/atomic_web/live/home_live/index.html.heex b/lib/atomic_web/live/home_live/index.html.heex new file mode 100644 index 000000000..4b6dfcd82 --- /dev/null +++ b/lib/atomic_web/live/home_live/index.html.heex @@ -0,0 +1,3 @@ +
    +

    Atomic Home

    +
    \ No newline at end of file diff --git a/lib/atomic_web/router.ex b/lib/atomic_web/router.ex index 932504fd7..7ccf7be28 100644 --- a/lib/atomic_web/router.ex +++ b/lib/atomic_web/router.ex @@ -20,7 +20,7 @@ defmodule AtomicWeb.Router do scope "/", AtomicWeb do pipe_through :browser - live "/", ActivityLive.Index, :index + live "/", HomeLive.Index, :index end scope "/", AtomicWeb do @@ -29,10 +29,10 @@ defmodule AtomicWeb.Router do live_session :logged_in, on_mount: [{AtomicWeb.Hooks, :current_user}] do live "/scanner", ScannerLive.Index, :index - live "/activities", ActivityLive.Index, :index - live "/activities/new", ActivityLive.New, :new - live "/activities/:id/edit", ActivityLive.Edit, :edit - live "/activities/:id", ActivityLive.Show, :show + live "/organizations/:organization_id/activities", ActivityLive.Index, :index + live "/organizations/:organization_id/activities/new", ActivityLive.New, :new + live "/organizations/:organization_id/activities/:id/edit", ActivityLive.Edit, :edit + live "/organizations/:organization_id/activities/:id", ActivityLive.Show, :show live "/organizations/:organization_id/departments", DepartmentLive.Index, :index live "/organizations/:organization_id/departments/new", DepartmentLive.Index, :new diff --git a/lib/atomic_web/templates/layout/root.html.heex b/lib/atomic_web/templates/layout/root.html.heex index 8578d431b..c89e6d294 100644 --- a/lib/atomic_web/templates/layout/root.html.heex +++ b/lib/atomic_web/templates/layout/root.html.heex @@ -15,10 +15,11 @@
    <%= submit do %> -
    +
    Save
    <% end %> diff --git a/lib/atomic_web/live/partner_live/index.ex b/lib/atomic_web/live/partner_live/index.ex index 01b517731..e8f671450 100644 --- a/lib/atomic_web/live/partner_live/index.ex +++ b/lib/atomic_web/live/partner_live/index.ex @@ -5,8 +5,8 @@ defmodule AtomicWeb.PartnerLive.Index do alias Atomic.Partnerships.Partner @impl true - def mount(_params, _session, socket) do - {:ok, assign(socket, :partnerships, list_partnerships())} + def mount(%{"organization_id" => organization_id}, _session, socket) do + {:ok, assign(socket, :partnerships, list_partnerships(organization_id))} end @impl true @@ -14,10 +14,15 @@ defmodule AtomicWeb.PartnerLive.Index do {:noreply, apply_action(socket, socket.assigns.live_action, params)} end - defp apply_action(socket, :edit, %{"id" => id}) do - socket - |> assign(:page_title, "Edit Partner") - |> assign(:partner, Partnerships.get_partner!(id)) + defp apply_action(socket, :edit, %{"organization_id" => organization_id, "id" => id}) do + partner = Partnerships.get_partner!(id) + if partner.organization_id == organization_id do + socket + |> assign(:page_title, "Edit Partner") + |> assign(:partner, Partnerships.get_partner!(id)) + else + raise AtomicWeb.MismatchError + end end defp apply_action(socket, :new, _params) do @@ -37,10 +42,10 @@ defmodule AtomicWeb.PartnerLive.Index do partner = Partnerships.get_partner!(id) {:ok, _} = Partnerships.delete_partner(partner) - {:noreply, assign(socket, :partnerships, list_partnerships())} + {:noreply, assign(socket, :partnerships, list_partnerships(socket.assigns.current_organization.id))} end - defp list_partnerships do - Partnerships.list_partnerships() + defp list_partnerships(id) do + Partnerships.list_partnerships_by_organization_id(id) end end diff --git a/lib/atomic_web/live/partner_live/index.html.heex b/lib/atomic_web/live/partner_live/index.html.heex index 7ab2cf743..7f892ded7 100644 --- a/lib/atomic_web/live/partner_live/index.html.heex +++ b/lib/atomic_web/live/partner_live/index.html.heex @@ -1,8 +1,8 @@

    Listing Partnerships

    <%= if @live_action in [:new, :edit] do %> - <.modal return_to={Routes.partner_index_path(@socket, :index)}> - <.live_component module={AtomicWeb.PartnerLive.FormComponent} id={@partner.id || :new} title={@page_title} action={@live_action} partner={@partner} return_to={Routes.partner_index_path(@socket, :index)} /> + <.modal return_to={Routes.partner_index_path(@socket, :index, @current_organization)}> + <.live_component module={AtomicWeb.PartnerLive.FormComponent} id={@partner.id || :new} organization={@current_organization} title={@page_title} action={@live_action} partner={@partner} return_to={Routes.partner_index_path(@socket, :index, @current_organization)} /> <% end %> @@ -22,8 +22,8 @@ <%= partner.description %> - <%= live_redirect("Show", to: Routes.partner_show_path(@socket, :show, partner)) %> - <%= live_patch("Edit", to: Routes.partner_index_path(@socket, :edit, partner)) %> + <%= live_redirect("Show", to: Routes.partner_show_path(@socket, :show, @current_organization, partner)) %> + <%= live_patch("Edit", to: Routes.partner_index_path(@socket, :edit, @current_organization, partner)) %> <%= link("Delete", to: "#", phx_click: "delete", phx_value_id: partner.id, data: [confirm: "Are you sure?"]) %> @@ -31,4 +31,4 @@ -<%= live_patch("New Partner", to: Routes.partner_index_path(@socket, :new)) %> +<%= live_patch("New Partner", to: Routes.partner_index_path(@socket, :new, @current_organization)) %> diff --git a/lib/atomic_web/live/partner_live/show.ex b/lib/atomic_web/live/partner_live/show.ex index 182ad97b5..7be5e9f7f 100644 --- a/lib/atomic_web/live/partner_live/show.ex +++ b/lib/atomic_web/live/partner_live/show.ex @@ -10,11 +10,16 @@ defmodule AtomicWeb.PartnerLive.Show do end @impl true - def handle_params(%{"id" => id}, _, socket) do - {:noreply, - socket - |> assign(:page_title, page_title(socket.assigns.live_action)) - |> assign(:partner, Partnerships.get_partner!(id))} + def handle_params(%{"organization_id" => organization_id, "id" => id}, _, socket) do + partner = Partnerships.get_partner!(id) + if partner.organization_id == organization_id do + {:noreply, + socket + |> assign(:page_title, page_title(socket.assigns.live_action)) + |> assign(:partner, partner)} + else + raise AtomicWeb.MismatchError + end end defp page_title(:show), do: "Show Partner" diff --git a/lib/atomic_web/live/partner_live/show.html.heex b/lib/atomic_web/live/partner_live/show.html.heex index 4f5f51268..daff0ce2e 100644 --- a/lib/atomic_web/live/partner_live/show.html.heex +++ b/lib/atomic_web/live/partner_live/show.html.heex @@ -1,8 +1,8 @@

    Show Partner

    <%= if @live_action in [:edit] do %> - <.modal return_to={Routes.partner_show_path(@socket, :show, @partner)}> - <.live_component module={AtomicWeb.PartnerLive.FormComponent} id={@partner.id} title={@page_title} action={@live_action} partner={@partner} return_to={Routes.partner_show_path(@socket, :show, @partner)} /> + <.modal return_to={Routes.partner_show_path(@socket, :show, @current_organization, @partner)}> + <.live_component module={AtomicWeb.PartnerLive.FormComponent} id={@partner.id} title={@page_title} action={@live_action} partner={@partner} return_to={Routes.partner_show_path(@socket, :show, @current_organization, @partner)} /> <% end %> @@ -24,5 +24,5 @@ <% end %> -<%= live_patch("Edit", to: Routes.partner_show_path(@socket, :edit, @partner), class: "button") %> | -<%= live_redirect("Back", to: Routes.partner_index_path(@socket, :index)) %> +<%= live_patch("Edit", to: Routes.partner_show_path(@socket, :edit, @current_organization, @partner), class: "button") %> | +<%= live_redirect("Back", to: Routes.partner_index_path(@socket, :index, @current_organization)) %> diff --git a/lib/atomic_web/router.ex b/lib/atomic_web/router.ex index 25840cdf8..f133426a6 100644 --- a/lib/atomic_web/router.ex +++ b/lib/atomic_web/router.ex @@ -40,11 +40,11 @@ defmodule AtomicWeb.Router do live "/organizations/:organization_id/departments/:id", DepartmentLive.Show, :show live "/organizations/:organization_id/departments/:id/show/edit", DepartmentLive.Show, :edit - live "/partners", PartnerLive.Index, :index - live "/partners/new", PartnerLive.Index, :new - live "/partners/:id/edit", PartnerLive.Index, :edit - live "/partners/:id", PartnerLive.Show, :show - live "/partners/:id/show/edit", PartnerLive.Show, :edit + live "/organizations/:organization_id/partners", PartnerLive.Index, :index + live "/organizations/:organization_id/partners/new", PartnerLive.Index, :new + live "/organizations/:organization_id/partners/:id/edit", PartnerLive.Index, :edit + live "/organizations/:organization_id/partners/:id", PartnerLive.Show, :show + live "/organizations/:organization_id/partners/:id/show/edit", PartnerLive.Show, :edit live "/speakers", SpeakerLive.Index, :index live "/speakers/new", SpeakerLive.Index, :new diff --git a/lib/atomic_web/templates/layout/root.html.heex b/lib/atomic_web/templates/layout/root.html.heex index ea955f775..8578d431b 100644 --- a/lib/atomic_web/templates/layout/root.html.heex +++ b/lib/atomic_web/templates/layout/root.html.heex @@ -18,7 +18,7 @@ <%= if @current_user do %>
  • <%= live_redirect("Activities", to: Routes.activity_index_path(@conn, :index)) %>
  • <%= live_redirect("Departments", to: Routes.department_index_path(@conn, :index, @current_organization)) %>
  • -
  • <%= live_redirect("Partners", to: Routes.partner_index_path(@conn, :index)) %>
  • +
  • <%= live_redirect("Partners", to: Routes.partner_index_path(@conn, :index, @current_organization)) %>
  • <%= live_redirect("Speakers", to: Routes.speaker_index_path(@conn, :index)) %>
  • <%= live_redirect("Organizations", to: Routes.organization_index_path(@conn, :index)) %>
  • <%= live_redirect("Scanner", to: Routes.scanner_index_path(@conn, :index)) %>
  • From 161f226b705873cb25d00f2e482508efebd09d83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lobo?= Date: Tue, 11 Jul 2023 00:12:02 +0100 Subject: [PATCH 26/42] Change organization routes id parameter's name --- lib/atomic_web/live/organization_live/index.ex | 4 ++-- lib/atomic_web/live/organization_live/show.ex | 2 +- lib/atomic_web/router.ex | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/atomic_web/live/organization_live/index.ex b/lib/atomic_web/live/organization_live/index.ex index 8ecb9635f..48b342d1c 100644 --- a/lib/atomic_web/live/organization_live/index.ex +++ b/lib/atomic_web/live/organization_live/index.ex @@ -14,7 +14,7 @@ defmodule AtomicWeb.OrganizationLive.Index do {:noreply, apply_action(socket, socket.assigns.live_action, params)} end - defp apply_action(socket, :edit, %{"id" => id}) do + defp apply_action(socket, :edit, %{"organization_id" => id}) do socket |> assign(:page_title, "Edit Organization") |> assign(:organization, Organizations.get_organization!(id)) @@ -33,7 +33,7 @@ defmodule AtomicWeb.OrganizationLive.Index do end @impl true - def handle_event("delete", %{"id" => id}, socket) do + def handle_event("delete", %{"organization_id" => id}, socket) do organization = Organizations.get_organization!(id) {:ok, _} = Organizations.delete_organization(organization) diff --git a/lib/atomic_web/live/organization_live/show.ex b/lib/atomic_web/live/organization_live/show.ex index 4b5122e24..00cbd169d 100644 --- a/lib/atomic_web/live/organization_live/show.ex +++ b/lib/atomic_web/live/organization_live/show.ex @@ -9,7 +9,7 @@ defmodule AtomicWeb.OrganizationLive.Show do end @impl true - def handle_params(%{"id" => id}, _, socket) do + def handle_params(%{"organization_id" => id}, _, socket) do org = Organizations.get_organization!(id, [:departments]) {:noreply, diff --git a/lib/atomic_web/router.ex b/lib/atomic_web/router.ex index f133426a6..759ed1727 100644 --- a/lib/atomic_web/router.ex +++ b/lib/atomic_web/router.ex @@ -54,9 +54,9 @@ defmodule AtomicWeb.Router do live "/organizations", OrganizationLive.Index, :index live "/organizations/new", OrganizationLive.Index, :new - live "/organizations/:id/edit", OrganizationLive.Index, :edit - live "/organizations/:id", OrganizationLive.Show, :show - live "/organizations/:id/show/edit", OrganizationLive.Show, :edit + live "/organizations/:organization_id/edit", OrganizationLive.Index, :edit + live "/organizations/:organization_id", OrganizationLive.Show, :show + live "/organizations/:organization_id/show/edit", OrganizationLive.Show, :edit live "/membership/:org", MembershipLive.Index, :index live "/membership/:org/new", MembershipLive.New, :new From 8f6d8cd41a4504cd279b2baad751d205059b5420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lobo?= Date: Tue, 11 Jul 2023 01:17:19 +0100 Subject: [PATCH 27/42] Change membership routes and detect id mismatches --- lib/atomic_web/live/membership_live/edit.ex | 26 +++++++++++--------- lib/atomic_web/live/membership_live/index.ex | 2 +- lib/atomic_web/live/membership_live/new.ex | 4 +-- lib/atomic_web/live/membership_live/show.ex | 15 ++++++----- lib/atomic_web/router.ex | 8 +++--- 5 files changed, 31 insertions(+), 24 deletions(-) diff --git a/lib/atomic_web/live/membership_live/edit.ex b/lib/atomic_web/live/membership_live/edit.ex index b12c0edf0..bb418b48e 100644 --- a/lib/atomic_web/live/membership_live/edit.ex +++ b/lib/atomic_web/live/membership_live/edit.ex @@ -9,19 +9,23 @@ defmodule AtomicWeb.MembershipLive.Edit do end @impl true - def handle_params(%{"org" => org, "id" => id}, _, socket) do + def handle_params(%{"organization_id" => organization_id, "id" => id}, _, socket) do membership = Organizations.get_membership!(id, [:user, :organization, :created_by]) - {:noreply, - socket - |> assign(:page_title, page_title(socket.assigns.live_action)) - |> assign(:organization, org) - |> assign(:membership, membership) - |> assign(:current_user, socket.assigns.current_user) - |> assign( - :allowed_roles, - Organizations.roles_less_than_or_equal(socket.assigns.current_user.role) - )} + if membership.organization_id == organization_id do + {:noreply, + socket + |> assign(:page_title, page_title(socket.assigns.live_action)) + |> assign(:organization, organization_id) + |> assign(:membership, membership) + |> assign(:current_user, socket.assigns.current_user) + |> assign( + :allowed_roles, + Organizations.roles_less_than_or_equal(socket.assigns.current_user.role) + )} + else + raise AtomicWeb.MismatchError + end end defp page_title(:index), do: "List memberships" diff --git a/lib/atomic_web/live/membership_live/index.ex b/lib/atomic_web/live/membership_live/index.ex index 454c68208..b745058e3 100644 --- a/lib/atomic_web/live/membership_live/index.ex +++ b/lib/atomic_web/live/membership_live/index.ex @@ -9,7 +9,7 @@ defmodule AtomicWeb.MembershipLive.Index do end @impl true - def handle_params(%{"org" => id}, _, socket) do + def handle_params(%{"organization_id" => id}, _, socket) do memberships = Organizations.list_memberships(%{"organization_id" => id}, [:user]) |> Enum.filter(fn m -> m.role != :follower end) diff --git a/lib/atomic_web/live/membership_live/new.ex b/lib/atomic_web/live/membership_live/new.ex index 020fe7df3..bbe906dd5 100644 --- a/lib/atomic_web/live/membership_live/new.ex +++ b/lib/atomic_web/live/membership_live/new.ex @@ -12,12 +12,12 @@ defmodule AtomicWeb.MembershipLive.New do end @impl true - def handle_params(%{"org" => org_id}, _url, socket) do + def handle_params(%{"organization_id" => organization_id}, _url, socket) do {:noreply, socket |> assign(:page_title, gettext("New Membership")) |> assign(:membership, %Membership{ - organization_id: org_id + organization_id: organization_id }) |> assign(:users, Enum.map(Accounts.list_users(), fn u -> [key: u.email, value: u.id] end)) |> assign( diff --git a/lib/atomic_web/live/membership_live/show.ex b/lib/atomic_web/live/membership_live/show.ex index fab8a6238..f75cba21a 100644 --- a/lib/atomic_web/live/membership_live/show.ex +++ b/lib/atomic_web/live/membership_live/show.ex @@ -9,13 +9,16 @@ defmodule AtomicWeb.MembershipLive.Show do end @impl true - def handle_params(%{"org" => _org, "id" => id}, _, socket) do + def handle_params(%{"organization_id" => organization_id, "id" => id}, _, socket) do membership = Organizations.get_membership!(id, [:user, :organization, :created_by]) - - {:noreply, - socket - |> assign(:page_title, page_title(socket.assigns.live_action)) - |> assign(:membership, membership)} + if membership.organization_id == organization_id do + {:noreply, + socket + |> assign(:page_title, page_title(socket.assigns.live_action)) + |> assign(:membership, membership)} + else + raise AtomicWeb.MismatchError + end end defp page_title(:index), do: "List memberships" diff --git a/lib/atomic_web/router.ex b/lib/atomic_web/router.ex index 759ed1727..a8a86fc6e 100644 --- a/lib/atomic_web/router.ex +++ b/lib/atomic_web/router.ex @@ -58,10 +58,10 @@ defmodule AtomicWeb.Router do live "/organizations/:organization_id", OrganizationLive.Show, :show live "/organizations/:organization_id/show/edit", OrganizationLive.Show, :edit - live "/membership/:org", MembershipLive.Index, :index - live "/membership/:org/new", MembershipLive.New, :new - live "/membership/:org/:id", MembershipLive.Show, :show - live "/membership/:org/:id/edit", MembershipLive.Edit, :edit + live "/organizations/:organization_id/memberships", MembershipLive.Index, :index + live "/organizations/:organization_id/memberships/new", MembershipLive.New, :new + live "/organizations/:organization_id/memberships/:id", MembershipLive.Show, :show + live "/organizations/:organization_id/memberships/:id/edit", MembershipLive.Edit, :edit live "/card/:membership_id", CardLive.Show, :show From a4205fc3d6ceb8650d3b680b1651889d015a2648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lobo?= Date: Tue, 11 Jul 2023 01:19:59 +0100 Subject: [PATCH 28/42] Remove duplicate routes --- lib/atomic_web/router.ex | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/atomic_web/router.ex b/lib/atomic_web/router.ex index a8a86fc6e..932504fd7 100644 --- a/lib/atomic_web/router.ex +++ b/lib/atomic_web/router.ex @@ -69,10 +69,6 @@ defmodule AtomicWeb.Router do live "/board/:org/new", BoardLive.New, :new live "/board/:org/:id", BoardLive.Show, :show live "/board/:org/:id/edit", BoardLive.Edit, :edit - live "/memberships/:org", MembershipLive.Index, :index - live "/memberships/:org/new", MembershipLive.New, :new - live "/memberships/:org/:id", MembershipLive.Show, :show - live "/memberships/:org/:id/edit", MembershipLive.Edit, :edit live "/user/edit", UserLive.Edit, :edit end From bfad6e5af4a49085e9ec0043f1d56ce8317cd9d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lobo?= Date: Fri, 14 Jul 2023 18:14:30 +0100 Subject: [PATCH 29/42] Add organization_id param to activity routes --- lib/atomic_web/live/activity_live/edit.ex | 23 ++++++++++++------- .../live/activity_live/edit.html.heex | 2 +- .../live/activity_live/form_component.ex | 13 +++++++++-- .../live/activity_live/index.html.heex | 4 ++-- .../live/activity_live/new.html.heex | 2 +- lib/atomic_web/live/activity_live/show.ex | 20 +++++++++++----- .../live/activity_live/show.html.heex | 6 ++--- .../live/department_live/show.html.heex | 2 +- lib/atomic_web/live/home_live/index.ex | 16 +++++++++++++ lib/atomic_web/live/home_live/index.html.heex | 3 +++ lib/atomic_web/router.ex | 10 ++++---- .../templates/layout/root.html.heex | 3 ++- 12 files changed, 74 insertions(+), 30 deletions(-) create mode 100644 lib/atomic_web/live/home_live/index.ex create mode 100644 lib/atomic_web/live/home_live/index.html.heex diff --git a/lib/atomic_web/live/activity_live/edit.ex b/lib/atomic_web/live/activity_live/edit.ex index 8f63b4003..810fc6ef0 100644 --- a/lib/atomic_web/live/activity_live/edit.ex +++ b/lib/atomic_web/live/activity_live/edit.ex @@ -10,13 +10,20 @@ defmodule AtomicWeb.ActivityLive.Edit do end @impl true - def handle_params(%{"id" => id} = _params, _url, socket) do - {:noreply, - socket - |> assign(:page_title, gettext("Edit Activity")) - |> assign( - :activity, - Activities.get_activity!(id, [:activity_sessions, :speakers, :departments]) - )} + def handle_params(%{"organization_id" => organization_id, "id" => id} = _params, _url, socket) do + activity = Activities.get_activity!(id, [:activity_sessions, :speakers, :departments]) + + organizations = Enum.map(activity.departments, fn department -> + department.organization_id + end) + + if organization_id in organizations do + {:noreply, + socket + |> assign(:page_title, gettext("Edit Activity")) + |> assign(:activity, activity)} + else + raise AtomicWeb.MismatchError + end end end diff --git a/lib/atomic_web/live/activity_live/edit.html.heex b/lib/atomic_web/live/activity_live/edit.html.heex index 76dc631a2..598333bc2 100644 --- a/lib/atomic_web/live/activity_live/edit.html.heex +++ b/lib/atomic_web/live/activity_live/edit.html.heex @@ -1,3 +1,3 @@
    - <.live_component module={AtomicWeb.ActivityLive.FormComponent} id={@activity.id} title={@page_title} action={@live_action} activity={@activity} return_to={Routes.activity_show_path(@socket, :show, @activity)} /> + <.live_component module={AtomicWeb.ActivityLive.FormComponent} id={@activity.id} organization={@current_organization} title={@page_title} action={@live_action} activity={@activity} return_to={Routes.activity_show_path(@socket, :show, @current_organization, @activity)} />
    diff --git a/lib/atomic_web/live/activity_live/form_component.ex b/lib/atomic_web/live/activity_live/form_component.ex index 2c246194b..36df61df7 100644 --- a/lib/atomic_web/live/activity_live/form_component.ex +++ b/lib/atomic_web/live/activity_live/form_component.ex @@ -7,25 +7,34 @@ defmodule AtomicWeb.ActivityLive.FormComponent do @impl true def mount(socket) do - departments = Departments.list_departments() speakers = Activities.list_speakers() {:ok, socket - |> assign(:departments, departments) + |> assign(:departments, []) |> assign(:speakers, speakers)} end @impl true def update(%{activity: activity} = assigns, socket) do + departments = Departments.list_departments_by_organization_id(assigns.organization.id) changeset = Activities.change_activity(activity) {:ok, socket |> assign(assigns) + |> assign(:departments, departments) |> assign(:changeset, changeset)} end + @impl true + def update(%{"organization_id" => organization_id}, socket) do + departments = Departments.list_departments_by_organization_id(organization_id) + {:ok, + socket + |> assign(:departments, departments)} + end + @impl true def handle_event("validate", %{"activity" => activity_params}, socket) do changeset = diff --git a/lib/atomic_web/live/activity_live/index.html.heex b/lib/atomic_web/live/activity_live/index.html.heex index 2b959a11f..6cdc03b3f 100644 --- a/lib/atomic_web/live/activity_live/index.html.heex +++ b/lib/atomic_web/live/activity_live/index.html.heex @@ -22,11 +22,11 @@ <%= activity.maximum_entries %> - <%= live_redirect("Show", to: Routes.activity_show_path(@socket, :show, activity)) %> + <%= live_redirect("Show", to: Routes.activity_show_path(@socket, :show, @current_organization, activity)) %> <% end %> -<%= live_patch("New Activity", to: Routes.activity_new_path(@socket, :new)) %> +<%= live_patch("New Activity", to: Routes.activity_new_path(@socket, :new, @current_organization)) %> diff --git a/lib/atomic_web/live/activity_live/new.html.heex b/lib/atomic_web/live/activity_live/new.html.heex index b6676be95..0cd31fb2a 100644 --- a/lib/atomic_web/live/activity_live/new.html.heex +++ b/lib/atomic_web/live/activity_live/new.html.heex @@ -1,3 +1,3 @@
    - <.live_component module={AtomicWeb.ActivityLive.FormComponent} id={:new} title={@page_title} action={@live_action} activity={@activity} return_to={Routes.activity_index_path(@socket, :index)} /> + <.live_component module={AtomicWeb.ActivityLive.FormComponent} id={:new} organization={@current_organization} title={@page_title} action={@live_action} activity={@activity} return_to={Routes.activity_index_path(@socket, :index, @current_organization)} />
    diff --git a/lib/atomic_web/live/activity_live/show.ex b/lib/atomic_web/live/activity_live/show.ex index 7f2b21ccc..a8b2787e3 100644 --- a/lib/atomic_web/live/activity_live/show.ex +++ b/lib/atomic_web/live/activity_live/show.ex @@ -14,14 +14,22 @@ defmodule AtomicWeb.ActivityLive.Show do end @impl true - def handle_params(%{"id" => id}, _, socket) do + def handle_params(%{"organization_id" => organization_id, "id" => id}, _, socket) do activity = Activities.get_activity!(id, [:activity_sessions, :departments, :speakers]) - {:noreply, - socket - |> assign(:enrolled?, Activities.is_user_enrolled?(activity, socket.assigns.current_user)) - |> assign(:page_title, page_title(socket.assigns.live_action)) - |> assign(:activity, %{activity | enrolled: Activities.get_total_enrolled(activity)})} + organizations = Enum.map(activity.departments, fn department -> + department.organization_id + end) + + if organization_id in organizations do + {:noreply, + socket + |> assign(:enrolled?, Activities.is_user_enrolled?(activity, socket.assigns.current_user)) + |> assign(:page_title, page_title(socket.assigns.live_action)) + |> assign(:activity, %{activity | enrolled: Activities.get_total_enrolled(activity)})} + else + raise AtomicWeb.MismatchError + end end @impl true diff --git a/lib/atomic_web/live/activity_live/show.html.heex b/lib/atomic_web/live/activity_live/show.html.heex index fa94dcc61..c56fb19df 100644 --- a/lib/atomic_web/live/activity_live/show.html.heex +++ b/lib/atomic_web/live/activity_live/show.html.heex @@ -2,7 +2,7 @@ <%= if @live_action in [:edit] do %> <.modal return_to={Routes.activity_show_path(@socket, :show, @activity)}> - <.live_component module={AtomicWeb.ActivityLive.FormComponent} id={@activity.id} title={@page_title} action={@live_action} activity={@activity} return_to={Routes.activity_show_path(@socket, :show, @activity)} /> + <.live_component module={AtomicWeb.ActivityLive.FormComponent} id={@activity.id} organization={@current_organization} title={@page_title} action={@live_action} activity={@activity} return_to={Routes.activity_show_path(@socket, :show, @current_organization, @activity)} /> <% end %> @@ -94,6 +94,6 @@ <% end %> <%= if @current_user.role in [:admin, :staff] do %> - <%= live_patch("Edit", to: Routes.activity_edit_path(@socket, :edit, @activity), class: "button") %> | <%= link("Delete", to: "#", phx_click: "delete", phx_value_id: @activity.id, data: [confirm: "Are you sure?"]) %> | - <%= live_redirect("Back", to: Routes.activity_index_path(@socket, :index)) %> + <%= live_patch("Edit", to: Routes.activity_edit_path(@socket, :edit, @current_organization, @activity), class: "button") %> | <%= link("Delete", to: "#", phx_click: "delete", phx_value_id: @activity.id, data: [confirm: "Are you sure?"]) %> | + <%= live_redirect("Back", to: Routes.activity_index_path(@socket, :index, @current_organization)) %> <% end %> diff --git a/lib/atomic_web/live/department_live/show.html.heex b/lib/atomic_web/live/department_live/show.html.heex index 241fd62c6..a48601716 100644 --- a/lib/atomic_web/live/department_live/show.html.heex +++ b/lib/atomic_web/live/department_live/show.html.heex @@ -17,7 +17,7 @@
      <%= for activity <- @department.activities do %>
    • - <%= live_redirect(activity.title, to: Routes.activity_show_path(@socket, :show, activity)) %> + <%= live_redirect(activity.title, to: Routes.activity_show_path(@socket, :show, @current_organization, activity)) %>
    • <% end %>
    diff --git a/lib/atomic_web/live/home_live/index.ex b/lib/atomic_web/live/home_live/index.ex new file mode 100644 index 000000000..f0551b825 --- /dev/null +++ b/lib/atomic_web/live/home_live/index.ex @@ -0,0 +1,16 @@ +defmodule AtomicWeb.HomeLive.Index do + @moduledoc false + use AtomicWeb, :live_view + + @impl true + def mount(_params, _session, socket) do + {:ok, socket} + end + + @impl true + def handle_params(_params, _url, socket) do + {:noreply, + socket + |> assign(:page_title, "Home")} + end +end diff --git a/lib/atomic_web/live/home_live/index.html.heex b/lib/atomic_web/live/home_live/index.html.heex new file mode 100644 index 000000000..4b6dfcd82 --- /dev/null +++ b/lib/atomic_web/live/home_live/index.html.heex @@ -0,0 +1,3 @@ +
    +

    Atomic Home

    +
    \ No newline at end of file diff --git a/lib/atomic_web/router.ex b/lib/atomic_web/router.ex index 932504fd7..7ccf7be28 100644 --- a/lib/atomic_web/router.ex +++ b/lib/atomic_web/router.ex @@ -20,7 +20,7 @@ defmodule AtomicWeb.Router do scope "/", AtomicWeb do pipe_through :browser - live "/", ActivityLive.Index, :index + live "/", HomeLive.Index, :index end scope "/", AtomicWeb do @@ -29,10 +29,10 @@ defmodule AtomicWeb.Router do live_session :logged_in, on_mount: [{AtomicWeb.Hooks, :current_user}] do live "/scanner", ScannerLive.Index, :index - live "/activities", ActivityLive.Index, :index - live "/activities/new", ActivityLive.New, :new - live "/activities/:id/edit", ActivityLive.Edit, :edit - live "/activities/:id", ActivityLive.Show, :show + live "/organizations/:organization_id/activities", ActivityLive.Index, :index + live "/organizations/:organization_id/activities/new", ActivityLive.New, :new + live "/organizations/:organization_id/activities/:id/edit", ActivityLive.Edit, :edit + live "/organizations/:organization_id/activities/:id", ActivityLive.Show, :show live "/organizations/:organization_id/departments", DepartmentLive.Index, :index live "/organizations/:organization_id/departments/new", DepartmentLive.Index, :new diff --git a/lib/atomic_web/templates/layout/root.html.heex b/lib/atomic_web/templates/layout/root.html.heex index 8578d431b..c89e6d294 100644 --- a/lib/atomic_web/templates/layout/root.html.heex +++ b/lib/atomic_web/templates/layout/root.html.heex @@ -15,10 +15,11 @@
    diff --git a/lib/atomic_web/live/membership_live/show.ex b/lib/atomic_web/live/membership_live/show.ex index f75cba21a..9b2e1c42b 100644 --- a/lib/atomic_web/live/membership_live/show.ex +++ b/lib/atomic_web/live/membership_live/show.ex @@ -11,6 +11,7 @@ defmodule AtomicWeb.MembershipLive.Show do @impl true def handle_params(%{"organization_id" => organization_id, "id" => id}, _, socket) do membership = Organizations.get_membership!(id, [:user, :organization, :created_by]) + if membership.organization_id == organization_id do {:noreply, socket diff --git a/lib/atomic_web/live/partner_live/form_component.ex b/lib/atomic_web/live/partner_live/form_component.ex index f34a63e2b..6ee1d0d97 100644 --- a/lib/atomic_web/live/partner_live/form_component.ex +++ b/lib/atomic_web/live/partner_live/form_component.ex @@ -57,8 +57,8 @@ defmodule AtomicWeb.PartnerLive.FormComponent do end defp save_partner(socket, :new, partner_params) do - partner_params = - Map.put(partner_params, "organization_id", socket.assigns.organization.id) + partner_params = Map.put(partner_params, "organization_id", socket.assigns.organization.id) + case Partnerships.create_partner(partner_params, &consume_image_data(socket, &1)) do {:ok, _partner} -> {:noreply, diff --git a/lib/atomic_web/live/partner_live/index.ex b/lib/atomic_web/live/partner_live/index.ex index e8f671450..b1937ef67 100644 --- a/lib/atomic_web/live/partner_live/index.ex +++ b/lib/atomic_web/live/partner_live/index.ex @@ -16,6 +16,7 @@ defmodule AtomicWeb.PartnerLive.Index do defp apply_action(socket, :edit, %{"organization_id" => organization_id, "id" => id}) do partner = Partnerships.get_partner!(id) + if partner.organization_id == organization_id do socket |> assign(:page_title, "Edit Partner") @@ -42,7 +43,8 @@ defmodule AtomicWeb.PartnerLive.Index do partner = Partnerships.get_partner!(id) {:ok, _} = Partnerships.delete_partner(partner) - {:noreply, assign(socket, :partnerships, list_partnerships(socket.assigns.current_organization.id))} + {:noreply, + assign(socket, :partnerships, list_partnerships(socket.assigns.current_organization.id))} end defp list_partnerships(id) do diff --git a/lib/atomic_web/live/partner_live/show.ex b/lib/atomic_web/live/partner_live/show.ex index 7be5e9f7f..b8a4701f9 100644 --- a/lib/atomic_web/live/partner_live/show.ex +++ b/lib/atomic_web/live/partner_live/show.ex @@ -12,6 +12,7 @@ defmodule AtomicWeb.PartnerLive.Show do @impl true def handle_params(%{"organization_id" => organization_id, "id" => id}, _, socket) do partner = Partnerships.get_partner!(id) + if partner.organization_id == organization_id do {:noreply, socket diff --git a/lib/atomic_web/live/speaker_live/form_component.ex b/lib/atomic_web/live/speaker_live/form_component.ex index 6244d8f9a..144e7a59d 100644 --- a/lib/atomic_web/live/speaker_live/form_component.ex +++ b/lib/atomic_web/live/speaker_live/form_component.ex @@ -41,8 +41,7 @@ defmodule AtomicWeb.SpeakerLive.FormComponent do end defp save_speaker(socket, :new, speaker_params) do - speaker_params = - Map.put(speaker_params, "organization_id", socket.assigns.organization.id) + speaker_params = Map.put(speaker_params, "organization_id", socket.assigns.organization.id) case Activities.create_speaker(speaker_params) do {:ok, _speaker} -> diff --git a/lib/atomic_web/live/speaker_live/show.ex b/lib/atomic_web/live/speaker_live/show.ex index e06f9ff4e..167bb5ded 100644 --- a/lib/atomic_web/live/speaker_live/show.ex +++ b/lib/atomic_web/live/speaker_live/show.ex @@ -14,9 +14,9 @@ defmodule AtomicWeb.SpeakerLive.Show do if speaker.organization_id == organization_id do {:noreply, - socket - |> assign(:page_title, page_title(socket.assigns.live_action)) - |> assign(:speaker, speaker)} + socket + |> assign(:page_title, page_title(socket.assigns.live_action)) + |> assign(:speaker, speaker)} else raise AtomicWeb.MismatchError end From 1c1187a94e94dd5849c76784bfaf8cba402455ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lobo?= Date: Sat, 15 Jul 2023 00:22:13 +0100 Subject: [PATCH 34/42] Solve warnings --- lib/atomic_web/live/activity_live/show.ex | 2 +- lib/atomic_web/live/user_live/edit.html.heex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/atomic_web/live/activity_live/show.ex b/lib/atomic_web/live/activity_live/show.ex index c2dfde4df..493b57eec 100644 --- a/lib/atomic_web/live/activity_live/show.ex +++ b/lib/atomic_web/live/activity_live/show.ex @@ -77,7 +77,7 @@ defmodule AtomicWeb.ActivityLive.Show do def handle_event("delete", _payload, socket) do {:ok, _} = Activities.delete_activity(socket.assigns.activity) - {:noreply, push_redirect(socket, to: Routes.activity_index_path(socket, :index))} + {:noreply, push_redirect(socket, to: Routes.activity_index_path(socket, :index, socket.assigns.current_organization))} end @impl true diff --git a/lib/atomic_web/live/user_live/edit.html.heex b/lib/atomic_web/live/user_live/edit.html.heex index dffb93cee..4896ca8b5 100644 --- a/lib/atomic_web/live/user_live/edit.html.heex +++ b/lib/atomic_web/live/user_live/edit.html.heex @@ -1 +1 @@ -<.live_component module={AtomicWeb.UserLive.FormComponent} user={@user} id={@current_user.id} courses={@courses} title={@page_title} action={@live_action} return_to={Routes.activity_index_path(@socket, :index)} /> +<.live_component module={AtomicWeb.UserLive.FormComponent} user={@user} id={@current_user.id} courses={@courses} title={@page_title} action={@live_action} return_to={Routes.home_index_path(@conn, :index)} /> From b4ce9fcb0f920b00b596a8fb342cfd27c7e79943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lobo?= Date: Mon, 17 Jul 2023 12:22:42 +0100 Subject: [PATCH 35/42] Update routes and add authorization --- lib/atomic/organizations.ex | 25 +++++ .../live/activity_live/show.html.heex | 2 +- lib/atomic_web/plugs/authorize.ex | 45 ++++++++ lib/atomic_web/router.ex | 103 +++++++++++------- 4 files changed, 137 insertions(+), 38 deletions(-) create mode 100644 lib/atomic_web/plugs/authorize.ex diff --git a/lib/atomic/organizations.ex b/lib/atomic/organizations.ex index 26bb50761..f18197f83 100644 --- a/lib/atomic/organizations.ex +++ b/lib/atomic/organizations.ex @@ -168,6 +168,13 @@ defmodule Atomic.Organizations do |> Repo.exists?() end + def get_role(user_id, organization_id) do + Membership + |> where([m], m.user_id == ^user_id and m.organization_id == ^organization_id) + |> Repo.one() + |> Map.get(:role) + end + @doc """ Gets a single membership. @@ -255,6 +262,24 @@ defmodule Atomic.Organizations do end end + @doc """ + Returns all roles bigger or equal to the given role. + + ## Examples + + iex> roles_bigger_than_or_equal(:member) + [:member, :admin, :owner] + + """ + def roles_bigger_than_or_equal(role) do + case role do + :follower -> [:follower, :member, :admin, :owner] + :member -> [:member, :admin, :owner] + :admin -> [:admin, :owner] + :owner -> [:owner] + end + end + @doc """ Returns the list of users organizations. diff --git a/lib/atomic_web/live/activity_live/show.html.heex b/lib/atomic_web/live/activity_live/show.html.heex index c56fb19df..2cbbe9b04 100644 --- a/lib/atomic_web/live/activity_live/show.html.heex +++ b/lib/atomic_web/live/activity_live/show.html.heex @@ -1,7 +1,7 @@

    Show Activity

    <%= if @live_action in [:edit] do %> - <.modal return_to={Routes.activity_show_path(@socket, :show, @activity)}> + <.modal return_to={Routes.activity_show_path(@socket, :show, @current_organization, @activity)}> <.live_component module={AtomicWeb.ActivityLive.FormComponent} id={@activity.id} organization={@current_organization} title={@page_title} action={@live_action} activity={@activity} return_to={Routes.activity_show_path(@socket, :show, @current_organization, @activity)} /> <% end %> diff --git a/lib/atomic_web/plugs/authorize.ex b/lib/atomic_web/plugs/authorize.ex new file mode 100644 index 000000000..79b33e47a --- /dev/null +++ b/lib/atomic_web/plugs/authorize.ex @@ -0,0 +1,45 @@ +defmodule AtomicWeb.Plugs.Authorize do + @moduledoc false + import Plug.Conn + import Atomic.Organizations + + def init(opts), do: opts + + def call(conn, minimum_authorized_role) do + if authorized?(conn, minimum_authorized_role) do + conn + else + conn + |> send_resp(:not_found, "") + |> halt() + end + end + + defp authorized?(conn, minimum_authorized_role) do + organization_id = get_organization_id(conn) + + case {organization_id, conn.assigns.current_user} do + {nil, _} -> + false + {id, user} -> + user_authorized?(user, id, minimum_authorized_role) + end + end + + defp get_organization_id(conn) do + case conn.params["organization_id"] do + organization_id when is_binary(organization_id) -> + organization_id + _ -> + nil + end + end + + defp user_authorized?(user, organization_id, minimum_authorized_role) do + user_organizations = Enum.map(user.organizations, & &1.id) + role = get_role(user.id, organization_id) + allowed_roles = roles_bigger_than_or_equal(minimum_authorized_role) + + organization_id in user_organizations && role in allowed_roles + end +end diff --git a/lib/atomic_web/router.ex b/lib/atomic_web/router.ex index de8fa1f8d..b88c917dc 100644 --- a/lib/atomic_web/router.ex +++ b/lib/atomic_web/router.ex @@ -17,10 +17,29 @@ defmodule AtomicWeb.Router do plug :accepts, ["json"] end + pipeline :admin do + plug AtomicWeb.Plugs.Authorize, :admin + end + + pipeline :member do + plug AtomicWeb.Plugs.Authorize, :member + end + + pipeline :follower do + plug AtomicWeb.Plugs.Authorize, :follower + end + scope "/", AtomicWeb do pipe_through :browser live "/", HomeLive.Index, :index + + live "/organizations", OrganizationLive.Index, :index + + scope "/organizations/:organization_id" do + live "/board/", BoardLive.Index, :index + live "/board/:id", BoardLive.Show, :show + end end scope "/", AtomicWeb do @@ -29,48 +48,58 @@ defmodule AtomicWeb.Router do live_session :logged_in, on_mount: [{AtomicWeb.Hooks, :current_user}] do live "/scanner", ScannerLive.Index, :index - live "/organizations/:organization_id/activities", ActivityLive.Index, :index - live "/organizations/:organization_id/activities/new", ActivityLive.New, :new - live "/organizations/:organization_id/activities/:id/edit", ActivityLive.Edit, :edit - live "/organizations/:organization_id/activities/:id", ActivityLive.Show, :show - - live "/organizations/:organization_id/departments", DepartmentLive.Index, :index - live "/organizations/:organization_id/departments/new", DepartmentLive.Index, :new - live "/organizations/:organization_id/departments/:id/edit", DepartmentLive.Index, :edit - live "/organizations/:organization_id/departments/:id", DepartmentLive.Show, :show - live "/organizations/:organization_id/departments/:id/show/edit", DepartmentLive.Show, :edit - - live "/organizations/:organization_id/partners", PartnerLive.Index, :index - live "/organizations/:organization_id/partners/new", PartnerLive.Index, :new - live "/organizations/:organization_id/partners/:id/edit", PartnerLive.Index, :edit - live "/organizations/:organization_id/partners/:id", PartnerLive.Show, :show - live "/organizations/:organization_id/partners/:id/show/edit", PartnerLive.Show, :edit - - live "/organizations/:organization_id/speakers", SpeakerLive.Index, :index - live "/organizations/:organization_id/speakers/new", SpeakerLive.Index, :new - live "/organizations/:organization_id/speakers/:id/edit", SpeakerLive.Index, :edit - live "/organizations/:organization_id/speakers/:id", SpeakerLive.Show, :show - live "/organizations/:organization_id/speakers/:id/show/edit", SpeakerLive.Show, :edit - - live "/organizations", OrganizationLive.Index, :index - live "/organizations/new", OrganizationLive.Index, :new - live "/organizations/:organization_id/edit", OrganizationLive.Index, :edit - live "/organizations/:organization_id", OrganizationLive.Show, :show - live "/organizations/:organization_id/show/edit", OrganizationLive.Show, :edit + scope "/organizations/:organization_id" do + live "/", OrganizationLive.Show, :show + + pipe_through :admin + live "/edit", OrganizationLive.Index, :edit + live "/show/edit", OrganizationLive.Show, :edit - live "/organizations/:organization_id/memberships", MembershipLive.Index, :index - live "/organizations/:organization_id/memberships/new", MembershipLive.New, :new - live "/organizations/:organization_id/memberships/:id", MembershipLive.Show, :show - live "/organizations/:organization_id/memberships/:id/edit", MembershipLive.Edit, :edit + live "/activities/new", ActivityLive.New, :new + live "/activities/:id/edit", ActivityLive.Edit, :edit - live "/card/:membership_id", CardLive.Show, :show + live "/departments/new", DepartmentLive.Index, :new + live "/departments/:id/edit", DepartmentLive.Index, :edit + live "/departments/:id/show/edit", DepartmentLive.Show, :edit - live "/organizations/:organization_id/board/", BoardLive.Index, :index - live "/organizations/:organization_id/board/new", BoardLive.New, :new - live "/organizations/:organization_id/board/:id", BoardLive.Show, :show - live "/organizations/:organization_id/board/:id/edit", BoardLive.Edit, :edit + live "/partners/new", PartnerLive.Index, :new + live "/partners/:id/edit", PartnerLive.Index, :edit + live "/partners/:id/show/edit", PartnerLive.Show, :edit + + live "/speakers/new", SpeakerLive.Index, :new + live "/speakers/:id/edit", SpeakerLive.Index, :edit + live "/speakers/:id/show/edit", SpeakerLive.Show, :edit + + live "/board/new", BoardLive.New, :new + live "/board/:id/edit", BoardLive.Edit, :edit + + live "/memberships", MembershipLive.Index, :index + live "/memberships/new", MembershipLive.New, :new + live "/memberships/:id", MembershipLive.Show, :show + live "/memberships/:id/edit", MembershipLive.Edit, :edit + end + + scope "/organizations/:organization_id" do + pipe_through :follower + live "/activities", ActivityLive.Index, :index + live "/activities/:id", ActivityLive.Show, :show + + live "/departments", DepartmentLive.Index, :index + live "/departments/:id", DepartmentLive.Show, :show + + live "/partners", PartnerLive.Index, :index + live "/partners/:id", PartnerLive.Show, :show + + live "/speakers", SpeakerLive.Index, :index + live "/speakers/:id", SpeakerLive.Show, :show + end + + live "/organizations/new", OrganizationLive.Index, :new live "/user/edit", UserLive.Edit, :edit + + pipe_through :member + live "/card/:membership_id", CardLive.Show, :show end end From e94d326bc525d91a9f801770613b0a4b2e2515d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lobo?= Date: Wed, 19 Jul 2023 13:53:21 +0100 Subject: [PATCH 36/42] Keep organization state trough routes --- lib/atomic/accounts.ex | 7 ++++ lib/atomic_web/controllers/user_auth.ex | 17 +++++----- lib/atomic_web/live/hooks.ex | 32 +++++++++++++++---- lib/atomic_web/router.ex | 14 ++++---- .../templates/layout/root.html.heex | 5 +-- 5 files changed, 52 insertions(+), 23 deletions(-) diff --git a/lib/atomic/accounts.ex b/lib/atomic/accounts.ex index 504714cb0..4ef52b75d 100644 --- a/lib/atomic/accounts.ex +++ b/lib/atomic/accounts.ex @@ -426,4 +426,11 @@ defmodule Atomic.Accounts do |> Course.changeset(attrs) |> Repo.insert() end + + @doc """ + Gets the user's organizations + """ + def get_user_organizations(user) do + Repo.all(Ecto.assoc(user, :organizations)) + end end diff --git a/lib/atomic_web/controllers/user_auth.ex b/lib/atomic_web/controllers/user_auth.ex index 8c3f35b64..58ad66174 100644 --- a/lib/atomic_web/controllers/user_auth.ex +++ b/lib/atomic_web/controllers/user_auth.ex @@ -34,6 +34,7 @@ defmodule AtomicWeb.UserAuth do conn |> renew_session() |> put_session(:user_token, token) + |> put_session(:current_organization, get_default_organization(user)) |> put_session(:live_socket_id, "users_sessions:#{Base.url_encode64(token)}") |> maybe_write_remember_me_cookie(token, params) |> redirect(to: user_return_to || signed_in_path(conn)) @@ -47,6 +48,14 @@ defmodule AtomicWeb.UserAuth do conn end + defp get_default_organization(user) do + if user do + List.first(Accounts.get_user_organizations(user)) + else + nil + end + end + # This function renews the session ID and erases the whole # session to avoid fixation attacks. If there is any data # in the session you may want to preserve after log in/log out, @@ -97,16 +106,8 @@ defmodule AtomicWeb.UserAuth do conn |> assign(:current_user, user) - |> assign(:current_organization, get_default_organization(user)) end - defp get_default_organization(user) do - if user do - List.first(user.organizations) - else - nil - end - end defp ensure_user_token(conn) do if user_token = get_session(conn, :user_token) do diff --git a/lib/atomic_web/live/hooks.ex b/lib/atomic_web/live/hooks.ex index e895bccf4..d44adc31b 100644 --- a/lib/atomic_web/live/hooks.ex +++ b/lib/atomic_web/live/hooks.ex @@ -5,21 +5,39 @@ defmodule AtomicWeb.Hooks do import Phoenix.LiveView alias Atomic.Accounts + alias Atomic.Organizations def on_mount(:default, _params, _session, socket) do {:cont, assign(socket, :page_title, "Atomic")} end - def on_mount(:current_user, _params, %{"user_token" => user_token}, socket) do + def on_mount(:authenticated_user_state, params, %{"user_token" => user_token, "current_organization" => current_organization}, socket) do current_user = Accounts.get_user_by_session_token(user_token) - current_organization = List.first(current_user.organizations) - socket = - socket - |> assign(:current_user, current_user) - |> assign(:current_organization, current_organization) + if params["organization_id"] != nil && params["organization_id"] != current_organization.id do + socket = + socket + |> assign(:current_user, current_user) + |> assign(:current_organization, Organizations.get_organization!(params["organization_id"])) - {:cont, socket} + {:cont, socket} + else + socket = + socket + |> assign(:current_user, current_user) + |> assign(:current_organization, current_organization) + + {:cont, socket} + end + end + + def on_mount(:general_user_state, _params, session, socket) do + current_organization = session["current_organization"] + if current_organization do + {:cont, socket |> assign(:current_organization, current_organization)} + else + {:cont, socket} + end end def on_mount(:current_user, _params, _session, socket) do diff --git a/lib/atomic_web/router.ex b/lib/atomic_web/router.ex index b88c917dc..b01d2b50f 100644 --- a/lib/atomic_web/router.ex +++ b/lib/atomic_web/router.ex @@ -32,20 +32,22 @@ defmodule AtomicWeb.Router do scope "/", AtomicWeb do pipe_through :browser - live "/", HomeLive.Index, :index + live_session :general, on_mount: [{AtomicWeb.Hooks, :general_user_state}] do + live "/", HomeLive.Index, :index - live "/organizations", OrganizationLive.Index, :index + live "/organizations", OrganizationLive.Index, :index - scope "/organizations/:organization_id" do - live "/board/", BoardLive.Index, :index - live "/board/:id", BoardLive.Show, :show + scope "/organizations/:organization_id" do + live "/board/", BoardLive.Index, :index + live "/board/:id", BoardLive.Show, :show + end end end scope "/", AtomicWeb do pipe_through [:browser, :require_authenticated_user] - live_session :logged_in, on_mount: [{AtomicWeb.Hooks, :current_user}] do + live_session :logged_in, on_mount: [{AtomicWeb.Hooks, :authenticated_user_state}] do live "/scanner", ScannerLive.Index, :index scope "/organizations/:organization_id" do diff --git a/lib/atomic_web/templates/layout/root.html.heex b/lib/atomic_web/templates/layout/root.html.heex index f01407c08..78f665758 100644 --- a/lib/atomic_web/templates/layout/root.html.heex +++ b/lib/atomic_web/templates/layout/root.html.heex @@ -16,14 +16,15 @@