From f00d01c50f4f76ea0a9cc68e9b39b0636df9beb6 Mon Sep 17 00:00:00 2001 From: Faizaan Gagan Date: Mon, 2 Aug 2021 13:01:49 +0530 Subject: [PATCH] FIX: ensure single incomplete submission existence (#136) * created method to fetch incomplete submissions * added new field 'updated_at' to submission schema * Revert "created method to fetch incomplete submissions" This reverts commit 15c65236e7cb6310be827e187e2a041d37090ea8. * added logic to cleanup redundant incomplete submissions * logic improvements and spec * simplified the cleanup logic * simplified the logic further * early return to improve performance * consolidated cleanup logic * perform cleanup in wizard.update * fixed issue * minor fix * use consistent naming --- lib/custom_wizard/builder.rb | 1 + lib/custom_wizard/submission.rb | 26 ++++++++++- .../custom_wizard/submission_spec.rb | 46 +++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/lib/custom_wizard/builder.rb b/lib/custom_wizard/builder.rb index 51ca4183..aede16a2 100644 --- a/lib/custom_wizard/builder.rb +++ b/lib/custom_wizard/builder.rb @@ -75,6 +75,7 @@ class CustomWizard::Builder end @wizard.update! + CustomWizard::Submission.cleanup_incomplete_submissions(@wizard) @wizard end diff --git a/lib/custom_wizard/submission.rb b/lib/custom_wizard/submission.rb index e50cb259..e12299d1 100644 --- a/lib/custom_wizard/submission.rb +++ b/lib/custom_wizard/submission.rb @@ -3,7 +3,7 @@ class CustomWizard::Submission include ActiveModel::SerializerSupport KEY ||= "submissions" - META ||= %w(submitted_at route_to redirect_on_complete redirect_to) + META ||= %w(updated_at submitted_at route_to redirect_on_complete redirect_to) attr_reader :id, :user, @@ -45,6 +45,7 @@ class CustomWizard::Submission submission_list = self.class.list(wizard, user_id: user.id) submissions = submission_list.select { |submission| submission.id != self.id } + self.updated_at = Time.now.iso8601 submissions.push(self) submission_data = submissions.map { |submission| data_to_save(submission) } @@ -96,6 +97,29 @@ class CustomWizard::Submission new(wizard, data, user_id) end + def self.cleanup_incomplete_submissions(wizard) + user_id = wizard.user.id + all_submissions = list(wizard, user_id: user_id) + sorted_submissions = all_submissions.sort_by do |submission| + zero_epoch_time = DateTime.strptime("0", '%s') + [ + submission.submitted_at ? Time.iso8601(submission.submitted_at) : zero_epoch_time, + submission.updated_at ? Time.iso8601(submission.updated_at) : zero_epoch_time + ] + end.reverse + + has_incomplete = false + valid_submissions = sorted_submissions.select do |submission| + to_be_included = submission.submitted_at || !has_incomplete + has_incomplete = true if !submission.submitted_at + + to_be_included + end + + valid_data = valid_submissions.map { |submission| submission.data_to_save(submission) } + PluginStore.set("#{wizard.id}_#{KEY}", user_id, valid_data) + end + def self.list(wizard, user_id: nil, order_by: nil) params = { plugin_name: "#{wizard.id}_#{KEY}" } params[:key] = user_id if user_id.present? diff --git a/spec/components/custom_wizard/submission_spec.rb b/spec/components/custom_wizard/submission_spec.rb index a8c33861..b85af243 100644 --- a/spec/components/custom_wizard/submission_spec.rb +++ b/spec/components/custom_wizard/submission_spec.rb @@ -40,4 +40,50 @@ describe CustomWizard::Submission do it "list submissions by wizard and user" do expect(described_class.list(@wizard, user_id: user.id).size).to eq(1) end + + context "#cleanup_incomplete_submissions" do + it "cleans up redundant incomplete submissions on each build" do + freeze_time Time.now + 1 + described_class.new(@wizard, step_1_field_1: "I am the second submission").save + builder = CustomWizard::Builder.new(@wizard.id, @wizard.user) + builder.build + sub_list = described_class.list(@wizard, user_id: @wizard.user.id) + + expect(sub_list.length).to eq(1) + expect(sub_list.first.fields["step_1_field_1"]).to eq("I am the second submission") + end + + it "handles submissions without 'updated_at' field correctly" do + described_class.new(@wizard, step_1_field_1: "I am the second submission").save + described_class.new(@wizard, step_1_field_1: "I am the third submission").save + sub_data = PluginStore.get("#{@wizard.id}_submissions", @wizard.user.id) + sub_data.each do |sub| + sub['updated_at'] = nil + end + PluginStore.set("#{@wizard.id}_submissions", @wizard.user.id, sub_data) + builder = CustomWizard::Builder.new(@wizard.id, @wizard.user) + builder.build + sub_list = described_class.list(@wizard, user_id: @wizard.user.id) + + expect(sub_list.length).to eq(1) + expect(sub_list.first.fields["step_1_field_1"]).to eq("I am the third submission") + end + + it "handles submissions with and without 'updated_at' field correctly" do + freeze_time Time.now + 1 + described_class.new(@wizard, step_1_field_1: "I am the second submission").save + freeze_time Time.now + 2 + described_class.new(@wizard, step_1_field_1: "I am the third submission").save + sub_data = PluginStore.get("#{@wizard.id}_submissions", @wizard.user.id) + sub_data[0]['updated_at'] = nil + PluginStore.set("#{@wizard.id}_submissions", @wizard.user.id, sub_data) + + builder = CustomWizard::Builder.new(@wizard.id, @wizard.user) + builder.build + sub_list = described_class.list(@wizard, user_id: @wizard.user.id) + + expect(sub_list.length).to eq(1) + expect(sub_list.first.fields["step_1_field_1"]).to eq("I am the third submission") + end + end end