squash old migrations 202001-202002

Change-Id: I17c208f94ba440976c0265f782b1cd57448a109f
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/342169
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
Reviewed-by: Jacob Burroughs <jburroughs@instructure.com>
Migration-Review: Jacob Burroughs <jburroughs@instructure.com>
QA-Review: Cody Cutrer <cody@instructure.com>
Product-Review: Cody Cutrer <cody@instructure.com>
This commit is contained in:
Cody Cutrer 2024-03-05 15:34:20 -07:00
parent 1324efe12c
commit 5c6a4f9e04
20 changed files with 64 additions and 593 deletions

View File

@ -1230,7 +1230,6 @@ class GradebooksController < ApplicationController
def change_gradebook_column_size
if authorized_action(@context, @current_user, [:manage_grades, :view_all_grades])
@current_user.migrate_preferences_if_needed
sub_key = @current_user.shared_gradebook_column?(params[:column_id]) ? "shared" : @context.global_id
size_hash = @current_user.get_preference(:gradebook_column_size, sub_key) || {}
size_hash[params[:column_id]] = params[:column_size]
@ -1409,7 +1408,6 @@ class GradebooksController < ApplicationController
def change_gradebook_version
update_preferred_gradebook_view!("gradebook")
@current_user.migrate_preferences_if_needed
@current_user.set_preference(:gradebook_version, params[:version])
redirect_to polymorphic_url([@context, :gradebook])
end
@ -1712,7 +1710,6 @@ class GradebooksController < ApplicationController
end
def gradebook_column_size_preferences
@current_user.migrate_preferences_if_needed
@current_user.save if @current_user.changed?
shared_settings = @current_user.get_preference(:gradebook_column_size, "shared") || {}
course_settings = @current_user.get_preference(:gradebook_column_size, @context.global_id) || {}

View File

@ -69,34 +69,6 @@ class UserPreferenceValue < ActiveRecord::Base
end
module UserMethods
# i could just stuff all this in user.rb directly but it's so full already
def needs_preference_migration?
preferences.any? do |key, value|
UserPreferenceValue.settings[key] && value.present? && value != EXTERNAL
end
end
# can remove these when all preferences have been migrated
def migrate_preferences_if_needed
return unless needs_preference_migration?
reorganize_gradebook_preferences # may as well while we're at it
UserPreferenceValue.settings.each do |key, settings|
value = preferences[key]
next unless value.present?
next if value == EXTERNAL
if settings[:use_sub_keys]
value.each do |sub_key, sub_value|
create_user_preference_value(key, sub_key, sub_value)
end
else
create_user_preference_value(key, nil, value)
end
preferences[key] = EXTERNAL
end
end
def get_preference(key, sub_key = nil)
value = preferences[key]
if value == EXTERNAL
@ -122,9 +94,6 @@ class UserPreferenceValue < ActiveRecord::Base
end
raise "invalid key `#{key}`" unless UserPreferenceValue.settings[key]
# don't bother trying to merge things in - just move everything over
migrate_preferences_if_needed
if value.present? || sub_key
if value.nil?
remove_user_preference_value(key, sub_key)

View File

@ -30,7 +30,7 @@ class ValidateMigrationIntegrity < ActiveRecord::Migration[4.2]
def self.up
initial_migration_version = "20101210192618"
last_squashed_migration_version = "20191031154616"
last_squashed_migration_version = "20200227143541"
versions = if $canvas_rails == "7.1"
ActiveRecord::SchemaMigration.new(ActiveRecord::Base.connection).versions

View File

