add filters to submissionsConnection for enrollment state
closes EVAL-3897 flag=none Adds the include_concluded, include_deactivated, and apply_gradebook_enrollment_filters filters to the submissionsConnection. These filters allow for submissions belonging to concluded/deactivated students to be returned. Test Plan: - specs pass Change-Id: Ie6b6fa213a2d31d3c60fef5ce75c28bb6107b295 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/337515 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Derek Williams <derek.williams@instructure.com> Reviewed-by: Kai Bjorkman <kbjorkman@instructure.com> QA-Review: Spencer Olson <solson@instructure.com> Product-Review: Cameron Ray <cameron.ray@instructure.com>
This commit is contained in:
parent
b98805b6c2
commit
75e5d4da31
|
@ -22,12 +22,25 @@ module Types
|
|||
class SubmissionSearchFilterInputType < Types::BaseInputObject
|
||||
graphql_name "SubmissionSearchFilterInput"
|
||||
|
||||
argument :apply_gradebook_enrollment_filters, Boolean, <<~MD, required: false
|
||||
Filters submissions for deactivated and concluded users based on the calling user's
|
||||
'Show -> Inactive Enrollments' and 'Show -> Concluded Enrollments' settings in the Gradebook.
|
||||
When true, this filter takes precedence over the include_concluded and include_deactivated filters.
|
||||
MD
|
||||
|
||||
argument :include_unsubmitted, Boolean, required: false
|
||||
|
||||
argument :states, [SubmissionStateType], required: false, default_value: DEFAULT_SUBMISSION_STATES
|
||||
argument :section_ids, [ID], required: false, prepare: GraphQLHelpers.relay_or_legacy_ids_prepare_func("Section")
|
||||
|
||||
argument :enrollment_types, [EnrollmentTypeType], required: false
|
||||
argument :include_concluded, Boolean, <<~MD, required: false
|
||||
Include submissions for concluded students.
|
||||
MD
|
||||
|
||||
argument :include_deactivated, Boolean, <<~MD, required: false
|
||||
Include submissions for deactivated students.
|
||||
MD
|
||||
|
||||
argument :user_search, String, <<~MD, required: false
|
||||
The partial name or full ID of the users to match and return in the
|
||||
|
|
|
@ -3033,7 +3033,8 @@ class Course < ActiveRecord::Base
|
|||
user,
|
||||
visibilities,
|
||||
visibility,
|
||||
enrollment_state: opts[:enrollment_state])
|
||||
enrollment_state: opts[:enrollment_state],
|
||||
exclude_enrollment_state: opts[:exclude_enrollment_state])
|
||||
end
|
||||
|
||||
def enrollments_visible_to(user, opts = {})
|
||||
|
@ -3044,8 +3045,12 @@ class Course < ActiveRecord::Base
|
|||
apply_enrollment_visibilities_internal(enrollment_scope.except(:preload), user, visibilities, visibility)
|
||||
end
|
||||
|
||||
def apply_enrollment_visibilities_internal(scope, user, visibilities, visibility, enrollment_state: nil)
|
||||
scope = scope.where(enrollments: { workflow_state: enrollment_state }) if enrollment_state
|
||||
def apply_enrollment_visibilities_internal(scope, user, visibilities, visibility, enrollment_state: nil, exclude_enrollment_state: nil)
|
||||
if enrollment_state
|
||||
scope = scope.where(enrollments: { workflow_state: enrollment_state })
|
||||
elsif exclude_enrollment_state
|
||||
scope = scope.where.not(enrollments: { workflow_state: exclude_enrollment_state })
|
||||
end
|
||||
# See also MessageableUsers (same logic used to get users across multiple courses) (should refactor)
|
||||
case visibility
|
||||
when :full then scope
|
||||
|
|
|
@ -68,8 +68,7 @@ class SubmissionSearch
|
|||
search_scope = if @course.grants_any_right?(@searcher, @session, :manage_grades, :view_all_grades) || @course.participating_observers.map(&:id).include?(@searcher.id)
|
||||
# a user with manage_grades, view_all_grades, or an observer can see other users' submissions
|
||||
# TODO: may want to add a preloader for this
|
||||
allowed_user_ids = @course.users_visible_to(@searcher)
|
||||
search_scope.where(user_id: allowed_user_ids)
|
||||
search_scope.where(user_id: allowed_users)
|
||||
elsif @course.grants_right?(@searcher, @session, :read_grades)
|
||||
# a user can see their own submission
|
||||
search_scope.where(user_id: @searcher.id)
|
||||
|
@ -125,4 +124,36 @@ class SubmissionSearch
|
|||
end
|
||||
search_scope.order(:user_id)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def allowed_users
|
||||
if @options[:apply_gradebook_enrollment_filters]
|
||||
@course.users_visible_to(@searcher, true, exclude_enrollment_state: excluded_enrollment_states_from_gradebook_settings)
|
||||
elsif @options[:include_concluded] || @options[:include_deactivated]
|
||||
@course.users_visible_to(@searcher, true, exclude_enrollment_state: excluded_enrollment_states_from_filters)
|
||||
else
|
||||
@course.users_visible_to(@searcher)
|
||||
end
|
||||
end
|
||||
|
||||
def excluded_enrollment_states_from_gradebook_settings
|
||||
settings = @searcher.get_preference(:gradebook_settings, @course.global_id) || {}
|
||||
excluded_enrollment_states(
|
||||
completed: settings["show_concluded_enrollments"] != "true",
|
||||
inactive: settings["show_inactive_enrollments"] != "true"
|
||||
)
|
||||
end
|
||||
|
||||
def excluded_enrollment_states_from_filters
|
||||
excluded_enrollment_states(
|
||||
completed: !@options[:include_concluded],
|
||||
inactive: !@options[:include_deactivated]
|
||||
)
|
||||
end
|
||||
|
||||
def excluded_enrollment_states(states)
|
||||
excluded_states = states.filter_map { |state, excluded| state if excluded }
|
||||
excluded_states << :rejected
|
||||
end
|
||||
end
|
||||
|
|
|
@ -57,6 +57,110 @@ describe SubmissionSearch do
|
|||
expect(results.preload(:user).map(&:user)).to eq students
|
||||
end
|
||||
|
||||
it "excludes rejected students by default" do
|
||||
course.enrollments.find_by(user: jonah).reject
|
||||
results = SubmissionSearch.new(assignment, teacher, nil, order_by: [{ field: "username" }]).search
|
||||
expect(results.where(user: jonah).exists?).to be false
|
||||
end
|
||||
|
||||
it "excludes deactivated students by default" do
|
||||
course.enrollments.find_by(user: jonah).deactivate
|
||||
results = SubmissionSearch.new(assignment, teacher, nil, order_by: [{ field: "username" }]).search
|
||||
expect(results.where(user: jonah).exists?).to be false
|
||||
end
|
||||
|
||||
it "optionally includes deactivated students" do
|
||||
course.enrollments.find_by(user: jonah).deactivate
|
||||
results = SubmissionSearch.new(assignment, teacher, nil, order_by: [{ field: "username" }], include_deactivated: true).search
|
||||
expect(results.where(user: jonah).exists?).to be true
|
||||
end
|
||||
|
||||
it "excludes rejected students when including deactivated students" do
|
||||
course.enrollments.find_by(user: jonah).reject
|
||||
results = SubmissionSearch.new(assignment, teacher, nil, order_by: [{ field: "username" }], include_deactivated: true).search
|
||||
expect(results.where(user: jonah).exists?).to be false
|
||||
end
|
||||
|
||||
it "excludes concluded students by default" do
|
||||
course.enrollments.find_by(user: jonah).conclude
|
||||
results = SubmissionSearch.new(assignment, teacher, nil, order_by: [{ field: "username" }]).search
|
||||
expect(results.where(user: jonah).exists?).to be false
|
||||
end
|
||||
|
||||
it "optionally includes concluded students" do
|
||||
course.enrollments.find_by(user: jonah).conclude
|
||||
results = SubmissionSearch.new(assignment, teacher, nil, order_by: [{ field: "username" }], include_concluded: true).search
|
||||
expect(results.where(user: jonah).exists?).to be true
|
||||
end
|
||||
|
||||
it "excludes rejected students when including concluded students" do
|
||||
course.enrollments.find_by(user: jonah).reject
|
||||
results = SubmissionSearch.new(assignment, teacher, nil, order_by: [{ field: "username" }], include_concluded: true).search
|
||||
expect(results.where(user: jonah).exists?).to be false
|
||||
end
|
||||
|
||||
it "optionally includes deactivated students via gradebook settings" do
|
||||
course.enrollments.find_by(user: jonah).deactivate
|
||||
teacher.preferences[:gradebook_settings] = {
|
||||
course.global_id => {
|
||||
"show_inactive_enrollments" => "true"
|
||||
}
|
||||
}
|
||||
teacher.save!
|
||||
results = SubmissionSearch.new(
|
||||
assignment,
|
||||
teacher,
|
||||
nil,
|
||||
order_by: [{ field: "username" }],
|
||||
apply_gradebook_enrollment_filters: true
|
||||
).search
|
||||
expect(results.where(user: jonah).exists?).to be true
|
||||
end
|
||||
|
||||
it "optionally includes concluded students via gradebook settings" do
|
||||
course.enrollments.find_by(user: jonah).conclude
|
||||
teacher.preferences[:gradebook_settings] = {
|
||||
course.global_id => {
|
||||
"show_concluded_enrollments" => "true"
|
||||
}
|
||||
}
|
||||
teacher.save!
|
||||
results = SubmissionSearch.new(
|
||||
assignment,
|
||||
teacher,
|
||||
nil,
|
||||
order_by: [{ field: "username" }],
|
||||
apply_gradebook_enrollment_filters: true
|
||||
).search
|
||||
expect(results.where(user: jonah).exists?).to be true
|
||||
end
|
||||
|
||||
it "ignores include_concluded and include_deactivated when apply_gradebook_enrollment_filters is true" do
|
||||
course.enrollments.find_by(user: amanda).deactivate
|
||||
course.enrollments.find_by(user: jonah).conclude
|
||||
teacher.preferences[:gradebook_settings] = {
|
||||
course.global_id => {
|
||||
"show_concluded_enrollments" => "false",
|
||||
"show_inactive_enrollments" => "false"
|
||||
}
|
||||
}
|
||||
teacher.save!
|
||||
results = SubmissionSearch.new(
|
||||
assignment,
|
||||
teacher,
|
||||
nil,
|
||||
order_by: [{ field: "username" }],
|
||||
apply_gradebook_enrollment_filters: true,
|
||||
include_concluded: true,
|
||||
include_deactivated: true
|
||||
).search
|
||||
|
||||
aggregate_failures do
|
||||
expect(results.where(user: amanda).exists?).to be false
|
||||
expect(results.where(user: jonah).exists?).to be false
|
||||
end
|
||||
end
|
||||
|
||||
it "finds submissions with user name search" do
|
||||
results = SubmissionSearch.new(assignment,
|
||||
teacher,
|
||||
|
|
Loading…
Reference in New Issue