diff --git a/lib/atomic/activities.ex b/lib/atomic/activities.ex index 44e738ce7..cf787ea16 100644 --- a/lib/atomic/activities.ex +++ b/lib/atomic/activities.ex @@ -43,6 +43,7 @@ defmodule Atomic.Activities do |> where([a, d], d.organization_id == ^organization_id) |> select([a, _d], a) |> Repo.all() + |> Repo.preload(activity_sessions: :enrollments) end @doc """ @@ -97,25 +98,26 @@ defmodule Atomic.Activities do iex> get_activity_organizations!(activity) ** (Ecto.NoResultsError) """ - def get_activity_organizations!(activity, _preloads \\ []) do - Map.get(activity, :departments, []) + def get_activity_organizations!(activity, preloads \\ []) do + Repo.preload(activity, preloads) + |> Map.get(:departments, []) |> Enum.map(& &1.organization_id) end @doc """ - Verifies if an user is enrolled in an activity. + Verifies if an user is enrolled in an activity session. ## Examples - iex> is_participating?(activity_id, user_id) + iex> is_participating?(session_id, user_id) true - iex> is_participating?(activity_id, user_id) + iex> is_participating?(session_id, user_id) false """ - def is_participating?(activity_id, user_id) do + def is_participating?(session_id, user_id) do Enrollment - |> where(activity_id: ^activity_id, user_id: ^user_id) + |> where(session_id: ^session_id, user_id: ^user_id) |> Repo.exists?() end @@ -189,12 +191,14 @@ defmodule Atomic.Activities do ## Examples - iex> list_sessions() + iex> list_sessions(opts) [%Session{}, ...] """ - def list_sessions do - Repo.all(Session) + def list_sessions(opts) when is_list(opts) do + Session + |> apply_filters(opts) + |> Repo.all() end @doc """ @@ -211,7 +215,10 @@ defmodule Atomic.Activities do ** (Ecto.NoResultsError) """ - def get_session!(id), do: Repo.get!(Session, id) + def get_session!(id, preloads \\ []) do + Repo.get!(Session, id) + |> Repo.preload(preloads) + end @doc """ Creates a session. @@ -324,12 +331,12 @@ defmodule Atomic.Activities do iex> get_user_enrolled(user, activity) ** (Ecto.NoResultsError) """ - def get_user_enrolled(user, activity) do + def get_user_enrolled(user, session_id) do Enrollment - |> where(user_id: ^user.id, activity_id: ^activity.id) + |> where(user_id: ^user.id, session_id: ^session_id) |> Repo.one() |> case do - nil -> create_enrollment(activity, user) + nil -> create_enrollment(session_id, user) enrollment -> enrollment end end @@ -367,17 +374,17 @@ defmodule Atomic.Activities do ## Examples - iex> create_enrollment(%Activity{} = activity, %User{} = user) + iex> create_enrollment(session_id, %User{} = user) {:ok, %Enrollment{}} - iex> create_enrollment(%Activity{} = activity, %User{} = user) + iex> create_enrollment(session_id, %User{} = user) {:error, %Ecto.Changeset{}} """ - def create_enrollment(%Activity{} = activity, %User{} = user) do + def create_enrollment(session_id, %User{} = user) do %Enrollment{} |> Enrollment.changeset(%{ - activity_id: activity.id, + session_id: session_id, user_id: user.id }) |> Repo.insert() @@ -407,35 +414,35 @@ defmodule Atomic.Activities do ## Examples - iex> delete_enrollment(enrollment) + iex> delete_enrollment(session_id, %User{}) {:ok, %Enrollment{}} - iex> delete_enrollment(enrollment) + iex> delete_enrollment(session_id, %User{}) {:error, %Ecto.Changeset{}} """ - def delete_enrollment(%Activity{} = activity, %User{} = user) do + def delete_enrollment(session_id, %User{} = user) do Repo.delete_all( from e in Enrollment, - where: e.user_id == ^user.id and e.activity_id == ^activity.id + where: e.user_id == ^user.id and e.session_id == ^session_id ) |> broadcast(:deleted_enrollment) end @doc """ - Returns the total number of enrolled users in an activity. + Returns the total number of enrolled users in an activity session. ## Examples - iex> get_total_enrolled(activity) + iex> get_total_enrolled(session_id) 10 - iex> get_total_enrolled(activity) + iex> get_total_enrolled(session_id) 0 """ - def get_total_enrolled(%Activity{} = activity) do + def get_total_enrolled(session_id) do Enrollment - |> where(activity_id: ^activity.id) + |> where(session_id: ^session_id) |> Repo.aggregate(:count, :id) end diff --git a/lib/atomic/activities/activity.ex b/lib/atomic/activities/activity.ex index 0e3e34427..90b6c1829 100644 --- a/lib/atomic/activities/activity.ex +++ b/lib/atomic/activities/activity.ex @@ -7,7 +7,6 @@ defmodule Atomic.Activities.Activity do alias Atomic.Activities alias Atomic.Activities.ActivityDepartment alias Atomic.Activities.ActivitySpeaker - alias Atomic.Activities.Enrollment alias Atomic.Activities.Session alias Atomic.Activities.Speaker alias Atomic.Departments @@ -36,7 +35,6 @@ defmodule Atomic.Activities.Activity do foreign_key: :activity_id, preload_order: [asc: :start] - has_many :enrollments, Enrollment, foreign_key: :activity_id belongs_to :event, Event timestamps() diff --git a/lib/atomic/activities/enrollment.ex b/lib/atomic/activities/enrollment.ex index b0af97d37..8806e6279 100644 --- a/lib/atomic/activities/enrollment.ex +++ b/lib/atomic/activities/enrollment.ex @@ -5,12 +5,12 @@ defmodule Atomic.Activities.Enrollment do use Atomic.Schema alias Atomic.Accounts.User - alias Atomic.Activities.Activity + alias Atomic.Activities.Session schema "enrollments" do field :present, :boolean - belongs_to :activity, Activity + belongs_to :session, Session belongs_to :user, User @@ -20,7 +20,7 @@ defmodule Atomic.Activities.Enrollment do @doc false def changeset(enrollment, attrs) do enrollment - |> cast(attrs, [:activity_id, :user_id, :present]) - |> validate_required([:activity_id, :user_id]) + |> cast(attrs, [:session_id, :user_id, :present]) + |> validate_required([:session_id, :user_id]) end end diff --git a/lib/atomic/activities/session.ex b/lib/atomic/activities/session.ex index fca08397c..b43d35837 100644 --- a/lib/atomic/activities/session.ex +++ b/lib/atomic/activities/session.ex @@ -5,19 +5,22 @@ defmodule Atomic.Activities.Session do use Atomic.Schema alias Atomic.Activities.Activity + alias Atomic.Activities.Enrollment alias Atomic.Activities.Location + alias Atomic.Uploaders @required_fields ~w(start finish)a - @optional_fields ~w(delete)a + @optional_fields ~w(delete session_image)a schema "sessions" do field :start, :naive_datetime field :finish, :naive_datetime + field :session_image, Uploaders.Post.Type embeds_one :location, Location, on_replace: :delete field :delete, :boolean, virtual: true - + has_many :enrollments, Enrollment, foreign_key: :session_id belongs_to :activity, Activity timestamps() diff --git a/lib/atomic/organizations/department.ex b/lib/atomic/organizations/department.ex index fa558e56b..269af366d 100644 --- a/lib/atomic/organizations/department.ex +++ b/lib/atomic/organizations/department.ex @@ -17,7 +17,6 @@ defmodule Atomic.Organizations.Department do field :description, :string many_to_many :activities, Activity, join_through: ActivityDepartment, on_replace: :delete - belongs_to :organization, Organization, on_replace: :delete_if_exists timestamps() diff --git a/lib/atomic/uploaders/post.ex b/lib/atomic/uploaders/post.ex new file mode 100644 index 000000000..0764d2371 --- /dev/null +++ b/lib/atomic/uploaders/post.ex @@ -0,0 +1,28 @@ +defmodule Atomic.Uploaders.Post do + @moduledoc false + use Waffle.Definition + use Waffle.Ecto.Definition + alias Atomic.Activities.Session + + @versions [:original] + @extension_whitelist ~w(.svg .jpg .jpeg .gif .png) + + def validate({file, _}) do + file.file_name + |> Path.extname() + |> String.downcase() + |> then(&Enum.member?(@extension_whitelist, &1)) + |> case do + true -> :ok + false -> {:error, "invalid file type"} + end + end + + def filename(version, _) do + version + end + + def storage_dir(_version, {_file, %Session{} = scope}) do + "uploads/atomic/sessions/#{scope.id}" + end +end diff --git a/lib/atomic_web/live/activity_live/index.ex b/lib/atomic_web/live/activity_live/index.ex index a7b7c413a..e0aac999c 100644 --- a/lib/atomic_web/live/activity_live/index.ex +++ b/lib/atomic_web/live/activity_live/index.ex @@ -8,7 +8,7 @@ defmodule AtomicWeb.ActivityLive.Index do @impl true def mount(params, _session, socket) do - {:ok, assign(socket, :activities, list_activities(params["organization_id"]))} + {:ok, assign(socket, :activities, list_sessions(params["organization_id"]))} end @impl true @@ -52,12 +52,11 @@ defmodule AtomicWeb.ActivityLive.Index do activity = Activities.get_activity!(id) {:ok, _} = Activities.delete_activity(activity) - {:noreply, assign(socket, :activies, list_activities(socket.assigns.current_organization.id))} + {:noreply, assign(socket, :activies, list_sessions(socket.assigns.current_organization.id))} end def handle_event("open-enrollments", _payload, socket) do - {:noreply, - assign(socket, :activities, list_activities(socket.assigns.current_organization.id))} + {:noreply, assign(socket, :activities, list_sessions(socket.assigns.current_organization.id))} end def handle_event("activities-enrolled", _payload, socket) do @@ -67,9 +66,9 @@ defmodule AtomicWeb.ActivityLive.Index do {:noreply, assign(socket, :activities, activities)} end - defp list_activities(organization_id) do + defp list_sessions(organization_id) do Activities.list_activities_by_organization_id(organization_id, - preloads: [:activity_sessions, :enrollments, :speakers] + preloads: [:activity_sessions, :speakers] ) end end diff --git a/lib/atomic_web/live/activity_live/index.html.heex b/lib/atomic_web/live/activity_live/index.html.heex index a1d83e8c3..1134ea27f 100644 --- a/lib/atomic_web/live/activity_live/index.html.heex +++ b/lib/atomic_web/live/activity_live/index.html.heex @@ -33,58 +33,60 @@
diff --git a/lib/atomic_web/live/activity_live/show.ex b/lib/atomic_web/live/activity_live/show.ex index 729adcfc5..79174f8fa 100644 --- a/lib/atomic_web/live/activity_live/show.ex +++ b/lib/atomic_web/live/activity_live/show.ex @@ -18,8 +18,12 @@ defmodule AtomicWeb.ActivityLive.Show do @impl true def handle_params(%{"organization_id" => organization_id, "id" => id}, _, socket) do - activity = Activities.get_activity!(id, [:activity_sessions, :departments, :speakers]) - organizations = Activities.get_activity_organizations!(activity) + session = Activities.get_session!(id, [:activity]) + + activity = + Activities.get_activity!(session.activity_id, [:departments, :activity_sessions, :speakers]) + + organizations = Activities.get_activity_organizations!(activity, [:departments]) entries = [ %{ @@ -28,7 +32,7 @@ defmodule AtomicWeb.ActivityLive.Show do }, %{ name: activity.title, - route: Routes.activity_show_path(socket, :show, organization_id, activity.id) + route: Routes.activity_show_path(socket, :show, organization_id, session.id) } ] @@ -37,12 +41,12 @@ defmodule AtomicWeb.ActivityLive.Show do socket |> assign( :enrolled?, - Activities.is_participating?(activity.id, socket.assigns.current_user.id) + Activities.is_participating?(id, socket.assigns.current_user.id) ) |> assign(:page_title, page_title(socket.assigns.live_action)) |> assign(:breadcrumb_entries, entries) |> assign(:current_page, :activities) - |> assign(:activity, %{activity | enrolled: Activities.get_total_enrolled(activity)})} + |> assign(:activity, %{activity | enrolled: Activities.get_total_enrolled(id)})} else raise MismatchError end @@ -50,30 +54,30 @@ defmodule AtomicWeb.ActivityLive.Show do @impl true def handle_event("enroll", _payload, socket) do - activity = socket.assigns.activity + session_id = socket.assigns.id current_user = socket.assigns.current_user - case Activities.create_enrollment(activity, current_user) do + case Activities.create_enrollment(session_id, current_user) do {:ok, _enrollment} -> {:noreply, socket |> put_flash(:success, "Enrolled successufully!") - |> set_enrolled(activity, current_user)} + |> set_enrolled(session_id, current_user)} {:error, _error} -> {:noreply, socket |> put_flash(:error, "Unable to enroll") - |> set_enrolled(activity, current_user)} + |> set_enrolled(session_id, current_user)} end end @impl true def handle_event("unenroll", _payload, socket) do - activity = socket.assigns.activity + session_id = socket.assigns.id current_user = socket.assigns.current_user - case Activities.delete_enrollment(activity, current_user) do + case Activities.delete_enrollment(session_id, current_user) do {1, nil} -> {:noreply, socket @@ -130,8 +134,8 @@ defmodule AtomicWeb.ActivityLive.Show do defp page_title(:show), do: "Show Activity" defp page_title(:edit), do: "Edit Activity" - defp set_enrolled(socket, activity, current_user) do - Activities.get_user_enrolled(current_user, activity) + defp set_enrolled(socket, session_id, current_user) do + Activities.get_user_enrolled(current_user, session_id) {:noreply, socket} end diff --git a/priv/repo/migrations/20221023200102_create_sessions.exs b/priv/repo/migrations/20221023200102_create_sessions.exs index 349dbe313..0d596b586 100644 --- a/priv/repo/migrations/20221023200102_create_sessions.exs +++ b/priv/repo/migrations/20221023200102_create_sessions.exs @@ -7,6 +7,7 @@ defmodule Atomic.Repo.Migrations.CreateSessions do add :start, :utc_datetime add :finish, :utc_datetime add :location, :map + add :session_image, :string add :activity_id, references(:activities, on_delete: :delete_all, type: :binary_id) diff --git a/priv/repo/migrations/20221104160002_create_enrollments.exs b/priv/repo/migrations/20221104160002_create_enrollments.exs index 9a0a7037d..c51927558 100644 --- a/priv/repo/migrations/20221104160002_create_enrollments.exs +++ b/priv/repo/migrations/20221104160002_create_enrollments.exs @@ -6,9 +6,7 @@ defmodule Atomic.Repo.Migrations.CreateEnrollments do add :id, :binary_id, primary_key: true add :present, :boolean, null: false, default: false - add :activity_id, - references(:activities, on_delete: :delete_all, type: :binary_id) - + add :session_id, references(:sessions, on_delete: :delete_all, type: :binary_id) add :user_id, references(:users, on_delete: :delete_all, type: :binary_id) timestamps() diff --git a/priv/repo/seeds/activities.exs b/priv/repo/seeds/activities.exs index b4a3bc13b..6b60f7c23 100644 --- a/priv/repo/seeds/activities.exs +++ b/priv/repo/seeds/activities.exs @@ -5,6 +5,7 @@ defmodule Atomic.Repo.Seeds.Activities do alias Atomic.Accounts.User alias Atomic.Organizations.Department alias Atomic.Activities.ActivityDepartment + alias Atomic.Activities.Session alias Atomic.Organizations.Organization alias Atomic.Activities.{Activity, Enrollment, Location} @@ -207,12 +208,12 @@ defmodule Atomic.Repo.Seeds.Activities do def seed_enrollments() do case Repo.all(Enrollment) do [] -> - for activity <- Repo.all(Activity) do + for session <- Repo.all(Session) do for user <- Repo.all(User) do %Enrollment{} |> Enrollment.changeset(%{ user_id: user.id, - activity_id: activity.id, + session_id: session.id, present: Enum.random([true, false]) }) |> Repo.insert!() diff --git a/test/atomic/activities_test.exs b/test/atomic/activities_test.exs index d4f20a8b0..3fe24c510 100644 --- a/test/atomic/activities_test.exs +++ b/test/atomic/activities_test.exs @@ -74,7 +74,7 @@ defmodule Atomic.ActivitiesTest do test "list_sessions/0 returns all sessions" do session = session_fixture() - assert Activities.list_sessions() == [session] + assert Activities.list_sessions([]) == [session] end test "get_session!/1 returns the session with given id" do @@ -139,9 +139,9 @@ defmodule Atomic.ActivitiesTest do test "create_enrollment/1 with valid data creates a enrollment" do user = insert(:user) - activity = insert(:activity) + session = insert(:session) - assert {:ok, %Enrollment{}} = Activities.create_enrollment(activity, user) + assert {:ok, %Enrollment{}} = Activities.create_enrollment(session.id, user) end test "update_enrollment/2 with valid data updates the enrollment" do @@ -153,7 +153,7 @@ defmodule Atomic.ActivitiesTest do test "delete_enrollment/1 deletes the enrollment" do enrollment = insert(:enrollment) - assert {_, nil} = Activities.delete_enrollment(enrollment.activity, enrollment.user) + assert {_, nil} = Activities.delete_enrollment(enrollment.session.id, enrollment.user) assert_raise Ecto.NoResultsError, fn -> Activities.get_enrollment!(enrollment.id) end end diff --git a/test/support/factories/activities_factory.ex b/test/support/factories/activities_factory.ex index 4da782d8b..842864686 100644 --- a/test/support/factories/activities_factory.ex +++ b/test/support/factories/activities_factory.ex @@ -20,7 +20,7 @@ defmodule Atomic.Factories.ActivityFactory do def enrollment_factory do %Enrollment{ present: Enum.random([true, false]), - activity: build(:activity), + session: build(:session), user: build(:user) } end