@ -682,6 +682,11 @@ class InitCanvasDb < ActiveRecord::Migration[4.2]
add_index :attachments,
%i[md5 namespace content_type],
where: "root_attachment_id IS NULL and filename IS NOT NULL"
add_index :attachments,
%i[context_id context_type migration_id],
opclass: { migration_id: :text_pattern_ops },
where: "migration_id IS NOT NULL",
name: "index_attachments_on_context_and_migration_id_pattern_ops"
create_table "calendar_events", force: true do |t|
t.string "title", limit: 255
@ -870,6 +875,7 @@ class InitCanvasDb < ActiveRecord::Migration[4.2]
add_index :content_exports, :attachment_id
add_index :content_exports, :content_migration_id
add_index :content_exports, :user_id, where: "user_id IS NOT NULL"
add_index :content_exports, [:context_id, :context_type]
create_table "content_migrations", force: true do |t|
t.integer "context_id", limit: 8, null: false
@ -961,6 +967,7 @@ class InitCanvasDb < ActiveRecord::Migration[4.2]
t.integer "associated_asset_id", limit: 8
t.string "associated_asset_type", limit: 255
t.boolean "new_tab"
t.jsonb :link_settings
end
add_index "content_tags", ["content_id", "content_type"], name: "index_content_tags_on_content_id_and_content_type"
@ -1383,6 +1390,7 @@ class InitCanvasDb < ActiveRecord::Migration[4.2]
t.text :oidc_initiation_url
t.string :public_jwk_url
t.boolean :is_lti_key, default: false, null: false
t.boolean :allow_includes, default: false, null: false
end
add_index :developer_keys, :vendor_code
@ -2077,6 +2085,7 @@ class InitCanvasDb < ActiveRecord::Migration[4.2]
t.datetime "submitted_at"
t.boolean :hide_points, default: false, null: false
t.boolean :hidden, default: false, null: false
t.string :user_uuid, limit: 255
end
add_index :learning_outcome_results,
@ -2328,6 +2337,10 @@ class InitCanvasDb < ActiveRecord::Migration[4.2]
name: "index_child_content_tags_on_content"
add_index :master_courses_child_content_tags, :child_subscription_id, name: "index_child_content_tags_on_subscription"
add_index :master_courses_child_content_tags, :migration_id, name: "index_child_content_tags_on_migration_id"
add_index :master_courses_child_content_tags,
[:child_subscription_id, :migration_id],
opclass: { migration_id: :text_pattern_ops },
name: "index_mc_child_content_tags_on_sub_and_migration_id_pattern_ops"
create_table :master_courses_child_subscriptions do |t|
t.integer :master_template_id, limit: 8, null: false
@ -2586,6 +2599,33 @@ class InitCanvasDb < ActiveRecord::Migration[4.2]
add_index :notification_endpoints, :access_token_id
add_index :notification_endpoints, :workflow_state
create_table :notification_policy_overrides do |t|
t.belongs_to :context,
polymorphic: { default: "Course" },
null: false,
index: { name: "index_notification_policy_overrides_on_context" },
limit: 8
t.belongs_to :communication_channel, null: false, foreign_key: true, limit: 8, index: true
t.integer :notification_id, limit: 8
t.string :workflow_state, default: "active", null: false, index: true
t.string :frequency
t.timestamps null: false
end
add_index :notification_policy_overrides, :notification_id
add_index :notification_policy_overrides,
%i[communication_channel_id notification_id],
name: "index_notification_policies_overrides_on_cc_id_and_notification"
add_index :notification_policy_overrides,
%i[context_id context_type communication_channel_id notification_id],
where: "notification_id IS NOT NULL",
unique: true,
name: "index_notification_policies_overrides_uniq_context_notification"
add_index :notification_policy_overrides,
%i[context_id context_type communication_channel_id],
where: "notification_id IS NULL",
unique: true,
name: "index_notification_policies_overrides_uniq_context_and_cc"
create_table "notification_policies", force: true do |t|
t.integer "notification_id", limit: 8
t.integer "communication_channel_id", limit: 8, null: false
@ -3584,6 +3624,7 @@ class InitCanvasDb < ActiveRecord::Migration[4.2]
t.integer :extra_attempts
t.datetime :posted_at
t.boolean :cached_quiz_lti, default: false, null: false
t.string :cached_tardiness, limit: 16
end
add_index "submissions", ["assignment_id", "submission_type"], name: "index_submissions_on_assignment_id_and_submission_type"
@ -3628,6 +3669,10 @@ class InitCanvasDb < ActiveRecord::Migration[4.2]
:user_id,
where: "(score IS NOT NULL AND workflow_state = 'graded') OR excused = TRUE",
name: "index_submissions_graded_or_excused_on_user_id"
add_index :submissions,
:assignment_id,
where: "workflow_state <> 'deleted' AND ((score IS NOT NULL AND workflow_state = 'graded') OR excused = TRUE)",
name: "index_submissions_graded_or_excused_on_assignment_id"
# rubocop:disable Rails/SquishedSQLHeredocs
execute(<<~SQL)
@ -3826,6 +3871,14 @@ class InitCanvasDb < ActiveRecord::Migration[4.2]
add_index :user_past_lti_ids, :user_id
add_index :user_past_lti_ids, :user_uuid
create_table :user_preference_values do |t|
t.integer :user_id, limit: 8, null: false
t.string :key, null: false
t.string :sub_key
t.text :value
end
add_index :user_preference_values, %i[user_id key sub_key], unique: true, name: "index_user_preference_values_on_keys"
create_table "user_services", force: true do |t|
t.integer "user_id", limit: 8, null: false
t.text "token"
@ -4440,6 +4493,7 @@ class InitCanvasDb < ActiveRecord::Migration[4.2]
add_foreign_key :moderation_graders, :users
add_foreign_key :notification_endpoints, :access_tokens
add_foreign_key :notification_policies, :communication_channels
add_foreign_key :notification_policy_overrides, :notifications
add_foreign_key :oauth_requests, :users
add_foreign_key :observer_alert_thresholds, :users
add_foreign_key :observer_alert_thresholds, :users, column: :observer_id
@ -4536,6 +4590,7 @@ class InitCanvasDb < ActiveRecord::Migration[4.2]
add_foreign_key :user_observers, :users
add_foreign_key :user_observers, :users, column: :observer_id
add_foreign_key :user_past_lti_ids, :users
add_foreign_key :user_preference_values, :users
add_foreign_key :user_profile_links, :user_profiles
add_foreign_key :user_profiles, :users
add_foreign_key :user_services, :users

