Skip to content

Commit dfebb49

Browse files
author
Michael Nomitch
committed
DA - quiz/submission/discussion notifications
fixes CNVS-15156 test plan: - with DA on: - submission: - make a differentiated assignment - turn in a submission as a student - give the student a grade - as the student, ensure you have the notification, and then delete it - as a teacher, take away visibility and delete their grade - as the student, you should not have a new notification for grade changing - as a teacher, comment on this submission - as the student, you get notified about the comment - quiz: - as a teacher make a differentiated quiz - students without visibility dont get notified about it - discussion: - discussion notifications are broken so we cant QA - with DA off: - submission: - comment on a submission as a teacher and make sure the student is notified - grade a student as a teacher and make sure the student is notified - quiz: - making & assignment a quiz sends out notifications properly - discussion: - discussion notifications are broken so we cant QA Change-Id: I891f9782b5ae70252e7949a6858896b73ac28871 Reviewed-on: https://gerrit.instructure.com/41025 Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Cameron Sutter <csutter@instructure.com> QA-Review: Sean Lewis <slewis@instructure.com> Product-Review: Hilary Scharton <hilary@instructure.com>
1 parent 8059663 commit dfebb49

10 files changed

Lines changed: 153 additions & 14 deletions

app/models/assignment_override.rb

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,17 @@ def applies_to_students
219219
end
220220
end
221221

