Skip to content

Commit

Permalink
Merge pull request #27 from camino-school/activity_assessment
Browse files Browse the repository at this point in the history
Activity assessment
  • Loading branch information
endoooo authored Nov 30, 2023
2 parents d2ac028 + 7df327b commit 2ad0373
Show file tree
Hide file tree
Showing 67 changed files with 2,637 additions and 836 deletions.
219 changes: 215 additions & 4 deletions lib/lanttern/assessments.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ defmodule Lanttern.Assessments do
alias Lanttern.Repo

alias Lanttern.Assessments.AssessmentPoint
alias Lanttern.Assessments.ActivityAssessmentPoint
alias Lanttern.Assessments.AssessmentPointEntry
alias Lanttern.Assessments.Feedback
alias Lanttern.Conversation.Comment
alias Lanttern.LearningContext.Activity
alias Lanttern.Schools.Student

@doc """
Returns the list of assessment points.
Expand Down Expand Up @@ -49,7 +52,7 @@ defmodule Lanttern.Assessments do
@doc """
Gets a single assessment point.
Raises `Ecto.NoResultsError` if the AssessmentPoint does not exist.
Returns nil if the AssessmentPoint does not exist.
### Options:
Expand All @@ -63,6 +66,17 @@ defmodule Lanttern.Assessments do
iex> get_assessment_point!(456)
** (Ecto.NoResultsError)
"""
def get_assessment_point(id, opts \\ []) do
AssessmentPoint
|> Repo.get(id)
|> maybe_preload(opts)
end

@doc """
Gets a single assessment point.
Same as `get_assessment_point/2`, but raises `Ecto.NoResultsError` if the AssessmentPoint does not exist.
"""
def get_assessment_point!(id, opts \\ []) do
AssessmentPoint
Expand Down Expand Up @@ -119,7 +133,34 @@ defmodule Lanttern.Assessments do
"""
def delete_assessment_point(%AssessmentPoint{} = assessment_point) do
Repo.delete(assessment_point)
assessment_point
|> AssessmentPoint.delete_changeset()
|> Repo.delete()
end

@doc """
Deletes an assessment point and related entries.
## Examples
iex> delete_assessment_point_and_entries(assessment_point)
{:ok, %AssessmentPoint{}}
iex> delete_assessment_point_and_entries(assessment_point)
{:error, %Ecto.Changeset{}}
"""
def delete_assessment_point_and_entries(%AssessmentPoint{} = assessment_point) do
Ecto.Multi.new()
|> Ecto.Multi.delete_all(
:delete_entries,
from(
e in AssessmentPointEntry,
where: e.assessment_point_id == ^assessment_point.id
)
)
|> Ecto.Multi.delete(:delete_assessment_point, assessment_point)
|> Repo.transaction()
end

@doc """
Expand Down Expand Up @@ -222,7 +263,11 @@ defmodule Lanttern.Assessments do
def get_assessment_point_entry!(id), do: Repo.get!(AssessmentPointEntry, id)

@doc """
Creates a assessment_point_entry.
Creates an assessment_point_entry.
### Options:
`:preloads` – preloads associated data
## Examples
Expand All @@ -233,10 +278,11 @@ defmodule Lanttern.Assessments do
{:error, %Ecto.Changeset{}}
"""
def create_assessment_point_entry(attrs \\ %{}) do
def create_assessment_point_entry(attrs \\ %{}, opts \\ []) do
%AssessmentPointEntry{}
|> AssessmentPointEntry.changeset(attrs)
|> Repo.insert()
|> maybe_preload(opts)
end

@doc """
Expand Down Expand Up @@ -511,4 +557,169 @@ defmodule Lanttern.Assessments do
def change_feedback(%Feedback{} = feedback, attrs \\ %{}) do
Feedback.changeset(feedback, attrs)
end

