Skip to content

Commit

Permalink
Merge branch 'Simon-Initiative:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
dtiwarATS committed May 22, 2024
2 parents 53bf1ad + 3249805 commit 3f2feb1
Show file tree
Hide file tree
Showing 20 changed files with 904 additions and 70 deletions.
5 changes: 2 additions & 3 deletions lib/oli/analytics/by_activity.ex
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ defmodule Oli.Analytics.ByActivity do
defp get_base_query(project_slug, filtered_sections) do
subquery =
if filtered_sections != [] do
DeliveryResolver.revisions_filter_by_section_ids(
DeliveryResolver.revisions_by_section_ids(
filtered_sections,
ResourceType.id_for_activity()
)
Expand All @@ -39,7 +39,6 @@ defmodule Oli.Analytics.ByActivity do
number_of_attempts: analytics.number_of_attempts,
relative_difficulty: analytics.relative_difficulty
},
preload: [:resource_type],
distinct: [activity]
preload: [:resource_type]
end
end
2 changes: 1 addition & 1 deletion lib/oli/analytics/by_objective.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ defmodule Oli.Analytics.ByObjective do
defp get_base_query(project_slug, activity_objectives, filtered_sections) do
subquery =
if filtered_sections != [] do
DeliveryResolver.revisions_filter_by_section_ids(
DeliveryResolver.revisions_by_section_ids(
filtered_sections,
ResourceType.id_for_objective()
)
Expand Down
9 changes: 4 additions & 5 deletions lib/oli/analytics/by_page.ex
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ defmodule Oli.Analytics.ByPage do
defp get_base_query(project_slug, activity_pages, filtered_sections) do
subquery =
if filtered_sections != [] do
DeliveryResolver.revisions_filter_by_section_ids(
DeliveryResolver.revisions_by_section_ids(
filtered_sections,
ResourceType.id_for_page()
)
Expand All @@ -35,9 +35,9 @@ defmodule Oli.Analytics.ByPage do

subquery_activity =
if filtered_sections != [] do
DeliveryResolver.revisions_filter_by_section_ids(
DeliveryResolver.revisions_by_section_ids(
filtered_sections,
ResourceType.id_for_page()
ResourceType.id_for_activity()
)
else
Publishing.query_unpublished_revisions_by_type(
Expand All @@ -62,8 +62,7 @@ defmodule Oli.Analytics.ByPage do
number_of_attempts: analytics.number_of_attempts,
relative_difficulty: analytics.relative_difficulty
},
preload: [:resource_type],
distinct: [activity]
preload: [:resource_type]
)
end

Expand Down
71 changes: 71 additions & 0 deletions lib/oli/delivery/metrics.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1158,6 +1158,77 @@ defmodule Oli.Delivery.Metrics do
end)
end

@doc """
Calculates the learning proficiency ("High", "Medium", "Low", "Not enough data")
for a given student in a given section.
It returns a map:
%{objective_id_1 => "High",
...
objective_id_n => "Low"
}
"""
@spec proficiency_for_student_per_learning_objective(
section :: %Oli.Delivery.Sections.Section{},
student_id :: integer
) :: map
def proficiency_for_student_per_learning_objective(
%Section{slug: section_slug, analytics_version: :v1},
student_id
) do
query =
from(sn in Snapshot,
join: s in Section,
on: sn.section_id == s.id,
where:
sn.attempt_number == 1 and sn.part_attempt_number == 1 and s.slug == ^section_slug and
sn.user_id == ^student_id,
group_by: sn.objective_id,
select:
{sn.objective_id,
fragment(
"CAST(COUNT(CASE WHEN ? THEN 1 END) as float) / CAST(COUNT(*) as float)",
sn.correct
)}
)

Repo.all(query)
|> Enum.into(%{}, fn {objective_id, proficiency} ->
{objective_id, proficiency_range(proficiency)}
end)
end

def proficiency_for_student_per_learning_objective(
%Section{id: section_id, analytics_version: :v2},
student_id
) do
objective_type_id = Oli.Resources.ResourceType.id_for_objective()

query =
from(summary in Oli.Analytics.Summary.ResourceSummary,
where:
summary.section_id == ^section_id and
summary.project_id == -1 and
summary.publication_id == -1 and
summary.user_id == ^student_id and
summary.resource_type_id == ^objective_type_id,
group_by: summary.resource_id,
select:
{summary.resource_id,
fragment(
"CAST(SUM(?) as float) / CAST(SUM(?) as float)",
summary.num_first_attempts_correct,
summary.num_first_attempts
)}
)

Repo.all(query)
|> Enum.into(%{}, fn {objective_id, proficiency} ->
{objective_id, proficiency_range(proficiency)}
end)
end

def proficiency_range(nil), do: "Not enough data"
def proficiency_range(proficiency) when proficiency <= 0.5, do: "Low"
def proficiency_range(proficiency) when proficiency <= 0.8, do: "Medium"
Expand Down
85 changes: 78 additions & 7 deletions lib/oli/delivery/sections.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2335,7 +2335,8 @@ defmodule Oli.Delivery.Sections do
# create any remaining section resources which are not in the hierarchy
create_nonstructural_section_resources(section.id, [publication_id],
skip_resource_ids: processed_ids,
required_survey_resource_id: survey_id
required_survey_resource_id: survey_id,
reference_activity_ids: []
)

root_section_resource_id = section_resources_by_resource_id[root_resource_id].id
Expand Down Expand Up @@ -2823,10 +2824,15 @@ defmodule Oli.Delivery.Sections do
|> select([p], p.required_survey_resource_id)
|> Repo.one()

create_nonstructural_section_resources(section_id, publication_ids,
skip_resource_ids: processed_resource_ids,
required_survey_resource_id: survey_id
)
reference_activity_ids = build_reference_activity_ids(hierarchy.children)

if length(processed_resource_ids) != 1 do
create_nonstructural_section_resources(section_id, publication_ids,
skip_resource_ids: processed_resource_ids,
required_survey_resource_id: survey_id,
reference_activity_ids: reference_activity_ids
)
end

# Rebuild section previous next index
PreviousNextIndex.rebuild(section, hierarchy)
Expand All @@ -2838,6 +2844,62 @@ defmodule Oli.Delivery.Sections do
end)
end

