From 990e4020e9cecf1fed662b2d7fe38e369edf9ae8 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Sun, 17 Dec 2023 18:39:10 +0200 Subject: [PATCH] add submitter update endpoint --- app/controllers/api/submissions_controller.rb | 50 +------------ app/controllers/api/submitters_controller.rb | 74 +++++++++++++++++++ config/routes.rb | 2 +- lib/submissions/create_from_submitters.rb | 6 +- .../generate_result_attachments.rb | 2 +- lib/submissions/normalize_param_utils.rb | 61 +++++++++++++++ lib/submitters/normalize_values.rb | 40 ++++++---- 7 files changed, 171 insertions(+), 64 deletions(-) create mode 100644 lib/submissions/normalize_param_utils.rb diff --git a/app/controllers/api/submissions_controller.rb b/app/controllers/api/submissions_controller.rb index 8a512c38..3bb3ab88 100644 --- a/app/controllers/api/submissions_controller.rb +++ b/app/controllers/api/submissions_controller.rb @@ -85,7 +85,8 @@ module Api emails:, params:) else - submissions_attrs, attachments = normalize_submissions_params!(submissions_params, template) + submissions_attrs, attachments = + Submissions::NormalizeParamUtils.normalize_submissions_params!(submissions_params, template) submissions = Submissions.create_from_submitters( template:, @@ -97,7 +98,8 @@ module Api params: ) - save_default_value_attachments!(attachments, submissions.flat_map(&:submitters)) + Submissions::NormalizeParamUtils.save_default_value_attachments!(attachments, + submissions.flat_map(&:submitters)) submissions end @@ -133,49 +135,5 @@ module Api ] ).fetch(key, []) end - - def normalize_submissions_params!(submissions_params, template) - attachments = [] - - Array.wrap(submissions_params).each do |submission| - submission[:submitters].each_with_index do |submitter, index| - default_values = submitter[:values] || {} - - submitter[:fields]&.each { |f| default_values[f[:name]] = f[:default_value] if f[:default_value].present? } - - next if default_values.blank? - - values, new_attachments = - Submitters::NormalizeValues.call(template, - default_values, - submitter[:role] || template.submitters[index]['name'], - throw_errors: true) - - attachments.push(*new_attachments) - - submitter[:values] = values - end - end - - [submissions_params, attachments] - end - - def save_default_value_attachments!(attachments, submitters) - return if attachments.blank? - - attachments_index = attachments.index_by(&:uuid) - - submitters.each do |submitter| - submitter.values.to_a.each do |_, value| - attachment = attachments_index[value] - - next unless attachment - - attachment.record = submitter - - attachment.save! - end - end - end end end diff --git a/app/controllers/api/submitters_controller.rb b/app/controllers/api/submitters_controller.rb index a0abb9c8..dec241ba 100644 --- a/app/controllers/api/submitters_controller.rb +++ b/app/controllers/api/submitters_controller.rb @@ -30,5 +30,79 @@ module Api render json: Submitters::SerializeForApi.call(@submitter, with_template: true, with_events: true) end + + def update + if @submitter.completed_at? + return render json: { error: 'Submitter has already completed the submission.' }, status: :unprocessable_entity + end + + role = @submitter.submission.template_submitters.find { |e| e['uuid'] == @submitter.uuid }['name'] + + normalized_params, new_attachments = + Submissions::NormalizeParamUtils.normalize_submitter_params!(submitter_params.merge(role:), @submitter.template, + for_submitter: @submitter) + + Submissions::CreateFromSubmitters.maybe_set_template_fields(@submitter.submission, + [normalized_params], + submitter_uuid: @submitter.uuid) + + assign_submitter_attrs(@submitter, normalized_params) + + ApplicationRecord.transaction do + Submissions::NormalizeParamUtils.save_default_value_attachments!(new_attachments, [@submitter]) + + @submitter.save! + + @submitter.submission.save! + end + + if @submitter.completed_at? + ProcessSubmitterCompletionJob.perform_later(@submitter) + elsif normalized_params[:send_email] || normalized_params[:send_sms] + Submitters.send_signature_requests([@submitter]) + end + + render json: Submitters::SerializeForApi.call(@submitter, with_template: false, with_events: false) + end + + def submitter_params + submitter_params = params.key?(:submitter) ? params.require(:submitter) : params + + submitter_params.permit( + :send_email, :send_sms, :uuid, :name, :email, :role, :completed, :phone, :application_key, + { values: {}, readonly_fields: [], message: %i[subject body], + fields: [%i[name default_value readonly validation_pattern invalid_message]] } + ) + end + + private + + def assign_submitter_attrs(submitter, attrs) + submitter.email = Submissions.normalize_email(attrs[:email]) if attrs.key?(:email) + submitter.phone = attrs[:phone].to_s.gsub(/[^0-9+]/, '') if attrs.key?(:phone) + submitter.values = submitter.values.merge(attrs[:values].to_unsafe_h) if attrs[:values] + submitter.completed_at = attrs[:completed] ? Time.current : submitter.completed_at + submitter.application_key = attrs[:application_key] if attrs.key?(:application_key) + + assign_preferences(submitter, attrs) + + submitter + end + + def assign_preferences(submitter, attrs) + submitter_preferences = Submitters.normalize_preferences(submitter.account, current_user, attrs) + + if submitter_preferences.key?('send_email') + submitter.preferences['send_email'] = submitter_preferences['send_email'] + end + + submitter.preferences['send_sms'] = submitter_preferences['send_sms'] if submitter_preferences.key?('send_sms') + + return unless submitter_preferences.key?('email_message_uuid') + + submitter.preferences['email_message_uuid'] = submitter_preferences['email_message_uuid'] + + submitter + end end end diff --git a/config/routes.rb b/config/routes.rb index 2cd89c48..07902b4a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -35,7 +35,7 @@ Rails.application.routes.draw do resources :template_folders_autocomplete, only: %i[index] resources :submitter_email_clicks, only: %i[create] resources :submitter_form_views, only: %i[create] - resources :submitters, only: %i[index show] + resources :submitters, only: %i[index show update] resources :submissions, only: %i[index show create destroy] do collection do resources :emails, only: %i[create], controller: 'submissions', as: :submissions_emails diff --git a/lib/submissions/create_from_submitters.rb b/lib/submissions/create_from_submitters.rb index 7e822100..6863f35d 100644 --- a/lib/submissions/create_from_submitters.rb +++ b/lib/submissions/create_from_submitters.rb @@ -39,11 +39,11 @@ module Submissions end end - def maybe_set_template_fields(submission, submitters_attrs) - template_fields = submission.template.fields.deep_dup + def maybe_set_template_fields(submission, submitters_attrs, submitter_uuid: nil) + template_fields = (submission.template_fields || submission.template.fields).deep_dup submitters_attrs.each_with_index do |submitter_attrs, index| - submitter_uuid = find_submitter_uuid(submission.template, submitter_attrs, index) + submitter_uuid ||= find_submitter_uuid(submission.template, submitter_attrs, index) process_readonly_fields_param(submitter_attrs[:readonly_fields], template_fields, submitter_uuid) diff --git a/lib/submissions/generate_result_attachments.rb b/lib/submissions/generate_result_attachments.rb index 5015112b..42eb8550 100644 --- a/lib/submissions/generate_result_attachments.rb +++ b/lib/submissions/generate_result_attachments.rb @@ -268,7 +268,7 @@ module Submissions Submissions::EnsureResultGenerated.call(latest_submitter) if latest_submitter documents = latest_submitter&.documents&.preload(:blob).to_a.presence - documents ||= submitter.submission.template.documents.preload(:blob) + documents ||= submitter.submission.template.schema_documents.preload(:blob) documents.to_h do |attachment| pdf = diff --git a/lib/submissions/normalize_param_utils.rb b/lib/submissions/normalize_param_utils.rb new file mode 100644 index 00000000..8d4a4172 --- /dev/null +++ b/lib/submissions/normalize_param_utils.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +module Submissions + module NormalizeParamUtils + module_function + + def normalize_submissions_params!(submissions_params, template) + attachments = [] + + Array.wrap(submissions_params).each do |submission| + submission[:submitters].each_with_index do |submitter, index| + _, new_attachments = normalize_submitter_params!(submitter, template, index) + + attachments.push(*new_attachments) + end + end + + [submissions_params, attachments] + end + + def normalize_submitter_params!(submitter_params, template, index = nil, for_submitter: nil) + default_values = submitter_params[:values] || {} + + submitter_params[:fields]&.each do |f| + default_values[f[:name]] = f[:default_value] if f[:default_value].present? + end + + return submitter_params if default_values.blank? + + values, new_attachments = + Submitters::NormalizeValues.call(template, + default_values, + submitter_name: submitter_params[:role] || + template.submitters.dig(index, 'name'), + for_submitter:, + throw_errors: true) + + submitter_params[:values] = values + + [submitter_params, new_attachments] + end + + def save_default_value_attachments!(attachments, submitters) + return if attachments.blank? + + attachments_index = attachments.index_by(&:uuid) + + submitters.each do |submitter| + submitter.values.to_a.each do |_, value| + attachment = attachments_index[value] + + next unless attachment + + attachment.record = submitter + + attachment.save! + end + end + end + end +end diff --git a/lib/submitters/normalize_values.rb b/lib/submitters/normalize_values.rb index a5ba6f81..4a4a916d 100644 --- a/lib/submitters/normalize_values.rb +++ b/lib/submitters/normalize_values.rb @@ -9,12 +9,8 @@ module Submitters module_function - def call(template, values, submitter_name, throw_errors: false) - submitter = - template.submitters.find { |e| e['name'] == submitter_name } || - raise(UnknownSubmitterName, "Unknown submitter: #{submitter_name}") - - fields = template.fields.select { |e| e['submitter_uuid'] == submitter['uuid'] } + def call(template, values, submitter_name: nil, for_submitter: nil, throw_errors: false) + fields = fetch_fields(template, submitter_name:, for_submitter:) fields_uuid_index = fields.index_by { |e| e['uuid'] } fields_name_index = build_fields_index(fields) @@ -31,7 +27,7 @@ module Submitters next if key.blank? if fields_uuid_index[key]['type'].in?(%w[initials signature image file]) - new_value, new_attachments = normalize_attachment_value(value, template.account) + new_value, new_attachments = normalize_attachment_value(value, template.account, for_submitter) attachments.push(*new_attachments) @@ -44,27 +40,45 @@ module Submitters [normalized_values, attachments] end + def fetch_fields(template, submitter_name: nil, for_submitter: nil) + if submitter_name + submitter = + template.submitters.find { |e| e['name'] == submitter_name } || + raise(UnknownSubmitterName, "Unknown submitter: #{submitter_name}") + end + + fields = for_submitter&.submission&.template_fields || template.fields + + fields.select { |e| e['submitter_uuid'] == (for_submitter&.uuid || submitter['uuid']) } + end + def build_fields_index(fields) fields.index_by { |e| e['name'] }.merge(fields.index_by { |e| e['name'].to_s.parameterize.underscore }) end - def normalize_attachment_value(value, account) + def normalize_attachment_value(value, account, for_submitter = nil) if value.is_a?(Array) - new_attachments = value.map { |v| build_attachment(v, account) } + new_attachments = value.map { |v| find_or_build_attachment(v, account, for_submitter) } [new_attachments.map(&:uuid), new_attachments] else - new_attachment = build_attachment(value, account) + new_attachment = find_or_build_attachment(value, account, for_submitter) [new_attachment.uuid, new_attachment] end end - def build_attachment(value, account) - ActiveStorage::Attachment.new( - blob: find_or_create_blobs(account, value), + def find_or_build_attachment(value, account, for_submitter = nil) + blob = find_or_create_blobs(account, value) + + attachment = for_submitter.attachments.find_by(blob_id: blob.id) if for_submitter + + attachment ||= ActiveStorage::Attachment.new( + blob:, name: 'attachments' ) + + attachment end def find_or_create_blobs(account, url)