Skip to content

Commit ddd4378

Browse files
authored
Add sorting for grading (#1107)
* handled backend sorting * fixed sorting by inserted_at * removed unused code * changed inner_join to left_join * added new tests * fixed formatting * reformatted code * added more test * added more tests * updated grading sorter for progressStatus * fixed test * fixed sorting by group bug and made sorting work regardless of upper lower case * fixed formatting * fixed bug where xp was not sorted properly * fixed sorting by grading bug * fixed test * Prefer piping * Reduce nesting * Revert "Prefer piping" This reverts commit 415cdc0.
1 parent 76cb9f7 commit ddd4378

File tree

2 files changed

+312
-3
lines changed

2 files changed

+312
-3
lines changed

lib/cadet/assessments/assessments.ex

Lines changed: 130 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1906,7 +1906,9 @@ defmodule Cadet.Assessments do
19061906
"group" => "false",
19071907
"isFullyGraded" => "false",
19081908
"pageSize" => "10",
1909-
"offset" => "0"
1909+
"offset" => "0",
1910+
"sortBy" => "",
1911+
"sortDirection" => ""
19101912
}
19111913
) do
19121914
submission_answers_query =
@@ -1927,7 +1929,9 @@ defmodule Cadet.Assessments do
19271929
on: q.assessment_id == a.id,
19281930
select: %{
19291931
assessment_id: q.assessment_id,
1930-
question_count: count(q.id)
1932+
question_count: count(q.id),
1933+
title: max(a.title),
1934+
config_id: max(a.config_id)
19311935
}
19321936
)
19331937

@@ -1939,12 +1943,23 @@ defmodule Cadet.Assessments do
19391943
left_join: asst in subquery(question_answers_query),
19401944
on: asst.assessment_id == s.assessment_id,
19411945
as: :asst,
1946+
left_join: user in User,
1947+
on: user.id == s.student_id,
1948+
as: :user,
1949+
left_join: cr in CourseRegistration,
1950+
on: user.id == cr.user_id,
1951+
as: :cr,
1952+
left_join: group in Group,
1953+
on: cr.group_id == group.id,
1954+
as: :group,
1955+
inner_join: config in AssessmentConfig,
1956+
on: asst.config_id == config.id,
1957+
as: :config,
19421958
where: ^build_user_filter(params),
19431959
where: s.assessment_id in subquery(build_assessment_filter(params, course_id)),
19441960
where: s.assessment_id in subquery(build_assessment_config_filter(params)),
19451961
where: ^build_submission_filter(params),
19461962
where: ^build_course_registration_filter(params, grader),
1947-
order_by: [desc: s.inserted_at],
19481963
limit: ^elem(Integer.parse(Map.get(params, "pageSize", "10")), 0),
19491964
offset: ^elem(Integer.parse(Map.get(params, "offset", "0")), 0),
19501965
select: %{
@@ -1964,6 +1979,10 @@ defmodule Cadet.Assessments do
19641979
}
19651980
)
19661981

1982+
query =
1983+
sort_submission(query, Map.get(params, "sortBy", ""), Map.get(params, "sortDirection", ""))
1984+
1985+
query = from([s, ans, asst, user, cr, group] in query, order_by: [desc: s.inserted_at])
19671986
submissions = Repo.all(query)
19681987

19691988
count_query =
@@ -1987,6 +2006,114 @@ defmodule Cadet.Assessments do
19872006
{:ok, %{count: count, data: generate_grading_summary_view_model(submissions, course_id)}}
19882007
end
19892008