View File

@ -1,29 +0,0 @@
# frozen_string_literal: true
#
# Copyright (C) 2019 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
class AddAllowIncludeParamsToDeveloperKey < ActiveRecord::Migration[5.2]
tag :predeploy
def change
add_column :developer_keys, :allow_includes, :boolean
change_column_default(:developer_keys, :allow_includes, false)
DataFixup::BackfillNulls.run(DeveloperKey, :allow_includes, default_value: false)
change_column_null(:developer_keys, :allow_includes, false)
end
end

View File

@ -1,26 +0,0 @@
# frozen_string_literal: true
#
# Copyright (C) 2020 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
class AddContextIndexToContentExports < ActiveRecord::Migration[5.2]
tag :postdeploy
disable_ddl_transaction!
def change
add_index :content_exports, [:context_id, :context_type], algorithm: :concurrently
end
end

View File

@ -1,29 +0,0 @@
# frozen_string_literal: true
#
# Copyright (C) 2020 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
class GranularWikiPagePermissions < ActiveRecord::Migration[5.2]
tag :postdeploy
def up
# Since the old permission has been removed, skip_validation to support users with slower deploy cycles
DataFixup::AddRoleOverridesForNewPermission.run(:manage_wiki, :manage_wiki_create, skip_validation: true)
DataFixup::AddRoleOverridesForNewPermission.run(:manage_wiki, :manage_wiki_delete, skip_validation: true)
DataFixup::AddRoleOverridesForNewPermission.run(:manage_wiki, :manage_wiki_update, skip_validation: true)
end
end

