diff --git a/Gemfile b/Gemfile
index e2d74068..99e771b9 100644
--- a/Gemfile
+++ b/Gemfile
@@ -36,7 +36,7 @@ gem 'rotp'
gem 'rouge', require: false
gem 'rqrcode', require: false
gem 'ruby-vips'
-gem 'rubyXL', require: false
+gem 'rubyzip', require: false
gem 'shakapacker'
gem 'sidekiq'
gem 'sqlite3', require: false
@@ -45,6 +45,7 @@ gem 'trilogy', require: false
gem 'turbo-rails'
gem 'twitter_cldr', require: false
gem 'tzinfo-data'
+gem 'xlsxtream', require: false
group :development, :test do
gem 'better_html'
diff --git a/Gemfile.lock b/Gemfile.lock
index d320a892..5dc77e9f 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -497,9 +497,6 @@ GEM
ruby-vips (2.3.0)
ffi (~> 1.12)
logger
- rubyXL (3.4.35)
- nokogiri (>= 1.10.8)
- rubyzip (>= 3.2.2)
rubyzip (3.2.2)
securerandom (0.4.1)
semantic_range (3.1.1)
@@ -575,10 +572,13 @@ GEM
base64
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
+ xlsxtream (3.1.0)
+ zip_kit (>= 6.2, < 7)
xpath (3.2.0)
nokogiri (~> 1.8)
yaml (0.4.0)
zeitwerk (2.8.2)
+ zip_kit (6.3.4)
PLATFORMS
aarch64-linux
@@ -638,7 +638,7 @@ DEPENDENCIES
rubocop-rails
rubocop-rspec
ruby-vips
- rubyXL
+ rubyzip
shakapacker
sidekiq
simplecov
@@ -650,6 +650,7 @@ DEPENDENCIES
tzinfo-data
web-console
webmock
+ xlsxtream
RUBY VERSION
ruby 4.0.5
diff --git a/app/controllers/submit_form_decline_controller.rb b/app/controllers/submit_form_decline_controller.rb
index ca50e60c..139175cf 100644
--- a/app/controllers/submit_form_decline_controller.rb
+++ b/app/controllers/submit_form_decline_controller.rb
@@ -26,7 +26,8 @@ class SubmitFormDeclineController < ApplicationController
user = @submitter.submission.created_by_user || @submitter.template.author
- if user.user_configs.find_by(key: UserConfig::RECEIVE_DECLINED_EMAIL)&.value != false
+ if Users.send_emails?(user) &&
+ user.user_configs.find_by(key: UserConfig::RECEIVE_DECLINED_EMAIL)&.value != false
SubmitterMailer.declined_email(@submitter, user).deliver_later!
end
diff --git a/app/controllers/submit_form_delegate_controller.rb b/app/controllers/submit_form_delegate_controller.rb
index 6448a750..da0e4ed1 100644
--- a/app/controllers/submit_form_delegate_controller.rb
+++ b/app/controllers/submit_form_delegate_controller.rb
@@ -32,7 +32,8 @@ class SubmitFormDelegateController < ApplicationController
SubmissionEvents.create_with_tracking_data(@submitter, 'delegate_form', request,
{ old_email: @submitter.email, email: })
- @submitter.update!(email:, phone: nil, name: nil, slug: SecureRandom.base58(14))
+ @submitter.update!(email:, phone: nil, name: nil, slug: SecureRandom.base58(14),
+ values: Submitters.fetch_values_for_delegate(@submitter))
end
SendSubmitterInvitationEmailJob.perform_async('submitter_id' => @submitter.id)
diff --git a/app/controllers/submit_form_invite_controller.rb b/app/controllers/submit_form_invite_controller.rb
index 8a231e1c..0976d028 100644
--- a/app/controllers/submit_form_invite_controller.rb
+++ b/app/controllers/submit_form_invite_controller.rb
@@ -23,7 +23,7 @@ class SubmitFormInviteController < ApplicationController
@submitter.submission.submitters.create!(uuid: attrs[:uuid], email:, account_id: @submitter.account_id)
- SubmissionEvents.create_with_tracking_data(@submitter, 'invite_party', request, { uuid: @submitter.uuid })
+ SubmissionEvents.create_with_tracking_data(@submitter, 'invite_party', request, { uuid: attrs[:uuid] })
end
@submitter.submission.update!(submitters_order: :preserved)
diff --git a/app/controllers/templates_uploads_controller.rb b/app/controllers/templates_uploads_controller.rb
index d389bfe3..8ba06980 100644
--- a/app/controllers/templates_uploads_controller.rb
+++ b/app/controllers/templates_uploads_controller.rb
@@ -63,7 +63,7 @@ class TemplatesUploadsController < ApplicationController
tempfile.write(DownloadUtils.call(params[:url], validate: true).body)
tempfile.rewind
- filename = URI.decode_www_form_component(params[:filename]) if params[:filename].present?
+ filename = URI.decode_www_form_component(params[:filename]).tr('/', '-') if params[:filename].present?
filename ||= File.basename(URI.decode_www_form_component(params[:url]))
file = ActionDispatch::Http::UploadedFile.new(
diff --git a/app/controllers/webhook_secret_controller.rb b/app/controllers/webhook_secret_controller.rb
index b9b8a3f2..94a659e4 100644
--- a/app/controllers/webhook_secret_controller.rb
+++ b/app/controllers/webhook_secret_controller.rb
@@ -3,11 +3,19 @@
class WebhookSecretController < ApplicationController
load_and_authorize_resource :webhook_url, parent: false
+ HEADER_NAME_REGEXP = /\A[\w-]+\z/
+
def show; end
def update
+ key = webhook_secret_params[:key]
+
+ if key.present? && !HEADER_NAME_REGEXP.match?(key)
+ return redirect_back(fallback_location: settings_webhook_path(@webhook_url), alert: I18n.t('unable_to_save'))
+ end
+
@webhook_url.update!(secret: {
- webhook_secret_params[:key] => webhook_secret_params[:value]
+ key => webhook_secret_params[:value]
}.compact_blank)
redirect_back(fallback_location: settings_webhook_path(@webhook_url),
diff --git a/app/javascript/submission_form/phone_step.vue b/app/javascript/submission_form/phone_step.vue
index d3e95bed..c3e90fb3 100644
--- a/app/javascript/submission_form/phone_step.vue
+++ b/app/javascript/submission_form/phone_step.vue
@@ -261,7 +261,7 @@ export default {
}
},
resendCode () {
- if (this.codeSentAt && Date.now() - this.codeSentAt < 15000) {
+ if (this.codeSentAt && Date.now() - this.codeSentAt < 30000) {
this.startResendCodeCountdown()
} else {
this.isResendLoading = true
@@ -274,7 +274,7 @@ export default {
}
},
startResendCodeCountdown () {
- this.resendCodeCountdown = 15 - parseInt((Date.now() - this.codeSentAt) / 1000)
+ this.resendCodeCountdown = 30 - parseInt((Date.now() - this.codeSentAt) / 1000)
this.interval = setInterval(() => {
this.resendCodeCountdown--
diff --git a/app/javascript/template_builder/builder.vue b/app/javascript/template_builder/builder.vue
index f0146f39..46db0dc3 100644
--- a/app/javascript/template_builder/builder.vue
+++ b/app/javascript/template_builder/builder.vue
@@ -2371,7 +2371,6 @@ export default {
const areaCopy = JSON.parse(JSON.stringify(area))
delete fieldCopy.areas
- delete fieldCopy.submitter_uuid
areaCopy.relativeX = area.x - minX
areaCopy.relativeY = area.y - minY
@@ -2381,6 +2380,7 @@ export default {
const clipboardData = {
items,
+ submitters: this.template.submitters.map((submitter) => ({ uuid: submitter.uuid, name: submitter.name })),
templateId: this.template.id,
timestamp: Date.now(),
isGroup: true
@@ -2491,6 +2491,20 @@ export default {
const fieldUuidIndex = {}
const fieldOptionsMap = {}
+ const submitterUuidsMap = {}
+
+ const copiedSubmitterUuids = [...new Set(data.items.map((item) => item.field.submitter_uuid).filter(Boolean))]
+
+ if (copiedSubmitterUuids.length > 1) {
+ copiedSubmitterUuids.forEach((uuid) => {
+ const name = data.submitters?.find((submitter) => submitter.uuid === uuid)?.name
+
+ const submitter = this.template.submitters.find((s) => s.uuid === uuid) ||
+ (name && this.template.submitters.find((s) => s.name.toLowerCase() === name.toLowerCase()))
+
+ submitterUuidsMap[uuid] = (submitter || this.selectedSubmitter).uuid
+ })
+ }
data.items.forEach((item) => {
const field = JSON.parse(JSON.stringify(item.field))
@@ -2515,7 +2529,7 @@ export default {
const newField = fieldUuidIndex[field.uuid] || {
...field,
uuid: v4(),
- submitter_uuid: this.selectedSubmitter.uuid,
+ submitter_uuid: submitterUuidsMap[field.submitter_uuid] || this.selectedSubmitter.uuid,
areas: []
}
diff --git a/app/jobs/process_submitter_completion_job.rb b/app/jobs/process_submitter_completion_job.rb
index a6c02dc6..1dc1da13 100644
--- a/app/jobs/process_submitter_completion_job.rb
+++ b/app/jobs/process_submitter_completion_job.rb
@@ -133,7 +133,7 @@ class ProcessSubmitterCompletionJob
user_submitter = submission.submitters.find { |s| s.email == user.email }
is_sent_to_user =
- if user.role != 'integration' &&
+ if user.role != 'integration' && Users.send_emails?(user) &&
(!user_submitter || user_submitter.preferences['send_email'] == false || !is_copy_email_enabled) &&
user.user_configs.find_by(key: UserConfig::RECEIVE_COMPLETED_EMAIL)&.value != false
SubmitterMailer.completed_email(submitter, user).deliver_later!
diff --git a/app/models/submitter.rb b/app/models/submitter.rb
index 3d21e2d4..0a7f70b8 100644
--- a/app/models/submitter.rb
+++ b/app/models/submitter.rb
@@ -90,7 +90,7 @@ class Submitter < ApplicationRecord
def friendly_name
if name.present? && email.present? && email.exclude?(',')
- %("#{name.delete('"')}" <#{email}>)
+ %("#{name.delete('"').squish}" <#{email}>)
else
email
end
diff --git a/app/views/personalization_settings/_documents_copy_email_form.html.erb b/app/views/personalization_settings/_documents_copy_email_form.html.erb
index 4cc21d79..0f35fc69 100644
--- a/app/views/personalization_settings/_documents_copy_email_form.html.erb
+++ b/app/views/personalization_settings/_documents_copy_email_form.html.erb
@@ -6,7 +6,7 @@
- <%= form_for AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY), url: settings_personalization_path, method: :post, html: { autocomplete: 'off', class: 'space-y-4' } do |f| %>
+ <%= form_for AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY), url: settings_personalization_path, method: :post, html: { autocomplete: 'off', class: 'flex flex-col gap-4' } do |f| %>
<%= f.hidden_field :key %>
<%= f.fields_for :value, Struct.new(:subject, :body, :reply_to, :attach_audit_log, :attach_documents, :bcc_recipients, :enabled).new(*f.object.value.values_at('subject', 'body', 'reply_to', 'attach_audit_log', 'attach_documents', 'bcc_recipients', 'enabled')) do |ff| %>
diff --git a/app/views/personalization_settings/_form_completed_button_form.html.erb b/app/views/personalization_settings/_form_completed_button_form.html.erb
index 65017a91..e8d27aed 100644
--- a/app/views/personalization_settings/_form_completed_button_form.html.erb
+++ b/app/views/personalization_settings/_form_completed_button_form.html.erb
@@ -6,7 +6,7 @@
- <%= form_for AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::FORM_COMPLETED_BUTTON_KEY), url: settings_personalization_path, method: :post, html: { autocomplete: 'off', class: 'space-y-4' } do |f| %>
+ <%= form_for AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::FORM_COMPLETED_BUTTON_KEY), url: settings_personalization_path, method: :post, html: { autocomplete: 'off', class: 'flex flex-col gap-4' } do |f| %>
<%= f.hidden_field :key %>
<%= f.fields_for :value, Struct.new(:title, :url).new(*(f.object.value || {}).values_at('title', 'url')) do |ff| %>
diff --git a/app/views/personalization_settings/_form_completed_message_form.html.erb b/app/views/personalization_settings/_form_completed_message_form.html.erb
index 6030bffe..5f10da65 100644
--- a/app/views/personalization_settings/_form_completed_message_form.html.erb
+++ b/app/views/personalization_settings/_form_completed_message_form.html.erb
@@ -6,7 +6,7 @@
- <%= form_for AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::FORM_COMPLETED_MESSAGE_KEY), url: settings_personalization_path, method: :post, html: { autocomplete: 'off', class: 'space-y-4' } do |f| %>
+ <%= form_for AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::FORM_COMPLETED_MESSAGE_KEY), url: settings_personalization_path, method: :post, html: { autocomplete: 'off', class: 'flex flex-col gap-4' } do |f| %>
<%= f.hidden_field :key %>
<%= f.fields_for :value, Struct.new(:title, :body).new(*(f.object.value || {}).values_at('title', 'body')) do |ff| %>
diff --git a/app/views/personalization_settings/_form_policy_links_form.html.erb b/app/views/personalization_settings/_form_policy_links_form.html.erb
index cabf1b83..ecf967e4 100644
--- a/app/views/personalization_settings/_form_policy_links_form.html.erb
+++ b/app/views/personalization_settings/_form_policy_links_form.html.erb
@@ -7,7 +7,7 @@
- <%= form_for AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::POLICY_LINKS_KEY), url: settings_personalization_path, method: :post, html: { autocomplete: 'off', class: 'space-y-4' } do |f| %>
+ <%= form_for AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::POLICY_LINKS_KEY), url: settings_personalization_path, method: :post, html: { autocomplete: 'off', class: 'flex flex-col gap-4' } do |f| %>
<%= f.hidden_field :key %>
- <%= form_for AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY), url: settings_personalization_path, method: :post, html: { autocomplete: 'off', class: 'space-y-4' } do |f| %>
+ <%= form_for AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY), url: settings_personalization_path, method: :post, html: { autocomplete: 'off', class: 'flex flex-col gap-4' } do |f| %>
<%= f.hidden_field :key %>
<%= f.fields_for :value, Struct.new(:subject, :body, :reply_to).new(*f.object.value.values_at('subject', 'body', 'reply_to')) do |ff| %>
diff --git a/app/views/personalization_settings/_submitter_completed_email_form.html.erb b/app/views/personalization_settings/_submitter_completed_email_form.html.erb
index afd13aa8..f80ff410 100644
--- a/app/views/personalization_settings/_submitter_completed_email_form.html.erb
+++ b/app/views/personalization_settings/_submitter_completed_email_form.html.erb
@@ -6,7 +6,7 @@
- <%= form_for AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::SUBMITTER_COMPLETED_EMAIL_KEY), url: settings_personalization_path, method: :post, html: { autocomplete: 'off', class: 'space-y-4' } do |f| %>
+ <%= form_for AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::SUBMITTER_COMPLETED_EMAIL_KEY), url: settings_personalization_path, method: :post, html: { autocomplete: 'off', class: 'flex flex-col gap-4' } do |f| %>
<%= f.hidden_field :key %>
<%= f.fields_for :value, Struct.new(:subject, :body, :attach_audit_log, :attach_documents).new(*f.object.value.values_at('subject', 'body', 'attach_audit_log', 'attach_documents')) do |ff| %>
diff --git a/app/views/submissions_dashboard/index.html.erb b/app/views/submissions_dashboard/index.html.erb
index 9bfaf39a..3cfaf4c6 100644
--- a/app/views/submissions_dashboard/index.html.erb
+++ b/app/views/submissions_dashboard/index.html.erb
@@ -28,7 +28,7 @@
<% view_archived_html = capture do %>
- <% if can?(:manage, :countless) || current_account.submissions.where.not(archived_at: nil).exists? %>
+ <% if can?(:manage, :countless) || current_account.submissions.archived.exists? || current_account.templates.where(Submission.where(Submission.arel_table[:template_id].eq(::Template.arel_table[:id])).arel.exists).archived.exists? %>
diff --git a/app/views/templates_dashboard/index.html.erb b/app/views/templates_dashboard/index.html.erb
index 5406bf68..a65abca6 100644
--- a/app/views/templates_dashboard/index.html.erb
+++ b/app/views/templates_dashboard/index.html.erb
@@ -1,4 +1,4 @@
-<% has_archived = can?(:manage, :countless) || current_account.templates.where.not(archived_at: nil).exists? %>
+<% has_archived = can?(:manage, :countless) || current_account.templates.archived.exists? %>
<% show_dropzone = params[:q].blank? && @pagy.pages == 1 && ((@template_folders.size < 10 && @templates.size.zero?) || (@template_folders.size < 7 && @templates.size < 4) || (@template_folders.size < 4 && @templates.size < 7)) %>
<% if Docuseal.demo? %><%= render 'shared/demo_alert' %><% end %>
diff --git a/app/views/webhook_settings/show.html.erb b/app/views/webhook_settings/show.html.erb
index 49f4f1c6..47911b85 100644
--- a/app/views/webhook_settings/show.html.erb
+++ b/app/views/webhook_settings/show.html.erb
@@ -83,7 +83,7 @@
<% if @webhook_events.present? || params[:status].present? %>
-
<%= t('events_log') %>
+
<%= t('event_log') %>
<%= link_to t('all'), url_for(params: request.query_parameters.except('status', 'page')), style: 'margin-bottom: -1px', class: "tab h-10 text-base #{params[:status].blank? ? 'tab-active tab-bordered' : 'pb-[3px]'}" %>
<%= link_to t('succeeded'), url_for(params: request.query_parameters.except('page').merge('status' => 'success')), style: 'margin-bottom: -1px', class: "tab h-10 text-base #{params[:status] == 'success' ? 'tab-active tab-bordered' : 'pb-[3px]'}" %>
diff --git a/config/dotenv.rb b/config/dotenv.rb
index cb0f8e7c..0a6aedf0 100644
--- a/config/dotenv.rb
+++ b/config/dotenv.rb
@@ -105,6 +105,6 @@ if ENV['REDIS_URL'].to_s.empty?
redis_password = Digest::SHA1.hexdigest("redis#{ENV.fetch('SECRET_KEY_BASE', '')}")
- ENV['REDIS_URL'] = "redis://default:#{redis_password}@0.0.0.0:6379/0"
+ ENV['REDIS_URL'] = "redis://default:#{redis_password}@127.0.0.1:16379/0"
ENV['LOCAL_REDIS_URL'] = ENV.fetch('REDIS_URL', nil)
end
diff --git a/config/initializers/autoload.rb b/config/initializers/autoload.rb
index 99dc4962..fd307b35 100644
--- a/config/initializers/autoload.rb
+++ b/config/initializers/autoload.rb
@@ -2,7 +2,7 @@
autoload :CSV, 'csv'
autoload :CSVSafe, 'csv-safe'
-autoload :RubyXL, 'rubyXL'
+autoload :Xlsxtream, 'xlsxtream'
autoload :Zip, 'zip'
autoload :Numo, 'numo/narray'
autoload :OnnxRuntime, 'onnxruntime'
diff --git a/config/locales/i18n.yml b/config/locales/i18n.yml
index 869795e2..9e20f38d 100644
--- a/config/locales/i18n.yml
+++ b/config/locales/i18n.yml
@@ -8034,7 +8034,7 @@ nl: &nl
awaiting: Wachten
document_id: Document-ID
envelope_id: Envelop-ID
- event_log: Gebeurtenissenlogboek
+ event_log: Gebeurtenislogboek
verify: Verifiëren
testing_log_not_for_production_use: Testlogboek - Niet voor productiegebruik
original_sha256: Oorspronkelijke SHA256
diff --git a/lib/puma/plugin/redis_server.rb b/lib/puma/plugin/redis_server.rb
index cad448f9..e7bf7f28 100644
--- a/lib/puma/plugin/redis_server.rb
+++ b/lib/puma/plugin/redis_server.rb
@@ -54,6 +54,7 @@ Puma::Plugin.create do
Dir.chdir(ENV.fetch('WORKDIR', nil)) unless ENV['WORKDIR'].to_s.empty?
exec('redis-server', '--requirepass', Digest::SHA1.hexdigest("redis#{ENV.fetch('SECRET_KEY_BASE', '')}"),
+ '--bind', '127.0.0.1', '--port', '16379',
'--loglevel', 'warning')
end
end
diff --git a/lib/submissions/generate_audit_trail.rb b/lib/submissions/generate_audit_trail.rb
index 1e7bc33d..17733511 100644
--- a/lib/submissions/generate_audit_trail.rb
+++ b/lib/submissions/generate_audit_trail.rb
@@ -62,7 +62,7 @@ module Submissions
ActiveStorage::Attachment.create!(
blob: ActiveStorage::Blob.create_and_upload!(
io: io.tap(&:rewind), filename: "#{I18n.t('audit_log')} - " \
- "#{submission.name || submission.template&.name}.pdf"
+ "#{submission.name || submission.template&.name}.pdf".tr('/', '-')
),
name: 'audit_trail',
record: submission
diff --git a/lib/submissions/generate_combined_attachment.rb b/lib/submissions/generate_combined_attachment.rb
index d8a60bf9..45aadb1c 100644
--- a/lib/submissions/generate_combined_attachment.rb
+++ b/lib/submissions/generate_combined_attachment.rb
@@ -37,7 +37,7 @@ module Submissions
ActiveStorage::Attachment.create!(
blob: ActiveStorage::Blob.create_and_upload!(
- io: io.tap(&:rewind), filename: "#{submission.name || submission.template&.name}.pdf"
+ io: io.tap(&:rewind), filename: "#{submission.name || submission.template&.name}.pdf".tr('/', '-')
),
name: with_audit ? 'combined_document' : 'merged_document',
record: submission
diff --git a/lib/submissions/generate_export_files.rb b/lib/submissions/generate_export_files.rb
index f1096db2..ee115a77 100644
--- a/lib/submissions/generate_export_files.rb
+++ b/lib/submissions/generate_export_files.rb
@@ -19,22 +19,19 @@ module Submissions
end
def rows_to_xlsx(rows)
- workbook = RubyXL::Workbook.new
- worksheet = workbook[0]
- worksheet.sheet_name = Time.current.to_date.to_s
-
headers = build_headers(rows)
- headers.each_with_index do |column_name, column_index|
- worksheet.add_cell(0, column_index, column_name)
- end
- rows.each.with_index(1) do |row, row_index|
- extract_columns(row, headers).each_with_index do |value, column_index|
- worksheet.add_cell(row_index, column_index, value)
+ io = StringIO.new
+
+ Xlsxtream::Workbook.open(io) do |workbook|
+ workbook.write_worksheet(Time.current.to_date.to_s) do |sheet|
+ sheet << headers.to_a
+
+ rows.each { |row| sheet << extract_columns(row, headers) }
end
end
- workbook.stream.string
+ io.string
end
def rows_to_csv(rows)
@@ -150,8 +147,6 @@ module Submissions
ActiveStorage::Blob.proxy_url(attachment.blob, expires_at:) if attachment
end
- elsif submitter_value == true || submitter_value == false
- submitter_value.to_s
else
submitter_value
end
diff --git a/lib/submissions/generate_preview_attachments.rb b/lib/submissions/generate_preview_attachments.rb
index eb9011db..a35d18f0 100644
--- a/lib/submissions/generate_preview_attachments.rb
+++ b/lib/submissions/generate_preview_attachments.rb
@@ -71,7 +71,7 @@ module Submissions
submission:,
values_hash:,
name: 'preview_merged_document',
- filename: "#{submission.name || template&.name}.pdf"
+ filename: "#{submission.name || template&.name}.pdf".tr('/', '-')
)
ApplicationRecord.no_touching { attachment.save! }
@@ -115,7 +115,7 @@ module Submissions
submitter:,
uuid: GenerateResultAttachments.images_pdf_uuid(original_documents.select(&:image?)),
values_hash:,
- filename: "#{submission.name || template&.name}.pdf"
+ filename: "#{submission.name || template&.name}.pdf".tr('/', '-')
)
ApplicationRecord.no_touching do
diff --git a/lib/submissions/generate_result_attachments.rb b/lib/submissions/generate_result_attachments.rb
index c221d38a..44a047de 100644
--- a/lib/submissions/generate_result_attachments.rb
+++ b/lib/submissions/generate_result_attachments.rb
@@ -814,7 +814,7 @@ module Submissions
end
ActiveStorage::Attachment.new(
- blob: ActiveStorage::Blob.create_and_upload!(io: io.tap(&:rewind), filename: "#{name}.pdf"),
+ blob: ActiveStorage::Blob.create_and_upload!(io: io.tap(&:rewind), filename: "#{name}.pdf".tr('/', '-')),
metadata: { original_uuid: uuid,
analyzed: true,
sha256: Base64.urlsafe_encode64(Digest::SHA256.digest(io.string)) },
diff --git a/lib/submitters.rb b/lib/submitters.rb
index 3ea1aa07..b8de2bde 100644
--- a/lib/submitters.rb
+++ b/lib/submitters.rb
@@ -165,6 +165,21 @@ module Submitters
preferences
end
+ def fetch_values_for_delegate(submitter)
+ fields = submitter.submission.template_fields || submitter.template.fields
+ default_values = submitter.preferences['default_values'] || {}
+
+ field_uuids = fields.filter_map do |field|
+ next if field['submitter_uuid'] != submitter.uuid
+ next unless field['type'].in?(%w[signature phone verification kba initials])
+ next if default_values[field['uuid']].present?
+
+ field['uuid']
+ end
+
+ submitter.values.except(*field_uuids)
+ end
+
def send_signature_requests(submitters, delay_seconds: nil)
submitters.each_with_index do |submitter, index|
next if submitter.email.blank?
@@ -238,7 +253,7 @@ module Submitters
I18n.l(completed_at.in_time_zone(submitter.account.timezone), format: :short)
end
- "#{filename}.#{blob.filename.extension}"
+ "#{filename}.#{blob.filename.extension}".tr('/', '-')
end
def send_shared_link_email_verification_code(submitter, request:)
diff --git a/lib/submitters/submit_values.rb b/lib/submitters/submit_values.rb
index 3686b71c..e4ef2030 100644
--- a/lib/submitters/submit_values.rb
+++ b/lib/submitters/submit_values.rb
@@ -490,7 +490,7 @@ module Submitters
submission.submitters.create!(uuid: s['uuid'], email:, phone:, account_id: submitter.account_id)
- SubmissionEvents.create_with_tracking_data(submitter, 'invite_party', request, { uuid: submitter.uuid })
+ SubmissionEvents.create_with_tracking_data(submitter, 'invite_party', request, { uuid: s['uuid'] })
is_invited = true
end
diff --git a/lib/templates/create_attachments.rb b/lib/templates/create_attachments.rb
index f5b47fd9..6f8f695d 100644
--- a/lib/templates/create_attachments.rb
+++ b/lib/templates/create_attachments.rb
@@ -76,7 +76,7 @@ module Templates
blob = ActiveStorage::Blob.create_and_upload!(
io: StringIO.new(document_data),
- filename: file.original_filename,
+ filename: file.original_filename.tr('/', '-'),
metadata: {
**metadata,
identified: file.content_type == PDF_CONTENT_TYPE,
diff --git a/lib/users.rb b/lib/users.rb
index 49989a4f..9508fb78 100644
--- a/lib/users.rb
+++ b/lib/users.rb
@@ -3,6 +3,10 @@
module Users
module_function
+ def send_emails?(user)
+ !user.archived_at?
+ end
+
def generate_csv(users)
headers = %w[email first_name last_name role current_sign_in_at last_sign_in_at updated_at created_at]