222+
def applies_to_students_with_visibility
223+
return applies_to_students unless self.assignment.try(:differentiated_assignments_applies?) || self.quiz.try(:differentiated_assignments_applies?)
224+
if self.quiz
225+
applies_to_students.able_to_see_quiz_in_course_with_da(self.quiz_id, context.id)
226+
elsif self.assignment
227+
applies_to_students.able_to_see_assignment_in_course_with_da(self.assignment_id, context.id)
228+
else
229+
applies_to_students
230+
end
231+
end
232+
222233
def applies_to_admins
223234
case set_type
224235
when 'CourseSection'
@@ -242,7 +253,7 @@ def notify_change?
242253
has_a_broadcast_policy
243254
set_broadcast_policy do |p|
244255
p.dispatch :assignment_due_date_changed
245-
p.to { applies_to_students }
256+
p.to { applies_to_students_with_visibility }
246257
p.whenever { |record| record.notify_change? }
247258
p.filter_asset_by_recipient { |record, user|
248259
# note that our asset for this message is an Assignment, not an AssignmentOverride

app/models/broadcast_policies/quiz_submission_policy.rb

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@ def should_dispatch_submission_graded?
1515
def should_dispatch_submission_grade_changed?
1616
quiz_is_accepting_messages? &&
1717
quiz_submission.submission.graded_at &&
18-
quiz_submission.changed_in_state(:complete, :fields => [:score])
18+
quiz_submission.changed_in_state(:complete, :fields => [:score]) &&
19+
user_has_visibility?
1920
end
2021

2122
def should_dispatch_submission_needs_grading?
2223
!quiz.survey? &&
2324
quiz_is_accepting_messages? &&
24-
quiz_submission.pending_review?
25+
quiz_submission.pending_review? &&
26+
user_has_visibility?
2527
end
2628

2729
private
@@ -40,5 +42,10 @@ def quiz_is_accepting_messages?
4042
def manually_graded
4143
quiz_submission.changed_in_state(:pending_review, :fields => [:fudge_points])
4244
end
45+
46+
def user_has_visibility?
47+
return true unless quiz_submission.context.feature_enabled?(:differentiated_assignments)
48+
Quizzes::QuizStudentVisibility.where(quiz_id: quiz.id, user_id: quiz_submission.user_id).any?
49+
end
4350
end
4451
end

app/models/broadcast_policies/submission_policy.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,16 @@ def should_dispatch_group_assignment_submitted_late?
4343

4444
def should_dispatch_submission_graded?
4545
broadcasting_grades? &&
46+
user_has_visibility? &&
4647
(submission.changed_state_to(:graded) || (grade_updated? && graded_recently?))
4748
end
4849

4950
def should_dispatch_submission_grade_changed?
5051
broadcasting_grades? &&
5152
submission.graded_at &&
5253
!graded_recently? &&
53-
grade_updated?
54+
grade_updated? &&
55+
user_has_visibility?
5456
end
5557

5658
private
@@ -94,5 +96,9 @@ def graded_recently?
9496
submission.assignment_graded_in_the_last_hour?
9597
end
9698

99+
def user_has_visibility?
100+
return true unless submission.context.feature_enabled?(:differentiated_assignments)
101+
AssignmentStudentVisibility.where(assignment_id: submission.assignment_id, user_id: submission.user_id).any?
102+
end
97103
end
98104
end

app/models/discussion_topic.rb

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -837,7 +837,7 @@ def ensure_submission(user)
837837

838838
set_broadcast_policy do |p|
839839
p.dispatch :new_discussion_topic
840-
p.to { active_participants - [user] }
840+
p.to { active_participants_with_visibility - [user] }
841841
p.whenever { |record|
842842
record.context.available? and
843843
!record.context.concluded? and
@@ -862,6 +862,15 @@ def active_participants(include_observers=false)
862862
end
863863
end
864864

865+
def active_participants_with_visibility
866+
return active_participants unless context.feature_enabled?(:differentiated_assignments)
867+
users_with_visibility = AssignmentStudentVisibility.where(assignment_id: self.assignment_id).pluck(:user_id)
868+
# observers will not be returned, which is okay for the functions current use cases (but potentially not others)
869+
instructor_ids = context.participating_instructors.pluck(:id)
870+
users_with_visibility.concat(instructor_ids)
871+
active_participants.select{|p| users_with_visibility.include?(p.id)}
872+
end
873+
865874
def participating_users(user_ids)
866875
context.respond_to?(:participating_users) ? context.participating_users(user_ids) : User.find(user_ids)
867876
end
@@ -874,7 +883,23 @@ def subscribers
874883
poster_ids = posters.map(&:id)
875884
legacy_sub_ids &= poster_ids
876885
sub_ids += legacy_sub_ids
877-
participating_users(sub_ids)
886+
887+
subscribed_users = participating_users(sub_ids)
888+
889+
if context.feature_enabled?(:differentiated_assignments) && self.for_assignment?
890+
students_with_visibility = AssignmentStudentVisibility.where(course_id: context_id, assignment_id: assignment_id).pluck(:user_id)
891+
admin_ids = self.context.participating_admins.pluck(:id)
892+
observer_ids = self.context.participating_observers.pluck(:id)
893+
observed_students = ObserverEnrollment.observed_student_ids_by_observer_id(self.context,observer_ids)
894+
895+
subscribed_users.select!{ |user|
896+
students_with_visibility.include?(user.id) || admin_ids.include?(user.id) ||
897+
# an observer with no students or one with students who have visibility
898+
(observed_students[user.id] && (observed_students[user.id] == [] || (observed_students[user.id] & students_with_visibility).any?))
899+
}
900+
end
901+
902+
subscribed_users
878903
end
879904

880905
def posters

app/models/observer_enrollment.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,16 @@ def self.observed_student_ids(context, current_user)
4343
context.observer_enrollments.where("user_id=? AND associated_user_id IS NOT NULL", current_user).pluck(:associated_user_id)
4444
end
4545
end
46+
47+
def self.observed_student_ids_by_observer_id(course, observers)
48+
# select_all allows plucking multiplecolumns without instantiating AR objects
49+
obs_hash = connection.select_all( ObserverEnrollment.where(course_id: course, user_id: observers).select([:user_id, :associated_user_id])).group_by{|record| record["user_id"]}
50+
obs_hash.keys.each{ |key|
51+
obs_hash[key.to_i] = obs_hash.delete(key).map{|v|
52+
v["associated_user_id"].try(:to_i)
53+
}.compact
54+
}
55+
# should look something like this: {10 => [11,12,13], 20 => [11,24,32]}
56+
obs_hash
57+
end
4658
end

lib/dates_overridable.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def all_due_dates
7373
def differentiated_assignments_applies?
7474
return false if !context.feature_enabled?(:differentiated_assignments)
7575

76-
if self.is_a?(Assignment) || self.is_a?(Quizzes::Quiz)
76+
if self.is_a?(Assignment) || Quizzes::Quiz.class_names.include?(self.class_name)
7777
self.only_visible_to_overrides
7878
elsif self.assignment
7979
self.assignment.only_visible_to_overrides

spec/models/broadcast_policies/quiz_submission_policy_spec.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module BroadcastPolicies
66
let(:course) do
77
mock("Course").tap do |c|
88
c.stubs(:available?).returns(true)
9+
c.stubs(:feature_enabled?).with(:differentiated_assignments).returns(false)
910
end
1011
end
1112
let(:assignment) do
@@ -41,6 +42,7 @@ module BroadcastPolicies
4142
qs.stubs(:quiz).returns(quiz)
4243
qs.stubs(:submission).returns(submission)
4344
qs.stubs(:user).returns(user)
45+
qs.stubs(:context).returns(course)
4446
end
4547
end
4648
let(:policy) { QuizSubmissionPolicy.new(quiz_submission) }
@@ -92,6 +94,7 @@ def wont_send_when
9294
specify { wont_send_when { quiz.stubs(:deleted?).returns true } }
9395
specify { wont_send_when { submission.stubs(:graded_at).returns nil }}
9496
specify { wont_send_when { submission.stubs(:pending_review?).returns false }}
97+
specify { wont_send_when { submission.stubs(:user_has_visibility).returns false }}
9598
end
9699

97100

@@ -115,6 +118,7 @@ def wont_send_when
115118
specify { wont_send_when { course.stubs(:available?).returns false} }
116119
specify { wont_send_when { quiz.stubs(:deleted?).returns true } }
117120
specify { wont_send_when { submission.stubs(:graded_at).returns nil }}
121+
specify { wont_send_when { submission.stubs(:user_has_visibility).returns false }}
118122

119123
specify do
120124
wont_send_when do

spec/models/broadcast_policies/submission_policy_spec.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module BroadcastPolicies
77
stub("Course").tap do |c|
88
c.stubs(:available?).returns(true)
99
c.stubs(:id).returns(1)
10+
c.stubs(:feature_enabled?).with(:differentiated_assignments).returns(false)
1011
end
1112
end
1213
let(:assignment) do
@@ -48,6 +49,7 @@ module BroadcastPolicies
4849
s.stubs(:late?).returns(false)
4950
s.stubs(:quiz_submission).returns(nil)
5051
s.stubs(:user).returns(user)
52+
s.stubs(:context).returns(course)
5153
end
5254
end
5355

@@ -177,6 +179,7 @@ def wont_send_when
177179
specify { wont_send_when{ submission.stubs(:quiz_submission).returns stub }}
178180
specify { wont_send_when{ course.stubs(:available?).returns false }}
179181
specify { wont_send_when{ assignment.stubs(:published?).returns false }}
182+
specify { wont_send_when{ SubmissionPolicy.any_instance.stubs(:user_has_visibility?).returns(false)}}
180183
end
181184

182185
end

spec/models/discussion_topic_spec.rb

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,8 @@
191191
context "differentiated assignements" do
192192
before do
193193
@course = course(:active_course => true)
194-
discussion_topic_model(:user => @teacher)
194+
discussion_topic_model(:user => @teacher, :context => @course)
195+
@course.enroll_teacher(@teacher).accept!
195196
@course_section = @course.course_sections.create
196197
@student1, @student2, @student3 = create_users(3, return_type: :record)
197198

@@ -223,6 +224,14 @@
223224
it "should be visible to a teacher" do
224225
@topic.visible_for?(@teacher).should be_true
225226
end
227+
context "active_participants_with_visibility" do
228+
it "should filter participants by visibility" do
229+
[@student1, @teacher].each do |user|
230+
@topic.active_participants_with_visibility.include?(user).should be_true
231+
end
232+
@topic.active_participants_with_visibility.include?(@student2).should be_false
233+
end
234+
end
226235
end
227236

228237
context "feature flag off" do
@@ -232,6 +241,13 @@
232241
@topic.visible_for?(user).should be_true
233242
end
234243
end
244+
context "active_participants_with_visibility" do
245+
it "should not filter any participants" do
246+
[@student1,@student2].each do |user|
247+
@topic.active_participants_with_visibility.include?(user).should be_true
248+
end
249+
end
250+
end
235251
end
236252
end
237253
end
@@ -738,6 +754,52 @@ def delayed_discussion_topic(opts = {})
738754
@topic.subscribers.should_not include(@student)
739755
@topic2.subscribers.should_not include(@student)
740756
end
757+
758+
context "differentiated_assignments" do
759+
before do
760+
@assignment = @course.assignments.create!(:title => "some discussion assignment",only_visible_to_overrides: true)
761+
@assignment.submission_types = 'discussion_topic'
762+
@assignment.save!
763+
@topic.assignment_id = @assignment.id
764+
@topic.save!
765+
@section = @course.course_sections.create!(name: "test section")
766+
create_section_override_for_assignment(@topic.assignment, {course_section: @section})
767+
end
768+
context "enabled" do
769+
before{@course.enable_feature!(:differentiated_assignments)}
770+
it "should filter subscribers based on visibility" do
771+
@topic.subscribe(@student)
772+
@topic.subscribers.should_not include(@student)
773+
student_in_section(@section, user: @student)
774+
@topic.subscribers.should include(@student)
775+
end
776+
777+
it "filters observers if their student cant see" do
778+
@observer = user(:active_all => true, :name => "Observer")
779+
observer_enrollment = @course.enroll_user(@observer, 'ObserverEnrollment', :section => @section, :enrollment_state => 'active')
780+
observer_enrollment.update_attribute(:associated_user_id, @student.id)
781+
@topic.subscribe(@observer)
782+
@topic.subscribers.include?(@observer).should be_false
783+
student_in_section(@section, user: @student)
784+
@topic.subscribers.include?(@observer).should be_true
785+
end
786+
787+
it "doesnt filter for observers with no student" do
788+
@observer = user(:active_all => true)
789+
observer_enrollment = @course.enroll_user(@observer, 'ObserverEnrollment', :section => @section, :enrollment_state => 'active')
790+
@topic.subscribe(@observer)
791+
@topic.subscribers.should include(@observer)
792+
end
793+
794+
end
795+
context "disabled" do
796+
before{@course.disable_feature!(:differentiated_assignments)}
797+
it "should not filter subscribers based on visibility" do
798+
@topic.subscribe(@student)
799+
@topic.subscribers.should include(@student)
800+
end
801+
end
802+
end
741803
end
742804

743805
context "posters" do

spec/models/observer_enrollment_spec.rb

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,26 @@
1919
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
2020

2121
describe ObserverEnrollment do
22+
before do
23+
course(:active_all => 1)
24+
@student = user
25+
@observer = user
26+
@student_enrollment = @course.enroll_student(@student)
27+
@observer_enrollment = @course.enroll_user(@observer, 'ObserverEnrollment')
28+
@observer_enrollment.update_attribute(:associated_user_id, @student.id)
29+
end
2230
describe 'observed_students' do
2331
it "should not fail if the observed has been deleted" do
24-
course(:active_all => 1)
25-
@student = user
26-
@observer = user
27-
@student_enrollment = @course.enroll_student(@student)
28-
@observer_enrollment = @course.enroll_user(@observer, 'ObserverEnrollment')
29-
@observer_enrollment.update_attribute(:associated_user_id, @student.id)
3032
ObserverEnrollment.observed_students(@course, @observer).should == { @student => [@student_enrollment]}
3133
@student_enrollment.destroy
3234
ObserverEnrollment.observed_students(@course, @observer).should == {}
3335
end
3436
end
37+
describe 'observed_student_ids_by_observer_id' do
38+
it "should return a properly formatted hash" do
39+
@observer_two = user
40+
@observer_enrollment_two = @course.enroll_user(@observer_two, 'ObserverEnrollment')
41+
ObserverEnrollment.observed_student_ids_by_observer_id(@course, [@observer.id,@observer_two.id]).should == {@observer.id => [@student.id], @observer_two.id => []}
42+
end
43+
end
3544
end

0 commit comments

Comments
 (0)