fix more enrollment state mismatches

caused by sis user deletion and course state changes

also DRY up the enrollment recalculation a little

closes #CNVS-31060

Change-Id: Ife8b2a95223c423f2faec79f3f9d5af5377ce51e
Reviewed-on: https://gerrit.instructure.com/88307
Tested-by: Jenkins
Reviewed-by: Jeremy Stanley <jeremy@instructure.com>
Product-Review: James Williams  <jamesw@instructure.com>
QA-Review: James Williams  <jamesw@instructure.com>
This commit is contained in:
James Williams 2016-08-19 14:18:15 -06:00
parent 6c480f28f2
commit 0c64db0688
7 changed files with 53 additions and 7 deletions

View File

@ -846,14 +846,25 @@ class Course < ActiveRecord::Base
self.shard.activate do
if self.workflow_state_changed?
if self.completed?
Enrollment.where(:course_id => self, :workflow_state => ['active', 'invited']).update_all(:workflow_state => 'completed', :completed_at => Time.now.utc)
enrollment_ids = Enrollment.where(:course_id => self, :workflow_state => ['active', 'invited']).pluck(:id)
if enrollment_ids.any?
Enrollment.where(:id => enrollment_ids).update_all(:workflow_state => 'completed', :completed_at => Time.now.utc)
EnrollmentState.where(:enrollment_id => enrollment_ids).update_all(:state => 'completed', :state_is_current => true, :access_is_current => false)
EnrollmentState.send_later_if_production(:process_states_for_ids, enrollment_ids) # recalculate access
end
appointment_participants.active.current.update_all(:workflow_state => 'deleted')
appointment_groups.each(&:clear_cached_available_slots!)
elsif self.deleted?
enroll_scope = Enrollment.where("course_id=? AND workflow_state<>'deleted'", self)
user_ids = enroll_scope.group(:user_id).pluck(:user_id).uniq
if user_ids.any?
enroll_scope.update_all(:workflow_state => 'deleted')
enrollment_ids = enroll_scope.pluck(:id)
if enrollment_ids.any?
Enrollment.where(:id => enrollment_ids).update_all(:workflow_state => 'deleted')
EnrollmentState.where(:enrollment_id => enrollment_ids).update_all(:state => 'deleted', :state_is_current => true)
end
User.send_later_if_production(:update_account_associations, user_ids)
end
end

View File

@ -199,6 +199,13 @@ class EnrollmentState < ActiveRecord::Base
EnrollmentState.where(:enrollment_id => enrollment_scope, :state_is_current => true, :state => INVALIDATEABLE_STATES).update_all(:state_is_current => false, :state_invalidated_at => Time.now.utc)
end
def self.force_recalculation(enrollment_ids)
if enrollment_ids.any?
EnrollmentState.where(:enrollment_id => enrollment_ids, :state_is_current => true).update_all(:state_is_current => false)
EnrollmentState.send_later_if_production(:process_states_for_ids, enrollment_ids)
end
end
def self.invalidate_access(enrollment_scope, states_to_update)
EnrollmentState.where(:enrollment_id => enrollment_scope, :access_is_current => true, :state => states_to_update).update_all(:access_is_current => false, :access_invalidated_at => Time.now.utc)
end

View File

@ -9,8 +9,7 @@ class RecomputeMergedEnrollments < ActiveRecord::Migration
if merged_enrollment_ids.any?
Shard.partition_by_shard(merged_enrollment_ids) do |sliced_ids|
EnrollmentState.invalidate_states(Enrollment.where(:id => sliced_ids))
EnrollmentState.send_later_if_production(:process_states_for_ids, sliced_ids)
EnrollmentState.force_recalculation(sliced_ids)
end
end
end

View File

@ -0,0 +1,10 @@
class FixDeletedEnrollmentStates < ActiveRecord::Migration
tag :postdeploy
def up
DataFixup::FixDeletedEnrollmentStates.send_later_if_production(:run)
end
def down
end
end

View File

@ -0,0 +1,14 @@
module DataFixup
module FixDeletedEnrollmentStates
def self.run
Enrollment.find_ids_in_ranges(:batch_size => 20000) do |min_id, max_id|
# find deleted enrollments with states that haven't been properly synced
ids = Enrollment.where(:id => min_id..max_id).
where(:workflow_state => 'deleted').
joins(:enrollment_state).where("enrollment_states.state <> 'deleted'").pluck(:id)
EnrollmentState.force_recalculation(ids)
end
end
end
end

View File

@ -140,7 +140,13 @@ module SIS
if !status_is_active && !user.new_record?
# if this user is deleted, we're just going to make sure the user isn't enrolled in anything in this root account and
# delete the pseudonym.
d = @root_account.enrollments.active.where(user_id: user).update_all(workflow_state: 'deleted')
enrollment_ids = @root_account.enrollments.active.where(user_id: user).where.not(:workflow_state => 'deleted').pluck(:id)
if enrollment_ids.any?
Enrollment.where(:id => enrollment_ids).update_all(workflow_state: 'deleted')
EnrollmentState.where(:enrollment_id => enrollment_ids).update_all(:state => 'deleted', :state_is_current => true)
end
d = enrollment_ids.count
d += @root_account.all_group_memberships.active.where(user_id: user).update_all(workflow_state: 'deleted')
d += user.account_users.shard(@root_account).where(account_id: @root_account.all_accounts).delete_all
d += user.account_users.shard(@root_account).where(account_id: @root_account).delete_all

View File

@ -309,8 +309,7 @@ class UserMerge
enrollment_ids = Enrollment.where(id: scope).where.not(id: keeper).pluck(:id)
Enrollment.where(:id => enrollment_ids).update_all(workflow_state: keeper.workflow_state)
EnrollmentState.invalidate_states(Enrollment.where(:id => enrollment_ids))
EnrollmentState.send_later_if_production(:process_states_for_ids, enrollment_ids)
EnrollmentState.force_recalculation(enrollment_ids)
# mark the would be keeper from the from_user as deleted so it will not be moved later
keeper.destroy