Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions app/services/form_copy_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def initialize(form, logged_in_user)
@form = form
@copied_form = Form.new
@logged_in_user = logged_in_user
@exit_page_id_mapping = {}
end

def copy(tag: "draft")
Expand All @@ -28,6 +29,7 @@ def copy(tag: "draft")
prepend_name_for_language(:en)

copy_pages(content["steps"])
copy_exit_pages(content["steps"])
copy_routing_conditions(content["steps"])

@copied_form.copied_from_id = @form.id
Expand Down Expand Up @@ -71,6 +73,23 @@ def copy_pages(steps)
end
end

def copy_exit_pages(steps)
return if steps.blank?

steps.each_with_index do |step, index|
page = @copied_form.pages[index]

(step["exit_pages"] || []).each do |ep_data|
exit_page = page.exit_pages.build(
heading: ep_data["heading"],
markdown: ep_data["markdown"],
)
exit_page.save!
@exit_page_id_mapping[ep_data["id"]] = exit_page
end
end
end

def copy_page_attributes(page, step)
data = step["data"]
page.assign_attributes(
Expand Down Expand Up @@ -139,6 +158,10 @@ def copy_condition(condition_data, page_id_mapping)
exit_page_markdown: condition_data["exit_page_markdown"],
)

if condition_data["exit_page_id"].present?
condition.exit_page = @exit_page_id_mapping[condition_data["exit_page_id"]]
end
Comment thread
lfdebrux marked this conversation as resolved.

condition.save!
end

Expand All @@ -161,6 +184,7 @@ def copy_welsh_page_translations(welsh_steps)
page.send("#{attr}=", data[attr]) if data[attr].present?
end
copy_welsh_exit_page_conditions(step, page)
copy_welsh_exit_pages(step)
page.save!(validate: false)
end
end
Expand All @@ -177,4 +201,19 @@ def copy_welsh_exit_page_conditions(step, page)
end
end
end

def copy_welsh_exit_pages(step)
# Exit pages already linked to a condition are handled by copy_welsh_exit_page_conditions
# Here we are only copying exit pages that are not linked to a condition.
condition_exit_page_ids = (step["routing_conditions"] || []).filter_map { |c| c["exit_page_id"] }
standalone_exit_pages = (step["exit_pages"] || []).reject { |ep| condition_exit_page_ids.include?(ep["id"]) }

standalone_exit_pages.each do |ep_data|
exit_page = @exit_page_id_mapping[ep_data["id"]]

exit_page.heading = ep_data["heading"] if ep_data["heading"].present?
exit_page.markdown = ep_data["markdown"] if ep_data["markdown"].present?
exit_page.save!
end
end
end
5 changes: 2 additions & 3 deletions app/services/reports/form_documents_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,8 @@ def has_s3_submissions(form_document)

def has_exit_pages?(form_document)
form_document["content"]["steps"].any? do |step|
step["routing_conditions"].any? do |condition|
condition["exit_page_markdown"].present?
end
step["exit_pages"]&.any? ||
step["routing_conditions"]&.any? { |c| c["exit_page_markdown"].present? }
end
end

Expand Down
38 changes: 35 additions & 3 deletions app/services/revert_draft_form_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ def revert_pages_and_nested_associations(steps_data)

revert_pages(steps_data)

revert_exit_pages(steps_data)

# revert conditions after pages are created to make sure conditions don't
# have validation errors if the page hasn't been created yet
revert_routing_conditions(steps_data)
Expand All @@ -83,6 +85,26 @@ def revert_pages(steps_data)
end
end

def revert_exit_pages(steps_data)
form.exit_pages.reload

form_document_exit_page_ids = steps_data.flat_map { |step| step["exit_pages"] || [] }.map { |ep| ep["id"] }
form.exit_pages.where.not(id: form_document_exit_page_ids).destroy_all

steps_data.each do |step_data|
page = form.pages.find_by(external_id: step_data["id"])
next if page.blank?

(step_data["exit_pages"] || []).each do |exit_page_data|
exit_page = ExitPage.find_or_initialize_by(id: exit_page_data["id"])
exit_page.question_page = page
exit_page.heading = exit_page_data["heading"]
exit_page.markdown = exit_page_data["markdown"]
exit_page.save!
end
end
end

# steps in a form_document store the page attributes under "data"
def assign_page_attributes(page, step_data)
page_data = step_data["data"]
Expand Down Expand Up @@ -116,11 +138,21 @@ def revert_routing_conditions(steps_data)

def assign_condition_attributes(condition, condition_data)
condition.answer_value = condition_data["answer_value"]
condition.routing_page = Page.find_by!(external_id: condition_data["routing_page_id"]) if condition_data["routing_page_id"]
condition.check_page = Page.find_by!(external_id: condition_data["check_page_id"]) if condition_data["check_page_id"]
condition.goto_page = Page.find_by!(external_id: condition_data["goto_page_id"]) if condition_data["goto_page_id"]
condition.routing_page = if condition_data["routing_page_id"]
Page.find_by!(external_id: condition_data["routing_page_id"])
end

condition.check_page = if condition_data["check_page_id"]
Page.find_by!(external_id: condition_data["check_page_id"])
end

condition.goto_page = if condition_data["goto_page_id"].present?
Page.find_by!(external_id: condition_data["goto_page_id"])
end

condition.exit_page_heading = condition_data["exit_page_heading"]
condition.exit_page_markdown = condition_data["exit_page_markdown"]
condition.exit_page_id = condition_data["exit_page_id"]
end

def revert_welsh_translations(welsh_form_document)
Expand Down
98 changes: 98 additions & 0 deletions spec/services/form_copy_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,104 @@
end
end