View File

@ -1,51 +0,0 @@
# frozen_string_literal: true
#
# Copyright (C) 2020 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
class CreateNotificationPolicyOverrides < ActiveRecord::Migration[5.2]
tag :predeploy
def change
create_table :notification_policy_overrides do |t|
t.belongs_to :context,
polymorphic: { default: "Course" },
null: false,
index: { name: "index_notification_policy_overrides_on_context" }
t.belongs_to :communication_channel, null: false, foreign_key: true
t.belongs_to :notification, index: true
t.string :workflow_state, default: "active", null: false, index: true
t.string :frequency
t.timestamps
end
add_index :notification_policy_overrides,
%i[communication_channel_id notification_id],
name: "index_notification_policies_overrides_on_cc_id_and_notification"
add_index :notification_policy_overrides,
%i[context_id context_type communication_channel_id notification_id],
where: "notification_id IS NOT NULL",
unique: true,
name: "index_notification_policies_overrides_uniq_context_notification"
add_index :notification_policy_overrides,
%i[context_id context_type communication_channel_id],
where: "notification_id IS NULL",
unique: true,
name: "index_notification_policies_overrides_uniq_context_and_cc"
end
end

View File

@ -1,20 +0,0 @@
# frozen_string_literal: true
class AddBlueprintDeletionIndexes < ActiveRecord::Migration[5.2]
tag :postdeploy
disable_ddl_transaction!
def change
add_index :attachments,
%i[context_id context_type migration_id],
opclass: { migration_id: :text_pattern_ops },
where: "migration_id IS NOT NULL",
algorithm: :concurrently,
name: "index_attachments_on_context_and_migration_id_pattern_ops"
add_index :master_courses_child_content_tags,
[:child_subscription_id, :migration_id],
opclass: { migration_id: :text_pattern_ops },
algorithm: :concurrently,
name: "index_mc_child_content_tags_on_sub_and_migration_id_pattern_ops"
end
end

View File

@ -1,25 +0,0 @@
# frozen_string_literal: true
#
# Copyright (C) 2020 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
class AddLinkSettingsToContentTag < ActiveRecord::Migration[5.2]
tag :predeploy
def change
add_column :content_tags, :link_settings, :jsonb
end
end

View File

@ -1,38 +0,0 @@
# frozen_string_literal: true
#
# Copyright (C) 2020 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
class CreateUserPreferenceValues < ActiveRecord::Migration[5.2]
tag :predeploy
def up
create_table :user_preference_values do |t|
t.integer :user_id, limit: 8, null: false
t.string :key, null: false
t.string :sub_key
t.text :value
end
add_foreign_key :user_preference_values, :users
add_index :user_preference_values, %i[user_id key sub_key], unique: true, name: "index_user_preference_values_on_keys"
end
def down
drop_table :user_preference_values
end
end

View File

@ -1,25 +0,0 @@
# frozen_string_literal: true
#
# Copyright (C) 2020 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
class AddUserUuidToLearningOutcomeResults < ActiveRecord::Migration[5.2]
tag :predeploy
def change
add_column :learning_outcome_results, :user_uuid, :string, limit: 255
end
end

View File

@ -1,18 +0,0 @@
# frozen_string_literal: true
class SplitUpUserPreferences < ActiveRecord::Migration[5.2]
tag :postdeploy
disable_ddl_transaction!
def up
User.find_ids_in_ranges(batch_size: 20_000) do |min_id, max_id|
DataFixup::SplitUpUserPreferences
.delay_if_production(priority: Delayed::LOW_PRIORITY, n_strand: ["user_preference_migration", Shard.current.database_server.id])
.run(min_id, max_id)
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@ -1,26 +0,0 @@
# frozen_string_literal: true
#
# Copyright (C) 2020 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
class AddCachedTardinessToSubmissions < ActiveRecord::Migration[5.2]
tag :predeploy
def change
add_column :submissions, :cached_tardiness, :string, limit: 16
end
end

