Remove leftover database columns from Devise::Models::Rememberable (#17191)
* Remove leftover database columns from Devise::Models::Rememberable * Update fix-duplication maintenance script * Improve errors/warnings in the fix-duplicates maintenance script
This commit is contained in:
parent
96f0b33c8b
commit
8a07ecd377
5 changed files with 51 additions and 21 deletions
|
@ -10,7 +10,6 @@
|
||||||
# encrypted_password :string default(""), not null
|
# encrypted_password :string default(""), not null
|
||||||
# reset_password_token :string
|
# reset_password_token :string
|
||||||
# reset_password_sent_at :datetime
|
# reset_password_sent_at :datetime
|
||||||
# remember_created_at :datetime
|
|
||||||
# sign_in_count :integer default(0), not null
|
# sign_in_count :integer default(0), not null
|
||||||
# current_sign_in_at :datetime
|
# current_sign_in_at :datetime
|
||||||
# last_sign_in_at :datetime
|
# last_sign_in_at :datetime
|
||||||
|
@ -32,7 +31,6 @@
|
||||||
# disabled :boolean default(FALSE), not null
|
# disabled :boolean default(FALSE), not null
|
||||||
# moderator :boolean default(FALSE), not null
|
# moderator :boolean default(FALSE), not null
|
||||||
# invite_id :bigint(8)
|
# invite_id :bigint(8)
|
||||||
# remember_token :string
|
|
||||||
# chosen_languages :string is an Array
|
# chosen_languages :string is an Array
|
||||||
# created_by_application_id :bigint(8)
|
# created_by_application_id :bigint(8)
|
||||||
# approved :boolean default(TRUE), not null
|
# approved :boolean default(TRUE), not null
|
||||||
|
@ -44,6 +42,11 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
class User < ApplicationRecord
|
class User < ApplicationRecord
|
||||||
|
self.ignored_columns = %w(
|
||||||
|
remember_created_at
|
||||||
|
remember_token
|
||||||
|
)
|
||||||
|
|
||||||
include Settings::Extend
|
include Settings::Extend
|
||||||
include UserRoles
|
include UserRoles
|
||||||
|
|
||||||
|
@ -329,10 +332,9 @@ class User < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def reset_password!
|
def reset_password!
|
||||||
# First, change password to something random, invalidate the remember-me token,
|
# First, change password to something random and deactivate all sessions
|
||||||
# and deactivate all sessions
|
|
||||||
transaction do
|
transaction do
|
||||||
update(remember_token: nil, remember_created_at: nil, password: SecureRandom.hex)
|
update(password: SecureRandom.hex)
|
||||||
session_activations.destroy_all
|
session_activations.destroy_all
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class RemoveIndexUsersOnRememberToken < ActiveRecord::Migration[6.1]
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def up
|
||||||
|
remove_index :users, name: :index_users_on_remember_token
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
add_index :users, :remember_token, algorithm: :concurrently, unique: true, name: :index_users_on_remember_token
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,8 @@
|
||||||
|
class RemoveRememberableFromUsers < ActiveRecord::Migration[6.1]
|
||||||
|
def change
|
||||||
|
safety_assured do
|
||||||
|
remove_column :users, :remember_token, :string, null: true, default: nil
|
||||||
|
remove_column :users, :remember_created_at, :datetime, null: true, default: nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2022_01_16_202951) do
|
ActiveRecord::Schema.define(version: 2022_01_18_183123) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -937,7 +937,6 @@ ActiveRecord::Schema.define(version: 2022_01_16_202951) do
|
||||||
t.string "encrypted_password", default: "", null: false
|
t.string "encrypted_password", default: "", null: false
|
||||||
t.string "reset_password_token"
|
t.string "reset_password_token"
|
||||||
t.datetime "reset_password_sent_at"
|
t.datetime "reset_password_sent_at"
|
||||||
t.datetime "remember_created_at"
|
|
||||||
t.integer "sign_in_count", default: 0, null: false
|
t.integer "sign_in_count", default: 0, null: false
|
||||||
t.datetime "current_sign_in_at"
|
t.datetime "current_sign_in_at"
|
||||||
t.datetime "last_sign_in_at"
|
t.datetime "last_sign_in_at"
|
||||||
|
@ -959,7 +958,6 @@ ActiveRecord::Schema.define(version: 2022_01_16_202951) do
|
||||||
t.boolean "disabled", default: false, null: false
|
t.boolean "disabled", default: false, null: false
|
||||||
t.boolean "moderator", default: false, null: false
|
t.boolean "moderator", default: false, null: false
|
||||||
t.bigint "invite_id"
|
t.bigint "invite_id"
|
||||||
t.string "remember_token"
|
|
||||||
t.string "chosen_languages", array: true
|
t.string "chosen_languages", array: true
|
||||||
t.bigint "created_by_application_id"
|
t.bigint "created_by_application_id"
|
||||||
t.boolean "approved", default: true, null: false
|
t.boolean "approved", default: true, null: false
|
||||||
|
@ -972,7 +970,6 @@ ActiveRecord::Schema.define(version: 2022_01_16_202951) do
|
||||||
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
|
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
|
||||||
t.index ["created_by_application_id"], name: "index_users_on_created_by_application_id"
|
t.index ["created_by_application_id"], name: "index_users_on_created_by_application_id"
|
||||||
t.index ["email"], name: "index_users_on_email", unique: true
|
t.index ["email"], name: "index_users_on_email", unique: true
|
||||||
t.index ["remember_token"], name: "index_users_on_remember_token", unique: true
|
|
||||||
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
|
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ module Mastodon
|
||||||
end
|
end
|
||||||
|
|
||||||
MIN_SUPPORTED_VERSION = 2019_10_01_213028
|
MIN_SUPPORTED_VERSION = 2019_10_01_213028
|
||||||
MAX_SUPPORTED_VERSION = 2021_05_26_193025
|
MAX_SUPPORTED_VERSION = 2022_01_18_183123
|
||||||
|
|
||||||
# Stubs to enjoy ActiveRecord queries while not depending on a particular
|
# Stubs to enjoy ActiveRecord queries while not depending on a particular
|
||||||
# version of the code/database
|
# version of the code/database
|
||||||
|
@ -84,13 +84,14 @@ module Mastodon
|
||||||
|
|
||||||
owned_classes = [
|
owned_classes = [
|
||||||
Status, StatusPin, MediaAttachment, Poll, Report, Tombstone, Favourite,
|
Status, StatusPin, MediaAttachment, Poll, Report, Tombstone, Favourite,
|
||||||
Follow, FollowRequest, Block, Mute, AccountIdentityProof,
|
Follow, FollowRequest, Block, Mute,
|
||||||
AccountModerationNote, AccountPin, AccountStat, ListAccount,
|
AccountModerationNote, AccountPin, AccountStat, ListAccount,
|
||||||
PollVote, Mention
|
PollVote, Mention
|
||||||
]
|
]
|
||||||
owned_classes << AccountDeletionRequest if ActiveRecord::Base.connection.table_exists?(:account_deletion_requests)
|
owned_classes << AccountDeletionRequest if ActiveRecord::Base.connection.table_exists?(:account_deletion_requests)
|
||||||
owned_classes << AccountNote if ActiveRecord::Base.connection.table_exists?(:account_notes)
|
owned_classes << AccountNote if ActiveRecord::Base.connection.table_exists?(:account_notes)
|
||||||
owned_classes << FollowRecommendationSuppression if ActiveRecord::Base.connection.table_exists?(:follow_recommendation_suppressions)
|
owned_classes << FollowRecommendationSuppression if ActiveRecord::Base.connection.table_exists?(:follow_recommendation_suppressions)
|
||||||
|
owned_classes << AccountIdentityProof if ActiveRecord::Base.connection.table_exists?(:account_identity_proofs)
|
||||||
|
|
||||||
owned_classes.each do |klass|
|
owned_classes.each do |klass|
|
||||||
klass.where(account_id: other_account.id).find_each do |record|
|
klass.where(account_id: other_account.id).find_each do |record|
|
||||||
|
@ -139,17 +140,22 @@ module Mastodon
|
||||||
@prompt = TTY::Prompt.new
|
@prompt = TTY::Prompt.new
|
||||||
|
|
||||||
if ActiveRecord::Migrator.current_version < MIN_SUPPORTED_VERSION
|
if ActiveRecord::Migrator.current_version < MIN_SUPPORTED_VERSION
|
||||||
@prompt.warn 'Your version of the database schema is too old and is not supported by this script.'
|
@prompt.error 'Your version of the database schema is too old and is not supported by this script.'
|
||||||
@prompt.warn 'Please update to at least Mastodon 3.0.0 before running this script.'
|
@prompt.error 'Please update to at least Mastodon 3.0.0 before running this script.'
|
||||||
exit(1)
|
exit(1)
|
||||||
elsif ActiveRecord::Migrator.current_version > MAX_SUPPORTED_VERSION
|
elsif ActiveRecord::Migrator.current_version > MAX_SUPPORTED_VERSION
|
||||||
@prompt.warn 'Your version of the database schema is more recent than this script, this may cause unexpected errors.'
|
@prompt.warn 'Your version of the database schema is more recent than this script, this may cause unexpected errors.'
|
||||||
exit(1) unless @prompt.yes?('Continue anyway?')
|
exit(1) unless @prompt.yes?('Continue anyway? (Yes/No)')
|
||||||
|
end
|
||||||
|
|
||||||
|
if Sidekiq::ProcessSet.new.any?
|
||||||
|
@prompt.error 'It seems Sidekiq is running. All Mastodon processes need to be stopped when using this script.'
|
||||||
|
exit(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
@prompt.warn 'This task will take a long time to run and is potentially destructive.'
|
@prompt.warn 'This task will take a long time to run and is potentially destructive.'
|
||||||
@prompt.warn 'Please make sure to stop Mastodon and have a backup.'
|
@prompt.warn 'Please make sure to stop Mastodon and have a backup.'
|
||||||
exit(1) unless @prompt.yes?('Continue?')
|
exit(1) unless @prompt.yes?('Continue? (Yes/No)')
|
||||||
|
|
||||||
deduplicate_users!
|
deduplicate_users!
|
||||||
deduplicate_account_domain_blocks!
|
deduplicate_account_domain_blocks!
|
||||||
|
@ -236,12 +242,14 @@ module Mastodon
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
ActiveRecord::Base.connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM users WHERE remember_token IS NOT NULL GROUP BY remember_token HAVING count(*) > 1").each do |row|
|
if ActiveRecord::Migrator.current_version < 20220118183010
|
||||||
users = User.where(id: row['ids'].split(',')).sort_by(&:updated_at).reverse.drop(1)
|
ActiveRecord::Base.connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM users WHERE remember_token IS NOT NULL GROUP BY remember_token HAVING count(*) > 1").each do |row|
|
||||||
@prompt.warn "Unsetting remember token for those accounts: #{users.map(&:account).map(&:acct).join(', ')}"
|
users = User.where(id: row['ids'].split(',')).sort_by(&:updated_at).reverse.drop(1)
|
||||||
|
@prompt.warn "Unsetting remember token for those accounts: #{users.map(&:account).map(&:acct).join(', ')}"
|
||||||
|
|
||||||
users.each do |user|
|
users.each do |user|
|
||||||
user.update!(remember_token: nil)
|
user.update!(remember_token: nil)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -257,7 +265,7 @@ module Mastodon
|
||||||
@prompt.say 'Restoring users indexes…'
|
@prompt.say 'Restoring users indexes…'
|
||||||
ActiveRecord::Base.connection.add_index :users, ['confirmation_token'], name: 'index_users_on_confirmation_token', unique: true
|
ActiveRecord::Base.connection.add_index :users, ['confirmation_token'], name: 'index_users_on_confirmation_token', unique: true
|
||||||
ActiveRecord::Base.connection.add_index :users, ['email'], name: 'index_users_on_email', unique: true
|
ActiveRecord::Base.connection.add_index :users, ['email'], name: 'index_users_on_email', unique: true
|
||||||
ActiveRecord::Base.connection.add_index :users, ['remember_token'], name: 'index_users_on_remember_token', unique: true
|
ActiveRecord::Base.connection.add_index :users, ['remember_token'], name: 'index_users_on_remember_token', unique: true if ActiveRecord::Migrator.current_version < 20220118183010
|
||||||
ActiveRecord::Base.connection.add_index :users, ['reset_password_token'], name: 'index_users_on_reset_password_token', unique: true
|
ActiveRecord::Base.connection.add_index :users, ['reset_password_token'], name: 'index_users_on_reset_password_token', unique: true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -274,6 +282,8 @@ module Mastodon
|
||||||
end
|
end
|
||||||
|
|
||||||
def deduplicate_account_identity_proofs!
|
def deduplicate_account_identity_proofs!
|
||||||
|
return unless ActiveRecord::Base.connection.table_exists?(:account_identity_proofs)
|
||||||
|
|
||||||
remove_index_if_exists!(:account_identity_proofs, 'index_account_proofs_on_account_and_provider_and_username')
|
remove_index_if_exists!(:account_identity_proofs, 'index_account_proofs_on_account_and_provider_and_username')
|
||||||
|
|
||||||
@prompt.say 'Removing duplicate account identity proofs…'
|
@prompt.say 'Removing duplicate account identity proofs…'
|
||||||
|
|
Loading…
Reference in a new issue