context "when source form has standalone exit pages not connected to conditions" do
let(:source_form) { create(:form, :live_with_draft, :with_pages, pages_count: 2) }
let!(:source_exit_page) do
create(:exit_page, heading: "Exit heading", markdown: "Exit markdown",
question_page: source_form.pages.first)
end

before do
source_form.latest_form_document.update!(content: source_form.as_form_document)
end

it "copies all exit pages" do
expect(copied_form.exit_pages.count).to eq(1)
end

it "creates new exit page records with different IDs" do
expect(copied_form.exit_pages.pluck(:id)).not_to include(source_exit_page.id)
end

it "copies exit page content" do
copied_exit_page = copied_form.exit_pages.first

expect(copied_exit_page.heading).to eq("Exit heading")
expect(copied_exit_page.markdown).to eq("Exit markdown")
end

it "associates the exit page with the correct copied page" do
copied_exit_page = copied_form.exit_pages.first

expect(copied_exit_page.question_page).to eq(copied_form.pages.first)
expect(copied_exit_page.question_page).not_to eq(source_form.pages.first)
end
end

context "when a condition references an exit page via exit_page_id", :feature_multiple_branches do
let(:source_form) { create(:form, :live_with_draft, :ready_for_routing, pages_count: 2) }
let!(:source_exit_page) do
create(:exit_page, heading: "Condition exit heading", markdown: "Condition exit markdown",
question_page: source_form.pages.first)
end

before do
create(:condition,
form: source_form,
routing_page: source_form.pages.first,
check_page: source_form.pages.first,
answer_value: "No",
exit_page: source_exit_page)
source_form.reload
source_form.latest_form_document.update!(content: source_form.as_form_document)
end

it "copies the exit page for the condition" do
expect(copied_form.pages.first.routing_conditions.first.exit_page).to be_present
end

it "copies the exit page content" do
copied_condition = copied_form.pages.first.routing_conditions.first

expect(copied_condition.exit_page.heading).to eq("Condition exit heading")
expect(copied_condition.exit_page.markdown).to eq("Condition exit markdown")
end

it "creates a new exit page record distinct from the source" do
copied_condition = copied_form.pages.first.routing_conditions.first

expect(copied_condition.exit_page_id).not_to eq(source_exit_page.id)
end

it "links the copied exit page to the copied page" do
copied_exit_page = copied_form.pages.first.routing_conditions.first.exit_page

expect(copied_exit_page.question_page).to eq(copied_form.pages.first)
end
end

context "when source form has standalone exit pages with Welsh translations" do
let(:source_form) do
form = create(:form, :live, :with_pages, pages_count: 2, available_languages: %w[en cy])
exit_page = create(:exit_page, heading: "Exit heading", markdown: "Exit markdown",
question_page: form.pages.first)
exit_page.heading_cy = "Pennaw ymadael"
exit_page.markdown_cy = "Markdown ymadael"
exit_page.save!
FormDocumentSyncService.new(form).synchronize_live_form
form.reload
form
end

it "copies Welsh heading for the exit page" do
expect(copied_form.exit_pages.first.heading_cy).to eq("Pennaw ymadael")
end

it "copies Welsh markdown for the exit page" do
expect(copied_form.exit_pages.first.markdown_cy).to eq("Markdown ymadael")
end
end

context "when Welsh copy fails" do
let(:source_form) do
form = create(:form, :live, available_languages: %w[en cy])
Expand Down
78 changes: 76 additions & 2 deletions spec/services/reports/form_documents_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,27 @@
described_class.has_exit_pages?(form_document)
end

context "when form has one step with one exit page" do
let(:form_document) { branch_route_form.latest_form_document }
context "when a step has one exit page via the ExitPage model" do
let(:form_with_exit_page) do
form = create(:form, :live)
create(:exit_page, question_page: form.pages.first)
form.latest_form_document.update!(content: form.reload.as_form_document(live_at: form.updated_at))
form
end
let(:form_document) { form_with_exit_page.latest_form_document }

it { is_expected.to be true }
end

context "when a step has multiple exit pages via the ExitPage model" do
let(:form_with_multiple_exit_pages) do
form = create(:form, :live)
create(:exit_page, question_page: form.pages.first)
create(:exit_page, question_page: form.pages.first)
form.latest_form_document.update!(content: form.reload.as_form_document(live_at: form.updated_at))
form
end
let(:form_document) { form_with_multiple_exit_pages.latest_form_document }

it { is_expected.to be true }
end
Expand All @@ -242,6 +261,61 @@

it { is_expected.to be false }
end

context "when the form document is a legacy snapshot with exit_page_markdown on a routing condition" do
let(:form_document) do
{
"content" => {
"steps" => [
{
"routing_conditions" => [
{ "exit_page_markdown" => "Exit page markdown" },
],
},
],
},
}
end

it { is_expected.to be true }
end

context "when the form document is a legacy snapshot with an empty exit_pages array and exit_page_markdown on a routing condition" do
let(:form_document) do
{
"content" => {
"steps" => [
{
"exit_pages" => [],
"routing_conditions" => [
{ "exit_page_markdown" => "Exit page markdown" },
],
},
],
},
}
end

it { is_expected.to be true }
end

context "when the form document is a legacy snapshot with no exit pages" do
let(:form_document) do
{
"content" => {
"steps" => [
{
"routing_conditions" => [
{ "exit_page_markdown" => nil },
],
},
],
},
}
end

it { is_expected.to be false }
end
end

describe ".has_add_another_answer?" do
Expand Down
Loading