defp build_reference_activity_ids([]), do: []

defp build_reference_activity_ids(children_activities) do
tuple_of_children_activities =
process_activity_ids(children_activities)

tuple_of_children_activities
|> Tuple.to_list()
|> Enum.concat()
end

defp process_activity_ids(children_activities) do
children_activities
|> Enum.reduce({[], []}, fn r, {children_unit_activities_ids, children_activities_ids} ->
new_children_unit_activities_ids = build_child_activity_ids_for_units(r.children)

if Map.has_key?(r.revision, :content) do
new_children_activities_ids = build_child_activity_ids(r.revision.content)

{children_unit_activities_ids ++ new_children_unit_activities_ids,
children_activities_ids ++ new_children_activities_ids}
else
{children_unit_activities_ids ++ new_children_unit_activities_ids,
children_activities_ids ++ []}
end
end)
end

defp build_child_activity_ids_for_units([]), do: []

defp build_child_activity_ids_for_units(children) do
children
|> Enum.map(fn c ->
if Map.has_key?(c.revision, :content) do
build_child_activity_ids(c.revision.content)
else
[]
end
end)
|> List.flatten()
end

defp build_child_activity_ids(%{"model" => nil}), do: []

defp build_child_activity_ids(%{"model" => model}) do
model
|> Enum.reduce([], fn item, activity_ids ->
case item["activity_id"] do
nil -> activity_ids
activity_id -> [activity_id | activity_ids]
end
end)
end

defp build_child_activity_ids(_), do: []