View File

@ -1,31 +0,0 @@
# frozen_string_literal: true
#
# Copyright (C) 2020 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
class AddGradedOrExcusedIndexToSubmissions < ActiveRecord::Migration[5.2]
tag :postdeploy
disable_ddl_transaction!
def change
add_index :submissions,
:assignment_id,
algorithm: :concurrently,
where: "workflow_state <> 'deleted' AND ((score IS NOT NULL AND workflow_state = 'graded') OR excused = TRUE)",
name: "index_submissions_graded_or_excused_on_assignment_id"
end
end

View File

@ -1,31 +0,0 @@
# frozen_string_literal: true
#
# Copyright (C) 2020 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
module DataFixup::SplitUpUserPreferences
def self.run(start_at, end_at)
User.find_ids_in_ranges(start_at:, end_at:) do |min_id, max_id|
User.where(id: min_id..max_id).where("id < ? AND preferences IS NOT NULL", Shard::IDS_PER_SHARD).each do |u|
if u.needs_preference_migration?
u.migrate_preferences_if_needed
User.where(id: u).update_all(preferences: u.preferences, updated_at: Time.now.utc)
end
end
end
end
end

View File

@ -69,12 +69,8 @@ class UserMerge
merge_data.items.create!(user: from_user, item_type: "user_preferences", item: from_user.preferences)
merge_data.items.create!(user: target_user, item_type: "user_preferences", item: target_user.preferences)
if from_user.needs_preference_migration?
prefs = shard_aware_preferences
else
copy_migrated_preferences # uses new rows to store preferences
prefs = from_user.preferences
end
copy_migrated_preferences # uses new rows to store preferences
prefs = from_user.preferences
target_user.preferences = target_user.preferences.merge(prefs)
target_user.save if target_user.changed?
@ -225,25 +221,7 @@ class UserMerge
key.is_a?(String) ? [key.split("_").first, new_id].join("_") : new_id
end
# can remove when all preferences have been migrated
def shard_aware_preferences
return from_user.preferences if from_user.shard == target_user.shard
preferences = from_user.preferences.dup
%i[custom_colors course_nicknames].each do |pref|
preferences.delete(pref)
new_pref = {}
from_user.preferences[pref]&.each do |key, value|
new_key = translate_course_id_or_asset_string(key)
new_pref[new_key] = value
end
preferences[pref] = new_pref unless new_pref.empty?
end
preferences
end
def copy_migrated_preferences
target_user.migrate_preferences_if_needed # may as well
from_values = from_user.user_preference_values.to_a
target_values = target_user.user_preference_values.to_a.index_by { |r| [r.key, r.sub_key] }
@ -255,7 +233,6 @@ class UserMerge
sub_key = from_record.sub_key
value = from_record.value
if from_user.shard != target_user.shard
# tl;dr do the same thing as shard_aware_preferences
case key
when "custom_colors"
value = value.transform_keys { |id| translate_course_id_or_asset_string(id) }

View File

@ -963,22 +963,7 @@ describe UserMerge do
end
end
it "moves prefs over with old format" do
@shard1.activate do
@user2 = user_model
account = Account.create!
@shard_course = course_factory(account:)
@user2.preferences[:custom_colors] = { "course_#{@course.id}" => "#254284" }
end
course = course_factory
user1 = user_model
@user2.preferences[:custom_colors]["course_#{course.global_id}"] = "#346543"
@user2.save!
UserMerge.from(@user2).into(user1)
expect(user1.reload.preferences[:custom_colors].keys).to eq ["course_#{@shard_course.global_id}", "course_#{course.id}"]
end
it "moves prefs over with new format" do
it "moves prefs over" do
@shard1.activate do
@user2 = user_model
account = Account.create!
@ -994,22 +979,7 @@ describe UserMerge do
)
end
it "moves nicknames with old format" do
@shard1.activate do
@user2 = user_model
account = Account.create!
@shard_course = course_factory(account:)
@user2.preferences[:course_nicknames] = { @shard_course.id => "Marketing" }
end
course = course_factory
user1 = user_model
@user2.preferences[:course_nicknames][course.global_id] = "Math"
@user2.save!
UserMerge.from(@user2).into(user1)
expect(user1.reload.preferences[:course_nicknames].keys).to eq [@shard_course.global_id, course.id]
end
it "moves nicknames with new format" do
it "moves nicknames" do
@shard1.activate do
@user2 = user_model
account = Account.create!

