canvas-lms/lib/data_fixup/fix_orphaned_attachments.rb

94 lines
3.2 KiB
Ruby

module DataFixup
class FixOrphanedAttachments
def self.run
@new_roots = Set.new
Shackles.activate(:slave) do
scope = Attachment.
where("root_attachment_id IS NOT NULL AND
NOT EXISTS (SELECT id
FROM #{Attachment.quoted_table_name} ra
WHERE ra.id = attachments.root_attachment_id)")
create_users if scope.exists?
scope.find_each(start: 0) do |a|
next if @new_roots.include? a.root_attachment_id
fix_orphaned_file(a)
@new_roots << a.root_attachment_id
end
end
end
def self.create_users
Shackles.activate(:master) do
@deleted_user = User.create(name: 'rescued attachments')
@deleted_user.destroy
@broken_user = User.create(name: 'broken attachments')
@broken_user.destroy
end
end
def self.other_namespace(attachment)
account_id = attachment.namespace.sub('account_', '').to_i
if account_id.to_s.length > 8
namespace_account_id = Account.where(id: account_id).first.try(:local_id)
else
namespace_account_id = attachment.shard.global_id_for(account_id)
end
"account_#{namespace_account_id}"
end
def self.s3_save(rescued_orphan, ns)
if rescued_orphan.s3object.exists?
rescued_orphan.save!
rescued_orphan.namespace = ns
finalize_attachment(rescued_orphan)
else
ns = rescued_orphan.namespace = other_namespace(rescued_orphan)
if rescued_orphan.s3object.exists?
rescued_orphan.save!
rescued_orphan.namespace = ns
finalize_attachment(rescued_orphan)
else
rescued_orphan.context_id = @broken_user.id
finalize_attachment(rescued_orphan)
end
end
end
def self.local_storage_save(rescued_orphan)
if File.exist? rescued_orphan.full_filename
finalize_attachment(rescued_orphan)
else
rescued_orphan.context_id = @broken_user.id
finalize_attachment(rescued_orphan)
end
end
def self.finalize_attachment(attachment)
attachment.file_state = 'deleted'
attachment.save!
end
def self.fix_orphaned_file(attachment)
rescued_orphan = Attachment.new
rescued_orphan.id = attachment.root_attachment_id unless attachment.root_attachment_id > Shard::IDS_PER_SHARD
rescued_orphan.context_type = 'User'
rescued_orphan.context_id = @deleted_user.id
rescued_orphan.size = attachment.size
rescued_orphan.content_type = attachment.content_type
rescued_orphan.filename = attachment.filename || "none"
rescued_orphan.display_name = attachment.display_name
rescued_orphan.file_state = 'deleted'
rescued_orphan.md5 = attachment.md5
ns = rescued_orphan.namespace = attachment.namespace
Shackles.activate(:master) do
Attachment.s3_storage? ? s3_save(rescued_orphan, ns) : local_storage_save(rescued_orphan)
if rescued_orphan.id != attachment.root_attachment_id
Attachment.where(root_attachment_id: attachment.root_attachment_id).update_all(root_attachment_id: rescued_orphan.id)
end
end
end
end
end