OpenProject is the leading open source project management software.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openproject/lib/tasks/shared/attachment_migration.rb

164 lines
5.5 KiB

module Tasks
module Shared
module AttachmentMigration
module_function
def move_obsolete_attachments_to_wiki!
reset_journal_id_sequence!
move_project_attachments_to_wiki!
move_version_attachments_to_wiki!
end
##
# Why do we do this? Consider the migrations process:
#
# ... (other migrations)
# |A| delete version and project attachments
# |B| move these attachments to new wiki pages to prevent data loss (new)
# ... (other migrations)
# |C| migrate legacy journals to new format
#
# We are at 'B'. Creating new wiki pages and also updating attachment entries
# creates journal entries (starting with ID 1).
# Step 'C' assumes there are no journals yet which would normally be the case.
# Due to the newly introduced step B there are some already, though.
# The journal migrations wants to use the same IDs as in the original journals.
# These may now be taken by the new attachment journals.
#
# To prevent this we skip all possible IDs of the legacy journals so the
# journals created during the attachment business don't conflict with
# the legacy journals.
def reset_journal_id_sequence!
con = ActiveRecord::Base.connection
if OpenProject::Database.mysql?
max_id = con.execute("SELECT MAX(id) FROM legacy_journals").to_a.first.first
con.execute "ALTER TABLE journals AUTO_INCREMENT = #{max_id + 1}"
else # Postgres
max_id = con.execute("SELECT MAX(id) FROM legacy_journals").to_a.first["max"]
con.execute "ALTER SEQUENCE journals_id_seq RESTART WITH #{max_id + 1}"
end
end
def move_project_attachments_to_wiki!
projects = affected_containers(Project).to_a
projects.each_with_index do |project, i|
enable_wiki! project
page = create_project_attachments_page! project
attachments = Attachment.where(container_type: "Project", container_id: project.id)
puts "Moving #{attachments.size} Version attachments to wiki page \"#{page.title}\" [#{i + 1}/#{projects.size}]"
attachments.each do |attachment|
attachment.update! container_type: "WikiPage", container_id: page.id
end
end
end
def move_version_attachments_to_wiki!
versions = affected_containers(Version).to_a
versions.each_with_index do |version, i|
enable_wiki! version.project
page = create_version_attachments_page! version
attachments = Attachment.where(container_type: "Version", container_id: version.id)
puts "Moving #{attachments.size} Version attachments to wiki page '#{page.title}' [#{i + 1}/#{versions.size}]"
attachments.each do |attachment|
attachment.update! container_type: "WikiPage", container_id: page.id
end
end
end
def affected_containers(model)
Attachment
.where(container_type: model.name)
.group(:container_id)
.pluck(:container_id)
.map { |id| model.find_by(id: id) }
end
def enable_wiki!(project)
unless project.module_enabled? "wiki"
project.enabled_modules.create name: "wiki"
if project.wiki.nil?
Wiki.create! project: project, start_page: "Wiki", status: 1
project.reload
end
end
end
def create_project_attachments_page!(project, name: "Project Attachments")
page = attachments_page! project.wiki, name: name
if page.content.nil?
text = I18n.t(
:notice_attachment_migration_wiki_page,
container_type: "Project",
container_name: project.name
)
Migrations::Attachments::CurrentWikiContent.create!(
page_id: page.id, author_id: User.system.id, text: text
)
end
page
end
def create_version_attachments_page!(version, name: "Version '#{version.name}' Attachments")
page = attachments_page! version.project.wiki, name: name
if page.content.nil?
text = I18n.t(
:notice_attachment_migration_wiki_page,
container_type: "Version",
container_name: version.name
)
Migrations::Attachments::CurrentWikiContent.create!(
page_id: page.id, author_id: User.system.id, text: text
)
end
page
end
def attachments_page!(wiki, name:)
page = wiki.pages.where(title: name).first
if page
page
else
Migrations::Attachments::CurrentWikiPage.create wiki_id: wiki.id, title: name
end
end
def try_delete_attachments_from_projects_and_versions
if !$stdout.isatty || user_agrees_to_delete_versions_and_projects_documents
puts 'Delete all attachments attached to projects or versions...'
Attachment.where(container_type: ['Version', 'Project']).destroy_all
end
rescue
raise 'Cannot delete attachments from projects and versions! There may be migrations missing...?'
end
def user_agrees_to_delete_versions_and_projects_documents
questions = ['CAUTION: This rake task will delete ALL attachments attached to versions or projects!',
"DISCLAIMER: This is the final warning: You're going to lose information!"]
ask_for_confirmation(questions)
end
end
end
end