# frozen_string_literal: true require 'quby/answers/services/filters_answer_value' require 'quby/answers/services/outcome_calculation' module Quby module Answers module Services class UpdatesAnswers attr_reader :answer def initialize(answer) @answer = answer end def update(new_attributes = {}) save_raw_params_on_error(new_attributes) do attribute_filter = FiltersAnswerValue.new(answer.questionnaire) attribute_filter.filter(new_attributes).each { |name, value| answer.send("#{name}=", value) } answer.extend AnswerValidations answer.cleanup_input answer.validate_answers if answer.errors.empty? if new_attributes["rendered_at"].present? started_at = Time.at(new_attributes["rendered_at"].to_i) else started_at = nil end answer.mark_completed(started_at) answer.outcome = OutcomeCalculation.new(answer).calculate Quby.answers.update!(answer) succeed! else if defined?(::Roqua::Support) # We know that Quby v1 does not run client-side validations when the "Toch opslaan" # button is clicked. So if the answer is aborted, this is likely due to the user # ignoring/overlooking error messages other than the requires-answer validations that the # "Toch opslaan" button is designed to bypass. # # Since we know this is a current shortcoming of Quby v1 that's not likely to be fixed, # for now there's no point in sending these client-server validation mismatches # to AppSignal. unless answer.aborted ::Roqua::Support::Errors.report(Quby::ValidationError.new(answer.errors.full_messages)) end end fail! end end end def on_success(&block) @success_callback = block end def on_failure(&block) @failure_callback = block end protected def save_raw_params_on_error(new_attributes) if new_attributes.respond_to?(:to_unsafe_h) answer.raw_params = new_attributes.to_unsafe_h else answer.raw_params = new_attributes end backup_answer = answer.clone yield rescue # we dont save answer since it probably has a weird state now, instead we save the a clone of answer # that just has the raw_params set on it, so we can do data recovery with the raw_params backup_answer.raw_params['could_not_update_at'] = DateTime.now.to_i # to note this is was a failed update Quby.answers.update!(backup_answer) raise end def succeed! @success_callback.call if @success_callback end def fail! @failure_callback.call if @failure_callback end end end end end