Create alert for assignment_missing

Refs MBL-10482

Test Plan:
 - Create a super observer connected to a student
 - Student should be enrolled in a course
 - Create a threshold for `assignment_missing` for that student
   - POST /api/v1/users/observer_alert_thresholds
   - {
       student_id: :student_id,
       threshold: {
        alert_type: 'assignment_missing'
       }
     }
 - Create an assignment that is due in the course for a minute
   or two in the future
 - Wait at least 5 minutes
 - As the observer hit /api/v1/users/self/observer_alerts/:student_id
 - There should be an alert for that user

Change-Id: If2dea94052ff932c866a7382a2119a3287350c28
Reviewed-on: https://gerrit.instructure.com/152073
Reviewed-by: Cameron Sutter <csutter@instructure.com>
Product-Review: Cameron Sutter <csutter@instructure.com>
Tested-by: Jenkins
QA-Review: Taylor Wilson <twilson@instructure.com>
This commit is contained in:
Matt Sessions 2018-05-30 08:51:10 -06:00 committed by Taylor Wilson
parent 6f7dc1456c
commit 7286e89be7
3 changed files with 90 additions and 1 deletions

View File

@ -19,7 +19,7 @@ class ObserverAlert < ActiveRecord::Base
belongs_to :student, :class_name => 'User', inverse_of: :as_student_observer_alerts, :foreign_key => :user_id
belongs_to :observer, :class_name => 'User', inverse_of: :as_observer_observer_alerts
belongs_to :observer_alert_threshold, :inverse_of => :observer_alerts
belongs_to :context, polymorphic: [:discussion_topic, :assignment, :course, :account_notification]
belongs_to :context, polymorphic: [:discussion_topic, :assignment, :course, :account_notification, :submission]
ALERT_TYPES = %w(
assignment_missing
@ -53,4 +53,45 @@ class ObserverAlert < ActiveRecord::Base
def self.clean_up_old_alerts
ObserverAlert.where('created_at < ?', 6.months.ago).delete_all
end
def self.create_assignment_missing_alerts
submissions = Submission.active.
preload(user: :as_student_observer_alert_thresholds).
joins(:assignment).
joins("INNER JOIN #{ObserverAlertThreshold.quoted_table_name} observer_alert_thresholds ON observer_alert_thresholds.user_id = submissions.user_id AND observer_alert_thresholds.workflow_state <> 'deleted'").
joins("LEFT OUTER JOIN #{ObserverAlert.quoted_table_name} ON observer_alerts.context_id = submissions.id
AND observer_alerts.context_type = 'Submission'
AND observer_alerts.alert_type = 'assignment_missing'").
for_enrollments(Enrollment.all_active_or_pending).
missing.
merge(Assignment.submittable).
where('cached_due_date > ?', 1.day.ago).
where("observer_alerts.id IS NULL").
where("observer_alert_thresholds.alert_type = 'assignment_missing'")
alerts = []
submissions.find_each do |submission|
threshold = submission.user.as_student_observer_alert_thresholds.first
next unless threshold.users_are_still_linked?
now = Time.now.utc
alerts << { observer_id: threshold.observer.id,
user_id: threshold.student.id,
observer_alert_threshold_id: threshold.id,
alert_type: "assignment_missing",
context_type: 'Submission',
context_id: submission.id,
created_at: now,
updated_at: now,
action_date: now,
title: I18n.t('Assignment missing: %{assignment_name} in %{course_name}', {
assignment_name: submission.assignment.title,
course_name: submission.assignment.course.name
}) }
end
alerts.each_slice(1000) do |slice|
ObserverAlert.bulk_insert(slice)
end
end
end

View File

@ -216,6 +216,10 @@ Rails.configuration.after_initialize do
with_each_shard_by_database(ObserverAlert, :clean_up_old_alerts)
end
Delayed::Periodic.cron 'ObserverAlert.create_assignment_missing_alerts', '*/5 * * * *', priority: Delayed::LOW_PRIORITY do
with_each_shard_by_database(ObserverAlert, :create_missing_assignment_alerts)
end
Delayed::Periodic.cron 'abandoned job cleanup', '*/10 * * * *' do
Delayed::Worker::HealthCheck.reschedule_abandoned_jobs
end

View File

@ -155,6 +155,50 @@ describe ObserverAlert do
end
end
describe 'create_assignment_missing_alerts' do
before :once do
@course = course_factory()
@student1 = student_in_course(active_all: true, course: @course).user
@observer1 = course_with_observer(course: @course, associated_user_id: @student.id, active_all: true).user
observer_alert_threshold_model(student: @student, observer: @observer, alert_type: 'assignment_missing')
@student2 = student_in_course(active_all: true, course: @course).user
@observer2 = course_with_observer(course: @course, associated_user_id: @student2.id, active_all: true).user
@link2 = UserObservationLink.create!(student: @student2, observer: @observer2, root_account: @account)
assignment_model(context: @course, due_at: 5.minutes.ago, submission_types: 'online_text_entry')
@student3 = student_in_course(active_all: true, course: @course).user
@observer3 = course_with_observer(course: @course, associated_user_id: @student3.id, active_all: true).user
observer_alert_threshold_model(student: @student3, observer: @observer3, alert_type: 'assignment_missing')
@assignment.submit_homework(@student3, :submission_type => 'online_text_entry', :body => 'done')
ObserverAlert.create_assignment_missing_alerts
end
it 'creates an assignment_missing_alert' do
alert = ObserverAlert.active.where(student: @student1, alert_type: 'assignment_missing').first
expect(alert.alert_type).to eq 'assignment_missing'
expect(alert.context.user).to eq @student1
end
it 'doesnt create another alert if one already exists' do
alert = ObserverAlert.active.where(student: @student2, alert_type: 'assignment_missing').first
expect(alert).to be_nil
end
it 'doesnt create an alert if the submission is not missing' do
alert = ObserverAlert.where(student: @student3, alert_type: 'assignment_missing').first
expect(alert).to be_nil
end
it 'doesnt create an alert for if there is no threshold' do
ObserverAlert.create_assignment_missing_alerts
alert = ObserverAlert.where(student: @student2).first
expect(alert).to be_nil
end
end
describe 'institution_announcement' do
before :once do
@no_link_account = account_model