View File

@ -1,45 +0,0 @@
# frozen_string_literal: true
#
# Copyright (C) 2020 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
require_relative "../spec_helper"
describe DataFixup::SplitUpUserPreferences do
it "works" do
u = User.create!
original_prefs = { selected_calendar_contexts: ["course_1000"], course_nicknames: { 2 => "Why am i taking this course" }, some_other_thing: true }
User.where(id: u).update_all(preferences: original_prefs)
DataFixup::SplitUpUserPreferences.run(nil, nil)
u.reload
expect(u.reload.needs_preference_migration?).to be false
rows = u.user_preference_values.to_a.index_by { |v| [v.key, v.sub_key] }
expect(rows.count).to eq 2
expect(rows[["selected_calendar_contexts", nil]].value).to eq ["course_1000"]
expect(rows[["course_nicknames", 2]].value).to eq "Why am i taking this course"
expect(u.preferences).to eq(
{
selected_calendar_contexts: UserPreferenceValue::EXTERNAL,
course_nicknames: UserPreferenceValue::EXTERNAL,
some_other_thing: true
}
)
expect(u.get_preference(:selected_calendar_contexts)).to eq ["course_1000"]
expect(u.get_preference(:course_nicknames, 2)).to eq "Why am i taking this course"
end
end

View File