def get_contained_pages(%Section{id: section_id}) do
from(cp in ContainedPage,
where: cp.section_id == ^section_id
Expand Down Expand Up @@ -3630,10 +3692,11 @@ defmodule Oli.Delivery.Sections do
# any that belong to the resource ids in skip_resource_ids
defp create_nonstructural_section_resources(section_id, publication_ids,
skip_resource_ids: skip_resource_ids,
required_survey_resource_id: required_survey_resource_id
required_survey_resource_id: required_survey_resource_id,
reference_activity_ids: reference_activity_ids
) do
published_resources_by_resource_id =
MinimalHierarchy.published_resources_map(publication_ids)
build_published_resources_by_resource_id(publication_ids, reference_activity_ids)

now = DateTime.utc_now() |> DateTime.truncate(:second)

Expand Down Expand Up @@ -3677,6 +3740,14 @@ defmodule Oli.Delivery.Sections do
Database.batch_insert_all(SectionResource, section_resource_rows)
end

defp build_published_resources_by_resource_id(publication_ids, []),
do: MinimalHierarchy.published_resources_map(publication_ids)

defp build_published_resources_by_resource_id(publication_ids, list_children_section_ids),
do:
MinimalHierarchy.published_resources_map(publication_ids)
|> Map.take(list_children_section_ids)

def is_structural?(%Revision{resource_type_id: resource_type_id}) do
container = ResourceType.id_for_container()

Expand Down
5 changes: 3 additions & 2 deletions lib/oli/publishing/delivery_resolver.ex
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ defmodule Oli.Publishing.DeliveryResolver do
|> emit([:oli, :resolvers, :delivery], :duration)
end

def revisions_filter_by_section_ids(section_ids, resource_type_id) do
def revisions_by_section_ids(section_ids, resource_type_id) do
from(sr in SectionResource,
join: s in Section,
on: s.id == sr.section_id,
Expand All @@ -277,7 +277,8 @@ defmodule Oli.Publishing.DeliveryResolver do
join: rev in Revision,
on: rev.id == pr.revision_id,
where: rev.resource_type_id == ^resource_type_id and rev.deleted == false,
select: rev
select: rev,
distinct: [rev]
)
end

Expand Down
11 changes: 11 additions & 0 deletions lib/oli/resources.ex
Original file line number Diff line number Diff line change
Expand Up @@ -425,4 +425,15 @@ defmodule Oli.Resources do
)
|> Repo.one()
end

@doc """
Returns a list of revisions for the given resource ids.
"""
def get_revisions_by_resource_id(resource_ids) do
from(r in Revision,
where: r.resource_id in ^resource_ids,
select: r
)
|> Repo.all()
end
end
37 changes: 36 additions & 1 deletion lib/oli/utils/db_seeder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -198,14 +198,34 @@ defmodule Oli.Seeder do

create_published_resource(publication, container_resource, container_revision)

%{resource: _activity_resource, revision: activity_revision} =
create_activity(
%{
activity_type_id: Activities.get_registration_by_slug("oli_short_answer").id,
content: %{}
},
publication,
project,
author
)

%{resource: page1, revision: revision1} =
create_page("Page one", publication, project, author)

%{resource: page2, revision: revision2} =
create_page("Page two", publication, project, author, create_sample_content())

%{resource: page3, revision: revision3} =
create_page(
"Page three",
publication,
project,
author,
create_activity_content(activity_revision.resource_id)
)

container_revision =
attach_pages_to([page1, page2], container_resource, container_revision, publication)
attach_pages_to([page1, page2, page3], container_resource, container_revision, publication)

{:ok, pub1} = Publishing.publish_project(project, "some changes", author.id)

Expand All @@ -229,8 +249,10 @@ defmodule Oli.Seeder do
|> Map.put(:container, %{resource: container_resource, revision: container_revision})
|> Map.put(:page1, page1)
|> Map.put(:page2, page2)
|> Map.put(:page3, page3)
|> Map.put(:revision1, revision1)
|> Map.put(:revision2, revision2)
|> Map.put(:revision3, revision3)
|> Map.put(:section, section)
end

Expand Down Expand Up @@ -1290,6 +1312,19 @@ defmodule Oli.Seeder do
}
end

def create_activity_content(activity_resource_id) do
%{
"model" => [
%{
"type" => "activity-reference",
"activity_id" => activity_resource_id,
"custom" => %{}
}
],
"advancedDelivery" => false
}
end

def create_sample_content() do
%{
"model" => [
Expand Down
Loading

0 comments on commit 3f2feb1

Please sign in to comment.