Skip to content

Commit

Permalink
[FEATURE] [MER-1908] Transfer student data to another section (#4069)
Browse files Browse the repository at this point in the history
* [MER-1908] Adds / Modifies some context functions

* [MER-1908] Adds Transfer module

* [MER-1908] Adds table models and transfer component

* [MER-1908] Calls transfer component in actions component

* [MER-1908] Adds needed handle_info to show put_flash

* [MER-1908] Fix tests

* avoid dev env problem when automatic atom does not exist yet

* handle nils (seen with guest users)

---------

Co-authored-by: Darren Siegel <[email protected]>
  • Loading branch information
simonchoxx and darrensiegel authored Aug 16, 2023
1 parent bad5144 commit bb51fae
Show file tree
Hide file tree
Showing 15 changed files with 1,535 additions and 20 deletions.
10 changes: 8 additions & 2 deletions lib/oli/activities/model/part.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ defmodule Oli.Activities.Model.Part do
:explanation
]

@grading_approaches MapSet.new(["automatic", "manual"])

def parse(%{"id" => id} = part) do
scoring_strategy =
Map.get(part, "scoringStrategy", Oli.Resources.ScoringStrategy.get_id_by_type("average"))
Expand All @@ -19,9 +21,13 @@ defmodule Oli.Activities.Model.Part do
responses = Map.get(part, "responses", [])
explanation = Map.get(part, "explanation")

grading_approach =
grading_approach_str =
Map.get(part, "gradingApproach", "automatic")
|> String.to_existing_atom()

grading_approach = case MapSet.member?(@grading_approaches, grading_approach_str) do
true -> String.to_atom(grading_approach_str)
false -> :automatic
end

out_of = Map.get(part, "outOf")

Expand Down
108 changes: 92 additions & 16 deletions lib/oli/delivery/attempts/core.ex
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@ defmodule Oli.Delivery.Attempts.Core do

def get_user_from_attempt(%ResourceAttempt{resource_access_id: resource_access_id}) do
query =
from access in ResourceAccess,
from(access in ResourceAccess,
join: user in User,
on: access.user_id == user.id,
select: user,
where: access.id == ^resource_access_id
)

Repo.one(query)
end
Expand All @@ -40,13 +41,14 @@ defmodule Oli.Delivery.Attempts.Core do
"""
def has_any_attempts?(%User{id: user_id}, %Section{id: section_id}, resource_id) do
query =
from access in ResourceAccess,
from(access in ResourceAccess,
join: attempt in ResourceAttempt,
on: access.id == attempt.resource_access_id,
select: count(attempt.id),
where:
access.user_id == ^user_id and access.section_id == ^section_id and
access.resource_id == ^resource_id
)

Repo.one(query) > 0
end
Expand Down Expand Up @@ -419,14 +421,15 @@ defmodule Oli.Delivery.Attempts.Core do
def get_part_attempts_and_users(project_id) do
# This is our base, reusable query designed to get the part attempts
core =
from snapshot in Snapshot,
from(snapshot in Snapshot,
as: :snapshot,
join: part_attempt in PartAttempt,
as: :part_attempt,
on: snapshot.part_attempt_id == part_attempt.id,
where:
snapshot.project_id == ^project_id and
part_attempt.lifecycle_state == :evaluated
)

# Now get the resource attempt revision for those part attempts, distinctly, and
# create a map of their ids to the attempts
Expand Down Expand Up @@ -589,16 +592,18 @@ defmodule Oli.Delivery.Attempts.Core do
end

def get_latest_non_active_activity_attempts(resource_attempt_id) do

query = from(
aa in ActivityAttempt,
where: (aa.lifecycle_state == :evaluated or aa.lifecycle_state == :submitted) and aa.resource_attempt_id == ^resource_attempt_id,
group_by: aa.resource_id,
select: max(aa.id)
)
query =
from(
aa in ActivityAttempt,
where:
(aa.lifecycle_state == :evaluated or aa.lifecycle_state == :submitted) and
aa.resource_attempt_id == ^resource_attempt_id,
group_by: aa.resource_id,
select: max(aa.id)
)

Repo.all(
from(aa in ActivityAttempt ,
from(aa in ActivityAttempt,
where: aa.id in subquery(query),
select: aa
)
Expand Down Expand Up @@ -678,12 +683,14 @@ defmodule Oli.Delivery.Attempts.Core do
end

def is_scoreable_first_attempt?(activity_attempt_guid) do
{attempt_number, scoreable} = Repo.one(
from(a in ActivityAttempt,
where: a.attempt_guid == ^activity_attempt_guid,
select: {a.attempt_number, a.scoreable}
{attempt_number, scoreable} =
Repo.one(
from(a in ActivityAttempt,
where: a.attempt_guid == ^activity_attempt_guid,
select: {a.attempt_number, a.scoreable}
)
)
)

case {attempt_number, scoreable} do
{1, true} -> true
_ -> false
Expand Down Expand Up @@ -801,6 +808,19 @@ defmodule Oli.Delivery.Attempts.Core do
|> Repo.update()
end

@doc """
Gets all part attempts for a given activity attempts.
"""

def get_part_attempts_by_activity_attempts(activity_attempts) do
Repo.all(
from(pa in PartAttempt,
where: pa.activity_attempt_id in ^activity_attempts,
select: pa
)
)
end

@doc """
Creates a resource attempt.
## Examples
Expand Down Expand Up @@ -868,6 +888,23 @@ defmodule Oli.Delivery.Attempts.Core do
|> Repo.update()
end

@doc """
Updates all resource accesses for a given section and user.
"""