@ -22,18 +22,11 @@ describe UserPreferenceValue do
let(:regular_key) { :custom_colors }
let(:subbed_key) { :course_nicknames }
let(:sample_preferences) do
{ regular_key => [:arbitrary_data], subbed_key => { a: 1, b: [:other_stuff] } }
end
let(:preexisting_user) do
User.create!(preferences: sample_preferences)
end
let(:migrated_user) do
u = User.create!(preferences: sample_preferences)
u.migrate_preferences_if_needed
u.save!
u = User.create!
u.set_preference(regular_key, [:arbitrary_data])
u.set_preference(subbed_key, :a, 1)
u.set_preference(subbed_key, :b, [:other_stuff])
u
end
@ -59,30 +52,6 @@ describe UserPreferenceValue do
expect(migrated_user.get_preference(subbed_key, :a)).to eq "more new data"
end
it "uses the existing data if the user's preferences hasn't been migrated yet" do
expect(preexisting_user.preferences[regular_key]).to eq sample_preferences[regular_key]
expect(preexisting_user.preferences[subbed_key]).to eq sample_preferences[subbed_key]
end
it "does not migrate all existing preferences automatically on save unless to a migrated preference" do
expect(preexisting_user.needs_preference_migration?).to be true
preexisting_user.save!
expect(preexisting_user.reload.needs_preference_migration?).to be true
preexisting_user.set_preference(regular_key, "new_value")
expect(preexisting_user.reload.needs_preference_migration?).to be false
rows = preexisting_user.user_preference_values.to_a.index_by { |v| [v.key, v.sub_key] }
expect(rows.count).to eq 3
expect(rows[[regular_key.to_s, nil]].value).to eq "new_value"
expect(rows[[subbed_key.to_s, "a"]].value).to eq sample_preferences[subbed_key][:a]
expect(rows[[subbed_key.to_s, "b"]].value).to eq sample_preferences[subbed_key][:b]
expect(preexisting_user.preferences).to eq(
{ regular_key => UserPreferenceValue::EXTERNAL, subbed_key => UserPreferenceValue::EXTERNAL }
)
end
it "does not query for preferences when saving an unrelated attribute on an already migrated user" do
expect(migrated_user).to_not receive(:user_preference_values)
migrated_user.update_attribute(:name, "name1")
@ -115,76 +84,4 @@ describe UserPreferenceValue do
expect(migrated_user.user_preference_values.where(key: subbed_key).pluck(:sub_key)).to eq(["a"])
expect(migrated_user.preferences[subbed_key]).to eq(UserPreferenceValue::EXTERNAL)
end
context "gradebook_column_size" do
specs_require_sharding
let(:course1) { Course.create! }
let(:course2) { Course.create! }
let(:assignment1) { course1.assignments.create! }
let(:assignment2) { course2.assignments.create! }
let(:assignment_group1) { course1.assignment_groups.create! }
let(:assignment_group2) { course2.assignment_groups.create! }
let(:column1) { course1.custom_gradebook_columns.create!(title: "1") }
let(:column2) { course2.custom_gradebook_columns.create!(title: "2") }
let(:old_format) do
{
"student" => "100",
"assignment_#{assignment1.id}" => "10",
"assignment_#{assignment2.id}" => "20",
"assignment_group_#{assignment_group1.id}" => "30",
"assignment_group_#{assignment_group2.id}" => "40",
"custom_col_#{column1.id}" => "50",
"custom_col_#{column2.id}" => "60"
}
end
it "splits the old gradebook column size preference by course" do
u = User.create!
User.where(id: u).update_all(preferences: { gradebook_column_size: old_format })
u.reload
u.migrate_preferences_if_needed
u.save!
expect(u.get_preference(:gradebook_column_size, "shared")).to eq old_format.slice("student")
expect(u.get_preference(:gradebook_column_size, course1.global_id)).to eq old_format.slice(
"assignment_#{assignment1.id}", "assignment_group_#{assignment_group1.id}", "custom_col_#{column1.id}"
)
expect(u.get_preference(:gradebook_column_size, course2.global_id)).to eq old_format.slice(
"assignment_#{assignment2.id}", "assignment_group_#{assignment_group2.id}", "custom_col_#{column2.id}"
)
end
it "does not attempt to re-migrate when a new non-migrated preference value appears" do
u = User.create!
User.where(id: u).update_all(preferences: { closed_notifications: [], gradebook_column_size: old_format })
u.reload
u.migrate_preferences_if_needed
u.save!
u.preferences[:closed_notifications] << 123
expect(u.needs_preference_migration?).to be true
expect { u.migrate_preferences_if_needed }.not_to raise_error
expect(u.user_preference_values.where(key: "closed_notifications").take.value).to eq [123]
end
it "works even if the objects are from a different shard than the user" do
old_format # instantiate on default shard
@shard1.activate do
u = User.create!
u.associate_with_shard(Shard.default)
User.where(id: u).update_all(preferences: { gradebook_column_size: old_format })
u.reload
u.migrate_preferences_if_needed
u.save!
expect(u.get_preference(:gradebook_column_size, "shared")).to eq old_format.slice("student")
# save the subkey as a global but the columns with local ids since we'll only ever access them from their own shard
expect(u.get_preference(:gradebook_column_size, course1.global_id)).to eq old_format.slice(
"assignment_#{assignment1.local_id}", "assignment_group_#{assignment_group1.local_id}", "custom_col_#{column1.local_id}"
)
expect(u.get_preference(:gradebook_column_size, course2.global_id)).to eq old_format.slice(
"assignment_#{assignment2.local_id}", "assignment_group_#{assignment_group2.local_id}", "custom_col_#{column2.local_id}"
)
end
end
end
end