class NewPlanTemplateStructure < ActiveRecord::Migration
def up
# new template tables
create_table :templates do |t|
t.string :title
t.text :description
t.boolean :published
t.integer :organisation_id
t.string :locale
t.boolean :is_default
t.timestamps
# new fields
t.integer :version
t.integer :visibility
t.integer :customization_of
t.integer :dmptemplate_id # remove on next migration
end
create_table :new_phases do |t|
t.string :title
t.text :description
t.integer :number
t.integer :template_id
t.timestamps
t.string :slug
t.integer :vid # remove on next migration
# new fields
t.boolean :modifiable
end
create_table :new_sections do |t|
t.string :title
t.text :description
t.integer :number
t.timestamps
t.boolean :published
# new fields
t.integer :new_phase_id
t.boolean :modifiable
end
create_table :new_questions do |t|
t.text :text
t.text :default_value
t.text :guidance
t.integer :number
t.integer :new_section_id
t.timestamps
t.integer :question_format_id
t.boolean :option_comment_display, default: true
# new fields
t.boolean :modifiable
t.integer :question_id # remove on next migration
end
create_join_table :new_questions, :themes do |t|
end
create_table :new_answers do |t|
t.text :text
t.integer :new_plan_id
t.integer :user_id
t.integer :new_question_id
t.timestamps
end
create_table :question_options do |t|
t.integer :new_question_id
t.integer :option_id # remove on next migration
t.string :text
t.integer :number
t.boolean :is_default
t.timestamps
end
create_join_table :new_answers, :question_options do |t|
end
create_table :notes do |t|
t.integer :user_id
t.text :text
t.boolean :archived # do we need this?
t.integer :new_answer_id
t.integer :archived_by # do we need this?
t.timestamps
end
create_table :new_suggested_answers do |t|
t.integer :new_question_id
t.integer :organisation_id
t.text :text
t.boolean :is_example
t.timestamps
end
# new plans table
create_table :new_plans do |t|
t.integer :project_id
t.string :title
t.integer :template_id
t.timestamps
t.string :slug
t.string :grant_number
t.string :identifier
t.text :description
t.string :principal_investigator
t.string :principal_investigator_identifier
t.string :data_contact
t.string :funder_name
end
create_table :roles do |t|
t.boolean :creator
t.boolean :editor
t.boolean :administrator
t.integer :user_id
t.integer :new_plan_id
t.timestamps
end
# migrate all of the data from plans into templates (user facing)
# first migrate all "pure"(uncustomised) plans
# find template for plan
# find versions for plan
# find phases for template
# find sections for version
# find questions for section
# find question_options for question
# find answers for question
# find notes from question & link to answer
# find guidance_by_question for question
# find themes for question
# IF EXISTS Template SUCH THAT:
# dmptemplate.name = template.name,
# phase.title = new_phase.title,
# new_phase.version_id in versions.id
# SUCCESSFUL MATCH, copy over all data
# Then migrate all customised plans
# migrate most current template into templates (org facing)
proj_number = 0
# migrating uncustomised plans
Template.transaction do
Project.includes( { dmptemplate: [ { phases: [ { versions: [:sections] } ] } ] }, {plans: [:version ]}, :organisation).find_each(batch_size: 20) do |project|
puts ""
puts "beginning number #{proj_number}"
proj_number +=1
if project.dmptemplate.nil? # one of the templates dosent exist
next
end
new_plan = initNewPlan(project) # copy data from project to NewPlan object
plans = project.plans # select plans for project
version_ids = []
versions = []
plans.each do |plan| # select version ids from plans list
version_ids << plan.version.id
versions << plan.version
end
dmptemplate = project.dmptemplate # select template for project
phases = dmptemplate.phases # select phases for project
temp_match = false # flag for if we found a matching template
puts "checking for matching templates for #{dmptemplate.title} customised by #{project.organisation.name}" unless project.organisation.nil?
puts "checking for matching templates for #{dmptemplate.title} uncustomised" unless project.organisation.present?
possible_templates = project.organisation.nil? ?
Template.includes(:new_phases).where(dmptemplate_id: dmptemplate.id, organisation_id: dmptemplate.organisation_id) :
Template.includes(:new_phases).where(dmptemplate_id: dmptemplate.id, organisation_id: project.organisation_id)
possible_templates.find_each do |t| # for templates with same id
# early cut for un-even number of phases
new_phase_versions = t.new_phases.pluck(:vid)
if new_phase_versions.sort == version_ids.sort
temp_match = true # flag that we found match
# we can point the new_plan to this template and init all data
new_plan.template_id = t.id
new_plan.save!
puts "found a match: #{t.title} version #{t.version}"
break
end
end
# this section handles for customisations
unless temp_match # no matches found, init template & phase & sections & questions & themes & options
puts "creating new template for #{dmptemplate.title}" unless project.organisation.present?
puts "creating new template for #{dmptemplate.title} customised by #{project.organisation.name}" unless project.organisation.nil?
template = initTemplate(dmptemplate) # needs to select next version of temp based on old_temp_id
# some differences between a customised and un-customised template
# customised templates need a different organisation_id
template.organisation_id = project.organisation_id
# customised templates follow different version rules
template.save!
# since template was not a match, need to gen/copy all data below the template level
versions.each do |version|
new_phase = initNewPhase(version.phase, version, template, true)
new_phase.save!
sections = []
sections += version.sections.where("organisation_id = ? ", dmptemplate.organisation_id).pluck(:id)
unless project.organisation_id.nil?
sections += Section.where(organisation_id: project.organisation_id, version_id: version.id).pluck(:id)
end
Section.includes(questions: [:themes, :options, :suggested_answers]).where(id: sections).each do |section|
new_section = initNewSection(section, new_phase, true)
new_section.save!
section.questions.each do |question|
new_question = initNewQuestion(question, new_section, true)
new_question.save!
question.themes.each do |theme|
new_question.themes << theme
end
question.options.each do |option|
question_option = initQuestionOption(option, new_question)
question_option.save!
end
question.suggested_answers.each do |suggested_answer|
new_suggested_answer = initNewSuggestedAnswers(suggested_answer, new_question)
new_suggested_answer.save!
end
end
end
end
new_plan.template_id = template.id
new_plan.save!
end
# up to this point, we have either found a matching template and pointed the
# new_plan obj at it, or we have generated a new:
# template/phases/sections/questions/question_options/question_themes
# now need to init answers, notes, answers_options
#new_plan.template.new_phases.each do |new_phase|
puts "transfering plan data"
project.project_groups.each do |group|
role = initRole(group, new_plan)
role.save!
end
template = Template.includes(new_phases: {new_sections: :new_questions}).find(new_plan.template_id)
template.new_phases.each do |new_phase|
old_plan = project.plans.where(version_id: new_phase.vid).first
puts "old plan id: #{old_plan.id}"
puts "plan ids :#{plans.pluck(:id)}"
if old_plan.id == 46
puts "IT'S NOT WORKING RITE HERE!!!!!!!!!!!!!!!!!!!!!!! IT'S NOT WORKING RITE HERE!!!!!!!!!!!!!!!!!!!!!!! IT'S NOT WORKING RITE HERE!!!!!!!!!!!!!!!!!!!!!!!"
end
new_phase.new_sections.each do |new_section|
new_section.new_questions.each do |new_question|
# init new answer
old_ans = Answer.where(question_id: new_question.question_id, plan_id: old_plan.id).order("created_at DESC").first
# init comments on answer
new_ans = nil
comments = Comment.where(question_id: new_question.question_id, plan_id: old_plan.id)
# unless there is no old answer, and no comments, create an answer
unless old_ans.nil? && comments.length < 1
new_ans = initNewAnswer(old_ans, new_plan, new_question)
new_ans.save!
end
comments.find_each do |comment|
note = initNote(comment, new_ans)
note.save!
end
if new_ans.present? && new_ans.text.present? && new_ans.text.include?("test2")
puts "!!!!!!!!!!!!!!!!DEBUG MODE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
puts "old answer: #{old_ans.text}"
puts "old answer: #{old_ans.id}"
puts "new answer: #{new_ans.text}"
puts "old plans: #{project.plans.pluck(:id)}"
puts "old_plan: #{old_plan.id}"
puts "old project: #{project.id}"
puts "question: #{new_question.question_id}"
puts "old user: #{old_ans.user.email}"
end
end
end
end
end
end
# indexes on join tables at the end
change_table :new_answers_question_options do |t|
t.index [:new_answer_id, :question_option_id], name: 'answer_question_option_index'
t.index [:question_option_id, :new_answer_id], name: 'question_option_answer_index'
end
change_table :new_questions_themes do |t|
t.index [:new_question_id, :theme_id], name: 'question_theme_index'
t.index [:theme_id, :new_question_id], name: 'theme_question_index'
end
end
def down
drop_table :templates
drop_table :new_phases
drop_table :new_sections
drop_table :new_questions
drop_join_table :new_questions, :themes
drop_table :new_answers
drop_table :question_options
drop_join_table :new_answers, :question_options
drop_table :notes
drop_table :new_suggested_answers
drop_table :new_plans
drop_table :roles
end
end
def initTemplate(dmptemp)
template = Template.new
template.title = dmptemp.title
template.description = dmptemp.description
template.published = dmptemp.published
template.organisation_id = dmptemp.organisation_id
template.locale = dmptemp.locale
template.is_default = dmptemp.is_default
template.created_at = dmptemp.created_at
template.updated_at = dmptemp.updated_at
template.visibility = 0 # dummy value for private
template.customization_of = nil
template.version = Template.where(dmptemplate_id: dmptemp.id).blank? ?
0 : Template.where(dmptemplate_id: dmptemp.id).pluck(:version).max + 1
puts "NEW TEMPLATE: \n title: #{template.title} \n version: #{template.version} \n others_present? #{Template.where(dmptemplate_id: dmptemp.id).count}"
template.dmptemplate_id = dmptemp.id
return template
end
def initNewPhase(phase, version, temp, modifiable)
new_phase = NewPhase.new
new_phase.title = phase.title
new_phase.description = phase.description
new_phase.number = phase.number
new_phase.template_id = temp.id
new_phase.created_at = phase.created_at
new_phase.updated_at = phase.updated_at
new_phase.slug = phase.slug
new_phase.vid = version.id
new_phase.modifiable = modifiable
return new_phase
end
def initNewSection(section, new_phase, modifiable)
new_section = NewSection.new
new_section.title = section.title
new_section.description = section.description
new_section.number = section.number
new_section.published = section.published
new_section.new_phase_id = new_phase.id
new_section.modifiable = modifiable
new_section.created_at = section.created_at
new_section.updated_at = section.updated_at
return new_section
end
def initNewQuestion(question, new_section, modifiable)
new_question = NewQuestion.new
new_question.text = question.text
new_question.default_value = question.default_value
new_question.guidance = question.guidance.nil? ? "" : question.guidance
Guidance.where(question_id: question.id).each do |guidance|
new_question.guidance += guidance.text
end
new_question.number = question.number
new_question.new_section_id = new_section.id
new_question.question_format_id = question.question_format_id
new_question.option_comment_display = question.option_comment_display
new_question.modifiable = modifiable
new_question.question_id = question.id
new_question.updated_at = question.updated_at
new_question.created_at = question.created_at
return new_question
end
def initNewAnswer(answer, new_plan, new_question)
new_answer = NewAnswer.new
unless answer.nil?
new_answer.text = answer.text
new_answer.new_plan_id = new_plan.id
new_answer.new_question_id = new_question.id
new_answer.user_id = answer.user_id
new_answer.created_at = answer.created_at
new_answer.updated_at = answer.updated_at
# not sure if these get saved properly as new_answer has no id yet
answer.options.each do |option|
new_answer.question_options << QuestionOption.find_by(option_id: option.id)
end
end
return new_answer
end
def initQuestionOption(option, new_question)
question_option = QuestionOption.new
question_option.new_question_id = new_question.id
question_option.option_id = option.id
question_option.text = option.text
question_option.number = option.number
question_option.is_default = option.is_default
question_option.created_at = option.created_at
question_option.updated_at = option.updated_at
return question_option
end
def initNote(comment, new_answer)
note = Note.new
note.user_id = comment.user_id
note.text = comment.text
note.archived = comment.archived
note.archived_by = comment.archived_by
note.new_answer_id = new_answer.id
note.created_at = comment.created_at
note.updated_at = comment.updated_at
return note
end
def initNewPlan(project)
new_plan = NewPlan.new
new_plan.project_id = project.id
new_plan.title = project.title
new_plan.slug = project.slug
new_plan.grant_number = project.grant_number
new_plan.identifier = project.identifier
new_plan.description = project.description
new_plan.principal_investigator = project.principal_investigator
new_plan.principal_investigator_identifier = project.principal_investigator_identifier
new_plan.data_contact = project.data_contact
new_plan.funder_name = project.funder_name
new_plan.created_at = project.created_at
new_plan.updated_at = project.updated_at
return new_plan
end
def initNewSuggestedAnswers(suggested_answer, new_question)
new_suggested_answer = NewSuggestedAnswer.new
new_suggested_answer.text = suggested_answer.text
new_suggested_answer.organisation_id = suggested_answer.organisation_id
new_suggested_answer.new_question_id = new_question.id
new_suggested_answer.is_example = suggested_answer.is_example
new_suggested_answer.created_at = suggested_answer.created_at
new_suggested_answer.updated_at = suggested_answer.updated_at
return new_suggested_answer
end
def initRole(project_group, new_plan)
role = Role.new
role.creator = project_group.project_creator
role.administrator = project_group.project_administrator
role.editor = project_group.project_editor
role.created_at = project_group.created_at
role.updated_at = project_group.updated_at
role.user_id = project_group.user_id
role.new_plan_id = new_plan.id
return role
end