@doc """
Returns the list of activity assessment points, ordered by its position.
## Examples
iex> list_activity_assessment_points(1)
[%AssessmentPoint{}, ...]
"""
def list_activity_assessment_points(activity_id) do
from(
ap in AssessmentPoint,
join: aap in ActivityAssessmentPoint,
on: aap.assessment_point_id == ap.id,
join: a in Activity,
on: a.id == aap.activity_id,
where: a.id == ^activity_id,
order_by: aap.position
)
|> Repo.all()
|> Repo.preload(scale: :ordinal_values)
end

@doc """
Returns the list of the assessment point entries for every student in the given activity.
Entries are ordered by `ActivityAssessmentPoint` position,
which is the same order used by `list_activity_assessment_points/1`.
## Options:
- `:classes_ids` – filter entries by classes
"""

@spec list_activity_students_entries(integer(), Keyword.t()) :: [
{Student.t(), [AssessmentPointEntry.t()]}
]

def list_activity_students_entries(activity_id, opts \\ []) do
students_query =
case Keyword.get(opts, :classes_ids) do
nil ->
from(s in Student)

classes_ids ->
from(
s in Student,
join: c in assoc(s, :classes),
where: c.id in ^classes_ids
)
end

results =
from(
ap in AssessmentPoint,
join: aap in assoc(ap, :activity_assessment_points),
join: s in subquery(students_query),
on: true,
left_join: e in AssessmentPointEntry,
on: e.student_id == s.id and e.assessment_point_id == ap.id,
where: aap.activity_id == ^activity_id,
order_by: [s.name, aap.position],
select: {s, e}
)
|> Repo.all()

grouped_entries =
results
|> Enum.group_by(fn {s, _e} -> s.id end)
|> Enum.map(fn {s_id, list} ->
{
s_id,
list |> Enum.map(fn {_s, e} -> e end)
}
end)
|> Enum.into(%{})

results
|> Enum.map(fn {s, _} -> s end)
|> Enum.uniq()
|> Enum.map(&{&1, grouped_entries[&1.id]})
end