def update_resource_accesses_by_section_and_user(
current_section_id,
current_user_id,
target_section_id,
target_user_id
) do
from(
ra in ResourceAccess,
where: ra.section_id == ^current_section_id and ra.user_id == ^current_user_id
)
|> Repo.update_all(set: [section_id: target_section_id, user_id: target_user_id])
end

@doc """
Creates an activity attempt.
## Examples
Expand All @@ -882,6 +919,19 @@ defmodule Oli.Delivery.Attempts.Core do
|> Repo.insert()
end

@doc """
Gets all activity attempts for a given resource attempts.
"""

def get_activity_attempts_by_resource_attempts(resource_attempts) do
Repo.all(
from(aa in ActivityAttempt,
where: aa.resource_attempt_id in ^resource_attempts,
select: aa
)
)
end

@doc """
Updates a resource attempt.
## Examples
Expand All @@ -905,4 +955,30 @@ defmodule Oli.Delivery.Attempts.Core do
"""
def get_resource_attempt(clauses),
do: Repo.get_by(ResourceAttempt, clauses)

@doc """
Gets all resource attempts for a given resource accesses.
"""

def get_resource_attempts_by_resource_accesses(resource_accesses) do
Repo.all(
from(ra in ResourceAttempt,
where: ra.resource_access_id in ^resource_accesses,
select: ra
)
)
end

@doc """
Deletes part attempts, activity attempts, resource attempts, and resource accesses for a given section and user.
Deleting resource accesses will cascade to deleting resource attempts, which will cascade to deleting activity
"""

def delete_resource_accesses_by_section_and_user(target_section_id, target_user_id) do
Repo.delete_all(
from(res_acc in ResourceAccess,
where: res_acc.section_id == ^target_section_id and res_acc.user_id == ^target_user_id
)
)
end
end
16 changes: 14 additions & 2 deletions lib/oli/delivery/paywall.ex
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ defmodule Oli.Delivery.Paywall do
end
end

defp has_paid?(nil), do: false
def has_paid?(nil), do: false

defp has_paid?(%Enrollment{id: id}) do
def has_paid?(%Enrollment{id: id}) do
query =
from(
p in Payment,
Expand Down Expand Up @@ -491,6 +491,18 @@ defmodule Oli.Delivery.Paywall do
|> Repo.update()
end

def update_payments_for_enrollment(
%Enrollment{id: current_enrollment_id},
%Enrollment{id: target_enrollment_id},
target_section_id
) do
from(
p in Payment,
where: p.enrollment_id == ^current_enrollment_id
)
|> Repo.update_all(set: [enrollment_id: target_enrollment_id, section_id: target_section_id])
end

# ------------------------------------------
# Discounts

Expand Down
45 changes: 45 additions & 0 deletions lib/oli/delivery/sections.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3296,4 +3296,49 @@ defmodule Oli.Delivery.Sections do
end

def get_revision_by_index(_, _), do: nil

@doc """
Get all students for a given section with their enrollment date.
"""

def get_students_for_section_with_enrollment_date(section_id) do
student_context_role_id = ContextRoles.get_role(:context_learner).id

Repo.all(
from(enrollment in Enrollment,
join: enrollment_context_role in EnrollmentContextRole,
on: enrollment_context_role.enrollment_id == enrollment.id,
join: user in User,
on: enrollment.user_id == user.id,
where:
enrollment.section_id == ^section_id and
enrollment_context_role.context_role_id == ^student_context_role_id,
select: {user, enrollment}
)
)
|> Enum.map(fn {user, enrollment} ->
Map.put(user, :enrollment_date, enrollment.inserted_at)
end)
|> Enum.sort_by(fn user -> user.name end)
end

@doc """
Get all instructors for a given section.
"""
def get_instructors_for_section(section_id) do
instructor_context_role_id = ContextRoles.get_role(:context_instructor).id

Repo.all(
from(enrollment in Enrollment,
join: enrollment_context_role in EnrollmentContextRole,
on: enrollment_context_role.enrollment_id == enrollment.id,
join: user in User,
on: enrollment.user_id == user.id,
where:
enrollment.section_id == ^section_id and
enrollment_context_role.context_role_id == ^instructor_context_role_id,
select: user
)
)
end
end
34 changes: 34 additions & 0 deletions lib/oli/delivery/snapshots.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ defmodule Oli.Delivery.Snapshots do
|> Snapshots.maybe_create_snapshot(part_inputs, section_slug)
```
"""

import Ecto.Query, warn: false

alias Oli.Repo
alias Oli.Delivery.Snapshots.Snapshot

def maybe_create_snapshot(result, part_inputs, section_slug) do
case result do
{:ok, _} ->
Expand Down Expand Up @@ -41,4 +47,32 @@ defmodule Oli.Delivery.Snapshots do
|> Oban.insert()
end
end

@doc """
Updates all snapshot records for a given section and user.
"""

def update_snapshots_by_section_and_user(
current_section_id,
current_user_id,
target_section_id,
target_user_id
) do
from(
sn in Snapshot,
where: sn.section_id == ^current_section_id and sn.user_id == ^current_user_id
)
|> Repo.update_all(set: [section_id: target_section_id, user_id: target_user_id])
end

@doc """
Deletes all snapshot records for a given section and user.
"""
def delete_snapshots_by_section_and_user(target_section_id, target_user_id) do
from(
sn in Snapshot,
where: sn.section_id == ^target_section_id and sn.user_id == ^target_user_id
)
|> Repo.delete_all()
end
end
Loading

0 comments on commit bb51fae

Please sign in to comment.