diff --git a/bin/oneoff/backfill_data/studio_people b/bin/oneoff/backfill_data/studio_people index 448d6eb0c0230..7a8532382f868 100755 --- a/bin/oneoff/backfill_data/studio_people +++ b/bin/oneoff/backfill_data/studio_people @@ -1,31 +1,78 @@ #!/usr/bin/env ruby -# This script creates a StudioPerson (if one does not already exist) for every teacher. +# This script creates a StudioPerson (if one does not already exist) for every teacher. It can be +# run with or without a CSV file. If there is no file, the script iterates over all users, creating +# StudioPerson's as necessary. If there is a file, the script creates StudioPersons for the users +# specified in the file. +# +# The CSV for production was created by the following SQL query. +# +# SELECT id +# FROM users +# WHERE user_type = "teacher" AND studio_person_id IS NULL; +# +# USAGE: ./bin/oneoff/backfill_data/studio_people +# ./bin/oneoff/backfill_data/studio_people studio_people_data.csv +require 'csv' require_relative '../../../dashboard/config/environment' # The user_id variable is used to track the in-progress user in case of an exception. user_id = 0 begin - # Unfortunately, this query will not be peformant as the result of no index existing on - # users.user_type. As we are batching (via find_each), this should not impact live site traffic. - # And since we are willing to allow this script to run for hours, we are fine with this. - User. - with_deleted. - where(studio_person_id: nil). - where(user_type: User::TYPE_TEACHER). - find_each do |user| - user_id = user.id + # Depending on whether a filename is specified (via ARGV[0]), we iterate over all users or over + # the filename, creating StudioPerson's as necessary. + if ARGV[0].nil? + # Unfortunately, this query will not be peformant as the result of no index existing on + # users.user_type. As we are batching (via find_each), this should not impact users of the site. + # It may take a long time for the DB updates to occur, though. + User. + with_deleted. + where(studio_person_id: nil). + where(user_type: User::TYPE_TEACHER). + find_each do |user| + user_id = user.id - puts "PROCESSING ID: #{user_id}..." unless user_id % 10_000 + puts "PROCESSING ID: #{user_id}..." unless user_id % 10_000 - user.update!( - studio_person: ( - user.email ? StudioPerson.create!(emails: user.email) : StudioPerson.create! + user.update!( + studio_person: ( + user.email ? StudioPerson.create!(emails: user.email) : StudioPerson.create! + ) ) - ) + end + else + filename = ARGV[0] + + CSV.foreach(filename, headers: true) do |row| + puts "ROW: #{row}" + user_id = row['id'] + + puts "PROCESSING ID: #{user_id}..." unless user_id % 10_000 + + user = User.with_deleted.find_by_id(user_id) + + # This shouldn't happen... But just in case. + unless user + puts "MISSING USER: #{user_id}" + next + end + # This may happen if a user is saved (with callbacks) between when the CSV was generated and + # the script was run. + if user.studio_person_id + puts "UNNECESSARY USER: #{user_id}" + next + end + # This may happen if a user changes between when the CSV was generated and the script was run. + if user.user_type == 'student' + puts "STUDENT USER: #{user_id}" + next + end + + user.update!(studio_person: StudioPerson.create!(emails: user.email)) end + end rescue Exception => e puts "EXCEPTION (ID: #{user_id}): #{e.message}" raise e