From a1fb38b8cb490f4f2540ad3b604e3e18de68ff33 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Tue, 18 Feb 2025 10:40:41 +0200 Subject: [PATCH 1/8] add email variables --- lib/replace_email_variables.rb | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/lib/replace_email_variables.rb b/lib/replace_email_variables.rb index 430b5757..a78cedf9 100644 --- a/lib/replace_email_variables.rb +++ b/lib/replace_email_variables.rb @@ -15,7 +15,10 @@ module ReplaceEmailVariables SUBMITTER_SLUG = /\{+submitter\.slug\}+/i SUBMISSION_LINK = /\{+submission\.link\}+/i SUBMISSION_ID = /\{+submission\.id\}+/i - SUBMISSION_SUBMITTERS = /\{+submission\.submitters\}+/i + SUBMITTERS = /\{+(?:submission\.)?submitters\}+/i + SUBMITTERS_N_EMAIL = /\{+submitters\[(?\d+)\]\.email\}+/i + SUBMITTERS_N_NAME = /\{+submitters\[(?\d+)\]\.name\}+/i + SUBMITTERS_N_FIRST_NAME = /\{+submitters\[(?\d+)\]\.first_name\}+/i DOCUMENTS_LINKS = /\{+documents\.links\}+/i DOCUMENTS_LINK = /\{+documents\.link\}+/i @@ -37,13 +40,25 @@ module ReplaceEmailVariables text = replace(text, SUBMISSION_LINK, html_escape:) do submitter.submission ? build_submission_link(submitter.submission) : '' end - text = replace(text, SUBMISSION_SUBMITTERS, html_escape:) { build_submission_submitters(submitter.submission) } + text = replace(text, SUBMITTERS, html_escape:) { build_submission_submitters(submitter.submission) } text = replace(text, DOCUMENTS_LINKS, html_escape:) { build_documents_links_text(submitter, sig) } text = replace(text, DOCUMENTS_LINK, html_escape:) { build_documents_links_text(submitter, sig) } text = replace(text, ACCOUNT_NAME, html_escape:) { submitter.submission.account.name } text = replace(text, SENDER_NAME, html_escape:) { submitter.submission.created_by_user&.full_name } text = replace(text, SENDER_FIRST_NAME, html_escape:) { submitter.submission.created_by_user&.first_name } + text = replace(text, SUBMITTERS_N_NAME, html_escape:) do |match| + build_submitters_n_field(submitter.submission, match[:index].to_i - 1, :name) + end + + text = replace(text, SUBMITTERS_N_EMAIL, html_escape:) do |match| + build_submitters_n_field(submitter.submission, match[:index].to_i - 1, :email) + end + + text = replace(text, SUBMITTERS_N_FIRST_NAME, html_escape:) do |match| + build_submitters_n_field(submitter.submission, match[:index].to_i - 1, :first_name) + end + replace(text, SENDER_EMAIL, html_escape:) { submitter.submission.created_by_user&.email.to_s.sub(/\+\w+@/, '@') } end # rubocop:enable Metrics @@ -54,12 +69,18 @@ module ReplaceEmailVariables ) end + def build_submitters_n_field(submission, index, field_name) + uuid = (submission.template_submitters || submission.template.submitters).dig(index, 'uuid') + + submission.submitters.find { |s| s.uuid == uuid }.try(field_name) + end + def replace(text, var, html_escape: false) text.gsub(var) do if html_escape - ERB::Util.html_escape(yield) + ERB::Util.html_escape(yield(Regexp.last_match)) else - yield + yield(Regexp.last_match) end end end From 07ce76537b00a2a32a63e57decd826ed55f32cde Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Tue, 18 Feb 2025 16:50:01 +0200 Subject: [PATCH 2/8] use ubuntu arm --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 2315d2b1..3250e475 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -7,7 +7,7 @@ on: jobs: build: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm steps: - name: Checkout code From 6f3be168266b8cbf90f43f3cb72ebfad0359a901 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Tue, 18 Feb 2025 16:50:48 +0200 Subject: [PATCH 3/8] fix dockerfile --- Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index cfabc332..23fa1ad7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.4.1-alpine as fonts +FROM ruby:3.4.1-alpine AS fonts WORKDIR /fonts @@ -6,7 +6,7 @@ RUN apk --no-cache add fontforge wget && wget https://github.com/satbyy/go-noto- RUN fontforge -lang=py -c 'font1 = fontforge.open("FreeSans.ttf"); font2 = fontforge.open("NotoSansSymbols2-Regular.ttf"); font1.mergeFonts(font2); font1.generate("FreeSans.ttf")' -FROM ruby:3.4.1-alpine as webpack +FROM ruby:3.4.1-alpine AS webpack ENV RAILS_ENV=production ENV NODE_ENV=production @@ -32,7 +32,7 @@ COPY ./app/views ./app/views RUN echo "gem 'shakapacker'" > Gemfile && ./bin/shakapacker -FROM ruby:3.4.1-alpine as app +FROM ruby:3.4.1-alpine AS app ENV RAILS_ENV=production ENV BUNDLE_WITHOUT="development:test" From 3affa6557165d03ab90e24147fb2b17cdd22132d Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Thu, 20 Feb 2025 11:59:29 +0200 Subject: [PATCH 4/8] fix formula condition --- app/controllers/api/submitters_controller.rb | 8 +++++++- app/javascript/submission_form/form.vue | 2 +- lib/submissions/create_from_submitters.rb | 8 +++++++- lib/submitters/submit_values.rb | 14 +++++++++++--- 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/app/controllers/api/submitters_controller.rb b/app/controllers/api/submitters_controller.rb index f85e2f60..1fd06d74 100644 --- a/app/controllers/api/submitters_controller.rb +++ b/app/controllers/api/submitters_controller.rb @@ -146,9 +146,15 @@ module Api if attrs[:completed] submitter.values = Submitters::SubmitValues.merge_default_values(submitter) - submitter.values = Submitters::SubmitValues.merge_formula_values(submitter) submitter.values = Submitters::SubmitValues.maybe_remove_condition_values(submitter) + formula_values = Submitters::SubmitValues.build_formula_values(submitter) + + if formula_values.present? + submitter.values = submitter.values.merge(formula_values) + submitter.values = Submitters::SubmitValues.maybe_remove_condition_values(submitter) + end + submitter.values = submitter.values.transform_values do |v| v == '{{date}}' ? Time.current.in_time_zone(submitter.account.timezone).to_date.to_s : v end diff --git a/app/javascript/submission_form/form.vue b/app/javascript/submission_form/form.vue index b7d17e27..addf7570 100644 --- a/app/javascript/submission_form/form.vue +++ b/app/javascript/submission_form/form.vue @@ -1037,7 +1037,7 @@ export default { }, []) }, formulaFields () { - return this.fields.filter((f) => f.preferences?.formula && f.type !== 'payment') + return this.fields.filter((f) => f.preferences?.formula && f.type !== 'payment' && this.checkFieldConditions(f) && this.checkFieldDocumentsConditions(f)) }, attachmentsIndex () { return this.attachments.reduce((acc, a) => { diff --git a/lib/submissions/create_from_submitters.rb b/lib/submissions/create_from_submitters.rb index c2144ad8..083c3573 100644 --- a/lib/submissions/create_from_submitters.rb +++ b/lib/submissions/create_from_submitters.rb @@ -225,9 +225,15 @@ module Submissions def assign_completed_attributes(submitter) submitter.values = Submitters::SubmitValues.merge_default_values(submitter) - submitter.values = Submitters::SubmitValues.merge_formula_values(submitter) submitter.values = Submitters::SubmitValues.maybe_remove_condition_values(submitter) + formula_values = Submitters::SubmitValues.build_formula_values(submitter) + + if formula_values.present? + submitter.values = submitter.values.merge(formula_values) + submitter.values = Submitters::SubmitValues.maybe_remove_condition_values(submitter) + end + submitter.values = submitter.values.transform_values do |v| v == '{{date}}' ? Time.current.in_time_zone(submitter.submission.account.timezone).to_date.to_s : v end diff --git a/lib/submitters/submit_values.rb b/lib/submitters/submit_values.rb index b23e7005..15f2da02 100644 --- a/lib/submitters/submit_values.rb +++ b/lib/submitters/submit_values.rb @@ -53,9 +53,17 @@ module Submitters submitter.completed_at = Time.current submitter.ip = request.remote_ip submitter.ua = request.user_agent + submitter.values = merge_default_values(submitter) submitter.values = maybe_remove_condition_values(submitter) - submitter.values = merge_formula_values(submitter) + + formula_values = build_formula_values(submitter) + + if formula_values.present? + submitter.values = submitter.values.merge(formula_values) + submitter.values = maybe_remove_condition_values(submitter) + end + submitter.values = submitter.values.transform_values do |v| v == '{{date}}' ? Time.current.in_time_zone(submitter.account.timezone).to_date.to_s : v end @@ -149,7 +157,7 @@ module Submitters default_values.compact_blank.merge(submitter.values) end - def merge_formula_values(submitter) + def build_formula_values(submitter) computed_values = submitter.submission.template_fields.each_with_object({}) do |field, acc| next if field['submitter_uuid'] != submitter.uuid next if field['type'] == 'payment' @@ -161,7 +169,7 @@ module Submitters acc[field['uuid']] = calculate_formula_value(formula, submitter.values.merge(acc.compact_blank)) end - submitter.values.merge(computed_values.compact_blank) + computed_values.compact_blank end def calculate_formula_value(_formula, _values) From f2306b334b8028c0c8864d70be048ec90db51a7b Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Thu, 20 Feb 2025 13:02:58 +0200 Subject: [PATCH 5/8] update gem --- Gemfile.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index de6e71b3..d223af2a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -337,18 +337,18 @@ GEM net-smtp (0.5.0) net-protocol nio4r (2.7.4) - nokogiri (1.18.2) + nokogiri (1.18.3) mini_portile2 (~> 2.8.2) racc (~> 1.4) - nokogiri (1.18.2-aarch64-linux-gnu) + nokogiri (1.18.3-aarch64-linux-gnu) racc (~> 1.4) - nokogiri (1.18.2-aarch64-linux-musl) + nokogiri (1.18.3-aarch64-linux-musl) racc (~> 1.4) - nokogiri (1.18.2-arm64-darwin) + nokogiri (1.18.3-arm64-darwin) racc (~> 1.4) - nokogiri (1.18.2-x86_64-linux-gnu) + nokogiri (1.18.3-x86_64-linux-gnu) racc (~> 1.4) - nokogiri (1.18.2-x86_64-linux-musl) + nokogiri (1.18.3-x86_64-linux-musl) racc (~> 1.4) oj (3.16.8) bigdecimal (>= 3.0) From 47b3a2d09e3335d82c82ab4c818ddfa52a33c174 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Fri, 21 Feb 2025 21:24:27 +0200 Subject: [PATCH 6/8] multiple recipient emails --- app/views/templates_preferences/show.html.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/templates_preferences/show.html.erb b/app/views/templates_preferences/show.html.erb index 54532ad0..12c020b1 100644 --- a/app/views/templates_preferences/show.html.erb +++ b/app/views/templates_preferences/show.html.erb @@ -285,12 +285,12 @@
<%= ff.text_field :name, class: 'w-full outline-none border-transparent focus:border-transparent focus:ring-0 bg-base-100 px-1 peer mb-2', autocomplete: 'off', placeholder: "#{index + 1}#{(index + 1).ordinal} Party", required: true %> <% if @template.submitters.size == 2 %> - <%= ff.email_field :email, class: 'base-input', autocomplete: 'off', placeholder: t('default_email'), disabled: ff.object.is_requester || ff.object.invite_by_uuid.present? || ff.object.optional_invite_by_uuid.present?, id: field_uuid = SecureRandom.uuid %> + <%= tag.input name: ff.field_name(:email), value: ff.object.email, type: :email, class: 'base-input', multiple: true, autocomplete: 'off', placeholder: t('default_email'), disabled: ff.object.is_requester || ff.object.invite_by_uuid.present? || ff.object.optional_invite_by_uuid.present?, id: field_uuid = SecureRandom.uuid %> <% else %> <%= ff.select :option, [[t('not_specified'), 'not_set'], [t('submission_requester'), 'is_requester'], [t('specified_email'), 'email'], *(@template.submitters - [submitter]).flat_map { |e| [[t('invite_by_name', name: e['name']), "invite_by_#{e['uuid']}"], [t('invite_by_name', name: e['name']) + " (#{t(:optional).capitalize})", "optional_invite_by_#{e['uuid']}"]] }, *(@template.submitters - [submitter]).map { |e| [t('same_as_name', name: e['name']), "linked_to_#{e['uuid']}"] }], {}, class: 'base-select mb-3' %> - <%= ff.email_field :email, class: "base-input #{'hidden' if item.option != 'email'}", autocomplete: 'off', placeholder: t('default_email'), id: email_field_uuid %> + <%= tag.input name: ff.field_name(:email), type: :email, value: ff.object.email, multiple: true, class: "base-input #{'hidden' if item.option != 'email'}", autocomplete: 'off', placeholder: t('default_email'), id: email_field_uuid %> <% end %>
<% if @template.submitters.size == 2 %> From 146b37f8cd88f669a08f7a853724e68ea76be7d8 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Fri, 21 Feb 2025 22:21:31 +0200 Subject: [PATCH 7/8] fix clone --- lib/templates/clone.rb | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/templates/clone.rb b/lib/templates/clone.rb index 6210354d..2c15858f 100644 --- a/lib/templates/clone.rb +++ b/lib/templates/clone.rb @@ -9,7 +9,6 @@ module Templates template.external_id = external_id template.author = author - template.preferences = original_template.preferences.deep_dup template.name = name.presence || "#{original_template.name} (#{I18n.t('clone')})" if folder_name.present? @@ -18,10 +17,11 @@ module Templates template.folder_id = original_template.folder_id end - template.submitters, template.fields, template.schema = + template.submitters, template.fields, template.schema, template.preferences = update_submitters_and_fields_and_schema(original_template.submitters.deep_dup, original_template.fields.deep_dup, - original_template.schema.deep_dup) + original_template.schema.deep_dup, + original_template.preferences.deep_dup) if name.present? && template.schema.size == 1 && original_template.schema.first['name'] == original_template.name && @@ -33,7 +33,7 @@ module Templates end # rubocop:disable Metrics, Style/CombinableLoops - def update_submitters_and_fields_and_schema(cloned_submitters, cloned_fields, cloned_schema) + def update_submitters_and_fields_and_schema(cloned_submitters, cloned_fields, cloned_schema, cloned_preferences) submitter_uuids_replacements = {} field_uuids_replacements = {} @@ -58,6 +58,10 @@ module Templates end end + cloned_preferences['submitters'].to_a.each do |submitter| + submitter['uuid'] = submitter_uuids_replacements[submitter['uuid']] + end + cloned_fields.each do |field| new_field_uuid = SecureRandom.uuid @@ -88,7 +92,7 @@ module Templates end end - [cloned_submitters, cloned_fields, cloned_schema] + [cloned_submitters, cloned_fields, cloned_schema, cloned_preferences] end # rubocop:enable Metrics, Style/CombinableLoops end From 5032676bd2fff1d3f67668974e9861b0ac0025ae Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Mon, 24 Feb 2025 13:24:16 +0200 Subject: [PATCH 8/8] fix url download --- lib/download_utils.rb | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/download_utils.rb b/lib/download_utils.rb index 3fc32950..78316b80 100644 --- a/lib/download_utils.rb +++ b/lib/download_utils.rb @@ -8,19 +8,20 @@ module DownloadUtils module_function def call(url) - uri = Addressable::URI.parse(url) + uri = begin + URI(url) + rescue URI::Error + Addressable::URI.parse(url).normalize + end if Docuseal.multitenant? - raise UnableToDownload, "Error loading: #{uri.display_uri}. Only HTTPS is allowed." if uri.scheme != 'https' - - if uri.host.in?(LOCALHOSTS) - raise UnableToDownload, "Error loading: #{uri.display_uri}. Can't download from localhost." - end + raise UnableToDownload, "Error loading: #{uri}. Only HTTPS is allowed." if uri.scheme != 'https' + raise UnableToDownload, "Error loading: #{uri}. Can't download from localhost." if uri.host.in?(LOCALHOSTS) end - resp = conn.get(uri.display_uri.to_s) + resp = conn.get(uri) - raise UnableToDownload, "Error loading: #{uri.display_uri}" if resp.status >= 400 + raise UnableToDownload, "Error loading: #{uri}" if resp.status >= 400 resp end