diff --git a/lib/oli/accounts.ex b/lib/oli/accounts.ex index 3decaf11d4..c0737d9b8d 100644 --- a/lib/oli/accounts.ex +++ b/lib/oli/accounts.ex @@ -21,6 +21,8 @@ defmodule Oli.Accounts do alias Oli.Repo.{Paging, Sorting} alias Oli.AccountLookupCache alias PowEmailConfirmation.Ecto.Context, as: EmailConfirmationContext + alias Oli.Delivery.Sections.Enrollment + alias Lti_1p3.DataProviders.EctoProvider def browse_users( %Paging{limit: limit, offset: offset}, @@ -318,6 +320,29 @@ defmodule Oli.Accounts do end end + @doc """ + Updates the context role for a specific enrollment. + """ + + def update_user_context_role(enrollment, role) do + context_role = EctoProvider.Marshaler.to([role]) + + res = + enrollment + |> Repo.preload([:context_roles]) + |> Enrollment.changeset(%{}) + |> Ecto.Changeset.put_assoc(:context_roles, context_role) + |> Repo.update() + + case res do + {:ok, %Enrollment{}} -> + res + + error -> + error + end + end + @doc """ Links a User to Author account diff --git a/lib/oli/delivery/sections.ex b/lib/oli/delivery/sections.ex index 9f9e9161a7..c0920f0bbc 100644 --- a/lib/oli/delivery/sections.ex +++ b/lib/oli/delivery/sections.ex @@ -197,6 +197,18 @@ defmodule Oli.Delivery.Sections do ) end + @doc """ + Get the user's role in a given section. + """ + + def get_user_role_from_enrollment(enrollment) do + enrollment + |> Repo.preload(:context_roles) + |> Map.get(:context_roles) + |> List.first() + |> Map.get(:id) + end + @doc """ Determines if a user is a platform (institution) instructor. """ diff --git a/lib/oli_web/components/delivery/actions/actions.ex b/lib/oli_web/components/delivery/actions/actions.ex new file mode 100644 index 0000000000..a62c0a23fe --- /dev/null +++ b/lib/oli_web/components/delivery/actions/actions.ex @@ -0,0 +1,119 @@ +defmodule OliWeb.Components.Delivery.Actions do + use Surface.LiveComponent + use OliWeb.Common.Modal + + alias Lti_1p3.Tool.ContextRoles + alias Oli.Accounts + alias OliWeb.Common.Confirm + alias Phoenix.LiveView.JS + + prop(enrollment_info, :map, required: true) + prop(section_slug, :string, required: true) + prop(user, :map, required: true) + + data(enrollment, :map, default: %{}) + data(user_role_data, :list, default: []) + data(user_role_id, :integer, default: nil) + + @user_role_data [ + %{id: 3, name: :instructor, title: "Instructor"}, + %{id: 4, name: :student, title: "Student"} + ] + + def update( + %{user: user, section_slug: section_slug, enrollment_info: enrollment_info} = _assigns, + socket + ) do + {:ok, + assign(socket, + enrollment: enrollment_info.enrollment, + section_slug: section_slug, + user: user, + user_role_id: enrollment_info.user_role_id, + user_role_data: @user_role_data + )} + end + + def render(assigns) do + ~F""" +
+
+

Actions

+
+ +
+
+ Change enrolled user role + Select the role to change for the user in this section. +
+
+ +
+
+
+ """ + end + + def handle_event( + "change_user_role", + %{"filter_by_role_id" => filter_by_role_id}, + socket + ) do + context_role = + case String.to_integer(filter_by_role_id) do + 3 -> ContextRoles.get_role(:context_instructor) + 4 -> ContextRoles.get_role(:context_learner) + end + + Accounts.update_user_context_role( + socket.assigns.enrollment, + context_role + ) + + {:noreply, + socket + |> assign(user_role_id: String.to_integer(filter_by_role_id)) + |> hide_modal(modal_assigns: nil)} + end + + def handle_event("display_confirm_modal", %{"filter_by_role_id" => filter_by_role_id}, socket) do + modal_assigns = %{ + title: "Change role", + id: "change_role_modal", + ok: + JS.push("change_user_role", + target: socket.assigns.myself, + value: %{"filter_by_role_id" => filter_by_role_id} + ), + cancel: + JS.push("cancel_confirm_modal", + target: socket.assigns.myself, + value: %{"previous_role_id" => socket.assigns.user_role_id} + ) + } + + %{given_name: given_name, family_name: family_name} = socket.assigns.user + + modal = fn assigns -> + ~F""" + + Are you sure you want to change user role to {given_name} {family_name}? + + """ + end + + send(self(), {:show_modal, modal, modal_assigns}) + + {:noreply, assign(socket, user_role_id: filter_by_role_id)} + end + + def handle_event("cancel_confirm_modal", %{"previous_role_id" => previous_role_id}, socket) do + send(self(), {:hide_modal}) + + {:noreply, assign(socket, user_role_id: previous_role_id)} + end +end diff --git a/lib/oli_web/live/delivery/student_dashboard/components/helpers.ex b/lib/oli_web/live/delivery/student_dashboard/components/helpers.ex index a7cb8a13cb..b4a6c753b3 100644 --- a/lib/oli_web/live/delivery/student_dashboard/components/helpers.ex +++ b/lib/oli_web/live/delivery/student_dashboard/components/helpers.ex @@ -76,6 +76,7 @@ defmodule OliWeb.Delivery.StudentDashboard.Components.Helpers do {"Learning Objectives", path_for(:learning_objectives, @section_slug, @student_id, @preview_mode), nil, is_active_tab?(:learning_objectives, @active_tab)}, {"Quiz Scores", path_for(:quizz_scores, @section_slug, @student_id, @preview_mode), nil, is_active_tab?(:quizz_scores, @active_tab)}, {"Progress", path_for(:progress, @section_slug, @student_id, @preview_mode), nil, is_active_tab?(:progress, @active_tab)}, + {"Actions", path_for(:actions, @section_slug, @student_id, @preview_mode), nil, is_active_tab?(:actions, @active_tab)}, ] do %>