From d7a6e80bb1d27475caed22f8bb33584416ee63a1 Mon Sep 17 00:00:00 2001
From: Pete Matsyburka
Date: Tue, 11 Nov 2025 11:11:07 +0200
Subject: [PATCH 01/20] html escape font signature
---
lib/submitters/generate_font_image.rb | 2 ++
1 file changed, 2 insertions(+)
diff --git a/lib/submitters/generate_font_image.rb b/lib/submitters/generate_font_image.rb
index b64580fc..b70d7450 100644
--- a/lib/submitters/generate_font_image.rb
+++ b/lib/submitters/generate_font_image.rb
@@ -20,6 +20,8 @@ module Submitters
def call(text, font: nil)
font = FONT_ALIASES[font] || font
+ text = ERB::Util.html_escape(text)
+
text_image = Vips::Image.text(text, font:, fontfile: FONTS[font],
width: WIDTH, height: HEIGHT, wrap: :none)
From 4c1c70ff04cd7d18e4797ef62ea63ac910d2c04a Mon Sep 17 00:00:00 2001
From: Pete Matsyburka
Date: Tue, 11 Nov 2025 11:55:39 +0200
Subject: [PATCH 02/20] fix audit generation
---
lib/submissions/generate_audit_trail.rb | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/lib/submissions/generate_audit_trail.rb b/lib/submissions/generate_audit_trail.rb
index b6505695..2619c949 100644
--- a/lib/submissions/generate_audit_trail.rb
+++ b/lib/submissions/generate_audit_trail.rb
@@ -23,6 +23,8 @@ module Submissions
RTL_REGEXP = TextUtils::RTL_REGEXP
MAX_IMAGE_HEIGHT = 100
+ CHECKSUM_LIMIT = 30
+
US_TIMEZONES = TimeUtils::US_TIMEZONES
module_function
@@ -216,7 +218,7 @@ module Submissions
composer.document.layout.formatted_text_box(
[
{ text: "#{I18n.t('original_sha256')}:\n", font: [FONT_NAME, { variant: :bold }] },
- original_documents.map { |d| d.metadata['sha256'] || d.checksum }.join("\n"),
+ original_documents.map { |d| d.metadata['sha256'] || d.checksum }.first(CHECKSUM_LIMIT).join("\n"),
"\n",
{ text: "#{I18n.t('result_sha256')}:\n", font: [FONT_NAME, { variant: :bold }] },
document.metadata['sha256'] || document.checksum,
From ab8c41a520011fc746a4b5fb52f1ad6b5b098dba Mon Sep 17 00:00:00 2001
From: Pete Matsyburka
Date: Tue, 11 Nov 2025 13:42:01 +0200
Subject: [PATCH 03/20] add signature reasons param
---
.../submission_form/signature_step.vue | 57 ++++++++++++-------
1 file changed, 37 insertions(+), 20 deletions(-)
diff --git a/app/javascript/submission_form/signature_step.vue b/app/javascript/submission_form/signature_step.vue
index 519b77fe..cf870735 100644
--- a/app/javascript/submission_form/signature_step.vue
+++ b/app/javascript/submission_form/signature_step.vue
@@ -211,7 +211,7 @@
@input="updateWrittenSignature"
>
{{ t('select_a_reason') }}
-
- {{ label }}
-
-
- {{ t('other') }}
-
+
+
+ {{ option }}
+
+
+
+
+ {{ label }}
+
+
+ {{ t('other') }}
+
+
Date: Tue, 11 Nov 2025 17:34:50 +0200
Subject: [PATCH 04/20] i18n
---
app/javascript/template_builder/fields.vue | 6 +++---
app/javascript/template_builder/i18n.js | 6 ++++++
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/app/javascript/template_builder/fields.vue b/app/javascript/template_builder/fields.vue
index 2c8b10c8..822ecc0b 100644
--- a/app/javascript/template_builder/fields.vue
+++ b/app/javascript/template_builder/fields.vue
@@ -236,7 +236,7 @@
-
+
@@ -268,7 +268,7 @@
import Field from './field'
import FieldType from './field_type'
import FieldSubmitter from './field_submitter'
-import { IconLock, IconCirclePlus, IconInnerShadowTop, IconListSearch } from '@tabler/icons-vue'
+import { IconLock, IconCirclePlus, IconInnerShadowTop, IconSparkles } from '@tabler/icons-vue'
import IconDrag from './icon_drag'
export default {
@@ -277,7 +277,7 @@ export default {
Field,
FieldType,
IconCirclePlus,
- IconListSearch,
+ IconSparkles,
IconInnerShadowTop,
FieldSubmitter,
IconDrag,
diff --git a/app/javascript/template_builder/i18n.js b/app/javascript/template_builder/i18n.js
index 284989e4..ef97059d 100644
--- a/app/javascript/template_builder/i18n.js
+++ b/app/javascript/template_builder/i18n.js
@@ -188,6 +188,7 @@ const en = {
}
const es = {
+ autodetect_fields: 'Autodetectar campos',
analyzing_: 'Analizando...',
download: 'Descargar',
downloading_: 'Descargando...',
@@ -376,6 +377,7 @@ const es = {
}
const it = {
+ autodetect_fields: 'Rileva campi',
analyzing_: 'Analisi...',
download: 'Scarica',
downloading_: 'Download in corso...',
@@ -564,6 +566,7 @@ const it = {
}
const pt = {
+ autodetect_fields: 'Detectar campos',
analyzing_: 'Analisando...',
download: 'Baixar',
downloading_: 'Baixando...',
@@ -752,6 +755,7 @@ const pt = {
}
const fr = {
+ autodetect_fields: 'Détecter les champs',
analyzing_: 'Analyse...',
download: 'Télécharger',
downloading_: 'Téléchargement...',
@@ -940,6 +944,7 @@ const fr = {
}
const de = {
+ autodetect_fields: 'Felder erkennen',
analyzing_: 'Analysiere...',
download: 'Download',
downloading_: 'Download...',
@@ -1128,6 +1133,7 @@ const de = {
}
const nl = {
+ autodetect_fields: 'Velden detecteren',
analyzing_: 'Analyseren...',
download: 'Downloaden',
downloading_: 'Downloaden...',
From c8fe36a2b6a8373dba8a594261049822be7165bd Mon Sep 17 00:00:00 2001
From: Alex Turchyn
Date: Wed, 22 Oct 2025 14:11:17 +0300
Subject: [PATCH 05/20] add desktop/mobile/tablet badges to events log
---
app/views/icons/_device_desktop.html.erb | 8 +++++++
app/views/icons/_device_mobile.html.erb | 6 ++++++
app/views/icons/_device_tablet.html.erb | 5 +++++
app/views/submission_events/index.html.erb | 12 ++++++++---
config/locales/i18n.yml | 21 ++++++++++++++++++
lib/detect_browser_device.rb | 25 ++++++++++++++++++++++
6 files changed, 74 insertions(+), 3 deletions(-)
create mode 100644 app/views/icons/_device_desktop.html.erb
create mode 100644 app/views/icons/_device_mobile.html.erb
create mode 100644 app/views/icons/_device_tablet.html.erb
create mode 100644 lib/detect_browser_device.rb
diff --git a/app/views/icons/_device_desktop.html.erb b/app/views/icons/_device_desktop.html.erb
new file mode 100644
index 00000000..3a6ba14f
--- /dev/null
+++ b/app/views/icons/_device_desktop.html.erb
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/app/views/icons/_device_mobile.html.erb b/app/views/icons/_device_mobile.html.erb
new file mode 100644
index 00000000..c820a773
--- /dev/null
+++ b/app/views/icons/_device_mobile.html.erb
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/app/views/icons/_device_tablet.html.erb b/app/views/icons/_device_tablet.html.erb
new file mode 100644
index 00000000..7dc1b8e4
--- /dev/null
+++ b/app/views/icons/_device_tablet.html.erb
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/views/submission_events/index.html.erb b/app/views/submission_events/index.html.erb
index a0a2b867..02a93b65 100644
--- a/app/views/submission_events/index.html.erb
+++ b/app/views/submission_events/index.html.erb
@@ -21,6 +21,7 @@
<% @submission.submission_events.order(:event_timestamp).each do |event| %>
+ <% device = DetectBrowserDevice.call(event.data['ua']) %>
<% submitter = @submission.submitters.find { |e| e.id == event.submitter_id } %>
<% bg_class = event_colors[submitters_uuids.index(submitter.uuid) % event_colors.length] %>
<% submitter_name = event.event_type.include?('sms') || event.event_type.include?('phone') ? (event.data['phone'] || submitter.phone) : (submitter.name || submitter.email || submitter.phone) %>
@@ -28,9 +29,14 @@
<%= svg_icon(SubmissionEventsController::SUBMISSION_EVENT_ICONS.fetch(event.event_type, 'circle_dot'), class: 'w-4 h-4') %>
-
- <%= l(event.event_timestamp.in_time_zone(current_account.timezone), format: :long, locale: current_account.locale) %>
-
+
+
+ <%= l(event.event_timestamp.in_time_zone(current_account.timezone), format: :long, locale: current_account.locale) %>
+
+
+ <%= svg_icon("device_#{device}", class: 'w-3.5 h-3.5') %>
+
+
<% if event.event_type == 'complete_verification' %>
<%= t('submission_event_names.complete_verification_by_html', provider: event.data['method'], submitter_name:) %>
diff --git a/config/locales/i18n.yml b/config/locales/i18n.yml
index c08944eb..30a30231 100644
--- a/config/locales/i18n.yml
+++ b/config/locales/i18n.yml
@@ -837,6 +837,9 @@ en: &en
connect_google_drive: Connect Google Drive
google_drive_has_been_connected: Google Drive has been connected
unable_to_identify_reset_your_password_to_sign_in: Unable to identify. Reset your password to sign in.
+ desktop: Desktop
+ mobile: Mobile
+ tablet: Tablet
submission_sources:
api: API
bulk: Bulk Send
@@ -1758,6 +1761,9 @@ es: &es
connect_google_drive: Conectar Google Drive
google_drive_has_been_connected: Google Drive se ha conectado
unable_to_identify_reset_your_password_to_sign_in: No se pudo identificar. Restablece tu contraseña para iniciar sesión.
+ desktop: Escritorio
+ mobile: Móvil
+ tablet: Tableta
submission_sources:
api: API
bulk: Envío masivo
@@ -2680,6 +2686,9 @@ it: &it
connect_google_drive: Connetti Google Drive
google_drive_has_been_connected: Google Drive è stato connesso
unable_to_identify_reset_your_password_to_sign_in: Impossibile identificare. Reimposta la password per accedere.
+ desktop: Desktop
+ mobile: Mobile
+ tablet: Tablet
submission_sources:
api: API
bulk: Invio massivo
@@ -3599,6 +3608,9 @@ fr: &fr
connect_google_drive: Connecter Google Drive
google_drive_has_been_connected: Google Drive a été connecté
unable_to_identify_reset_your_password_to_sign_in: Impossible d’identifier. Réinitialisez votre mot de passe pour vous connecter.
+ desktop: Bureau
+ mobile: Mobile
+ tablet: Tablette
submission_sources:
api: API
bulk: Envoi en masse
@@ -4522,6 +4534,9 @@ pt: &pt
connect_google_drive: Conectar Google Drive
google_drive_has_been_connected: O Google Drive foi conectado
unable_to_identify_reset_your_password_to_sign_in: Não foi possível identificar. Redefina sua senha para fazer login.
+ desktop: Computador
+ mobile: Celular
+ tablet: Tablet
submission_sources:
api: API
bulk: Envio em massa
@@ -5445,6 +5460,9 @@ de: &de
connect_google_drive: Google Drive verbinden
google_drive_has_been_connected: Google Drive wurde verbunden
unable_to_identify_reset_your_password_to_sign_in: Identifizierung nicht möglich. Setzen Sie Ihr Passwort zurück, um sich anzumelden.
+ desktop: Desktop
+ mobile: Mobil
+ tablet: Tablet
submission_sources:
api: API
bulk: Massenversand
@@ -6729,6 +6747,9 @@ nl: &nl
connect_google_drive: Verbind Google Drive
google_drive_has_been_connected: Google Drive is verbonden
unable_to_identify_reset_your_password_to_sign_in: Kan niet worden geïdentificeerd. Stel je wachtwoord opnieuw in om in te loggen.
+ desktop: Desktop
+ mobile: Mobiel
+ tablet: Tablet
submission_sources:
api: API
bulk: Bulkverzending
diff --git a/lib/detect_browser_device.rb b/lib/detect_browser_device.rb
new file mode 100644
index 00000000..349679f5
--- /dev/null
+++ b/lib/detect_browser_device.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module DetectBrowserDevice
+ module_function
+
+ # rubocop:disable Metrics/LineLength
+ MOBILE_USER_AGENT_REGEXP = /iPhone|iPod|Android.*Mobile|Opera Mini|Opera Mobi|webOS|IEMobile|Windows Phone|BlackBerry|BB10|Mobile/i
+ TABLET_USER_AGENT_REGEXP = /iPad|Android(?!.*Mobile)|Tablet|Kindle|PlayBook|Silk/i
+ # rubocop:enable Metrics/LineLength
+
+ def call(user_agent)
+ return :mobile if mobile?(user_agent)
+ return :tablet if tablet?(user_agent)
+
+ :desktop
+ end
+
+ def mobile?(user_agent)
+ user_agent.to_s =~ MOBILE_USER_AGENT_REGEXP
+ end
+
+ def tablet?(user_agent)
+ user_agent.to_s =~ TABLET_USER_AGENT_REGEXP
+ end
+end
From 9537fe8c91354da667fcf589929af1b2db441956 Mon Sep 17 00:00:00 2001
From: Alex Turchyn
Date: Wed, 22 Oct 2025 15:53:41 +0300
Subject: [PATCH 06/20] update constants
---
lib/detect_browser_device.rb | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/lib/detect_browser_device.rb b/lib/detect_browser_device.rb
index 349679f5..64f4bf51 100644
--- a/lib/detect_browser_device.rb
+++ b/lib/detect_browser_device.rb
@@ -3,10 +3,28 @@
module DetectBrowserDevice
module_function
- # rubocop:disable Metrics/LineLength
- MOBILE_USER_AGENT_REGEXP = /iPhone|iPod|Android.*Mobile|Opera Mini|Opera Mobi|webOS|IEMobile|Windows Phone|BlackBerry|BB10|Mobile/i
- TABLET_USER_AGENT_REGEXP = /iPad|Android(?!.*Mobile)|Tablet|Kindle|PlayBook|Silk/i
- # rubocop:enable Metrics/LineLength
+ MOBILE_USER_AGENT_REGEXP = /
+ iPhone |
+ iPod |
+ Android.*Mobile|
+ Opera\ Mini |
+ Opera\ Mobi |
+ webOS |
+ IEMobile |
+ Windows\ Phone |
+ BlackBerry |
+ BB10 |
+ Mobile
+ /ix
+
+ TABLET_USER_AGENT_REGEXP = /
+ iPad |
+ Android(?!.*Mobile)|
+ Tablet |
+ Kindle |
+ PlayBook |
+ Silk
+ /ix
def call(user_agent)
return :mobile if mobile?(user_agent)
From 884865cffca1396f26eed95e791aba12bd10933f Mon Sep 17 00:00:00 2001
From: Pete Matsyburka
Date: Wed, 12 Nov 2025 16:39:29 +0200
Subject: [PATCH 07/20] adjust size
---
app/views/submission_events/index.html.erb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/views/submission_events/index.html.erb b/app/views/submission_events/index.html.erb
index 02a93b65..c97f7a7d 100644
--- a/app/views/submission_events/index.html.erb
+++ b/app/views/submission_events/index.html.erb
@@ -34,7 +34,7 @@
<%= l(event.event_timestamp.in_time_zone(current_account.timezone), format: :long, locale: current_account.locale) %>
- <%= svg_icon("device_#{device}", class: 'w-3.5 h-3.5') %>
+ <%= svg_icon("device_#{device}", class: 'w-4 h-4') %>
From 2c33ec382d7a2bd64fca65a96477698ed3ef4b60 Mon Sep 17 00:00:00 2001
From: Pete Matsyburka
Date: Wed, 12 Nov 2025 16:44:58 +0200
Subject: [PATCH 08/20] fix device icon
---
app/views/submission_events/index.html.erb | 9 +++++----
lib/detect_browser_device.rb | 14 ++++----------
2 files changed, 9 insertions(+), 14 deletions(-)
diff --git a/app/views/submission_events/index.html.erb b/app/views/submission_events/index.html.erb
index c97f7a7d..8dec75f3 100644
--- a/app/views/submission_events/index.html.erb
+++ b/app/views/submission_events/index.html.erb
@@ -21,7 +21,6 @@
<% @submission.submission_events.order(:event_timestamp).each do |event| %>
- <% device = DetectBrowserDevice.call(event.data['ua']) %>
<% submitter = @submission.submitters.find { |e| e.id == event.submitter_id } %>
<% bg_class = event_colors[submitters_uuids.index(submitter.uuid) % event_colors.length] %>
<% submitter_name = event.event_type.include?('sms') || event.event_type.include?('phone') ? (event.data['phone'] || submitter.phone) : (submitter.name || submitter.email || submitter.phone) %>
@@ -33,9 +32,11 @@
<%= l(event.event_timestamp.in_time_zone(current_account.timezone), format: :long, locale: current_account.locale) %>
-
- <%= svg_icon("device_#{device}", class: 'w-4 h-4') %>
-
+ <% if (device = DetectBrowserDevice.call(event.data['ua'])) %>
+
+ <%= svg_icon("device_#{device}", class: 'w-4 h-4') %>
+
+ <% end %>
<% if event.event_type == 'complete_verification' %>
diff --git a/lib/detect_browser_device.rb b/lib/detect_browser_device.rb
index 64f4bf51..0240d278 100644
--- a/lib/detect_browser_device.rb
+++ b/lib/detect_browser_device.rb
@@ -27,17 +27,11 @@ module DetectBrowserDevice
/ix
def call(user_agent)
- return :mobile if mobile?(user_agent)
- return :tablet if tablet?(user_agent)
+ return if user_agent.blank?
- :desktop
- end
-
- def mobile?(user_agent)
- user_agent.to_s =~ MOBILE_USER_AGENT_REGEXP
- end
+ return 'mobile' if MOBILE_USER_AGENT_REGEXP.match?(user_agent)
+ return 'tablet' if TABLET_USER_AGENT_REGEXP.match?(user_agent)
- def tablet?(user_agent)
- user_agent.to_s =~ TABLET_USER_AGENT_REGEXP
+ 'desktop'
end
end
From 80f60a5d88dc61192ed4840628c70562da712ffd Mon Sep 17 00:00:00 2001
From: Pete Matsyburka
Date: Wed, 12 Nov 2025 20:19:57 +0200
Subject: [PATCH 09/20] re-invite archived user
---
app/controllers/users_controller.rb | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 39cbc223..129a90c0 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -24,10 +24,18 @@ class UsersController < ApplicationController
def edit; end
def create
- if User.accessible_by(current_ability).exists?(email: @user.email)
- @user.errors.add(:email, I18n.t('already_exists'))
+ existing_user = User.accessible_by(current_ability).find_by(email: @user.email)
- return render turbo_stream: turbo_stream.replace(:modal, template: 'users/new'), status: :unprocessable_content
+ if existing_user
+ if existing_user.archived_at? && authorize!(:manage, existing_user) && authorize!(:manage, @user.account)
+ existing_user.assign_attributes(@user.slice(:first_name, :last_name, :role, :account_id))
+ existing_user.archived_at = nil
+ @user = existing_user
+ else
+ @user.errors.add(:email, I18n.t('already_exists'))
+
+ return render turbo_stream: turbo_stream.replace(:modal, template: 'users/new'), status: :unprocessable_content
+ end
end
@user.password = SecureRandom.hex if @user.password.blank?
From 8e71d9f9e957e0626c4a0bc24d1bfe8edad714c1 Mon Sep 17 00:00:00 2001
From: Pete Matsyburka
Date: Thu, 13 Nov 2025 08:29:27 +0200
Subject: [PATCH 10/20] skip email
---
app/jobs/send_submitter_invitation_email_job.rb | 2 ++
1 file changed, 2 insertions(+)
diff --git a/app/jobs/send_submitter_invitation_email_job.rb b/app/jobs/send_submitter_invitation_email_job.rb
index 335e3665..49bf22bd 100644
--- a/app/jobs/send_submitter_invitation_email_job.rb
+++ b/app/jobs/send_submitter_invitation_email_job.rb
@@ -7,6 +7,8 @@ class SendSubmitterInvitationEmailJob
submitter = Submitter.find(params['submitter_id'])
return if submitter.completed_at?
+ return if submitter.submission.archived_at?
+ return if submitter.template&.archived_at?
return if submitter.submission.source == 'invite' && !Accounts.can_send_emails?(submitter.account, on_events: true)
unless Accounts.can_send_invitation_emails?(submitter.account)
From 6c73c82a2740cc82b4ebeabb4460fc04951fcf59 Mon Sep 17 00:00:00 2001
From: Alex Turchyn
Date: Fri, 7 Nov 2025 22:05:49 +0200
Subject: [PATCH 11/20] add ability to reset custom template emails to default
---
.../templates_preferences_controller.rb | 26 +++
.../_submitter_completed_email_form.html.erb | 66 ++++++
...bmitter_documents_copy_email_form.html.erb | 72 +++++++
.../_submitter_invitation_email_form.html.erb | 108 ++++++++++
app/views/templates_preferences/show.html.erb | 203 +-----------------
config/locales/i18n.yml | 14 ++
config/routes.rb | 2 +-
7 files changed, 293 insertions(+), 198 deletions(-)
create mode 100644 app/views/templates_preferences/_submitter_completed_email_form.html.erb
create mode 100644 app/views/templates_preferences/_submitter_documents_copy_email_form.html.erb
create mode 100644 app/views/templates_preferences/_submitter_invitation_email_form.html.erb
diff --git a/app/controllers/templates_preferences_controller.rb b/app/controllers/templates_preferences_controller.rb
index cbee0993..47e1a562 100644
--- a/app/controllers/templates_preferences_controller.rb
+++ b/app/controllers/templates_preferences_controller.rb
@@ -3,6 +3,13 @@
class TemplatesPreferencesController < ApplicationController
load_and_authorize_resource :template
+ RESETTABLE_PREFERENCE_KEYS = {
+ AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY => %w[request_email_subject request_email_body submitters],
+ AccountConfig::SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY => %w[documents_copy_email_subject documents_copy_email_body],
+ AccountConfig::SUBMITTER_COMPLETED_EMAIL_KEY => %w[completed_notification_email_subject
+ completed_notification_email_body]
+ }.freeze
+
def show; end
def create
@@ -15,6 +22,25 @@ class TemplatesPreferencesController < ApplicationController
head :ok
end
+ def destroy
+ authorize!(:update, @template)
+
+ config_key = params[:config_key]
+ preferences_to_delete = RESETTABLE_PREFERENCE_KEYS[config_key] || []
+
+ return head :ok if preferences_to_delete.blank?
+
+ preferences_to_delete.each do |key|
+ @template.preferences.delete(key)
+ end
+
+ @template.save!
+
+ render turbo_stream: turbo_stream.replace("#{config_key}_form",
+ partial: "templates_preferences/#{config_key}_form"),
+ status: :ok
+ end
+
private
def template_params
diff --git a/app/views/templates_preferences/_submitter_completed_email_form.html.erb b/app/views/templates_preferences/_submitter_completed_email_form.html.erb
new file mode 100644
index 00000000..74626f79
--- /dev/null
+++ b/app/views/templates_preferences/_submitter_completed_email_form.html.erb
@@ -0,0 +1,66 @@
+
+ <% configs = AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::SUBMITTER_COMPLETED_EMAIL_KEY).value %>
+ <% template_email_preferences_values = @template.preferences.values_at('completed_notification_email_subject', 'completed_notification_email_body').compact_blank.presence %>
+ <% is_custom_template_email = template_email_preferences_values.present? %>
+ <% if is_custom_template_email %>
+ <%= button_to nil, template_preferences_path(@template), id: 'submitter_completed_email_reset_link', method: :delete, class: 'hidden', params: { config_key: AccountConfig::SUBMITTER_COMPLETED_EMAIL_KEY }, data: { turbo_confirm: t('are_you_sure_') }, form: { data: { close_on_submit: false } } %>
+ <% end %>
+ <%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-1' }, data: { close_on_submit: false } do |f| %>
+
+ <%= f.hidden_field :config_key, value: AccountConfig::SUBMITTER_COMPLETED_EMAIL_KEY %>
+ <%= f.fields_for :preferences, Struct.new(:completed_notification_email_subject, :completed_notification_email_body, :completed_notification_email_enabled, :completed_notification_email_attach_audit, :completed_notification_email_attach_documents).new(@template.preferences['completed_notification_email_subject'].presence || configs['subject'], @template.preferences['completed_notification_email_body'].presence || configs['body'], @template.preferences['completed_notification_email_enabled'], configs['attach_audit_log'] != false && @template.preferences['completed_notification_email_attach_audit'] != false, configs['attach_documents'] != false && @template.preferences['completed_notification_email_attach_documents'] != false) do |ff| %>
+
+
+
+
+ <%= t('attach_documents_to_the_email') %>
+
+
+ <%= ff.check_box :completed_notification_email_attach_documents, { checked: ff.object.completed_notification_email_attach_documents != false, class: 'toggle', disabled: configs['attach_documents'] == false }, 'true', 'false' %>
+
+
+
+
+ <%= t('attach_audit_log_pdf_to_the_email') %>
+
+
+ <%= ff.check_box :completed_notification_email_attach_audit, { checked: ff.object.completed_notification_email_attach_audit != false, class: 'toggle', disabled: configs['attach_audit_log'] == false }, 'true', 'false' %>
+
+
+
+
+ <%= t('send_emails_automatically_on_completion') %>
+
+
+ <%= ff.check_box :completed_notification_email_enabled, { checked: ff.object.completed_notification_email_enabled != false, class: 'toggle', disabled: configs['enabled'] == false }, 'true', 'false' %>
+
+
+ <% end %>
+
+ <% end %>
+
diff --git a/app/views/templates_preferences/_submitter_documents_copy_email_form.html.erb b/app/views/templates_preferences/_submitter_documents_copy_email_form.html.erb
new file mode 100644
index 00000000..0ce23e59
--- /dev/null
+++ b/app/views/templates_preferences/_submitter_documents_copy_email_form.html.erb
@@ -0,0 +1,72 @@
+
+ <% configs = AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY).value %>
+ <% template_email_preferences_values = @template.preferences.values_at('documents_copy_email_subject', 'documents_copy_email_body').compact_blank.presence %>
+ <% is_custom_template_email = template_email_preferences_values.present? %>
+ <% if is_custom_template_email %>
+ <%= button_to nil, template_preferences_path(@template), id: 'submitter_documents_copy_email_reset_link', method: :delete, class: 'hidden', params: { config_key: AccountConfig::SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY }, data: { turbo_confirm: t('are_you_sure_') }, form: { data: { close_on_submit: false } } %>
+ <% end %>
+ <%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-1' }, data: { close_on_submit: false } do |f| %>
+
+ <%= f.hidden_field :config_key, value: AccountConfig::SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY %>
+ <%= f.fields_for :preferences, Struct.new(:documents_copy_email_reply_to, :documents_copy_email_subject, :documents_copy_email_body, :documents_copy_email_enabled, :documents_copy_email_attach_audit, :documents_copy_email_attach_documents).new(@template.preferences['documents_copy_email_reply_to'].presence || configs['reply_to'], @template.preferences['documents_copy_email_subject'].presence || configs['subject'], @template.preferences['documents_copy_email_body'].presence || configs['body'], @template.preferences['documents_copy_email_enabled'], configs['attach_audit_log'] != false && @template.preferences['documents_copy_email_attach_audit'] != false, configs['attach_documents'] != false && @template.preferences['documents_copy_email_attach_documents'] != false) do |ff| %>
+
+
+ <% if can?(:manage, :reply_to) %>
+
+ <%= ff.label :documents_copy_email_reply_to, t('reply_to'), class: 'label' %>
+ <%= ff.email_field :documents_copy_email_reply_to, class: 'base-input', dir: 'auto', placeholder: t(:email) %>
+
+ <% end %>
+
+
+ <%= t('attach_documents_to_the_email') %>
+
+
+ <%= ff.check_box :documents_copy_email_attach_documents, { checked: ff.object.documents_copy_email_attach_documents != false, class: 'toggle', disabled: configs['attach_documents'] == false }, 'true', 'false' %>
+
+
+
+
+ <%= t('attach_audit_log_pdf_to_the_email') %>
+
+
+ <%= ff.check_box :documents_copy_email_attach_audit, { checked: ff.object.documents_copy_email_attach_audit != false, class: 'toggle', disabled: configs['attach_audit_log'] == false }, 'true', 'false' %>
+
+
+
+
+ <%= t('send_emails_automatically_on_completion') %>
+
+
+ <%= ff.check_box :documents_copy_email_enabled, { checked: ff.object.documents_copy_email_enabled != false && configs['enabled'] != false, class: 'toggle', disabled: configs['enabled'] == false }, 'true', 'false' %>
+
+
+ <% end %>
+
+ <% end %>
+
diff --git a/app/views/templates_preferences/_submitter_invitation_email_form.html.erb b/app/views/templates_preferences/_submitter_invitation_email_form.html.erb
new file mode 100644
index 00000000..6f6118d6
--- /dev/null
+++ b/app/views/templates_preferences/_submitter_invitation_email_form.html.erb
@@ -0,0 +1,108 @@
+
+ <% template_email_preferences_values = @template.preferences.values_at('request_email_subject', 'request_email_body').compact_blank %>
+ <% default_template_email_preferences_values = AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY).value.values_at('subject', 'body') %>
+ <% is_custom_template_email = template_email_preferences_values.present? %>
+ <% multiple_submitters = @template.submitters.size > 1 && @template.submitters.size < 5 %>
+ <% if is_custom_template_email || @template.preferences['submitters'].to_a.any? %>
+ <%= button_to nil, template_preferences_path(@template), id: 'submitter_invitation_email_reset_link', method: :delete, class: 'hidden', params: { config_key: AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY }, data: { turbo_confirm: t('are_you_sure_') }, form: { data: { close_on_submit: false } } %>
+ <% end %>
+ <%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-1' }, data: { close_on_submit: false } do |f| %>
+
+ <%= f.hidden_field :config_key, value: AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY %>
+ <%= tag.input id: 'request_email_per_submitter', value: '1', name: 'request_email_per_submitter', class: 'peer', type: 'checkbox', hidden: true, checked: @template.preferences['submitters'].to_a.size > 1 %>
+
+ <%= f.fields_for :preferences, Struct.new(:request_email_subject, :request_email_body).new(*(template_email_preferences_values.presence || default_template_email_preferences_values)) do |ff| %>
+
+
+ <% end %>
+
+ <% if multiple_submitters %>
+
+ <% options = @template.submitters.map { |e| [e['name'], "request_email_#{e['uuid']}"] } %>
+
+
+ <% options.each_with_index do |(label, val), index| %>
+
+ <%= f.radio_button :selected, val, checked: index.zero?, id: "#{val}_radio", data: { action: 'click:toggle-visible#trigger' }, class: 'hidden peer' %>
+ <%= f.label :selected, label, value: val, for: "#{val}_radio", class: 'tab w-full tab-lifted peer-checked:tab-active' %>
+
+ <% end %>
+
+
+ <%= f.fields_for :preferences do |ff| %>
+ <% @template.submitters.each_with_index do |submitter, index| %>
+
+ <% submitter_preferences = f.object.preferences['submitters'].to_a.find { |e| e['uuid'] == submitter['uuid'] } || {} %>
+ <% submitter_email_preferences_values = submitter_preferences.values_at('request_email_subject', 'request_email_body').compact_blank.presence %>
+ <%= ff.fields_for :submitters, Struct.new(:request_email_subject, :request_email_body).new(*(submitter_preferences.values_at('request_email_subject', 'request_email_body').compact_blank.presence || template_email_preferences_values.presence || default_template_email_preferences_values)), index: nil do |fff| %>
+ <%= fff.hidden_field :uuid, value: submitter['uuid'] %>
+
+
+ <% end %>
+
+ <% end %>
+ <% end %>
+
+ <% end %>
+ <%= f.fields_for :preferences, Struct.new(:request_email_enabled).new(@template.preferences['request_email_enabled']) do |ff| %>
+
+
+ <%= t('send_signature_request_email') %>
+
+
+ <%= ff.check_box :request_email_enabled, { checked: ff.object.request_email_enabled != false, class: 'toggle' }, 'true', 'false' %>
+
+
+ <% end %>
+
+ <% end %>
+
diff --git a/app/views/templates_preferences/show.html.erb b/app/views/templates_preferences/show.html.erb
index 54f8d83f..71c0f7e4 100644
--- a/app/views/templates_preferences/show.html.erb
+++ b/app/views/templates_preferences/show.html.erb
@@ -98,92 +98,7 @@
<%= t('signature_request_email') %>
- <%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-1' }, data: { close_on_submit: false } do |f| %>
-
- <%= tag.input id: 'request_email_per_submitter', value: '1', name: 'request_email_per_submitter', class: 'peer', type: 'checkbox', hidden: true, checked: @template.preferences['submitters'].to_a.size > 1 %>
-
- <%= f.fields_for :preferences, Struct.new(:request_email_subject, :request_email_body).new(*(@template.preferences.values_at('request_email_subject', 'request_email_body').compact_blank.presence || AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY).value.values_at('subject', 'body'))) do |ff| %>
-
-
- <% end %>
-
- <% if @template.submitters.size > 1 && @template.submitters.size < 5 %>
-
- <% options = @template.submitters.map { |e| [e['name'], "request_email_#{e['uuid']}"] } %>
-
-
- <% options.each_with_index do |(label, val), index| %>
-
- <%= f.radio_button :selected, val, checked: index.zero?, id: "#{val}_radio", data: { action: 'click:toggle-visible#trigger' }, class: 'hidden peer' %>
- <%= f.label :selected, label, value: val, for: "#{val}_radio", class: 'tab w-full tab-lifted peer-checked:tab-active' %>
-
- <% end %>
-
-
- <%= f.fields_for :preferences do |ff| %>
- <% @template.submitters.each_with_index do |submitter, index| %>
-
- <% submitter_preferences = f.object.preferences['submitters'].to_a.find { |e| e['uuid'] == submitter['uuid'] } || {} %>
- <%= ff.fields_for :submitters, Struct.new(:request_email_subject, :request_email_body).new(*(submitter_preferences.values_at('request_email_subject', 'request_email_body').compact_blank.presence || @template.preferences.values_at('request_email_subject', 'request_email_body').compact_blank.presence || AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY).value.values_at('subject', 'body'))), index: nil do |fff| %>
- <%= fff.hidden_field :uuid, value: submitter['uuid'] %>
-
- <%= fff.label :request_email_subject, t('email_subject'), class: 'label' %>
- <%= fff.text_field :request_email_subject, required: true, class: 'base-input', dir: 'auto' %>
-
-
- <% end %>
-
- <% end %>
- <% end %>
-
- <% end %>
- <%= f.fields_for :preferences, Struct.new(:request_email_enabled).new(@template.preferences['request_email_enabled']) do |ff| %>
-
-
- <%= 'Send signature request email' %>
-
-
- <%= ff.check_box :request_email_enabled, { checked: ff.object.request_email_enabled != false, class: 'toggle' }, 'true', 'false' %>
-
-
- <% end %>
-
- <% end %>
+ <%= render 'templates_preferences/submitter_invitation_email_form' %>
@@ -192,63 +107,7 @@
<%= t('documents_copy_email') %>
- <%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-1' }, data: { close_on_submit: false } do |f| %>
-
- <% configs = AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY).value %>
- <%= f.fields_for :preferences, Struct.new(:documents_copy_email_reply_to, :documents_copy_email_subject, :documents_copy_email_body, :documents_copy_email_enabled, :documents_copy_email_attach_audit, :documents_copy_email_attach_documents).new(@template.preferences['documents_copy_email_reply_to'].presence || configs['reply_to'], @template.preferences['documents_copy_email_subject'].presence || configs['subject'], @template.preferences['documents_copy_email_body'].presence || configs['body'], @template.preferences['documents_copy_email_enabled'], configs['attach_audit_log'] != false && @template.preferences['documents_copy_email_attach_audit'] != false, configs['attach_documents'] != false && @template.preferences['documents_copy_email_attach_documents'] != false) do |ff| %>
-
- <%= ff.label :documents_copy_email_subject, t('email_subject'), class: 'label' %>
- <%= ff.text_field :documents_copy_email_subject, required: true, class: 'base-input', dir: 'auto' %>
-
-
- <% if can?(:manage, :reply_to) %>
-
- <%= ff.label :documents_copy_email_reply_to, t('reply_to'), class: 'label' %>
- <%= ff.email_field :documents_copy_email_reply_to, class: 'base-input', dir: 'auto', placeholder: t(:email) %>
-
- <% end %>
-
-
- <%= t('attach_documents_to_the_email') %>
-
-
- <%= ff.check_box :documents_copy_email_attach_documents, { checked: ff.object.documents_copy_email_attach_documents != false, class: 'toggle', disabled: configs['attach_documents'] == false }, 'true', 'false' %>
-
-
-
-
- <%= t('attach_audit_log_pdf_to_the_email') %>
-
-
- <%= ff.check_box :documents_copy_email_attach_audit, { checked: ff.object.documents_copy_email_attach_audit != false, class: 'toggle', disabled: configs['attach_audit_log'] == false }, 'true', 'false' %>
-
-
-
-
- <%= t('send_emails_automatically_on_completion') %>
-
-
- <%= ff.check_box :documents_copy_email_enabled, { checked: ff.object.documents_copy_email_enabled != false && configs['enabled'] != false, class: 'toggle', disabled: configs['enabled'] == false }, 'true', 'false' %>
-
-
- <% end %>
-
- <% end %>
+ <%= render 'templates_preferences/submitter_documents_copy_email_form' %>
@@ -257,57 +116,7 @@
<%= t('completed_notification_email') %>
- <%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-1' }, data: { close_on_submit: false } do |f| %>
-
- <% configs = AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::SUBMITTER_COMPLETED_EMAIL_KEY).value %>
- <%= f.fields_for :preferences, Struct.new(:completed_notification_email_subject, :completed_notification_email_body, :completed_notification_email_enabled, :completed_notification_email_attach_audit, :completed_notification_email_attach_documents).new(@template.preferences['completed_notification_email_subject'].presence || configs['subject'], @template.preferences['completed_notification_email_body'].presence || configs['body'], @template.preferences['completed_notification_email_enabled'], configs['attach_audit_log'] != false && @template.preferences['completed_notification_email_attach_audit'] != false, configs['attach_documents'] != false && @template.preferences['completed_notification_email_attach_documents'] != false) do |ff| %>
-
- <%= ff.label :completed_notification_email_subject, t('email_subject'), class: 'label' %>
- <%= ff.text_field :completed_notification_email_subject, required: true, class: 'base-input', dir: 'auto' %>
-
-
-
-
- <%= t('attach_documents_to_the_email') %>
-
-
- <%= ff.check_box :completed_notification_email_attach_documents, { checked: ff.object.completed_notification_email_attach_documents != false, class: 'toggle', disabled: configs['attach_documents'] == false }, 'true', 'false' %>
-
-
-
-
- <%= t('attach_audit_log_pdf_to_the_email') %>
-
-
- <%= ff.check_box :completed_notification_email_attach_audit, { checked: ff.object.completed_notification_email_attach_audit != false, class: 'toggle', disabled: configs['attach_audit_log'] == false }, 'true', 'false' %>
-
-
-
-
- <%= t('send_emails_automatically_on_completion') %>
-
-
- <%= ff.check_box :completed_notification_email_enabled, { checked: ff.object.completed_notification_email_enabled != false, class: 'toggle', disabled: configs['enabled'] == false }, 'true', 'false' %>
-
-
- <% end %>
-
- <% end %>
+ <%= render 'templates_preferences/submitter_completed_email_form' %>
@@ -359,9 +168,9 @@
<%= t('share_template_with_test_mode') %>
-
- <%= f.check_box :value, class: 'toggle', checked: @template.template_sharings.exists?(account_id: current_account.testing_accounts) %>
-
+
+ <%= f.check_box :value, class: 'toggle', checked: @template.template_sharings.exists?(account_id: current_account.testing_accounts) %>
+
<% end %>
diff --git a/config/locales/i18n.yml b/config/locales/i18n.yml
index 30a30231..92d43e72 100644
--- a/config/locales/i18n.yml
+++ b/config/locales/i18n.yml
@@ -840,6 +840,8 @@ en: &en
desktop: Desktop
mobile: Mobile
tablet: Tablet
+ reset_default: Reset default
+ send_signature_request_email: Send signature request email
submission_sources:
api: API
bulk: Bulk Send
@@ -1764,6 +1766,8 @@ es: &es
desktop: Escritorio
mobile: Móvil
tablet: Tableta
+ reset_default: Restablecer por defecto
+ send_signature_request_email: Enviar correo de solicitud de firma
submission_sources:
api: API
bulk: Envío masivo
@@ -2689,6 +2693,8 @@ it: &it
desktop: Desktop
mobile: Mobile
tablet: Tablet
+ reset_default: Reimposta predefinito
+ send_signature_request_email: Invia email di richiesta firma
submission_sources:
api: API
bulk: Invio massivo
@@ -3611,6 +3617,8 @@ fr: &fr
desktop: Bureau
mobile: Mobile
tablet: Tablette
+ reset_default: Réinitialiser par défaut
+ send_signature_request_email: Envoyer un e-mail de demande de signature
submission_sources:
api: API
bulk: Envoi en masse
@@ -4537,6 +4545,8 @@ pt: &pt
desktop: Computador
mobile: Celular
tablet: Tablet
+ reset_default: Redefinir para padrão
+ send_signature_request_email: Enviar e-mail de solicitação de assinatura
submission_sources:
api: API
bulk: Envio em massa
@@ -5463,6 +5473,8 @@ de: &de
desktop: Desktop
mobile: Mobil
tablet: Tablet
+ reset_default: Standard zurücksetzen
+ send_signature_request_email: Signaturanfrage-E-Mail senden
submission_sources:
api: API
bulk: Massenversand
@@ -6750,6 +6762,8 @@ nl: &nl
desktop: Desktop
mobile: Mobiel
tablet: Tablet
+ reset_default: Standaard herstellen
+ send_signature_request_email: E-mail met handtekeningaanvraag verzenden
submission_sources:
api: API
bulk: Bulkverzending
diff --git a/config/routes.rb b/config/routes.rb
index 20a3035d..05abbfc4 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -108,7 +108,7 @@ Rails.application.routes.draw do
resource :preview, only: %i[show], controller: 'templates_preview'
resource :form, only: %i[show], controller: 'templates_form_preview'
resource :code_modal, only: %i[show], controller: 'templates_code_modal'
- resource :preferences, only: %i[show create], controller: 'templates_preferences'
+ resource :preferences, only: %i[show create destroy], controller: 'templates_preferences'
resource :share_link, only: %i[show create], controller: 'templates_share_link'
resources :recipients, only: %i[create], controller: 'templates_recipients'
resources :prefillable_fields, only: %i[create], controller: 'templates_prefillable_fields'
From 4603efc04e2106f9dc7f713ff18804809c2088e8 Mon Sep 17 00:00:00 2001
From: Pete Matsyburka
Date: Thu, 13 Nov 2025 09:50:26 +0200
Subject: [PATCH 12/20] refactor toggles form
---
.../templates_preferences_controller.rb | 2 +-
.../_submitter_completed_email_form.html.erb | 24 +++++++++++--------
...bmitter_documents_copy_email_form.html.erb | 23 ++++++++++--------
.../_submitter_invitation_email_form.html.erb | 20 +++++++++-------
4 files changed, 39 insertions(+), 30 deletions(-)
diff --git a/app/controllers/templates_preferences_controller.rb b/app/controllers/templates_preferences_controller.rb
index 47e1a562..6b610b57 100644
--- a/app/controllers/templates_preferences_controller.rb
+++ b/app/controllers/templates_preferences_controller.rb
@@ -26,7 +26,7 @@ class TemplatesPreferencesController < ApplicationController
authorize!(:update, @template)
config_key = params[:config_key]
- preferences_to_delete = RESETTABLE_PREFERENCE_KEYS[config_key] || []
+ preferences_to_delete = RESETTABLE_PREFERENCE_KEYS[config_key]
return head :ok if preferences_to_delete.blank?
diff --git a/app/views/templates_preferences/_submitter_completed_email_form.html.erb b/app/views/templates_preferences/_submitter_completed_email_form.html.erb
index 74626f79..7025409d 100644
--- a/app/views/templates_preferences/_submitter_completed_email_form.html.erb
+++ b/app/views/templates_preferences/_submitter_completed_email_form.html.erb
@@ -5,10 +5,9 @@
<% if is_custom_template_email %>
<%= button_to nil, template_preferences_path(@template), id: 'submitter_completed_email_reset_link', method: :delete, class: 'hidden', params: { config_key: AccountConfig::SUBMITTER_COMPLETED_EMAIL_KEY }, data: { turbo_confirm: t('are_you_sure_') }, form: { data: { close_on_submit: false } } %>
<% end %>
- <%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-1' }, data: { close_on_submit: false } do |f| %>
+ <%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-1', id: 'submitter_completed_email_template_form' }, data: { close_on_submit: false } do |f| %>
- <%= f.hidden_field :config_key, value: AccountConfig::SUBMITTER_COMPLETED_EMAIL_KEY %>
- <%= f.fields_for :preferences, Struct.new(:completed_notification_email_subject, :completed_notification_email_body, :completed_notification_email_enabled, :completed_notification_email_attach_audit, :completed_notification_email_attach_documents).new(@template.preferences['completed_notification_email_subject'].presence || configs['subject'], @template.preferences['completed_notification_email_body'].presence || configs['body'], @template.preferences['completed_notification_email_enabled'], configs['attach_audit_log'] != false && @template.preferences['completed_notification_email_attach_audit'] != false, configs['attach_documents'] != false && @template.preferences['completed_notification_email_attach_documents'] != false) do |ff| %>
+ <%= f.fields_for :preferences, Struct.new(:completed_notification_email_subject, :completed_notification_email_body).new(@template.preferences['completed_notification_email_subject'].presence || configs['subject'], @template.preferences['completed_notification_email_body'].presence || configs['body']) do |ff| %>
+ <% end %>
+ <% end %>
+ <%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-1' }, data: { close_on_submit: false } do |f| %>
+
+ <%= f.fields_for :preferences, Struct.new(:completed_notification_email_enabled, :completed_notification_email_attach_audit, :completed_notification_email_attach_documents).new(@template.preferences['completed_notification_email_enabled'], configs['attach_audit_log'] != false && @template.preferences['completed_notification_email_attach_audit'] != false, configs['attach_documents'] != false && @template.preferences['completed_notification_email_attach_documents'] != false) do |ff| %>
<%= t('attach_documents_to_the_email') %>
@@ -56,11 +60,11 @@
<% end %>
-
<% end %>
+
diff --git a/app/views/templates_preferences/_submitter_documents_copy_email_form.html.erb b/app/views/templates_preferences/_submitter_documents_copy_email_form.html.erb
index 0ce23e59..6a5e8d45 100644
--- a/app/views/templates_preferences/_submitter_documents_copy_email_form.html.erb
+++ b/app/views/templates_preferences/_submitter_documents_copy_email_form.html.erb
@@ -5,10 +5,9 @@
<% if is_custom_template_email %>
<%= button_to nil, template_preferences_path(@template), id: 'submitter_documents_copy_email_reset_link', method: :delete, class: 'hidden', params: { config_key: AccountConfig::SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY }, data: { turbo_confirm: t('are_you_sure_') }, form: { data: { close_on_submit: false } } %>
<% end %>
- <%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-1' }, data: { close_on_submit: false } do |f| %>
+ <%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-1', id: 'submitter_documents_copy_email_template_form' }, data: { close_on_submit: false } do |f| %>
- <%= f.hidden_field :config_key, value: AccountConfig::SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY %>
- <%= f.fields_for :preferences, Struct.new(:documents_copy_email_reply_to, :documents_copy_email_subject, :documents_copy_email_body, :documents_copy_email_enabled, :documents_copy_email_attach_audit, :documents_copy_email_attach_documents).new(@template.preferences['documents_copy_email_reply_to'].presence || configs['reply_to'], @template.preferences['documents_copy_email_subject'].presence || configs['subject'], @template.preferences['documents_copy_email_body'].presence || configs['body'], @template.preferences['documents_copy_email_enabled'], configs['attach_audit_log'] != false && @template.preferences['documents_copy_email_attach_audit'] != false, configs['attach_documents'] != false && @template.preferences['documents_copy_email_attach_documents'] != false) do |ff| %>
+ <%= f.fields_for :preferences, Struct.new(:documents_copy_email_reply_to, :documents_copy_email_subject, :documents_copy_email_body).new(@template.preferences['documents_copy_email_reply_to'].presence || configs['reply_to'], @template.preferences['documents_copy_email_subject'].presence || configs['subject'], @template.preferences['documents_copy_email_body'].presence || configs['body']) do |ff| %>
+ <% end %>
+ <% end %>
+ <%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-1', id: 'submitter_documents_copy_email_template_form' }, data: { close_on_submit: false } do |f| %>
+ <%= f.fields_for :preferences, Struct.new(:documents_copy_email_enabled, :documents_copy_email_attach_audit, :documents_copy_email_attach_documents).new(@template.preferences['documents_copy_email_enabled'], configs['attach_audit_log'] != false && @template.preferences['documents_copy_email_attach_audit'] != false, configs['attach_documents'] != false && @template.preferences['documents_copy_email_attach_documents'] != false) do |ff| %>
<% if can?(:manage, :reply_to) %>
<%= ff.label :documents_copy_email_reply_to, t('reply_to'), class: 'label' %>
@@ -62,11 +65,11 @@
<% end %>
-
<% end %>
+
diff --git a/app/views/templates_preferences/_submitter_invitation_email_form.html.erb b/app/views/templates_preferences/_submitter_invitation_email_form.html.erb
index 6f6118d6..0f87ddcd 100644
--- a/app/views/templates_preferences/_submitter_invitation_email_form.html.erb
+++ b/app/views/templates_preferences/_submitter_invitation_email_form.html.erb
@@ -6,9 +6,8 @@
<% if is_custom_template_email || @template.preferences['submitters'].to_a.any? %>
<%= button_to nil, template_preferences_path(@template), id: 'submitter_invitation_email_reset_link', method: :delete, class: 'hidden', params: { config_key: AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY }, data: { turbo_confirm: t('are_you_sure_') }, form: { data: { close_on_submit: false } } %>
<% end %>
- <%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-1' }, data: { close_on_submit: false } do |f| %>
+ <%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-1', id: 'submitter_invitation_email_template_form' }, data: { close_on_submit: false } do |f| %>
- <%= f.hidden_field :config_key, value: AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY %>
<%= tag.input id: 'request_email_per_submitter', value: '1', name: 'request_email_per_submitter', class: 'peer', type: 'checkbox', hidden: true, checked: @template.preferences['submitters'].to_a.size > 1 %>
<%= f.fields_for :preferences, Struct.new(:request_email_subject, :request_email_body).new(*(template_email_preferences_values.presence || default_template_email_preferences_values)) do |ff| %>
@@ -35,7 +34,7 @@
- <%= ff.text_area :request_email_body, required: true, class: 'base-input w-full py-2', dir: 'auto' %>
+ <%= ff.text_area :request_email_body, required: true, class: 'base-input w-full py-2 !rounded-2xl', dir: 'auto' %>
<% end %>
@@ -88,6 +87,9 @@
<% end %>
<% end %>
+ <% end %>
+ <%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-1' }, data: { close_on_submit: false } do |f| %>
+
<%= f.fields_for :preferences, Struct.new(:request_email_enabled).new(@template.preferences['request_email_enabled']) do |ff| %>
@@ -98,11 +100,11 @@
<% end %>
-
<% end %>
+
From 83e32bec9f4232967bde684dc0e3cde38ea09663 Mon Sep 17 00:00:00 2001
From: Pete Matsyburka
Date: Thu, 13 Nov 2025 10:34:52 +0200
Subject: [PATCH 13/20] fix preferences form
---
.../_submitter_documents_copy_email_form.html.erb | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/app/views/templates_preferences/_submitter_documents_copy_email_form.html.erb b/app/views/templates_preferences/_submitter_documents_copy_email_form.html.erb
index 6a5e8d45..8d178369 100644
--- a/app/views/templates_preferences/_submitter_documents_copy_email_form.html.erb
+++ b/app/views/templates_preferences/_submitter_documents_copy_email_form.html.erb
@@ -30,16 +30,16 @@
<%= ff.text_area :documents_copy_email_body, required: true, class: 'base-input w-full py-2 !rounded-2xl', dir: 'auto' %>
- <% end %>
- <% end %>
- <%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-1', id: 'submitter_documents_copy_email_template_form' }, data: { close_on_submit: false } do |f| %>
- <%= f.fields_for :preferences, Struct.new(:documents_copy_email_enabled, :documents_copy_email_attach_audit, :documents_copy_email_attach_documents).new(@template.preferences['documents_copy_email_enabled'], configs['attach_audit_log'] != false && @template.preferences['documents_copy_email_attach_audit'] != false, configs['attach_documents'] != false && @template.preferences['documents_copy_email_attach_documents'] != false) do |ff| %>
<% if can?(:manage, :reply_to) %>
<%= ff.label :documents_copy_email_reply_to, t('reply_to'), class: 'label' %>
<%= ff.email_field :documents_copy_email_reply_to, class: 'base-input', dir: 'auto', placeholder: t(:email) %>
<% end %>
+ <% end %>
+ <% end %>
+ <%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-1', id: 'submitter_documents_copy_email_template_form' }, data: { close_on_submit: false } do |f| %>
+ <%= f.fields_for :preferences, Struct.new(:documents_copy_email_enabled, :documents_copy_email_attach_audit, :documents_copy_email_attach_documents).new(@template.preferences['documents_copy_email_enabled'], configs['attach_audit_log'] != false && @template.preferences['documents_copy_email_attach_audit'] != false, configs['attach_documents'] != false && @template.preferences['documents_copy_email_attach_documents'] != false) do |ff| %>
<%= t('attach_documents_to_the_email') %>
From de5cd92dba5e1024d6c2406af422222e84442450 Mon Sep 17 00:00:00 2001
From: Pete Matsyburka
Date: Thu, 13 Nov 2025 19:36:06 +0200
Subject: [PATCH 14/20] adjust send email
---
app/views/submissions/_send_email.html.erb | 117 +-----------------
.../submissions/_send_email_base.html.erb | 116 +++++++++++++++++
2 files changed, 117 insertions(+), 116 deletions(-)
create mode 100644 app/views/submissions/_send_email_base.html.erb
diff --git a/app/views/submissions/_send_email.html.erb b/app/views/submissions/_send_email.html.erb
index eaf04b3a..18e03eda 100644
--- a/app/views/submissions/_send_email.html.erb
+++ b/app/views/submissions/_send_email.html.erb
@@ -1,116 +1 @@
-<% submitter_preferences_index = template&.preferences&.dig('submitters').to_a.index_by { |e| e['uuid'] } %>
-<% template_submitters = local_assigns[:submitter]&.submission&.template_submitters || template.submitters %>
-<% message_field_id = "message_field_#{SecureRandom.hex(3)}" %>
-
-<% config = AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY) %>
-
-
- <%= tag.input id: toggle_uuid = SecureRandom.uuid, value: '1', name: 'request_email_per_submitter', class: 'peer', type: 'checkbox', hidden: true, checked: local_assigns[:message_per_submitter] != false && template&.preferences&.dig('submitters').to_a.size > 1 %>
-
- <% if template_submitters.size > 1 && template_submitters.size < 5 && local_assigns[:message_per_submitter] != false %>
-
- <% end %>
-
-
+<%= render partial: 'submissions/send_email_base', locals: local_assigns %>
diff --git a/app/views/submissions/_send_email_base.html.erb b/app/views/submissions/_send_email_base.html.erb
new file mode 100644
index 00000000..eaf04b3a
--- /dev/null
+++ b/app/views/submissions/_send_email_base.html.erb
@@ -0,0 +1,116 @@
+<% submitter_preferences_index = template&.preferences&.dig('submitters').to_a.index_by { |e| e['uuid'] } %>
+<% template_submitters = local_assigns[:submitter]&.submission&.template_submitters || template.submitters %>
+<% message_field_id = "message_field_#{SecureRandom.hex(3)}" %>
+
+<% config = AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY) %>
+
+
+ <%= tag.input id: toggle_uuid = SecureRandom.uuid, value: '1', name: 'request_email_per_submitter', class: 'peer', type: 'checkbox', hidden: true, checked: local_assigns[:message_per_submitter] != false && template&.preferences&.dig('submitters').to_a.size > 1 %>
+
+ <% if template_submitters.size > 1 && template_submitters.size < 5 && local_assigns[:message_per_submitter] != false %>
+
+ <% end %>
+
+
From 9333a1ba45672d72dd2204bdd4b76005982bd969 Mon Sep 17 00:00:00 2001
From: Pete Matsyburka
Date: Fri, 14 Nov 2025 16:35:02 +0200
Subject: [PATCH 15/20] fix fields error alert
---
app/javascript/template_builder/fields.vue | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/app/javascript/template_builder/fields.vue b/app/javascript/template_builder/fields.vue
index 822ecc0b..2bee841a 100644
--- a/app/javascript/template_builder/fields.vue
+++ b/app/javascript/template_builder/fields.vue
@@ -470,9 +470,13 @@ export default {
const data = JSON.parse(jsonStr)
if (data.error) {
- alert(data.error)
+ if ((data.fields || fields).length) {
+ this.template.fields = data.fields || fields
- this.template.fields = data.fields || fields
+ this.save()
+ } else {
+ alert(data.error)
+ }
break
} else if (data.analyzing) {
From c4fbcc103af931fcd5829c6e28f3fb4c37f22d67 Mon Sep 17 00:00:00 2001
From: Pete Matsyburka
Date: Sat, 15 Nov 2025 10:46:54 +0200
Subject: [PATCH 16/20] autocorrect pdf
---
lib/submissions/generate_result_attachments.rb | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/lib/submissions/generate_result_attachments.rb b/lib/submissions/generate_result_attachments.rb
index 934c86fc..e347d2ac 100644
--- a/lib/submissions/generate_result_attachments.rb
+++ b/lib/submissions/generate_result_attachments.rb
@@ -719,20 +719,30 @@ module Submissions
begin
pdf.sign(io, write_options: { validate: false }, **sign_params)
- rescue HexaPDF::MalformedPDFError, NoMethodError => e
+ rescue HexaPDF::Error, NoMethodError => e
Rollbar.error(e) if defined?(Rollbar)
- pdf.sign(io, write_options: { validate: false, incremental: false }, **sign_params)
+ begin
+ pdf.sign(io, write_options: { validate: false, incremental: false }, **sign_params)
+ rescue HexaPDF::Error
+ pdf.validate(auto_correct: true)
+ pdf.sign(io, write_options: { validate: false, incremental: false }, **sign_params)
+ end
end
maybe_enable_ltv(io, sign_params)
else
begin
pdf.write(io, incremental: true, validate: false)
- rescue HexaPDF::MalformedPDFError, NoMethodError => e
+ rescue HexaPDF::Error, NoMethodError => e
Rollbar.error(e) if defined?(Rollbar)
- pdf.write(io, incremental: false, validate: false)
+ begin
+ pdf.write(io, incremental: false, validate: false)
+ rescue HexaPDF::Error
+ pdf.validate(auto_correct: true)
+ pdf.write(io, incremental: false, validate: false)
+ end
end
end
From 5fec952b8cb11cd99a748f57cd5b62f1eae88c24 Mon Sep 17 00:00:00 2001
From: Pete Matsyburka
Date: Sat, 15 Nov 2025 19:48:42 +0200
Subject: [PATCH 17/20] adjust detections
---
.rubocop.yml | 3 +++
lib/templates/image_to_fields.rb | 8 +++++++-
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/.rubocop.yml b/.rubocop.yml
index aad5509e..294fc484 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -45,6 +45,9 @@ Metrics/PerceivedComplexity:
Style/MultipleComparison:
Enabled: false
+Style/NumericPredicate:
+ Enabled: false
+
Naming/PredicateMethod:
Enabled: false
diff --git a/lib/templates/image_to_fields.rb b/lib/templates/image_to_fields.rb
index fa342f4e..50837c1c 100755
--- a/lib/templates/image_to_fields.rb
+++ b/lib/templates/image_to_fields.rb
@@ -77,7 +77,7 @@ module Templates
end
def build_fields_from_detections(detections, image)
- Array.new(detections[:xyxy].shape[0]) do |i|
+ detections[:xyxy].shape[0].times.filter_map do |i|
x1 = detections[:xyxy][i, 0]
y1 = detections[:xyxy][i, 1]
x2 = detections[:xyxy][i, 2]
@@ -92,6 +92,12 @@ module Templates
x1_norm = x2 / image.width.to_f
y1_norm = y2 / image.height.to_f
+ x1_norm = 1 if x1_norm > 1
+ y1_norm = 1 if y1_norm > 1
+
+ next if x0_norm < 0 || x0_norm > 1
+ next if y0_norm < 0 || y0_norm > 1
+
type_name = ID_TO_CLASS[class_id]
Field.new(
From 1d87e210be7f1471dc2cc76d2800e0e8de4e67c1 Mon Sep 17 00:00:00 2001
From: Pete Matsyburka
Date: Sun, 16 Nov 2025 19:05:54 +0200
Subject: [PATCH 18/20] optimize detect fields
---
lib/templates/image_to_fields.rb | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/lib/templates/image_to_fields.rb b/lib/templates/image_to_fields.rb
index 50837c1c..786e9785 100755
--- a/lib/templates/image_to_fields.rb
+++ b/lib/templates/image_to_fields.rb
@@ -37,10 +37,10 @@ module Templates
transform_info[:trim_offset_x] = base_offset_x
transform_info[:trim_offset_y] = base_offset_y + r[:offset_y]
- outputs = model.predict({ 'input' => input_tensor })
+ outputs = model.predict({ 'input' => input_tensor }, output_type: :numo)
- boxes = Numo::SFloat.cast(outputs['dets'])[0, true, true]
- logits = Numo::SFloat.cast(outputs['labels'])[0, true, true]
+ boxes = outputs['dets'][0, true, true]
+ logits = outputs['labels'][0, true, true]
postprocess_outputs(boxes, logits, transform_info, acc, confidence:, temperature:, resolution:)
end
@@ -50,10 +50,10 @@ module Templates
transform_info[:trim_offset_x] = base_offset_x
transform_info[:trim_offset_y] = base_offset_y
- outputs = model.predict({ 'input' => input_tensor })
+ outputs = model.predict({ 'input' => input_tensor }, output_type: :numo)
- boxes = Numo::SFloat.cast(outputs['dets'])[0, true, true]
- logits = Numo::SFloat.cast(outputs['labels'])[0, true, true]
+ boxes = outputs['dets'][0, true, true]
+ logits = outputs['labels'][0, true, true]
detections = postprocess_outputs(boxes, logits, transform_info, confidence:, temperature:, resolution:)
end
From c53ed7f984bc0bfd4c499df473ab52ce4fd64558 Mon Sep 17 00:00:00 2001
From: Alex Turchyn
Date: Fri, 14 Nov 2025 00:32:30 +0200
Subject: [PATCH 19/20] add custom invitation reminder emails
---
app/controllers/personalization_settings_controller.rb | 1 +
app/controllers/templates_preferences_controller.rb | 6 ++++--
app/models/account_config.rb | 7 +++++++
.../_submitter_invitation_reminder_email_collapse.html.erb | 0
app/views/templates_preferences/show.html.erb | 1 +
config/locales/i18n.yml | 7 +++++++
6 files changed, 20 insertions(+), 2 deletions(-)
create mode 100644 app/views/templates_preferences/_submitter_invitation_reminder_email_collapse.html.erb
diff --git a/app/controllers/personalization_settings_controller.rb b/app/controllers/personalization_settings_controller.rb
index 9812aaee..d9d33490 100644
--- a/app/controllers/personalization_settings_controller.rb
+++ b/app/controllers/personalization_settings_controller.rb
@@ -4,6 +4,7 @@ class PersonalizationSettingsController < ApplicationController
ALLOWED_KEYS = [
AccountConfig::FORM_COMPLETED_BUTTON_KEY,
AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY,
+ AccountConfig::SUBMITTER_INVITATION_REMINDER_EMAIL_KEY,
AccountConfig::SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY,
AccountConfig::SUBMITTER_COMPLETED_EMAIL_KEY,
AccountConfig::FORM_COMPLETED_MESSAGE_KEY,
diff --git a/app/controllers/templates_preferences_controller.rb b/app/controllers/templates_preferences_controller.rb
index 6b610b57..391b6714 100644
--- a/app/controllers/templates_preferences_controller.rb
+++ b/app/controllers/templates_preferences_controller.rb
@@ -5,6 +5,8 @@ class TemplatesPreferencesController < ApplicationController
RESETTABLE_PREFERENCE_KEYS = {
AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY => %w[request_email_subject request_email_body submitters],
+ AccountConfig::SUBMITTER_INVITATION_REMINDER_EMAIL_KEY => %w[invitation_reminder_email_subject
+ invitation_reminder_email_body],
AccountConfig::SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY => %w[documents_copy_email_subject documents_copy_email_body],
AccountConfig::SUBMITTER_COMPLETED_EMAIL_KEY => %w[completed_notification_email_subject
completed_notification_email_body]
@@ -46,14 +48,14 @@ class TemplatesPreferencesController < ApplicationController
def template_params
params.require(:template).permit(
preferences: %i[bcc_completed request_email_subject request_email_body
+ invitation_reminder_email_subject invitation_reminder_email_body
documents_copy_email_subject documents_copy_email_body
documents_copy_email_enabled documents_copy_email_attach_audit
documents_copy_email_attach_documents documents_copy_email_reply_to
completed_notification_email_attach_documents
completed_redirect_url validate_unique_submitters
require_all_submitters submitters_order require_phone_2fa
- default_expire_at_duration shared_link_2fa
- default_expire_at request_email_enabled
+ default_expire_at_duration shared_link_2fa default_expire_at request_email_enabled
completed_notification_email_subject completed_notification_email_body
completed_notification_email_enabled completed_notification_email_attach_audit] +
[completed_message: %i[title body],
diff --git a/app/models/account_config.rb b/app/models/account_config.rb
index 462cc725..c2893360 100644
--- a/app/models/account_config.rb
+++ b/app/models/account_config.rb
@@ -22,6 +22,7 @@
#
class AccountConfig < ApplicationRecord
SUBMITTER_INVITATION_EMAIL_KEY = 'submitter_invitation_email'
+ SUBMITTER_INVITATION_REMINDER_EMAIL_KEY = 'submitter_invitation_reminder_email'
SUBMITTER_COMPLETED_EMAIL_KEY = 'submitter_completed_email'
SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY = 'submitter_documents_copy_email'
BCC_EMAILS = 'bcc_emails'
@@ -59,6 +60,12 @@ class AccountConfig < ApplicationRecord
'body' => I18n.t(:submitter_invitation_email_sign_body)
}
},
+ SUBMITTER_INVITATION_REMINDER_EMAIL_KEY => lambda {
+ {
+ 'subject' => I18n.t(:you_are_invited_to_sign_a_document),
+ 'body' => I18n.t(:submitter_invitation_email_sign_body)
+ }
+ },
SUBMITTER_COMPLETED_EMAIL_KEY => lambda {
{
'subject' => I18n.t(:template_name_has_been_completed_by_submitters),
diff --git a/app/views/templates_preferences/_submitter_invitation_reminder_email_collapse.html.erb b/app/views/templates_preferences/_submitter_invitation_reminder_email_collapse.html.erb
new file mode 100644
index 00000000..e69de29b
diff --git a/app/views/templates_preferences/show.html.erb b/app/views/templates_preferences/show.html.erb
index 71c0f7e4..290286cf 100644
--- a/app/views/templates_preferences/show.html.erb
+++ b/app/views/templates_preferences/show.html.erb
@@ -101,6 +101,7 @@
<%= render 'templates_preferences/submitter_invitation_email_form' %>
+ <%= render 'templates_preferences/submitter_invitation_reminder_email_collapse' %>
diff --git a/config/locales/i18n.yml b/config/locales/i18n.yml
index 92d43e72..3b6d649f 100644
--- a/config/locales/i18n.yml
+++ b/config/locales/i18n.yml
@@ -290,6 +290,7 @@ en: &en
invalid_timeserver: Invalid Timeserver
email_templates: Email Templates
signature_request_email: Signature request email
+ signature_request_reminder_email: Signature request reminder email
signature_request_sms: Signature Request SMS
verification_code_sms: Verification Code SMS
completed_notification_email: Completed notification email
@@ -1217,6 +1218,7 @@ es: &es
invalid_timeserver: Servidor de tiempo inválido
email_templates: Plantillas de correo electrónico
signature_request_email: Correo de solicitud de firma
+ signature_request_reminder_email: Correo de recordatorio de solicitud de firma
signature_request_sms: SMS de solicitud de firma
verification_code_sms: SMS de código de verificación
completed_notification_email: Correo de notificación de formulario completado
@@ -2143,6 +2145,7 @@ it: &it
invalid_timeserver: Server di timestamp non valido
email_templates: Modelli email
signature_request_email: Email di richiesta di firma
+ signature_request_reminder_email: Email di promemoria di richiesta di firma
signature_request_sms: SMS di richiesta di firma
verification_code_sms: SMS con codice di verifica
completed_notification_email: Email di notifica di completamento
@@ -3071,6 +3074,7 @@ fr: &fr
invalid_timeserver: Serveur d’horodatage invalide
email_templates: Modèles d’e‑mail
signature_request_email: E‑mail de demande de signature
+ signature_request_reminder_email: E‑mail de rappel de demande de signature
signature_request_sms: SMS de demande de signature
verification_code_sms: SMS de code de vérification
completed_notification_email: E‑mail de notification de finalisation
@@ -3995,6 +3999,7 @@ pt: &pt
invalid_timeserver: Servidor de carimbo de tempo inválido
email_templates: Modelos de e-mail
signature_request_email: E-mail de solicitação de assinatura
+ signature_request_reminder_email: E-mail de lembrete de solicitação de assinatura
signature_request_sms: SMS de solicitação de assinatura
verification_code_sms: SMS com código de verificação
completed_notification_email: E-mail de notificação de submissão concluída
@@ -4923,6 +4928,7 @@ de: &de
invalid_timeserver: Ungültiger Zeitstempelserver
email_templates: E-Mail-Vorlagen
signature_request_email: E-Mail für Signaturanfrage
+ signature_request_reminder_email: E-Mail-Erinnerung für Signaturanfrage
signature_request_sms: SMS für Signaturanfrage
verification_code_sms: SMS mit Verifizierungscode
completed_notification_email: E-Mail-Benachrichtigung bei Abschluss
@@ -6216,6 +6222,7 @@ nl: &nl
invalid_timeserver: Ongeldige tijdserver
email_templates: E-mailsjablonen
signature_request_email: E-mail voor handtekeningverzoek
+ signature_request_reminder_email: E-mailherinnering voor handtekeningverzoek
signature_request_sms: SMS voor handtekeningverzoek
verification_code_sms: Verificatiecode-SMS
completed_notification_email: E-mailmelding voltooid
From fd9eb09dd6b52f449cea6b4a012c82c260363fd3 Mon Sep 17 00:00:00 2001
From: Pete Matsyburka
Date: Mon, 17 Nov 2025 10:21:38 +0200
Subject: [PATCH 20/20] use can?
---
app/controllers/users_controller.rb | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 129a90c0..39555b59 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -27,7 +27,8 @@ class UsersController < ApplicationController
existing_user = User.accessible_by(current_ability).find_by(email: @user.email)
if existing_user
- if existing_user.archived_at? && authorize!(:manage, existing_user) && authorize!(:manage, @user.account)
+ if existing_user.archived_at? &&
+ current_ability.can?(:manage, existing_user) && current_ability.can?(:manage, @user.account)
existing_user.assign_attributes(@user.slice(:first_name, :last_name, :role, :account_id))
existing_user.archived_at = nil
@user = existing_user