2009+
# Given a query from submissions_by_grader_for_index,
2010+
# sorts it by the relevant field and direction
2011+
# sort_by is a string of either "", "assessmentName", "assessmentType", "studentName",
2012+
# "studentUsername", "groupName", "progressStatus", "xp"
2013+
# sort_direction is a string of either "", "sort-asc", "sort-desc"
2014+
defp sort_submission(query, sort_by, sort_direction) do
2015+
cond do
2016+
sort_direction == "sort-asc" ->
2017+
sort_submission_asc(query, sort_by)
2018+
2019+
sort_direction == "sort-desc" ->
2020+
sort_submission_desc(query, sort_by)
2021+
2022+
true ->
2023+
query
2024+
end
2025+
end
2026+
2027+
defp sort_submission_asc(query, sort_by) do
2028+
cond do
2029+
sort_by == "assessmentName" ->
2030+
from([s, ans, asst, user, cr, group, config] in query,
2031+
order_by: fragment("upper(?)", asst.title)
2032+
)
2033+
2034+
sort_by == "assessmentType" ->
2035+
from([s, ans, asst, user, cr, group, config] in query, order_by: asst.config_id)
2036+
2037+
sort_by == "studentName" ->
2038+
from([s, ans, asst, user, cr, group, config] in query,
2039+
order_by: fragment("upper(?)", user.name)
2040+
)
2041+
2042+
sort_by == "studentUsername" ->
2043+
from([s, ans, asst, user, cr, group, config] in query,
2044+
order_by: fragment("upper(?)", user.username)
2045+
)
2046+
2047+
sort_by == "groupName" ->
2048+
from([s, ans, asst, user, cr, group, config] in query,
2049+
order_by: fragment("upper(?)", group.name)
2050+
)
2051+
2052+
sort_by == "progressStatus" ->
2053+
from([s, ans, asst, user, cr, group, config] in query,
2054+
order_by: [
2055+
asc: config.is_manually_graded,
2056+
asc: s.status,
2057+
asc: ans.graded_count - asst.question_count,
2058+
asc: s.is_grading_published
2059+
]
2060+
)
2061+
2062+
sort_by == "xp" ->
2063+
from([s, ans, asst, user, cr, group, config] in query,
2064+
order_by: ans.xp + ans.xp_adjustment
2065+
)
2066+
2067+
true ->
2068+
query
2069+
end
2070+
end
2071+
2072+
defp sort_submission_desc(query, sort_by) do
2073+
cond do
2074+
sort_by == "assessmentName" ->
2075+
from([s, ans, asst, user, cr, group, config] in query,
2076+
order_by: [desc: fragment("upper(?)", asst.title)]
2077+
)
2078+
2079+
sort_by == "assessmentType" ->
2080+
from([s, ans, asst, user, cr, group, config] in query, order_by: [desc: asst.config_id])
2081+
2082+
sort_by == "studentName" ->
2083+
from([s, ans, asst, user, cr, group, config] in query,
2084+
order_by: [desc: fragment("upper(?)", user.name)]
2085+
)
2086+
2087+
sort_by == "studentUsername" ->
2088+
from([s, ans, asst, user, cr, group, config] in query,
2089+
order_by: [desc: fragment("upper(?)", user.username)]
2090+
)
2091+
2092+
sort_by == "groupName" ->
2093+
from([s, ans, asst, user, cr, group, config] in query,
2094+
order_by: [desc: fragment("upper(?)", group.name)]
2095+
)
2096+
2097+
sort_by == "progressStatus" ->
2098+
from([s, ans, asst, user, cr, group, config] in query,
2099+
order_by: [
2100+
desc: config.is_manually_graded,
2101+
desc: s.status,
2102+
desc: ans.graded_count - asst.question_count,
2103+
desc: s.is_grading_published
2104+
]
2105+
)
2106+
2107+
sort_by == "xp" ->
2108+
from([s, ans, asst, user, cr, group, config] in query,
2109+
order_by: [desc: ans.xp + ans.xp_adjustment]
2110+
)
2111+
2112+
true ->
2113+
query
2114+
end
2115+
end
2116+
19902117
defp build_assessment_filter(params, course_id) do
19912118
assessments_filters =
19922119
Enum.reduce(params, dynamic(true), fn

test/cadet/assessments/assessments_test.exs

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2815,6 +2815,188 @@ defmodule Cadet.AssessmentsTest do
28152815
assert Enum.find(assessments_from_res, fn a -> a.id == s.assessment_id end) != nil
28162816
end)
28172817
end
2818+
2819+
test "sorting by assessment title ascending", %{
2820+
course_regs: %{avenger1_cr: avenger},
2821+
assessments: _assessments,
2822+
total_submissions: total_submissions
2823+
} do
2824+
{_, res} =
2825+
Assessments.submissions_by_grader_for_index(avenger, %{
2826+
"pageSize" => total_submissions,
2827+
"sortBy" => "assessmentName",
2828+
"sortDirection" => "sort-asc"
2829+
})
2830+
2831+
submissions_from_res = res[:data][:submissions]
2832+
assessments_from_res = res[:data][:assessments]
2833+
2834+
submissions_by_title =
2835+
Enum.map(
2836+
submissions_from_res,
2837+
fn s ->
2838+
Enum.find(assessments_from_res, fn a ->
2839+
s.assessment_id == a.id
2840+
end)
2841+
end
2842+
)
2843+
2844+
Enum.reduce(
2845+
submissions_by_title,
2846+
fn x, y ->
2847+
assert x.title >= y.title
2848+
y
2849+
end
2850+
)
2851+
end
2852+
2853+
test "sorting by assessment title descending", %{
2854+
course_regs: %{avenger1_cr: avenger},
2855+
assessments: _assessments,
2856+
total_submissions: total_submissions
2857+
} do
2858+
{_, res} =
2859+
Assessments.submissions_by_grader_for_index(avenger, %{
2860+
"pageSize" => total_submissions,
2861+
"sortBy" => "assessmentName",
2862+
"sortDirection" => "sort-desc"
2863+
})
2864+
2865+
submissions_from_res = res[:data][:submissions]
2866+
assessments_from_res = res[:data][:assessments]
2867+
2868+
submissions_by_title =
2869+
Enum.map(
2870+
submissions_from_res,
2871+
fn s ->
2872+
Enum.find(assessments_from_res, fn a ->
2873+
s.assessment_id == a.id
2874+
end)
2875+
end
2876+
)
2877+
2878+
Enum.reduce(
2879+
submissions_by_title,
2880+
fn x, y ->
2881+
assert x.title <= y.title
2882+
y
2883+
end
2884+
)
2885+
end
2886+
2887+
test "sorting by assessment type ascending", %{
2888+
course_regs: %{avenger1_cr: avenger},
2889+
assessments: _assessments,
2890+
total_submissions: total_submissions
2891+
} do
2892+
{_, res} =
2893+
Assessments.submissions_by_grader_for_index(avenger, %{
2894+
"pageSize" => total_submissions,
2895+
"sortBy" => "assessmentType",
2896+
"sortDirection" => "sort-asc"
2897+
})
2898+
2899+
submissions_from_res = res[:data][:submissions]
2900+
assessments_from_res = res[:data][:assessments]
2901+
2902+
submissions_by_assessments_type =
2903+
Enum.map(
2904+
submissions_from_res,
2905+
fn s ->
2906+
Enum.find(assessments_from_res, fn a ->
2907+
s.assessment_id == a.id
2908+
end)
2909+
end
2910+
)
2911+
2912+
Enum.reduce(
2913+
submissions_by_assessments_type,
2914+
fn x, y ->
2915+
assert x.config_id >= y.config_id
2916+
y
2917+
end
2918+
)
2919+
end
2920+
2921+
test "sorting by assessment type descending", %{
2922+
course_regs: %{avenger1_cr: avenger},
2923+
assessments: _assessments,
2924+
total_submissions: total_submissions
2925+
} do
2926+
{_, res} =
2927+
Assessments.submissions_by_grader_for_index(avenger, %{
2928+
"pageSize" => total_submissions,
2929+
"sortBy" => "assessmentType",
2930+
"sortDirection" => "sort-desc"
2931+
})
2932+
2933+
submissions_from_res = res[:data][:submissions]
2934+
assessments_from_res = res[:data][:assessments]
2935+
2936+
submissions_by_assessments_type =
2937+
Enum.map(
2938+
submissions_from_res,
2939+
fn s ->
2940+
Enum.find(assessments_from_res, fn a ->
2941+
s.assessment_id == a.id
2942+
end)
2943+
end
2944+
)
2945+
2946+
Enum.reduce(
2947+
submissions_by_assessments_type,
2948+
fn x, y ->
2949+
assert x.config_id <= y.config_id
2950+
y
2951+
end
2952+
)
2953+
end
2954+
2955+
test "sorting by xp ascending", %{
2956+
course_regs: %{avenger1_cr: avenger},
2957+
assessments: _assessments,
2958+
total_submissions: total_submissions
2959+
} do
2960+
{_, res} =
2961+
Assessments.submissions_by_grader_for_index(avenger, %{
2962+
"pageSize" => total_submissions,
2963+
"sortBy" => "xp",
2964+
"sortDirection" => "sort-asc"
2965+
})
2966+
2967+
submissions_from_res = res[:data][:submissions]
2968+
2969+
Enum.reduce(
2970+
submissions_from_res,
2971+
fn x, y ->
2972+
assert x.xp >= y.xp
2973+
y
2974+
end
2975+
)
2976+
end
2977+
2978+
test "sorting by xp descending", %{
2979+
course_regs: %{avenger1_cr: avenger},
2980+
assessments: _assessments,
2981+
total_submissions: total_submissions
2982+
} do
2983+
{_, res} =
2984+
Assessments.submissions_by_grader_for_index(avenger, %{
2985+
"pageSize" => total_submissions,
2986+
"sortBy" => "xp",
2987+
"sortDirection" => "sort-desc"
2988+
})
2989+
2990+
submissions_from_res = res[:data][:submissions]
2991+
2992+
Enum.reduce(
2993+
submissions_from_res,
2994+
fn x, y ->
2995+
assert x.xp <= y.xp
2996+
y
2997+
end
2998+
)
2999+
end
28183000
end
28193001

28203002
describe "is_fully_autograded? function" do

0 commit comments

Comments
 (0)