@doc """
Creates an activity assessment point.
## Examples
iex> create_activity_assessment_point(activity_id, %{field: value})
{:ok, %AssessmentPoint{}}
iex> create_activity_assessment_point(activity_id, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_activity_assessment_point(activity_id, attrs \\ %{}) do
Ecto.Multi.new()
|> Ecto.Multi.insert(
:insert_assessment_point,
%AssessmentPoint{}
|> AssessmentPoint.changeset(attrs)
)
|> Ecto.Multi.run(
:link_activity,
fn _repo, %{insert_assessment_point: assessment_point} ->
position =
from(aap in ActivityAssessmentPoint,
where: aap.activity_id == ^activity_id,
select: count()
)
|> Repo.one()

%ActivityAssessmentPoint{}
|> ActivityAssessmentPoint.changeset(%{
assessment_point_id: assessment_point.id,
activity_id: activity_id,
position: position
})
|> Repo.insert()
end
)
|> Repo.transaction()
|> case do
{:error, _multi, changeset, _changes} -> {:error, changeset}
{:ok, %{insert_assessment_point: assessment_point}} -> {:ok, assessment_point}
end
end

@doc """
Update activity assessment points positions based on ids list order.
## Examples
iex> update_activity_assessment_points_positions(activity_id, [3, 2, 1])
{:ok, [%AssessmentPoint{}, ...]}
"""
def update_activity_assessment_points_positions(activity_id, assessment_points_ids) do
assessment_points_ids
|> Enum.with_index()
|> Enum.reduce(
Ecto.Multi.new(),
fn {id, i}, multi ->
multi
|> Ecto.Multi.update_all(
"update-#{id}",
from(
aap in ActivityAssessmentPoint,
where: aap.assessment_point_id == ^id,
where: aap.activity_id == ^activity_id
),
set: [position: i]
)
end
)
|> Repo.transaction()
|> case do
{:ok, _} ->
{:ok, list_activity_assessment_points(activity_id)}

_ ->
{:error, "Something went wrong"}
end
end
end
20 changes: 20 additions & 0 deletions lib/lanttern/assessments/activity_assessment_point.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
defmodule Lanttern.Assessments.ActivityAssessmentPoint do
use Ecto.Schema
import Ecto.Changeset

schema "activities_assessment_points" do
field :position, :integer

belongs_to :activity, Lanttern.LearningContext.Activity
belongs_to :assessment_point, Lanttern.Assessments.AssessmentPoint

timestamps()
end

@doc false
def changeset(activity_assessment_point, attrs) do
activity_assessment_point
|> cast(attrs, [:position, :activity_id, :assessment_point_id])
|> validate_required([:position, :activity_id, :assessment_point_id])
end
end
17 changes: 17 additions & 0 deletions lib/lanttern/assessments/assessment_point.ex
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ defmodule Lanttern.Assessments.AssessmentPoint do
belongs_to :scale, Lanttern.Grading.Scale
belongs_to :rubric, Lanttern.Rubrics.Rubric

has_many :activity_assessment_points, Lanttern.Assessments.ActivityAssessmentPoint
has_many :entries, Lanttern.Assessments.AssessmentPointEntry
has_many :feedbacks, Lanttern.Assessments.Feedback

Expand Down Expand Up @@ -85,6 +86,12 @@ defmodule Lanttern.Assessments.AssessmentPoint do
message:
"Error linking rubric. Check if it exists and uses the same scale used in the assessment point."
)
|> foreign_key_constraint(
:scale_id,
name: :assessment_point_entries_scale_id_fkey,
message:
"You may already have some entries for this assessment point. Changing the scale when entries exist is not allowed, as it would cause data loss."
)
end

defp validate_and_build_datetime(changeset) do
Expand Down Expand Up @@ -186,4 +193,14 @@ defmodule Lanttern.Assessments.AssessmentPoint do
end

defp cast_entries(changeset), do: changeset

def delete_changeset(assessment) do
assessment
|> cast(%{}, [])
|> foreign_key_constraint(
:id,
name: :assessment_point_entries_assessment_point_id_fkey,
message: "This jfalskflsealfesal."
)
end
end
47 changes: 47 additions & 0 deletions lib/lanttern/curricula.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ defmodule Lanttern.Curricula do
alias Lanttern.Curricula.CurriculumItem
alias Lanttern.Curricula.CurriculumRelationship

alias Lanttern.LearningContext.Activity

@doc """
Returns the list of curricula.
Expand Down Expand Up @@ -232,6 +234,51 @@ defmodule Lanttern.Curricula do
|> maybe_preload(opts)
end

@doc """
Returns the list of curriculum items linked to the given strand.
## Examples
iex> list_strand_curriculum_items(1)
[%CurriculumItem{}, ...]
"""
def list_strand_curriculum_items(strand_id) do
from(
ci in CurriculumItem,
join: sci in assoc(ci, :strand_links),
where: sci.strand_id == ^strand_id,
order_by: sci.position
)
|> Repo.all()
end

@doc """
Returns the list of curriculum items linked to the given activity.
## Options:
- `:preloads` – preloads associated data
## Examples
iex> list_activity_curriculum_items(1)
[%CurriculumItem{}, ...]
"""
def list_activity_curriculum_items(activity_id, opts \\ []) do
from(
a in Activity,
join: ci in assoc(a, :curriculum_items),
where: a.id == ^activity_id,
order_by: ci.name,
distinct: ci.id,
select: ci
)
|> Repo.all()
|> maybe_preload(opts)
end

@doc """
Search curriculum items by name.
Expand Down
1 change: 1 addition & 0 deletions lib/lanttern/curricula/curriculum_item.ex
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ defmodule Lanttern.Curricula.CurriculumItem do

has_many :grade_composition_component_items, Lanttern.Grading.CompositionComponentItem
has_many :assessment_points, Lanttern.Assessments.AssessmentPoint
has_many :strand_links, Lanttern.Curricula.StrandCurriculumItem
belongs_to :curriculum_component, Lanttern.Curricula.CurriculumComponent

many_to_many :subjects, Lanttern.Taxonomy.Subject,
Expand Down
Loading

0 comments on commit 2ad0373

Please sign in to comment.