From 8cb74e0bcc5d4e3bf8ec8afd26647258808ffbbd Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Mon, 28 Jul 2025 16:55:21 +0300 Subject: [PATCH 1/9] fix build --- .github/workflows/docker.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index c2c317e5..0b6c25f9 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -12,10 +12,15 @@ on: type: string required: false default: tonistiigi/binfmt:latest + os: + description: OS + type: string + required: false + default: ubuntu-24.04-arm jobs: build: - runs-on: ubuntu-24.04-arm + runs-on: ${{ inputs.os }} timeout-minutes: 20 steps: @@ -29,7 +34,7 @@ jobs: uses: docker/metadata-action@v4 with: images: docuseal/docuseal - tags: type=semver,pattern={{version}} + tags: latest,${{ inputs.version }} - name: Set up QEMU uses: docker/setup-qemu-action@v3 From 8d3295e1251ef753a33bb6e255c5f90a6d06a932 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Tue, 29 Jul 2025 12:14:26 +0300 Subject: [PATCH 2/9] better signature validation --- app/controllers/api/attachments_controller.rb | 17 ++++++++++++++--- lib/image_utils.rb | 8 ++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/app/controllers/api/attachments_controller.rb b/app/controllers/api/attachments_controller.rb index 37e827b5..dca89f67 100644 --- a/app/controllers/api/attachments_controller.rb +++ b/app/controllers/api/attachments_controller.rb @@ -10,10 +10,21 @@ module Api def create submitter = Submitter.find_by!(slug: params[:submitter_slug]) - if params[:type].in?(%w[initials signature]) && ImageUtils.blank?(Vips::Image.new_from_file(params[:file].path)) - Rollbar.error("Empty signature: #{submitter.id}") if defined?(Rollbar) + if params[:type].in?(%w[initials signature]) + image = Vips::Image.new_from_file(params[:file].path) - return render json: { error: "#{params[:type]} is empty" }, status: :unprocessable_entity + if ImageUtils.blank?(image) + Rollbar.error("Empty signature: #{submitter.id}") if defined?(Rollbar) + + return render json: { error: "#{params[:type]} is empty" }, status: :unprocessable_entity + end + + if ImageUtils.error?(image) + Rollbar.error("Error signature: #{submitter.id}") if defined?(Rollbar) + + return render json: { error: "#{params[:type]} error, try to sign on another device" }, + status: :unprocessable_entity + end end attachment = Submitters.create_attachment!(submitter, params) diff --git a/lib/image_utils.rb b/lib/image_utils.rb index d29fc8f9..8e7aa094 100644 --- a/lib/image_utils.rb +++ b/lib/image_utils.rb @@ -14,4 +14,12 @@ module ImageUtils false end + + def error?(image) + image = image.crop(0, 0, image.width / 4, 2) + + row1, row2 = image.to_a + + row1[3..] == row2[..-4] && row1.each_cons(2).none? { |a, b| a == b } + end end From 676b330aa3354e6fc3cc5fee1c2c2d3621655f64 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Tue, 29 Jul 2025 16:15:55 +0300 Subject: [PATCH 3/9] add submitters order param --- app/controllers/api/submissions_controller.rb | 2 +- app/jobs/process_submitter_completion_job.rb | 31 +++++++++++++------ lib/params/submission_create_validator.rb | 1 + lib/submissions.rb | 18 ++++++++--- lib/submissions/create_from_submitters.rb | 7 +++-- lib/submitters.rb | 19 +++++++++--- 6 files changed, 56 insertions(+), 22 deletions(-) diff --git a/app/controllers/api/submissions_controller.rb b/app/controllers/api/submissions_controller.rb index 77751066..f75d7299 100644 --- a/app/controllers/api/submissions_controller.rb +++ b/app/controllers/api/submissions_controller.rb @@ -185,7 +185,7 @@ module Api message: %i[subject body], submitters: [[:send_email, :send_sms, :completed_redirect_url, :uuid, :name, :email, :role, :completed, :phone, :application_key, :external_id, :reply_to, :go_to_last, - :require_phone_2fa, + :require_phone_2fa, :order, { metadata: {}, values: {}, roles: [], readonly_fields: [], message: %i[subject body], fields: [:name, :uuid, :default_value, :value, :title, :description, :readonly, :required, :validation_pattern, :invalid_message, diff --git a/app/jobs/process_submitter_completion_job.rb b/app/jobs/process_submitter_completion_job.rb index e8380a44..647aab5f 100644 --- a/app/jobs/process_submitter_completion_job.rb +++ b/app/jobs/process_submitter_completion_job.rb @@ -135,19 +135,32 @@ class ProcessSubmitterCompletionJob end def enqueue_next_submitter_request_notification(submitter) - next_submitter_item = - submitter.submission.template_submitters.find do |e| - sub = submitter.submission.submitters.find { |s| s.uuid == e['uuid'] } + submission = submitter.submission + submitters_index = submission.submitters.index_by(&:uuid) - next unless sub + next_submitter_items = + if submission.template_submitters.any? { |s| s['order'] } + submitter_groups = + submission.template_submitters.group_by.with_index { |s, index| s['order'] || index } - sub.completed_at.blank? && sub.sent_at.blank? - end + current_group_index = submitter_groups.find { |_, group| group.any? { |s| s['uuid'] == submitter.uuid } }&.first + + if submitter_groups[current_group_index + 1] && + submitters_index.values_at(*submitter_groups[current_group_index].pluck('uuid')).all?(&:completed_at?) + submitter_groups[current_group_index + 1] + end + else + submission.template_submitters.find do |e| + sub = submitters_index[e['uuid']] - return unless next_submitter_item + next unless sub + + sub.completed_at.blank? && sub.sent_at.blank? + end + end - next_submitter = submitter.submission.submitters.find { |s| s.uuid == next_submitter_item['uuid'] } + next_submitters = submitters_index.values_at(*Array.wrap(next_submitter_items).pluck('uuid')) - Submitters.send_signature_requests([next_submitter]) + Submitters.send_signature_requests(next_submitters) end end diff --git a/lib/params/submission_create_validator.rb b/lib/params/submission_create_validator.rb index 5737e1dd..8ce3becf 100644 --- a/lib/params/submission_create_validator.rb +++ b/lib/params/submission_create_validator.rb @@ -76,6 +76,7 @@ module Params type(submitter_params, :name, String) type(submitter_params, :reply_to, String) type(submitter_params, :email, String) + type(submitter_params, :order, Integer) email_format(submitter_params, :email, message: 'email is invalid') email_format(submitter_params, :reply_to, message: 'reply_to email is invalid') type(submitter_params, :phone, String) diff --git a/lib/submissions.rb b/lib/submissions.rb index e8085169..2870fb01 100644 --- a/lib/submissions.rb +++ b/lib/submissions.rb @@ -142,15 +142,23 @@ module Submissions submissions.each_with_index do |submission, index| delay_seconds = (delay + index).seconds if delay - submitters = submission.submitters.reject(&:completed_at?) + template_submitters = submission.template_submitters + submitters_index = submission.submitters.reject(&:completed_at?).index_by(&:uuid) - if submission.submitters_order_preserved? - first_submitter = - submission.template_submitters.filter_map { |s| submitters.find { |e| e.uuid == s['uuid'] } }.first + if template_submitters.any? { |s| s['order'] } + min_order = template_submitters.map.with_index { |s, i| s['order'] || i }.min + + first_submitters = template_submitters.filter_map do |s| + submitters_index[s['uuid']] if s['order'] == min_order + end + + Submitters.send_signature_requests(first_submitters, delay_seconds:) + elsif submission.submitters_order_preserved? + first_submitter = template_submitters.filter_map { |s| submitters_index[s['uuid']] }.first Submitters.send_signature_requests([first_submitter], delay_seconds:) if first_submitter else - Submitters.send_signature_requests(submitters, delay_seconds:) + Submitters.send_signature_requests(submitters_index.values, delay_seconds:) end end end diff --git a/lib/submissions/create_from_submitters.rb b/lib/submissions/create_from_submitters.rb index 4ad407df..f90720bb 100644 --- a/lib/submissions/create_from_submitters.rb +++ b/lib/submissions/create_from_submitters.rb @@ -52,9 +52,12 @@ module Submissions template_submitter = template_submitters.find { |e| e['uuid'] == uuid } end - submission.template_submitters << template_submitter.except('optional_invite_by_uuid', 'invite_by_uuid') + template_submitter = template_submitter.except('optional_invite_by_uuid', 'invite_by_uuid') + template_submitter['order'] = submitter_attrs['order'] if submitter_attrs['order'].present? - is_order_sent = submitters_order == 'random' || index.zero? + submission.template_submitters << template_submitter + + is_order_sent = submitters_order == 'random' || (template_submitter['order'] || index).zero? build_submitter(submission:, attrs: submitter_attrs, uuid:, is_order_sent:, user:, params:, diff --git a/lib/submitters.rb b/lib/submitters.rb index 8e7fd137..2e04b7b3 100644 --- a/lib/submitters.rb +++ b/lib/submitters.rb @@ -162,13 +162,22 @@ module Submitters end def current_submitter_order?(submitter) - submitter_items = submitter.submission.template_submitters || submitter.submission.template.submitters + submission = submitter.submission - before_items = submitter_items[0...(submitter_items.find_index { |e| e['uuid'] == submitter.uuid })] + submitter_items = submission.template_submitters || submission.template.submitters - before_items.reduce(true) do |acc, item| - acc && submitter.submission.submitters.find { |e| e.uuid == item['uuid'] }&.completed_at? - end + before_items = + if submitter_items.any? { |s| s['order'] } + submitter_groups = submitter_items.group_by.with_index { |s, index| s['order'] || index }.sort_by(&:first) + + current_group_index = submitter_groups.find_index { |_, group| group.any? { |s| s['uuid'] == submitter.uuid } } + + submitter_groups.first(current_group_index).flat_map(&:last) + else + submitter_items.first(submitter_items.find_index { |e| e['uuid'] == submitter.uuid }) + end + + before_items.all? { |item| submission.submitters.find { |e| e.uuid == item['uuid'] }&.completed_at? } end def build_document_filename(submitter, blob, filename_format) From ea227e82c955be6d8057b8be99b15be1a8227e3e Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Tue, 29 Jul 2025 22:49:20 +0300 Subject: [PATCH 4/9] force smtp auto --- app/views/email_smtp_settings/index.html.erb | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/app/views/email_smtp_settings/index.html.erb b/app/views/email_smtp_settings/index.html.erb index ad047b2b..76733144 100644 --- a/app/views/email_smtp_settings/index.html.erb +++ b/app/views/email_smtp_settings/index.html.erb @@ -35,17 +35,19 @@ <%= ff.select :authentication, options_for_select([%w[Plain plain], %w[Login login], %w[CRAM-MD5 cram_md5]], value.fetch('authentication', 'plain')), { prompt: true }, required: true, class: 'base-select' %> -
- <%= ff.label :security_label, 'SMTP Security', class: 'label' %> -
- <% [%w[Auto none], %w[SSL ssl], %w[TLS tls], %w[Noverify noverify]].each do |(label, val)| %> - <%= ff.label :security, value: val, for: "#{val}_radio", class: 'label' do %> - <%= ff.radio_button :security, val, checked: (value['security'].blank? && val == 'none') || value['security'] == val, id: "#{val}_radio", class: 'base-radio mr-2' %> - <%= label %> + <% if !Docuseal.multitenant? || can?(:manage, :personalization_advanced) %> +
+ <%= ff.label :security_label, 'SMTP Security', class: 'label' %> +
+ <% [%w[Auto none], %w[SSL ssl], %w[TLS tls], %w[Noverify noverify]].each do |(label, val)| %> + <%= ff.label :security, value: val, for: "#{val}_radio", class: 'label' do %> + <%= ff.radio_button :security, val, checked: (value['security'].blank? && val == 'none') || value['security'] == val, id: "#{val}_radio", class: 'base-radio mr-2' %> + <%= label %> + <% end %> <% end %> - <% end %> +
-
+ <% end %>
<%= ff.label :from_email, t('send_from_email'), class: 'label' %> <%= ff.email_field :from_email, value: value['from_email'], required: !Docuseal.multitenant?, class: 'base-input' %> From d3273d879a28e307208595d0d8e5513ff939a7bd Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Wed, 30 Jul 2025 10:22:38 +0300 Subject: [PATCH 5/9] add order ui --- app/controllers/api/templates_controller.rb | 2 +- app/controllers/templates_controller.rb | 2 +- .../templates_recipients_controller.rb | 7 ++++- app/javascript/application.js | 2 ++ app/javascript/elements/mount_on_click.js | 11 +++++++ .../submissions/_submitters_order.html.erb | 2 +- .../_recipients.html.erb | 31 +++++++++++++++++-- config/locales/i18n.yml | 6 ++++ 8 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 app/javascript/elements/mount_on_click.js diff --git a/app/controllers/api/templates_controller.rb b/app/controllers/api/templates_controller.rb index 88a606f4..7847e599 100644 --- a/app/controllers/api/templates_controller.rb +++ b/app/controllers/api/templates_controller.rb @@ -106,7 +106,7 @@ module Api :external_id, :shared_link, { - submitters: [%i[name uuid is_requester invite_by_uuid optional_invite_by_uuid linked_to_uuid email]], + submitters: [%i[name uuid is_requester invite_by_uuid optional_invite_by_uuid linked_to_uuid email order]], fields: [[:uuid, :submitter_uuid, :name, :type, :required, :readonly, :default_value, :title, :description, :prefillable, diff --git a/app/controllers/templates_controller.rb b/app/controllers/templates_controller.rb index 73e68e85..a3d78606 100644 --- a/app/controllers/templates_controller.rb +++ b/app/controllers/templates_controller.rb @@ -117,7 +117,7 @@ class TemplatesController < ApplicationController params.require(:template).permit( :name, { schema: [[:attachment_uuid, :name, { conditions: [%i[field_uuid value action operation]] }]], - submitters: [%i[name uuid is_requester linked_to_uuid invite_by_uuid optional_invite_by_uuid email]], + submitters: [%i[name uuid is_requester linked_to_uuid invite_by_uuid optional_invite_by_uuid email order]], fields: [[:uuid, :submitter_uuid, :name, :type, :required, :readonly, :default_value, :title, :description, :prefillable, diff --git a/app/controllers/templates_recipients_controller.rb b/app/controllers/templates_recipients_controller.rb index a1298094..17a4bbb8 100644 --- a/app/controllers/templates_recipients_controller.rb +++ b/app/controllers/templates_recipients_controller.rb @@ -9,6 +9,10 @@ class TemplatesRecipientsController < ApplicationController @template.submitters = submitters_params.map { |s| s.reject { |_, v| v.is_a?(String) && v.blank? } } + if @template.submitters.each_with_index.all? { |s, index| s['order'] == index } + @template.submitters.each { |s| s.delete('order') } + end + @template.save! render json: { submitters: @template.submitters } @@ -18,7 +22,7 @@ class TemplatesRecipientsController < ApplicationController def submitters_params permit_params = { submitters: [%i[name uuid is_requester optional_invite_by_uuid - invite_by_uuid linked_to_uuid email option]] } + invite_by_uuid linked_to_uuid email option order]] } params.require(:template).permit(permit_params).fetch(:submitters, {}).values.filter_map do |s| next if s[:uuid].blank? @@ -29,6 +33,7 @@ class TemplatesRecipientsController < ApplicationController s.delete(:is_requester) end + s[:order] = s[:order].to_i if s[:order].present? s.delete(:invite_by_uuid) if s[:invite_by_uuid].blank? s.delete(:optional_invite_by_uuid) if s[:optional_invite_by_uuid].blank? diff --git a/app/javascript/application.js b/app/javascript/application.js index dda88f7a..7b51186d 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -38,6 +38,7 @@ import DashboardDropzone from './elements/dashboard_dropzone' import RequiredCheckboxGroup from './elements/required_checkbox_group' import PageContainer from './elements/page_container' import EmailEditor from './elements/email_editor' +import MountOnClick from './elements/mount_on_click' import * as TurboInstantClick from './lib/turbo_instant_click' @@ -111,6 +112,7 @@ safeRegisterElement('check-on-click', CheckOnClick) safeRegisterElement('required-checkbox-group', RequiredCheckboxGroup) safeRegisterElement('page-container', PageContainer) safeRegisterElement('email-editor', EmailEditor) +safeRegisterElement('mount-on-click', MountOnClick) safeRegisterElement('template-builder', class extends HTMLElement { connectedCallback () { diff --git a/app/javascript/elements/mount_on_click.js b/app/javascript/elements/mount_on_click.js new file mode 100644 index 00000000..3a71f8ff --- /dev/null +++ b/app/javascript/elements/mount_on_click.js @@ -0,0 +1,11 @@ +export default class extends HTMLElement { + connectedCallback () { + this.addEventListener('click', () => { + document.body.append(this.template.content) + }) + } + + get template () { + return document.getElementById(this.dataset.templateId) + } +} diff --git a/app/views/submissions/_submitters_order.html.erb b/app/views/submissions/_submitters_order.html.erb index bb0827e9..c61820cc 100644 --- a/app/views/submissions/_submitters_order.html.erb +++ b/app/views/submissions/_submitters_order.html.erb @@ -1,4 +1,4 @@ -<% if template.preferences['submitters_order'] == 'preserved' %> +<% if template.preferences['submitters_order'] == 'preserved' || template.submitters.any? { |s| s['order'] } %> <%= f.hidden_field :preserve_order, value: '1' %> <% elsif template.submitters.size > 1 %>
diff --git a/app/views/templates_preferences/_recipients.html.erb b/app/views/templates_preferences/_recipients.html.erb index 4f278fd1..81bf71fa 100644 --- a/app/views/templates_preferences/_recipients.html.erb +++ b/app/views/templates_preferences/_recipients.html.erb @@ -1,4 +1,5 @@ <% close_on_submit = local_assigns.fetch(:close_on_submit, true) %> +<% is_order_set = template.submitters.any? { |s| s['order'] } %> <%= form_for template, url: template_recipients_path(template), method: :post, html: { autocomplete: 'off', class: 'mt-1', id: :submitters_form }, data: { close_on_submit: } do |f| %> <% unless close_on_submit %> @@ -6,11 +7,24 @@
<% template.submitters.each_with_index do |submitter, index| %>
- <%= f.fields_for :submitters, item = Struct.new(:name, :uuid, :is_requester, :email, :invite_by_uuid, :optional_invite_by_uuid, :linked_to_uuid, :option).new(*submitter.values_at('name', 'uuid', 'is_requester', 'email', 'invite_by_uuid', 'optional_invite_by_uuid', 'linked_to_uuid')), index: do |ff| %> + <%= f.fields_for :submitters, item = Struct.new(:name, :uuid, :is_requester, :email, :invite_by_uuid, :optional_invite_by_uuid, :linked_to_uuid, :order, :option).new(*submitter.values_at('name', 'uuid', 'is_requester', 'email', 'invite_by_uuid', 'optional_invite_by_uuid', 'linked_to_uuid', 'order')), index: do |ff| %> <% item.option = item.is_requester.present? ? 'is_requester' : (item.email.present? ? 'email' : (item.linked_to_uuid.present? ? "linked_to_#{item.linked_to_uuid}" : (item.invite_by_uuid.present? ? "invite_by_#{item.invite_by_uuid}" : (item.optional_invite_by_uuid.present? ? "optional_invite_by_#{item.optional_invite_by_uuid}" : '')))) %> <%= ff.hidden_field :uuid %>
- <%= 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 %> +
+ <%= 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 %> +
+ <% if is_order_set %> + <%= ff.select :order, options_for_select(template.submitters.map.with_index { |_, i| [(i + 1).ordinalize, i] }, submitter['order'].presence || index), {}, class: 'select select-xs text-sm input-bordered bg-white pl-3.5' %> + <% elsif index == 0 %> + + <%= t('edit_order') %> + + <% end %> +
+ <% end %> +
<% if template.submitters.size == 2 %> <%= 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 %> @@ -85,3 +99,16 @@
<% end %>
+<% if template.submitters.size > 2 && !is_order_set %> + +<% end %> diff --git a/config/locales/i18n.yml b/config/locales/i18n.yml index 99ec82ef..cf5cfc97 100644 --- a/config/locales/i18n.yml +++ b/config/locales/i18n.yml @@ -24,6 +24,7 @@ en: &en thanks: Thanks private: Private select: Select + edit_order: Edit Order invite_form_fields: Invite form fields default_parties: Default parties authenticate_embedded_form_preview_with_token: Authenticate embedded form preview with token @@ -898,6 +899,7 @@ en: &en range_without_total: "%{from}-%{to} events" es: &es + edit_order: Edita Pedido select: Seleccionar invite_form_fields: Invitar campos del formulario pro: Pro @@ -1776,6 +1778,7 @@ es: &es range_without_total: "%{from}-%{to} eventos" it: &it + edit_order: Modifica Ordine select: Seleziona invite_form_fields: Invita campi modulo pro: Pro @@ -2654,6 +2657,7 @@ it: &it range_without_total: "%{from}-%{to} eventi" fr: &fr + edit_order: Modifier la commande select: Sélectionner invite_form_fields: Inviter des champs de formulaire pro: Pro @@ -3535,6 +3539,7 @@ fr: &fr range_without_total: "%{from} à %{to} événements" pt: &pt + edit_order: Edita Pedido select: Selecionar invite_form_fields: Convidar campos do formulário pro: Pro @@ -4414,6 +4419,7 @@ pt: &pt range_without_total: "%{from}-%{to} eventos" de: &de + edit_order: Bestellung bearbeiten select: Auswählen invite_form_fields: Formularfelder einladen pro: Pro From 59fbea5c5fd5cf025c9253da4b1fc0228abc1f65 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Wed, 30 Jul 2025 18:45:28 +0300 Subject: [PATCH 6/9] fix migration --- ...816072859_populate_submitter_account_id.rb | 2 +- ...late_completed_submitters_and_documents.rb | 2 +- .../20241029192232_populate_webhook_urls.rb | 2 +- ...0523121121_add_shared_link_to_templates.rb | 2 +- .../20250603105556_create_search_enties.rb | 34 ++++++++++++++----- ...0250608163157_add_ngram_to_search_index.rb | 17 ++++++---- 6 files changed, 40 insertions(+), 19 deletions(-) diff --git a/db/migrate/20240816072859_populate_submitter_account_id.rb b/db/migrate/20240816072859_populate_submitter_account_id.rb index 29960068..d3ccf572 100644 --- a/db/migrate/20240816072859_populate_submitter_account_id.rb +++ b/db/migrate/20240816072859_populate_submitter_account_id.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class PopulateSubmitterAccountId < ActiveRecord::Migration[7.1] - disable_ddl_transaction + disable_ddl_transaction! class MigrationSubmitter < ApplicationRecord self.table_name = 'submitters' diff --git a/db/migrate/20241022125135_populate_completed_submitters_and_documents.rb b/db/migrate/20241022125135_populate_completed_submitters_and_documents.rb index c2c3dd57..6e373656 100644 --- a/db/migrate/20241022125135_populate_completed_submitters_and_documents.rb +++ b/db/migrate/20241022125135_populate_completed_submitters_and_documents.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class PopulateCompletedSubmittersAndDocuments < ActiveRecord::Migration[7.2] - disable_ddl_transaction + disable_ddl_transaction! class MigrationSubmitter < ApplicationRecord self.table_name = 'submitters' diff --git a/db/migrate/20241029192232_populate_webhook_urls.rb b/db/migrate/20241029192232_populate_webhook_urls.rb index cb8b5546..ae11d8ad 100644 --- a/db/migrate/20241029192232_populate_webhook_urls.rb +++ b/db/migrate/20241029192232_populate_webhook_urls.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class PopulateWebhookUrls < ActiveRecord::Migration[7.2] - disable_ddl_transaction + disable_ddl_transaction! class MigrationWebhookUrl < ActiveRecord::Base self.table_name = 'webhook_urls' diff --git a/db/migrate/20250523121121_add_shared_link_to_templates.rb b/db/migrate/20250523121121_add_shared_link_to_templates.rb index 6fe962eb..039872c2 100644 --- a/db/migrate/20250523121121_add_shared_link_to_templates.rb +++ b/db/migrate/20250523121121_add_shared_link_to_templates.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class AddSharedLinkToTemplates < ActiveRecord::Migration[8.0] - disable_ddl_transaction + disable_ddl_transaction! class MigrationTemplate < ActiveRecord::Base self.table_name = 'templates' diff --git a/db/migrate/20250603105556_create_search_enties.rb b/db/migrate/20250603105556_create_search_enties.rb index 2b219f84..bee12609 100644 --- a/db/migrate/20250603105556_create_search_enties.rb +++ b/db/migrate/20250603105556_create_search_enties.rb @@ -1,11 +1,11 @@ # frozen_string_literal: true class CreateSearchEnties < ActiveRecord::Migration[8.0] + disable_ddl_transaction! + def up return unless adapter_name == 'PostgreSQL' - enable_extension 'btree_gin' - create_table :search_entries do |t| t.references :record, null: false, polymorphic: true, index: false t.bigint :account_id, null: false @@ -14,12 +14,24 @@ class CreateSearchEnties < ActiveRecord::Migration[8.0] t.timestamps end - add_index :search_entries, %i[account_id tsvector], using: :gin, where: "record_type = 'Submitter'", - name: 'index_search_entries_on_account_id_tsvector_submitter' - add_index :search_entries, %i[account_id tsvector], using: :gin, where: "record_type = 'Submission'", - name: 'index_search_entries_on_account_id_tsvector_submission' - add_index :search_entries, %i[account_id tsvector], using: :gin, where: "record_type = 'Template'", - name: 'index_search_entries_on_account_id_tsvector_template' + begin + enable_extension 'btree_gin' + rescue StandardError + nil + end + + btree_gin_enabled = extension_enabled?('btree_gin') + + add_index :search_entries, btree_gin_enabled ? %i[account_id tsvector] : :tsvector, + using: :gin, where: "record_type = 'Submitter'", + name: 'index_search_entries_on_account_id_tsvector_submitter' + add_index :search_entries, btree_gin_enabled ? %i[account_id tsvector] : :tsvector, + using: :gin, where: "record_type = 'Submission'", + name: 'index_search_entries_on_account_id_tsvector_submission' + add_index :search_entries, btree_gin_enabled ? %i[account_id tsvector] : :tsvector, + using: :gin, where: "record_type = 'Template'", + name: 'index_search_entries_on_account_id_tsvector_template' + add_index :search_entries, %i[record_id record_type], unique: true end @@ -28,6 +40,10 @@ class CreateSearchEnties < ActiveRecord::Migration[8.0] drop_table :search_entries - disable_extension 'btree_gin' + begin + disable_extension 'btree_gin' + rescue StandardError + nil + end end end diff --git a/db/migrate/20250608163157_add_ngram_to_search_index.rb b/db/migrate/20250608163157_add_ngram_to_search_index.rb index 3af6729d..8d609ca4 100644 --- a/db/migrate/20250608163157_add_ngram_to_search_index.rb +++ b/db/migrate/20250608163157_add_ngram_to_search_index.rb @@ -4,13 +4,18 @@ class AddNgramToSearchIndex < ActiveRecord::Migration[8.0] def change return unless adapter_name == 'PostgreSQL' + btree_gin_enabled = extension_enabled?('btree_gin') + add_column :search_entries, :ngram, :tsvector - add_index :search_entries, %i[account_id ngram], using: :gin, where: "record_type = 'Submitter'", - name: 'index_search_entries_on_account_id_ngram_submitter' - add_index :search_entries, %i[account_id ngram], using: :gin, where: "record_type = 'Submission'", - name: 'index_search_entries_on_account_id_ngram_submission' - add_index :search_entries, %i[account_id ngram], using: :gin, where: "record_type = 'Template'", - name: 'index_search_entries_on_account_id_ngram_template' + add_index :search_entries, btree_gin_enabled ? %i[account_id tsvector] : :tsvector, + using: :gin, where: "record_type = 'Submitter'", + name: 'index_search_entries_on_account_id_ngram_submitter' + add_index :search_entries, btree_gin_enabled ? %i[account_id tsvector] : :tsvector, + using: :gin, where: "record_type = 'Submission'", + name: 'index_search_entries_on_account_id_ngram_submission' + add_index :search_entries, btree_gin_enabled ? %i[account_id tsvector] : :tsvector, + using: :gin, where: "record_type = 'Template'", + name: 'index_search_entries_on_account_id_ngram_template' end end From a8f1c1c3234329e3db508fd7be56edf8fdec6845 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Thu, 31 Jul 2025 11:25:30 +0300 Subject: [PATCH 7/9] add new signature formats --- app/javascript/submission_form/signature_step.vue | 8 ++++---- app/javascript/template_builder/field_settings.vue | 2 +- app/javascript/template_builder/i18n.js | 6 ++++++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/app/javascript/submission_form/signature_step.vue b/app/javascript/submission_form/signature_step.vue index d1625726..d4ece8e5 100644 --- a/app/javascript/submission_form/signature_step.vue +++ b/app/javascript/submission_form/signature_step.vue @@ -21,7 +21,7 @@
@@ -38,7 +38,7 @@ @@ -395,7 +395,7 @@ export default { isShowQr: false, isOtherReason: false, isUsePreviousValue: true, - isTextSignature: this.field.preferences?.format === 'typed', + isTextSignature: this.field.preferences?.format === 'typed' || this.field.preferences?.format === 'typed_or_upload', uploadImageInputKey: Math.random().toString() } }, diff --git a/app/javascript/template_builder/field_settings.vue b/app/javascript/template_builder/field_settings.vue index 22821f4c..158fb1ae 100644 --- a/app/javascript/template_builder/field_settings.vue +++ b/app/javascript/template_builder/field_settings.vue @@ -304,7 +304,7 @@ {{ t('any') }}