Add sort and order to pace contexts api

fixes LS-3542
flag=course_paces_redesign

test plan:
- tests pass

Change-Id: If23af3840527fd98fb7e99ff6d665696028483c4
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/303834
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
Reviewed-by: Davis Hyer <dhyer@instructure.com>
QA-Review: Davis Hyer <dhyer@instructure.com>
Product-Review: Davis Hyer <dhyer@instructure.com>
This commit is contained in:
Eric Saupe 2022-10-19 14:00:48 -07:00
parent 6170ded1b5
commit 64c6a849bd
3 changed files with 132 additions and 4 deletions

View File

@ -26,8 +26,27 @@ class CoursePacing::PaceContextsApiController < ApplicationController
PERMITTED_CONTEXT_TYPES = %w[course section student_enrollment].freeze
# @API List all pace contexts
#
# Returns a paginated list of pace contexts for the given course and context type.
#
# @argument type [String]
# The type of pace context to return. Must be one of "course", "section", or "student_enrollment". Each type will
# return the corresponding set of items that can be paced.
#
# @argument sort [Optional, String, "name"]
# When included, sorts all pace contexts by the given field. "name" is the only supported sort field and will sort
# sections by their section name and student enrollments by their user's sortable name.
#
# @argument order [Optional, String, "asc"|"desc"]
# When included, orders the results in the given order. "asc" is the default order and to reverse the order pass
# "desc". Works in conjunction with the "sort" argument.
#
# @example_request
# curl https://<canvas>/api/v1/courses/1/pace_contexts?type=course \
# -H 'Authorization: Bearer <token>'
def index
contexts = CoursePacing::PaceContextsService.new(@context).contexts_of_type(@type)
contexts = CoursePacing::PaceContextsService.new(@context).contexts_of_type(@type, sort: params[:sort], order: params[:order])
paginated_contexts = Api.paginate(contexts, self, api_v1_pace_contexts_url, total_entries: contexts.count)
render json: {
pace_contexts: paginated_contexts.map { |c| CoursePacing::PaceContextsPresenter.as_json(c) }

View File

@ -24,14 +24,20 @@ class CoursePacing::PaceContextsService
@course = course
end
def contexts_of_type(type)
def contexts_of_type(type, sort: nil, order: nil)
case type
when "course"
[course]
when "section"
course.active_course_sections
sections = course.active_course_sections
sections = sections.order(sort) if sort == "name"
sections = sections.reverse_order if order == "desc"
sections
when "student_enrollment"
course.student_enrollments.order(:user_id, created_at: :desc).select("DISTINCT ON(enrollments.user_id) enrollments.*").to_a
student_enrollments = course.student_enrollments.order(:user_id, created_at: :desc).select("DISTINCT ON(enrollments.user_id) enrollments.*")
student_enrollments = student_enrollments.joins(:user).order("users.sortable_name") if sort == "name"
student_enrollments = student_enrollments.reverse_order if order == "desc"
student_enrollments.to_a
else
Canvas::Errors.capture_exception(
:pace_contexts_service,

View File

@ -267,5 +267,108 @@ describe "Pace Contexts API" do
expect(response.status).to eq 404
end
end
context "when an order is specified" do
context "sections" do
let(:default_section) { course.default_section }
let!(:section_one) { add_section("Section One", course: course) }
let!(:section_two) { add_section("Section Two", course: course) }
let!(:section_three) { add_section("Section Three", course: course) }
it "orders the results in descending order with desc specified" do
get api_v1_pace_contexts_path(course.id), params: { type: "section", order: "desc", format: :json }
expect(response.status).to eq 200
json = JSON.parse(response.body)
expect(json["pace_contexts"].pluck("item_id")).to eq [section_three.id, section_two.id, section_one.id, default_section.id]
end
it "orders the results in ascending order with asc specified" do
get api_v1_pace_contexts_path(course.id), params: { type: "section", order: "asc", format: :json }
expect(response.status).to eq 200
json = JSON.parse(response.body)
expect(json["pace_contexts"].pluck("item_id")).to eq [default_section.id, section_one.id, section_two.id, section_three.id]
end
it "orders the results in ascending order by default" do
get api_v1_pace_contexts_path(course.id), params: { type: "section", format: :json }
expect(response.status).to eq 200
json = JSON.parse(response.body)
expect(json["pace_contexts"].pluck("item_id")).to eq [default_section.id, section_one.id, section_two.id, section_three.id]
end
end
context "student enrollments" do
let!(:first_student_enrollment) { course.enroll_student(user_model(name: "Foo Bar"), enrollment_state: "active") }
let!(:second_student_enrollment) { course.enroll_student(user_model(name: "Bar Foo"), enrollment_state: "active") }
it "orders the results in descending order with desc specified" do
get api_v1_pace_contexts_path(course.id), params: { type: "student_enrollment", order: "desc", format: :json }
expect(response.status).to eq 200
json = JSON.parse(response.body)
expect(json["pace_contexts"].pluck("item_id")).to eq [second_student_enrollment.id, first_student_enrollment.id]
end
it "orders the results in ascending order with asc specified" do
get api_v1_pace_contexts_path(course.id), params: { type: "student_enrollment", order: "asc", format: :json }
expect(response.status).to eq 200
json = JSON.parse(response.body)
expect(json["pace_contexts"].pluck("item_id")).to eq [first_student_enrollment.id, second_student_enrollment.id]
end
it "orders the results in ascending order by default" do
get api_v1_pace_contexts_path(course.id), params: { type: "student_enrollment", format: :json }
expect(response.status).to eq 200
json = JSON.parse(response.body)
expect(json["pace_contexts"].pluck("item_id")).to eq [first_student_enrollment.id, second_student_enrollment.id]
end
end
end
context "when a sort is specified" do
context "sections" do
before do
add_section("Section C", course: course)
add_section("Section A", course: course)
add_section("Section B", course: course)
end
it "sorts by the section name" do
get api_v1_pace_contexts_path(course.id), params: { type: "section", sort: "name", format: :json }
expect(response.status).to eq 200
json = JSON.parse(response.body)
expect(json["pace_contexts"].pluck("name")).to eq ["Section A", "Section B", "Section C", "Unnamed Course"]
end
it "sorts by the section name and respects descending order" do
get api_v1_pace_contexts_path(course.id), params: { type: "section", sort: "name", order: "desc", format: :json }
expect(response.status).to eq 200
json = JSON.parse(response.body)
expect(json["pace_contexts"].pluck("name")).to eq ["Unnamed Course", "Section C", "Section B", "Section A"]
end
end
context "student enrollments" do
before do
student = user_model(name: "Foo Bar", sortable_name: "A, Foo")
student_two = user_model(name: "Bar Foo", sortable_name: "B, Foo")
course.enroll_student(student, enrollment_state: "active")
course.enroll_student(student_two, enrollment_state: "active")
end
it "sorts by the sortable user name" do
get api_v1_pace_contexts_path(course.id), params: { type: "student_enrollment", sort: "name", format: :json }
expect(response.status).to eq 200
json = JSON.parse(response.body)
expect(json["pace_contexts"].pluck("name")).to eq ["Foo Bar", "Bar Foo"]
end
it "sorts by the sortable user name and respects descending order" do
get api_v1_pace_contexts_path(course.id), params: { type: "student_enrollment", sort: "name", order: "desc", format: :json }
expect(response.status).to eq 200
json = JSON.parse(response.body)
expect(json["pace_contexts"].pluck("name")).to eq ["Bar Foo", "Foo Bar"]
end
end
end
end
end