mirror of
https://github.com/docusealco/docuseal
synced 2026-11-09 15:42:32 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a00d4ad5c | ||
|
|
30704b59c2 | ||
|
|
d56c903596 | ||
|
|
5353e8fa23 | ||
|
|
038d780265 | ||
|
|
f3a8100734 | ||
|
|
dbf446efe1 | ||
|
|
621431166b | ||
|
|
92cfd5624d | ||
|
|
e39e84adfa | ||
|
|
1b63b16691 | ||
|
|
256d14eb94 | ||
|
|
49463d611c | ||
|
|
4fec8db589 | ||
|
|
0bc620fa90 | ||
|
|
c0c5ba48a0 | ||
|
|
8fe0293ebe |
No files matched your search
+65
-65
@@ -3,29 +3,29 @@ GEM
|
|||||||
specs:
|
specs:
|
||||||
action_text-trix (2.1.19)
|
action_text-trix (2.1.19)
|
||||||
railties
|
railties
|
||||||
actioncable (8.1.4)
|
actioncable (8.1.4.1)
|
||||||
actionpack (= 8.1.4)
|
actionpack (= 8.1.4.1)
|
||||||
activesupport (= 8.1.4)
|
activesupport (= 8.1.4.1)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
websocket-driver (>= 0.6.1)
|
websocket-driver (>= 0.6.1)
|
||||||
zeitwerk (~> 2.6)
|
zeitwerk (~> 2.6)
|
||||||
actionmailbox (8.1.4)
|
actionmailbox (8.1.4.1)
|
||||||
actionpack (= 8.1.4)
|
actionpack (= 8.1.4.1)
|
||||||
activejob (= 8.1.4)
|
activejob (= 8.1.4.1)
|
||||||
activerecord (= 8.1.4)
|
activerecord (= 8.1.4.1)
|
||||||
activestorage (= 8.1.4)
|
activestorage (= 8.1.4.1)
|
||||||
activesupport (= 8.1.4)
|
activesupport (= 8.1.4.1)
|
||||||
mail (>= 2.8.0)
|
mail (>= 2.8.0)
|
||||||
actionmailer (8.1.4)
|
actionmailer (8.1.4.1)
|
||||||
actionpack (= 8.1.4)
|
actionpack (= 8.1.4.1)
|
||||||
actionview (= 8.1.4)
|
actionview (= 8.1.4.1)
|
||||||
activejob (= 8.1.4)
|
activejob (= 8.1.4.1)
|
||||||
activesupport (= 8.1.4)
|
activesupport (= 8.1.4.1)
|
||||||
mail (>= 2.8.0)
|
mail (>= 2.8.0)
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
actionpack (8.1.4)
|
actionpack (8.1.4.1)
|
||||||
actionview (= 8.1.4)
|
actionview (= 8.1.4.1)
|
||||||
activesupport (= 8.1.4)
|
activesupport (= 8.1.4.1)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
rack (>= 2.2.4)
|
rack (>= 2.2.4)
|
||||||
rack-session (>= 1.0.1)
|
rack-session (>= 1.0.1)
|
||||||
@@ -33,36 +33,36 @@ GEM
|
|||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
rails-html-sanitizer (~> 1.6)
|
rails-html-sanitizer (~> 1.6)
|
||||||
useragent (~> 0.16)
|
useragent (~> 0.16)
|
||||||
actiontext (8.1.4)
|
actiontext (8.1.4.1)
|
||||||
action_text-trix (~> 2.1.15)
|
action_text-trix (~> 2.1.15)
|
||||||
actionpack (= 8.1.4)
|
actionpack (= 8.1.4.1)
|
||||||
activerecord (= 8.1.4)
|
activerecord (= 8.1.4.1)
|
||||||
activestorage (= 8.1.4)
|
activestorage (= 8.1.4.1)
|
||||||
activesupport (= 8.1.4)
|
activesupport (= 8.1.4.1)
|
||||||
globalid (>= 0.6.0)
|
globalid (>= 0.6.0)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
actionview (8.1.4)
|
actionview (8.1.4.1)
|
||||||
activesupport (= 8.1.4)
|
activesupport (= 8.1.4.1)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubi (~> 1.11)
|
erubi (~> 1.11)
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
rails-html-sanitizer (~> 1.6)
|
rails-html-sanitizer (~> 1.6, >= 1.7.2)
|
||||||
activejob (8.1.4)
|
activejob (8.1.4.1)
|
||||||
activesupport (= 8.1.4)
|
activesupport (= 8.1.4.1)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (8.1.4)
|
activemodel (8.1.4.1)
|
||||||
activesupport (= 8.1.4)
|
activesupport (= 8.1.4.1)
|
||||||
activerecord (8.1.4)
|
activerecord (8.1.4.1)
|
||||||
activemodel (= 8.1.4)
|
activemodel (= 8.1.4.1)
|
||||||
activesupport (= 8.1.4)
|
activesupport (= 8.1.4.1)
|
||||||
timeout (>= 0.4.0)
|
timeout (>= 0.4.0)
|
||||||
activestorage (8.1.4)
|
activestorage (8.1.4.1)
|
||||||
actionpack (= 8.1.4)
|
actionpack (= 8.1.4.1)
|
||||||
activejob (= 8.1.4)
|
activejob (= 8.1.4.1)
|
||||||
activerecord (= 8.1.4)
|
activerecord (= 8.1.4.1)
|
||||||
activesupport (= 8.1.4)
|
activesupport (= 8.1.4.1)
|
||||||
marcel (~> 1.0)
|
marcel (~> 1.0)
|
||||||
activesupport (8.1.4)
|
activesupport (8.1.4.1)
|
||||||
base64
|
base64
|
||||||
bigdecimal
|
bigdecimal
|
||||||
concurrent-ruby (~> 1.0, >= 1.3.1)
|
concurrent-ruby (~> 1.0, >= 1.3.1)
|
||||||
@@ -293,9 +293,9 @@ GEM
|
|||||||
activesupport (>= 4)
|
activesupport (>= 4)
|
||||||
railties (>= 4)
|
railties (>= 4)
|
||||||
request_store (~> 1.0)
|
request_store (~> 1.0)
|
||||||
loofah (2.25.2)
|
loofah (2.25.3)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.12.0)
|
nokogiri (>= 1.19.5)
|
||||||
mail (2.9.1)
|
mail (2.9.1)
|
||||||
logger
|
logger
|
||||||
mini_mime (>= 0.1.1)
|
mini_mime (>= 0.1.1)
|
||||||
@@ -323,15 +323,15 @@ GEM
|
|||||||
net-smtp (0.5.2)
|
net-smtp (0.5.2)
|
||||||
net-protocol
|
net-protocol
|
||||||
nio4r (2.7.5)
|
nio4r (2.7.5)
|
||||||
nokogiri (1.19.4-aarch64-linux-gnu)
|
nokogiri (1.19.7-aarch64-linux-gnu)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.19.4-aarch64-linux-musl)
|
nokogiri (1.19.7-aarch64-linux-musl)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.19.4-arm64-darwin)
|
nokogiri (1.19.7-arm64-darwin)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.19.4-x86_64-linux-gnu)
|
nokogiri (1.19.7-x86_64-linux-gnu)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.19.4-x86_64-linux-musl)
|
nokogiri (1.19.7-x86_64-linux-musl)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
numo-narray-alt (0.10.3)
|
numo-narray-alt (0.10.3)
|
||||||
onnxruntime (0.10.1-aarch64-linux)
|
onnxruntime (0.10.1-aarch64-linux)
|
||||||
@@ -373,7 +373,7 @@ GEM
|
|||||||
puma (8.0.2)
|
puma (8.0.2)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
racc (1.8.1)
|
racc (1.8.1)
|
||||||
rack (3.2.7)
|
rack (3.2.8)
|
||||||
rack-proxy (0.7.7)
|
rack-proxy (0.7.7)
|
||||||
rack
|
rack
|
||||||
rack-session (2.1.2)
|
rack-session (2.1.2)
|
||||||
@@ -383,33 +383,33 @@ GEM
|
|||||||
rack (>= 1.3)
|
rack (>= 1.3)
|
||||||
rackup (2.3.1)
|
rackup (2.3.1)
|
||||||
rack (>= 3)
|
rack (>= 3)
|
||||||
rails (8.1.4)
|
rails (8.1.4.1)
|
||||||
actioncable (= 8.1.4)
|
actioncable (= 8.1.4.1)
|
||||||
actionmailbox (= 8.1.4)
|
actionmailbox (= 8.1.4.1)
|
||||||
actionmailer (= 8.1.4)
|
actionmailer (= 8.1.4.1)
|
||||||
actionpack (= 8.1.4)
|
actionpack (= 8.1.4.1)
|
||||||
actiontext (= 8.1.4)
|
actiontext (= 8.1.4.1)
|
||||||
actionview (= 8.1.4)
|
actionview (= 8.1.4.1)
|
||||||
activejob (= 8.1.4)
|
activejob (= 8.1.4.1)
|
||||||
activemodel (= 8.1.4)
|
activemodel (= 8.1.4.1)
|
||||||
activerecord (= 8.1.4)
|
activerecord (= 8.1.4.1)
|
||||||
activestorage (= 8.1.4)
|
activestorage (= 8.1.4.1)
|
||||||
activesupport (= 8.1.4)
|
activesupport (= 8.1.4.1)
|
||||||
bundler (>= 1.15.0)
|
bundler (>= 1.15.0)
|
||||||
railties (= 8.1.4)
|
railties (= 8.1.4.1)
|
||||||
rails-dom-testing (2.3.0)
|
rails-dom-testing (2.3.0)
|
||||||
activesupport (>= 5.0.0)
|
activesupport (>= 5.0.0)
|
||||||
minitest
|
minitest
|
||||||
nokogiri (>= 1.6)
|
nokogiri (>= 1.6)
|
||||||
rails-html-sanitizer (1.7.1)
|
rails-html-sanitizer (1.7.2)
|
||||||
loofah (~> 2.25, >= 2.25.2)
|
loofah (~> 2.25, >= 2.25.3)
|
||||||
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
||||||
rails-i18n (8.1.0)
|
rails-i18n (8.1.0)
|
||||||
i18n (>= 0.7, < 2)
|
i18n (>= 0.7, < 2)
|
||||||
railties (>= 8.0.0, < 9)
|
railties (>= 8.0.0, < 9)
|
||||||
railties (8.1.4)
|
railties (8.1.4.1)
|
||||||
actionpack (= 8.1.4)
|
actionpack (= 8.1.4.1)
|
||||||
activesupport (= 8.1.4)
|
activesupport (= 8.1.4.1)
|
||||||
irb (~> 1.13)
|
irb (~> 1.13)
|
||||||
rackup (>= 1.0.0)
|
rackup (>= 1.0.0)
|
||||||
rake (>= 12.2)
|
rake (>= 12.2)
|
||||||
@@ -535,7 +535,7 @@ GEM
|
|||||||
thor (1.5.0)
|
thor (1.5.0)
|
||||||
timeout (0.6.1)
|
timeout (0.6.1)
|
||||||
trailblazer-option (0.1.2)
|
trailblazer-option (0.1.2)
|
||||||
trilogy (2.12.2)
|
trilogy (2.13.3)
|
||||||
bigdecimal
|
bigdecimal
|
||||||
tsort (0.2.0)
|
tsort (0.2.0)
|
||||||
turbo-rails (2.0.23)
|
turbo-rails (2.0.23)
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ DocuSeal is an open source platform that provides secure and efficient digital d
|
|||||||
<a href="https://docuseal.com/sign_up">☁️ Try in Cloud</a>
|
<a href="https://docuseal.com/sign_up">☁️ Try in Cloud</a>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
[](https://demo.docuseal.tech)
|
[](https://demo.docuseal.tech)
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
- PDF form fields builder (WYSIWYG)
|
- PDF form fields builder (WYSIWYG)
|
||||||
@@ -41,10 +41,11 @@ DocuSeal is an open source platform that provides secure and efficient digital d
|
|||||||
- Automatic PDF eSignature
|
- Automatic PDF eSignature
|
||||||
- PDF signature verification
|
- PDF signature verification
|
||||||
- User management
|
- User management
|
||||||
- Mobile-optimized
|
- Mobile-optimized signing
|
||||||
- 7 UI languages with signing available in 14 languages
|
- 7 UI languages with signing available in 14 languages
|
||||||
- API and Webhooks for integrations
|
- API and Webhooks for integrations
|
||||||
- Easy to deploy in minutes
|
- Easy to deploy in minutes
|
||||||
|
- Mobile apps for [iOS](https://apps.apple.com/us/app/docuseal-e-signature/id6823564236) and [Android](https://play.google.com/store/apps/details?id=com.docuseal.app)
|
||||||
|
|
||||||
## Pro Features
|
## Pro Features
|
||||||
- Company logo and white-label
|
- Company logo and white-label
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ Out of scope vulnerabilities:
|
|||||||
- DNSSEC, CAA, CSP headers
|
- DNSSEC, CAA, CSP headers
|
||||||
- DNS or email security related
|
- DNS or email security related
|
||||||
- SSRF
|
- SSRF
|
||||||
|
- DoS
|
||||||
- Rate Limiting
|
- Rate Limiting
|
||||||
|
|
||||||
Note: We reserve the right to classify any reported vulnerability as out of scope for the bug bounty program.
|
Note: We reserve the right to classify any reported vulnerability as out of scope for the bug bounty program.
|
||||||
@@ -34,6 +34,12 @@ module Api
|
|||||||
@record = attachment.record
|
@record = attachment.record
|
||||||
@record = @record.record if @record.is_a?(ActiveStorage::Attachment)
|
@record = @record.record if @record.is_a?(ActiveStorage::Attachment)
|
||||||
|
|
||||||
|
if DetectBrowserDevice.search_bot?(request.user_agent)
|
||||||
|
Rollbar.warning("Search bot: #{@record.class.name} #{@record.id}") if defined?(Rollbar)
|
||||||
|
|
||||||
|
raise ActionController::RoutingError, 'Not Found'
|
||||||
|
end
|
||||||
|
|
||||||
authorization_check!(attachment, @record, exp)
|
authorization_check!(attachment, @record, exp)
|
||||||
|
|
||||||
if request.headers['Range'].present?
|
if request.headers['Range'].present?
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ module Api
|
|||||||
render json: {
|
render json: {
|
||||||
id: @submission.id,
|
id: @submission.id,
|
||||||
documents: documents.map do |attachment|
|
documents: documents.map do |attachment|
|
||||||
{ name: attachment.filename.base, url: ActiveStorage::Blob.proxy_url(attachment.blob, expires_at:) }
|
{ name: FilenameUtils.basename(attachment.blob[:filename]), url: ActiveStorage::Blob.proxy_url(attachment.blob, expires_at:) }
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ class ApplicationController < ActionController::Base
|
|||||||
:true_ability,
|
:true_ability,
|
||||||
:form_link_host,
|
:form_link_host,
|
||||||
:svg_icon,
|
:svg_icon,
|
||||||
|
:browser_os,
|
||||||
:turbo_native_ios?,
|
:turbo_native_ios?,
|
||||||
:turbo_native_android?
|
:turbo_native_android?
|
||||||
|
|
||||||
@@ -58,6 +59,10 @@ class ApplicationController < ActionController::Base
|
|||||||
request.session[:impersonated_user_id] = user.uuid
|
request.session[:impersonated_user_id] = user.uuid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def browser_os
|
||||||
|
@browser_os ||= DetectBrowserDevice.os(request.user_agent)
|
||||||
|
end
|
||||||
|
|
||||||
def pagy_auto(collection, **keyword_args)
|
def pagy_auto(collection, **keyword_args)
|
||||||
if current_ability.can?(:manage, :countless)
|
if current_ability.can?(:manage, :countless)
|
||||||
pagy(:countless, collection, **keyword_args)
|
pagy(:countless, collection, **keyword_args)
|
||||||
|
|||||||
@@ -66,7 +66,9 @@ module Mcp
|
|||||||
@template.save!
|
@template.save!
|
||||||
|
|
||||||
documents, = Templates::CreateAttachments.call(@template, { files: [file] }, extract_fields: true)
|
documents, = Templates::CreateAttachments.call(@template, { files: [file] }, extract_fields: true)
|
||||||
schema = documents.map { |doc| { attachment_uuid: doc.uuid, name: doc.filename.base } }
|
schema = documents.map do |doc|
|
||||||
|
{ attachment_uuid: doc.uuid, name: FilenameUtils.basename(doc.blob[:filename]) }
|
||||||
|
end
|
||||||
|
|
||||||
if @template.fields.blank?
|
if @template.fields.blank?
|
||||||
@template.fields = Templates::ProcessDocument.normalize_attachment_fields(@template, documents)
|
@template.fields = Templates::ProcessDocument.normalize_attachment_fields(@template, documents)
|
||||||
|
|||||||
@@ -92,8 +92,11 @@ class StartFormController < ApplicationController
|
|||||||
|
|
||||||
blank_fields = required_fields.select { |key| submitter_params[key].blank? }
|
blank_fields = required_fields.select { |key| submitter_params[key].blank? }
|
||||||
|
|
||||||
|
is_invalid_email = required_fields.include?('email') && submitter_params[:email].present? &&
|
||||||
|
!submitter_params[:email].match?(User::VALIDATE_EMAIL_REGEXP)
|
||||||
|
|
||||||
submitter =
|
submitter =
|
||||||
if blank_fields.present?
|
if blank_fields.present? || is_invalid_email
|
||||||
Submitter.new(submitter_params)
|
Submitter.new(submitter_params)
|
||||||
else
|
else
|
||||||
Submitters::StartForm.find_or_initialize_submitter(
|
Submitters::StartForm.find_or_initialize_submitter(
|
||||||
@@ -104,6 +107,12 @@ class StartFormController < ApplicationController
|
|||||||
|
|
||||||
blank_fields.each { |key| submitter.errors.add(key.to_sym, :blank) }
|
blank_fields.each { |key| submitter.errors.add(key.to_sym, :blank) }
|
||||||
|
|
||||||
|
if is_invalid_email
|
||||||
|
Rollbar.warning("Invalid start form email: #{submitter_params[:email]}") if defined?(Rollbar)
|
||||||
|
|
||||||
|
submitter.errors.add(:email, :invalid)
|
||||||
|
end
|
||||||
|
|
||||||
submitter
|
submitter
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ class SubmissionEventsController < ApplicationController
|
|||||||
'send_2fa_sms' => '2fa',
|
'send_2fa_sms' => '2fa',
|
||||||
'send_2fa_email' => '2fa',
|
'send_2fa_email' => '2fa',
|
||||||
'send_sms' => 'send',
|
'send_sms' => 'send',
|
||||||
|
'fail_sms' => 'alert_circle',
|
||||||
'phone_verified' => 'phone_check',
|
'phone_verified' => 'phone_check',
|
||||||
'email_verified' => 'email_check',
|
'email_verified' => 'email_check',
|
||||||
'click_sms' => 'hand_click',
|
'click_sms' => 'hand_click',
|
||||||
|
|||||||
@@ -26,6 +26,6 @@ class SubmissionsExportController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
render layout: turbo_native_android? ? 'plain' : true
|
render layout: 'plain'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -14,6 +14,6 @@ class SubmissionsFiltersController < ApplicationController
|
|||||||
def show
|
def show
|
||||||
return head :not_found unless ALLOWED_NAMES.include?(params[:name])
|
return head :not_found unless ALLOWED_NAMES.include?(params[:name])
|
||||||
|
|
||||||
render params[:name], layout: turbo_native_android? ? 'plain' : true
|
render params[:name], layout: 'plain'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -8,6 +8,7 @@ class SubmitFormController < ApplicationController
|
|||||||
skip_authorization_check
|
skip_authorization_check
|
||||||
|
|
||||||
before_action :load_submitter, only: %i[show update completed]
|
before_action :load_submitter, only: %i[show update completed]
|
||||||
|
before_action :maybe_render_not_found_for_search_bot, only: %i[show completed]
|
||||||
before_action :maybe_redirect_delegated, only: %i[show completed]
|
before_action :maybe_redirect_delegated, only: %i[show completed]
|
||||||
before_action :maybe_render_locked_page, only: :show
|
before_action :maybe_render_locked_page, only: :show
|
||||||
before_action :maybe_require_link_2fa, only: %i[show]
|
before_action :maybe_require_link_2fa, only: %i[show]
|
||||||
@@ -111,6 +112,14 @@ class SubmitFormController < ApplicationController
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def maybe_render_not_found_for_search_bot
|
||||||
|
return unless DetectBrowserDevice.search_bot?(request.user_agent)
|
||||||
|
|
||||||
|
Rollbar.warning("Search bot: submitter #{@submitter&.id}") if defined?(Rollbar)
|
||||||
|
|
||||||
|
raise ActionController::RoutingError, I18n.t('not_found')
|
||||||
|
end
|
||||||
|
|
||||||
def maybe_require_link_2fa
|
def maybe_require_link_2fa
|
||||||
return if Submitters::AuthorizedForForm.pass_link_2fa?(@submitter, current_user, request)
|
return if Submitters::AuthorizedForForm.pass_link_2fa?(@submitter, current_user, request)
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class TemplateDocumentsController < ApplicationController
|
|||||||
documents, = Templates::CreateAttachments.call(@template, params, extract_fields: true)
|
documents, = Templates::CreateAttachments.call(@template, params, extract_fields: true)
|
||||||
|
|
||||||
schema = documents.map do |doc|
|
schema = documents.map do |doc|
|
||||||
{ attachment_uuid: doc.uuid, name: doc.filename.base }
|
{ attachment_uuid: doc.uuid, name: FilenameUtils.basename(doc.blob[:filename]) }
|
||||||
end
|
end
|
||||||
|
|
||||||
render json: {
|
render json: {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class TemplateFoldersController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
render layout: turbo_native_android? ? 'plain' : true
|
render layout: 'plain'
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ class TemplatesCloneController < ApplicationController
|
|||||||
|
|
||||||
@template = Template.new(name: "#{@base_template.name} (#{I18n.t('clone')})")
|
@template = Template.new(name: "#{@base_template.name} (#{I18n.t('clone')})")
|
||||||
|
|
||||||
render layout: turbo_native_android? ? 'plain' : true
|
render layout: 'plain'
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ class TemplatesDebugController < ApplicationController
|
|||||||
schema = documents.map do |doc|
|
schema = documents.map do |doc|
|
||||||
{
|
{
|
||||||
attachment_uuid: doc.uuid,
|
attachment_uuid: doc.uuid,
|
||||||
name: doc.filename.base,
|
name: FilenameUtils.basename(doc.blob[:filename]),
|
||||||
dynamic: dynamic_documents.find { |e| e.uuid == doc.uuid }.present?
|
dynamic: dynamic_documents.find { |e| e.uuid == doc.uuid }.present?
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ class TemplatesFoldersController < ApplicationController
|
|||||||
load_and_authorize_resource :template
|
load_and_authorize_resource :template
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
render layout: turbo_native_android? ? 'plain' : true
|
render layout: 'plain'
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class TemplatesUploadsController < ApplicationController
|
|||||||
save_template!(@template, url_params)
|
save_template!(@template, url_params)
|
||||||
|
|
||||||
documents, = Templates::CreateAttachments.call(@template, url_params || params, extract_fields: true)
|
documents, = Templates::CreateAttachments.call(@template, url_params || params, extract_fields: true)
|
||||||
schema = documents.map { |doc| { attachment_uuid: doc.uuid, name: doc.filename.base } }
|
schema = documents.map { |doc| { attachment_uuid: doc.uuid, name: FilenameUtils.basename(doc.blob[:filename]) } }
|
||||||
|
|
||||||
if @template.fields.blank?
|
if @template.fields.blank?
|
||||||
@template.fields = Templates::ProcessDocument.normalize_attachment_fields(@template, documents)
|
@template.fields = Templates::ProcessDocument.normalize_attachment_fields(@template, documents)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ class UserInitialsController < ApplicationController
|
|||||||
authorize_resource :user_config
|
authorize_resource :user_config
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
render layout: turbo_native_android? ? 'plain' : true
|
render layout: 'plain'
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ class UserSignaturesController < ApplicationController
|
|||||||
authorize_resource :user_config
|
authorize_resource :user_config
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
render layout: turbo_native_android? ? 'plain' : true
|
render layout: 'plain'
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
|
|||||||
@@ -32,11 +32,11 @@ class UsersController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
render layout: turbo_native_android? ? 'plain' : true
|
render layout: turbo_native_app? ? 'plain' : true
|
||||||
end
|
end
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
render layout: turbo_native_android? ? 'plain' : true
|
render layout: turbo_native_app? ? 'plain' : true
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ class WebhookSettingsController < ApplicationController
|
|||||||
else
|
else
|
||||||
@webhook_events = @webhook_url.webhook_events
|
@webhook_events = @webhook_url.webhook_events
|
||||||
|
|
||||||
@webhook_events = @webhook_events.where(status: params[:status]) if %w[success error].include?(params[:status])
|
if %w[success error].include?(params[:status])
|
||||||
|
@webhook_events = @webhook_events.where(WebhookEvent.arel_table[:status].eq(params[:status]))
|
||||||
|
end
|
||||||
|
|
||||||
@pagy, @webhook_events = pagy(:countless, @webhook_events.order(id: :desc))
|
@pagy, @webhook_events = pagy(:countless, @webhook_events.order(id: :desc))
|
||||||
|
|
||||||
@@ -24,7 +26,9 @@ class WebhookSettingsController < ApplicationController
|
|||||||
def show
|
def show
|
||||||
@webhook_events = @webhook_url.webhook_events
|
@webhook_events = @webhook_url.webhook_events
|
||||||
|
|
||||||
@webhook_events = @webhook_events.where(status: params[:status]) if %w[success error].include?(params[:status])
|
if %w[success error].include?(params[:status])
|
||||||
|
@webhook_events = @webhook_events.where(WebhookEvent.arel_table[:status].eq(params[:status]))
|
||||||
|
end
|
||||||
|
|
||||||
@pagy, @webhook_events = pagy(:countless, @webhook_events.order(id: :desc))
|
@pagy, @webhook_events = pagy(:countless, @webhook_events.order(id: :desc))
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
class="absolute top-0 bottom-0 right-0 left-0"
|
class="absolute top-0 bottom-0 right-0 left-0"
|
||||||
@click.prevent="$emit('close')"
|
@click.prevent="$emit('close')"
|
||||||
/>
|
/>
|
||||||
<div :class="inline ? (nativePlatform === 'android' ? 'px-4 pt-1.5 pb-6' : 'px-4 pt-3 pb-6') : 'modal-box pt-4 pb-6 px-6 mt-20 w-full max-w-xl'">
|
<div :class="inline ? (nativePlatform === 'android' ? 'pt-1.5 pb-6' : 'pt-3 pb-6') : 'modal-box pt-4 pb-6 px-6 mt-20 w-full max-w-xl'" :style="inline ? { paddingInline: '18px' } : null">
|
||||||
<div
|
<div
|
||||||
v-if="!inline"
|
v-if="!inline"
|
||||||
class="flex justify-between items-center border-b pb-2 mb-2 font-medium"
|
class="flex justify-between items-center border-b pb-2 mb-2 font-medium"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
class="absolute top-0 bottom-0 right-0 left-0"
|
class="absolute top-0 bottom-0 right-0 left-0"
|
||||||
@click.prevent="$emit('close')"
|
@click.prevent="$emit('close')"
|
||||||
/>
|
/>
|
||||||
<div :class="inline ? (nativePlatform === 'android' ? 'px-4 pt-1.5 pb-6' : 'px-4 pt-3 pb-6') : 'modal-box pt-4 pb-6 px-6 mt-20 max-h-none w-full max-w-xl'">
|
<div :class="inline ? (nativePlatform === 'android' ? 'pt-1.5 pb-6' : 'pt-3 pb-6') : 'modal-box pt-4 pb-6 px-6 mt-20 max-h-none w-full max-w-xl'" :style="inline ? { paddingInline: '18px' } : null">
|
||||||
<div
|
<div
|
||||||
v-if="!inline"
|
v-if="!inline"
|
||||||
class="flex justify-between items-center border-b pb-2 mb-2 font-medium"
|
class="flex justify-between items-center border-b pb-2 mb-2 font-medium"
|
||||||
|
|||||||
@@ -63,7 +63,7 @@
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex-1 overflow-y-auto overflow-x-hidden px-4 md:px-6 py-4 space-y-4"
|
class="flex-1 overflow-y-auto overflow-x-hidden px-4 md:px-6 py-4 space-y-4"
|
||||||
:style="inline && nativePlatform === 'ios' ? { paddingTop: '86px' } : null"
|
:style="inline ? { paddingInline: '18px', ...(nativePlatform === 'ios' ? { paddingTop: '86px' } : {}) } : null"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-for="(doc, docIndex) in layout"
|
v-for="(doc, docIndex) in layout"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
class="absolute top-0 bottom-0 right-0 left-0"
|
class="absolute top-0 bottom-0 right-0 left-0"
|
||||||
@click.prevent="$emit('close')"
|
@click.prevent="$emit('close')"
|
||||||
/>
|
/>
|
||||||
<div :class="inline ? (nativePlatform === 'android' ? 'px-4 pt-1.5 pb-6' : 'px-4 pt-3 pb-6') : 'modal-box pt-4 pb-6 px-6 mt-20 max-h-none w-full max-w-xl'">
|
<div :class="inline ? (nativePlatform === 'android' ? 'pt-1.5 pb-6' : 'pt-3 pb-6') : 'modal-box pt-4 pb-6 px-6 mt-20 max-h-none w-full max-w-xl'" :style="inline ? { paddingInline: '18px' } : null">
|
||||||
<div
|
<div
|
||||||
v-if="!inline"
|
v-if="!inline"
|
||||||
class="flex justify-between items-center border-b pb-2 mb-2 font-medium"
|
class="flex justify-between items-center border-b pb-2 mb-2 font-medium"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
class="absolute top-0 bottom-0 right-0 left-0"
|
class="absolute top-0 bottom-0 right-0 left-0"
|
||||||
@click.prevent="$emit('close')"
|
@click.prevent="$emit('close')"
|
||||||
/>
|
/>
|
||||||
<div :class="inline ? (nativePlatform === 'android' ? 'px-4 pt-1.5 pb-6' : 'px-4 pt-3 pb-6') : 'modal-box pt-4 pb-6 px-6 mt-20 max-h-none w-full max-w-xl'">
|
<div :class="inline ? (nativePlatform === 'android' ? 'pt-1.5 pb-6' : 'pt-3 pb-6') : 'modal-box pt-4 pb-6 px-6 mt-20 max-h-none w-full max-w-xl'" :style="inline ? { paddingInline: '18px' } : null">
|
||||||
<div
|
<div
|
||||||
v-if="!inline"
|
v-if="!inline"
|
||||||
class="flex justify-between items-center border-b pb-2 mb-2 font-medium"
|
class="flex justify-between items-center border-b pb-2 mb-2 font-medium"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
class="absolute top-0 bottom-0 right-0 left-0"
|
class="absolute top-0 bottom-0 right-0 left-0"
|
||||||
@click.prevent="$emit('close')"
|
@click.prevent="$emit('close')"
|
||||||
/>
|
/>
|
||||||
<div :class="inline ? (nativePlatform === 'android' ? 'px-4 pt-1.5 pb-6' : 'px-4 pt-3 pb-6') : 'modal-box pt-4 pb-6 mt-20 w-full'">
|
<div :class="inline ? (nativePlatform === 'android' ? 'pt-1.5 pb-6' : 'pt-3 pb-6') : 'modal-box pt-4 pb-6 mt-20 w-full'" :style="inline ? { paddingInline: '18px' } : null">
|
||||||
<div
|
<div
|
||||||
v-if="!inline"
|
v-if="!inline"
|
||||||
class="flex justify-between items-center border-b pb-2 mb-3 font-medium"
|
class="flex justify-between items-center border-b pb-2 mb-3 font-medium"
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ class SubmissionEvent < ApplicationRecord
|
|||||||
send_email: 'send_email',
|
send_email: 'send_email',
|
||||||
bounce_email: 'bounce_email',
|
bounce_email: 'bounce_email',
|
||||||
complaint_email: 'complaint_email',
|
complaint_email: 'complaint_email',
|
||||||
|
fail_sms: 'fail_sms',
|
||||||
send_reminder_email: 'send_reminder_email',
|
send_reminder_email: 'send_reminder_email',
|
||||||
send_sms: 'send_sms',
|
send_sms: 'send_sms',
|
||||||
send_2fa_sms: 'send_2fa_sms',
|
send_2fa_sms: 'send_2fa_sms',
|
||||||
|
|||||||
+3
-1
@@ -56,6 +56,8 @@ class User < ApplicationRecord
|
|||||||
FULL_EMAIL_REGEXP =
|
FULL_EMAIL_REGEXP =
|
||||||
/\A[a-z0-9][.']?(?:(?:[a-z0-9_-]+[.+'])*[a-z0-9_-]+)*@(?:[a-z0-9]+[.-])*[a-z0-9]+\.[a-z]{2,}\z/i
|
/\A[a-z0-9][.']?(?:(?:[a-z0-9_-]+[.+'])*[a-z0-9_-]+)*@(?:[a-z0-9]+[.-])*[a-z0-9]+\.[a-z]{2,}\z/i
|
||||||
|
|
||||||
|
VALIDATE_EMAIL_REGEXP = /\A[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\z/
|
||||||
|
|
||||||
has_one_attached :signature
|
has_one_attached :signature
|
||||||
has_one_attached :initials
|
has_one_attached :initials
|
||||||
|
|
||||||
@@ -78,7 +80,7 @@ class User < ApplicationRecord
|
|||||||
scope :archived, -> { where.not(archived_at: nil) }
|
scope :archived, -> { where.not(archived_at: nil) }
|
||||||
scope :admins, -> { where(role: ADMIN_ROLE) }
|
scope :admins, -> { where(role: ADMIN_ROLE) }
|
||||||
|
|
||||||
validates :email, format: { with: /\A[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\z/ }
|
validates :email, format: { with: VALIDATE_EMAIL_REGEXP }
|
||||||
|
|
||||||
def access_token
|
def access_token
|
||||||
super || build_access_token.tap(&:save!)
|
super || build_access_token.tap(&:save!)
|
||||||
|
|||||||
@@ -28,9 +28,7 @@
|
|||||||
<open-modal src="<%= url_for(**url_params, params: modal_uri.query_values) %>"></open-modal>
|
<open-modal src="<%= url_for(**url_params, params: modal_uri.query_values) %>"></open-modal>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% unless content_for?(:native_modal) %>
|
|
||||||
<turbo-frame id="modal"></turbo-frame>
|
<turbo-frame id="modal"></turbo-frame>
|
||||||
<% end %>
|
|
||||||
<turbo-frame id="drawer"></turbo-frame>
|
<turbo-frame id="drawer"></turbo-frame>
|
||||||
<%= render turbo_native_app? ? 'shared/native_navbar' : 'shared/navbar' %>
|
<%= render turbo_native_app? ? 'shared/native_navbar' : 'shared/navbar' %>
|
||||||
<main class="max-w-6xl mx-auto px-4 md:px-2 mb-8">
|
<main class="max-w-6xl mx-auto px-4 md:px-2 mb-8">
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<div id="mobile_app_alert" class="px-4 md:px-2 py-2 text-center bg-yellow-300 text-base-content w-full flex items-center justify-center gap-2">
|
||||||
|
<span>
|
||||||
|
<%= t('get_the_docuseal_app_for_a_better_mobile_experience') %>
|
||||||
|
<%= link_to t('install_app'), browser_os == 'ios' ? Docuseal::APP_STORE_URL : Docuseal::GOOGLE_PLAY_URL, class: 'link font-medium', target: '_blank', rel: 'noopener noreferrer nofollow' %>
|
||||||
|
</span>
|
||||||
|
<toggle-cookies data-key="mobile_app_alert" data-value="hidden" class="flex">
|
||||||
|
<remove-on-event data-selector-id="mobile_app_alert" class="flex">
|
||||||
|
<button type="button" class="btn btn-ghost btn-circle btn-sm" aria-label="<%= t('close') %>">
|
||||||
|
<%= svg_icon('x', class: 'w-5 h-5') %>
|
||||||
|
</button>
|
||||||
|
</remove-on-event>
|
||||||
|
</toggle-cookies>
|
||||||
|
</div>
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
<%= render 'shared/navbar_warning' %>
|
<%= render 'shared/navbar_warning' %>
|
||||||
|
<%= render 'shared/mobile_app_alert' if signed_in? && cookies[:mobile_app_alert].blank? && (browser_os == 'ios' || browser_os == 'android') %>
|
||||||
<nav class="max-w-6xl mb-4 mx-auto px-4 md:px-2 py-3 flex items-center justify-between">
|
<nav class="max-w-6xl mb-4 mx-auto px-4 md:px-2 py-3 flex items-center justify-between">
|
||||||
<div class="flex items-center space-x-4">
|
<div class="flex items-center space-x-4">
|
||||||
<a href="<%= root_path %>" class="text-2xl font-bold items-center flex space-x-2">
|
<a href="<%= root_path %>" class="text-2xl font-bold items-center flex space-x-2">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<% if turbo_native_app? && !turbo_frame_request? %>
|
<% if turbo_native_app? %>
|
||||||
<% content_for(:native_title, local_assigns[:title]) if local_assigns[:title] %>
|
<% content_for(:native_title, local_assigns[:title]) if local_assigns[:title] %>
|
||||||
<turbo-frame id="drawer">
|
<turbo-frame id="drawer">
|
||||||
<native-modal class="block w-full" data-close-after-submit="<%= local_assigns.key?(:close_after_submit) ? local_assigns[:close_after_submit] : true %>">
|
<native-modal class="block max-w-lg mx-auto <%= turbo_native_android? ? 'pb-4' : 'pb-6' %>" data-close-after-submit="<%= local_assigns.key?(:close_after_submit) ? local_assigns[:close_after_submit] : true %>">
|
||||||
<%= yield %>
|
<%= yield %>
|
||||||
</native-modal>
|
</native-modal>
|
||||||
</turbo-frame>
|
</turbo-frame>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<% if turbo_native_ios? || (turbo_native_app? && !turbo_frame_request?) %>
|
<% if turbo_native_app? %>
|
||||||
<% content_for(:native_modal, 'true') %>
|
|
||||||
<% content_for(:native_title, local_assigns[:title]) if local_assigns[:title] %>
|
<% content_for(:native_title, local_assigns[:title]) if local_assigns[:title] %>
|
||||||
<turbo-frame id="modal">
|
<turbo-frame id="modal">
|
||||||
<native-modal class="block max-w-lg mx-auto <%= turbo_native_android? ? 'pb-4' : 'pb-6' %>" data-close-after-submit="<%= local_assigns.key?(:close_after_submit) ? local_assigns[:close_after_submit] : true %>">
|
<native-modal class="block max-w-lg mx-auto <%= turbo_native_android? ? 'pb-4' : 'pb-6' %>" data-close-after-submit="<%= local_assigns.key?(:close_after_submit) ? local_assigns[:close_after_submit] : true %>">
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
<% if turbo_frame_request? %>
|
<% if turbo_native_app? %>
|
||||||
|
<% content_for(:native_title, local_assigns[:title]) if local_assigns[:title] %>
|
||||||
|
<turbo-frame id="modal">
|
||||||
|
<native-modal class="block max-w-lg mx-auto <%= turbo_native_android? ? 'pb-4' : 'pb-6' %>" data-close-after-submit="<%= local_assigns.key?(:close_after_submit) ? local_assigns[:close_after_submit] : true %>">
|
||||||
|
<%= yield %>
|
||||||
|
</native-modal>
|
||||||
|
</turbo-frame>
|
||||||
|
<% elsif turbo_frame_request? %>
|
||||||
<turbo-frame id="modal">
|
<turbo-frame id="modal">
|
||||||
<turbo-modal class="modal modal-open items-start !animate-none overflow-y-auto !justify-normal md:!justify-center" data-close-after-submit="<%= local_assigns.key?(:close_after_submit) ? local_assigns[:close_after_submit] : true %>">
|
<turbo-modal class="modal modal-open items-start !animate-none overflow-y-auto !justify-normal md:!justify-center" data-close-after-submit="<%= local_assigns.key?(:close_after_submit) ? local_assigns[:close_after_submit] : true %>">
|
||||||
<div class="absolute top-0 bottom-0 right-0 left-0" data-action="click:turbo-modal#close"></div>
|
<div class="absolute top-0 bottom-0 right-0 left-0" data-action="click:turbo-modal#close"></div>
|
||||||
@@ -17,11 +24,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</turbo-modal>
|
</turbo-modal>
|
||||||
</turbo-frame>
|
</turbo-frame>
|
||||||
<% elsif turbo_native_app? %>
|
|
||||||
<% content_for(:native_title, local_assigns[:title]) if local_assigns[:title] %>
|
|
||||||
<native-modal class="block w-full [&>.px-5]:px-4" data-close-after-submit="<%= local_assigns.key?(:close_after_submit) ? local_assigns[:close_after_submit] : true %>">
|
|
||||||
<%= yield %>
|
|
||||||
</native-modal>
|
|
||||||
<% else %>
|
<% else %>
|
||||||
<% if local_assigns[:title] %>
|
<% if local_assigns[:title] %>
|
||||||
<div class="sticky top-0 z-10 flex justify-between bg-base-100 py-2 px-5 items-center border-b pb-2 font-medium">
|
<div class="sticky top-0 z-10 flex justify-between bg-base-100 py-2 px-5 items-center border-b pb-2 font-medium">
|
||||||
|
|||||||
@@ -50,8 +50,11 @@
|
|||||||
<% elsif event.event_type == 'delegate_form' %>
|
<% elsif event.event_type == 'delegate_form' %>
|
||||||
<% delegate_from = event.data['old_email'].presence || versions.rfind { |v| v.created_at <= event.event_timestamp }&.then { |v| v.name || v.phone } %>
|
<% delegate_from = event.data['old_email'].presence || versions.rfind { |v| v.created_at <= event.event_timestamp }&.then { |v| v.name || v.phone } %>
|
||||||
<%= t('submission_event_names.delegate_form_by_html', from: delegate_from, to: event.data['email']) %>
|
<%= t('submission_event_names.delegate_form_by_html', from: delegate_from, to: event.data['email']) %>
|
||||||
<% elsif event.event_type.include?('send_') %>
|
<% elsif event.event_type.include?('send_') || event.event_type == 'fail_sms' %>
|
||||||
<%= t("submission_event_names.#{event.event_type}_to_html", submitter_name:) %>
|
<%= t("submission_event_names.#{event.event_type}_to_html", submitter_name:) %>
|
||||||
|
<% if event.data['error_code'].present? %>
|
||||||
|
<span class="text-base-content/60">(<%= t('error') %>: <%= event.data['error_code'] %>)</span>
|
||||||
|
<% end %>
|
||||||
<% elsif event.event_type.start_with?('bounce_') || event.event_type.start_with?('complaint_') %>
|
<% elsif event.event_type.start_with?('bounce_') || event.event_type.start_with?('complaint_') %>
|
||||||
<%= t("submission_event_names.#{event.event_type}_html", submitter_name:) %>
|
<%= t("submission_event_names.#{event.event_type}_html", submitter_name:) %>
|
||||||
<% else %>
|
<% else %>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</toggle-visible>
|
</toggle-visible>
|
||||||
<% end %>
|
<% end %>
|
||||||
<div class="px-5 mb-5 mt-5">
|
<div class="px-5 mt-5 <%= 'mb-5' unless turbo_native_app? %>" style="<%= 'padding-inline: 18px' if turbo_native_app? %>">
|
||||||
<% unless only_detailed %>
|
<% unless only_detailed %>
|
||||||
<div id="email" class="<%= 'hidden' if default_tab != 'email' %>">
|
<div id="email" class="<%= 'hidden' if default_tab != 'email' %>">
|
||||||
<%= render 'email_form', template: @template, variables_form:, can_send_emails:, viewer_submitter_uuids: %>
|
<%= render 'email_form', template: @template, variables_form:, can_send_emails:, viewer_submitter_uuids: %>
|
||||||
|
|||||||
@@ -134,9 +134,9 @@
|
|||||||
<% document = @submission.schema_documents.find { |a| item['attachment_uuid'] == a.uuid } %>
|
<% document = @submission.schema_documents.find { |a| item['attachment_uuid'] == a.uuid } %>
|
||||||
<% if document.preview_images.first %>
|
<% if document.preview_images.first %>
|
||||||
<scroll-to data-selector-id="page-<%= document.uuid %>-0" class="block cursor-pointer">
|
<scroll-to data-selector-id="page-<%= document.uuid %>-0" class="block cursor-pointer">
|
||||||
<img src="<%= (document.preview_images.find { |e| e.filename.base.to_i.zero? } || document.preview_images.first).url(time: service_url_time) %>" width="<%= document.preview_images.first.metadata['width'] %>" height="<%= document.preview_images.first.metadata['height'] %>" class="rounded border" loading="lazy" alt="<%= item['name'].presence || document.filename.base %>">
|
<img src="<%= (document.preview_images.find { |e| e.filename.base.to_i.zero? } || document.preview_images.first).url(time: service_url_time) %>" width="<%= document.preview_images.first.metadata['width'] %>" height="<%= document.preview_images.first.metadata['height'] %>" class="rounded border" loading="lazy" alt="<%= item['name'].presence || FilenameUtils.basename(document.blob[:filename]) %>">
|
||||||
<div class="pb-2 pt-1.5 text-center" dir="auto">
|
<div class="pb-2 pt-1.5 text-center" dir="auto">
|
||||||
<%= item['name'].presence || document.filename.base %>
|
<%= item['name'].presence || FilenameUtils.basename(document.blob[:filename]) %>
|
||||||
</div>
|
</div>
|
||||||
</scroll-to>
|
</scroll-to>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<% filter_params = params.permit(:q, :archived, *Submissions::Filter::ALLOWED_PARAMS) %>
|
<% filter_params = params.permit(:q, :archived, *Submissions::Filter::ALLOWED_PARAMS) %>
|
||||||
<%= render 'shared/turbo_modal', title: t('export'), close_after_submit: false do %>
|
<%= render 'shared/turbo_modal', title: t('export'), close_after_submit: false do %>
|
||||||
<div class="space-y-2 <%= 'mt-1.5 px-4' if turbo_native_android? %>">
|
<div class="space-y-2 <%= 'mt-1.5' if turbo_native_android? %>" style="<%= 'padding-inline: 18px' if turbo_native_app? %>">
|
||||||
<%= button_to template_submissions_export_index_path(@template), params: { format: :xlsx, **filter_params }, method: :get, data: { turbo_frame: :_top } do %>
|
<%= button_to template_submissions_export_index_path(@template), params: { format: :xlsx, **filter_params }, method: :get, data: { turbo_frame: :_top } do %>
|
||||||
<div class="flex items-center p-4 text-left rounded-2xl border border-neutral-300 hover:cursor-pointer hover:bg-neutral hover:text-gray-300">
|
<div class="flex items-center p-4 text-left rounded-2xl border border-neutral-300 hover:cursor-pointer hover:bg-neutral hover:text-gray-300">
|
||||||
<div class="enabled">
|
<div class="enabled">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<% path_uri = Addressable::URI.parse(params[:path].to_s) %>
|
<% path_uri = Addressable::URI.parse(params[:path].to_s) %>
|
||||||
<% path = url_for(**Rails.application.routes.recognize_path(path_uri.path, method: :get)) %>
|
<% path = url_for(**Rails.application.routes.recognize_path(path_uri.path, method: :get)) %>
|
||||||
<%= render 'shared/turbo_modal', title: local_assigns[:title] do %>
|
<%= render 'shared/turbo_modal', title: local_assigns[:title] do %>
|
||||||
<%= form_for '', url: path, method: :get, data: { turbo_frame: :_top }, html: { autocomplete: :off, class: ('px-4' if turbo_native_android?) } do |f| %>
|
<%= form_for '', url: path, method: :get, data: { turbo_frame: :_top }, html: { autocomplete: :off, style: ('padding-inline: 18px' if turbo_native_app?) } do |f| %>
|
||||||
<%= hidden_field_tag :q, params[:q] if params[:q].present? %>
|
<%= hidden_field_tag :q, params[:q] if params[:q].present? %>
|
||||||
<%= hidden_field_tag :scope, params[:scope] if params[:scope].present? %>
|
<%= hidden_field_tag :scope, params[:scope] if params[:scope].present? %>
|
||||||
<%= hidden_field_tag :archived, params[:archived] if params[:archived].present? %>
|
<%= hidden_field_tag :archived, params[:archived] if params[:archived].present? %>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<%= render 'shared/turbo_modal_large', title: t('edit_recipient') do %>
|
<%= render 'shared/turbo_modal_large', title: t('edit_recipient') do %>
|
||||||
<div class="px-5 mb-5 mt-4">
|
<div class="px-5 mt-4 <%= 'mb-5' unless turbo_native_app? %>" style="<%= 'padding-inline: 18px' if turbo_native_app? %>">
|
||||||
<%= form_for '', url: submitter_path(@submitter), method: :patch, html: { autocomplete: 'off' }, data: { turbo_frame: :_top } do |f| %>
|
<%= form_for '', url: submitter_path(@submitter), method: :patch, html: { autocomplete: 'off' }, data: { turbo_frame: :_top } do |f| %>
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<submitter-item class="form-control">
|
<submitter-item class="form-control">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<%= render 'shared/turbo_modal', title: t('rename_folder') do %>
|
<%= render 'shared/turbo_modal', title: t('rename_folder') do %>
|
||||||
<%= form_for @template_folder, url: folder_path(@template_folder), data: { turbo_frame: :_top }, html: { autocomplete: :off, class: ('px-4' if turbo_native_android?) } do |f| %>
|
<%= form_for @template_folder, url: folder_path(@template_folder), data: { turbo_frame: :_top }, html: { autocomplete: :off, style: ('padding-inline: 18px' if turbo_native_app?) } do |f| %>
|
||||||
<div class="form-control <%= turbo_native_android? ? 'mt-1.5 mb-6' : 'my-6' %>">
|
<div class="form-control <%= turbo_native_android? ? 'mt-1.5 mb-6' : 'my-6' %>">
|
||||||
<%= f.text_field :name, required: true, placeholder: "#{t('folder_name')}...", class: 'base-input w-full', autofocus: true, dir: 'auto' %>
|
<%= f.text_field :name, required: true, placeholder: "#{t('folder_name')}...", class: 'base-input w-full', autofocus: true, dir: 'auto' %>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<%= render 'shared/turbo_modal', title: @base_template ? t('clone_template') : t('new_document_template') do %>
|
<%= render 'shared/turbo_modal', title: @base_template ? t('clone_template') : t('new_document_template') do %>
|
||||||
<div class="<%= 'px-4' if turbo_native_app? %>">
|
<div style="<%= 'padding-inline: 18px' if turbo_native_app? %>">
|
||||||
<%= render 'templates/file_form' %>
|
<%= render 'templates/file_form' %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<%= form_for @template, url: template_clone_index_path(@base_template), data: { turbo_frame: :_top }, html: { autocomplete: :off, class: ('px-4' if turbo_native_android?) } do |f| %>
|
<%= form_for @template, url: template_clone_index_path(@base_template), data: { turbo_frame: :_top }, html: { autocomplete: :off, style: ('padding-inline: 18px' if turbo_native_app?) } do |f| %>
|
||||||
<% accounts = Account.accessible_by(true_ability).where.not(id: true_user.account.testing_accounts).where(User.where(User.arel_table[:account_id].eq(Account.arel_table[:id])).arel.exists).active %>
|
<% accounts = Account.accessible_by(true_ability).where.not(id: true_user.account.testing_accounts).where(User.where(User.arel_table[:account_id].eq(Account.arel_table[:id])).arel.exists).active %>
|
||||||
<% with_accounts = (can?(:manage, :tenants) || true_user != current_user) && accounts.where.not(id: current_account.id).exists? %>
|
<% with_accounts = (can?(:manage, :tenants) || true_user != current_user) && accounts.where.not(id: current_account.id).exists? %>
|
||||||
<% if with_accounts %>
|
<% if with_accounts %>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<% with_subfolder = @template.folder.name != TemplateFolder::DEFAULT_NAME && params[:subfolder] != 'false' %>
|
<% with_subfolder = @template.folder.name != TemplateFolder::DEFAULT_NAME && params[:subfolder] != 'false' %>
|
||||||
<%= render 'shared/turbo_modal', title: t('move_into_folder') do %>
|
<%= render 'shared/turbo_modal', title: t('move_into_folder') do %>
|
||||||
<% if with_subfolder %>
|
<% if with_subfolder %>
|
||||||
<%= form_for '', url: template_folder_path(@template), method: :put, data: { turbo_frame: :_top }, html: { id: 'subfolder_form', autocomplete: :off, class: ('px-4' if turbo_native_android?) } do |f| %>
|
<%= form_for '', url: template_folder_path(@template), method: :put, data: { turbo_frame: :_top }, html: { id: 'subfolder_form', autocomplete: :off, style: ('padding-inline: 18px' if turbo_native_app?) } do |f| %>
|
||||||
<%= f.hidden_field :parent_name, value: @template.folder.parent_folder&.name || @template.folder.name %>
|
<%= f.hidden_field :parent_name, value: @template.folder.parent_folder&.name || @template.folder.name %>
|
||||||
<toggle-visible data-element-ids="<%= %w[folder_form subfolder_form].to_json %>" class="block relative" data-focus-id="name">
|
<toggle-visible data-element-ids="<%= %w[folder_form subfolder_form].to_json %>" class="block relative" data-focus-id="name">
|
||||||
<div class="flex items-center justify-between mb-2.5">
|
<div class="flex items-center justify-between mb-2.5">
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= form_for '', url: template_folder_path(@template), method: :put, data: { turbo_frame: :_top }, html: { id: 'folder_form', autocomplete: :off, class: "#{turbo_native_android? ? 'mt-1.5 px-4' : 'mt-6'} #{'hidden' if with_subfolder}" } do |f| %>
|
<%= form_for '', url: template_folder_path(@template), method: :put, data: { turbo_frame: :_top }, html: { id: 'folder_form', autocomplete: :off, class: "#{turbo_native_android? ? 'mt-1.5' : 'mt-6'} #{'hidden' if with_subfolder}", style: ('padding-inline: 18px' if turbo_native_app?) } do |f| %>
|
||||||
<div class="form-control mb-6">
|
<div class="form-control mb-6">
|
||||||
<folder-autocomplete class="block" data-submit-on-select="true" data-enabled="<%= params[:autocomplete] != 'false' %>">
|
<folder-autocomplete class="block" data-submit-on-select="true" data-enabled="<%= params[:autocomplete] != 'false' %>">
|
||||||
<%= f.text_field :name, required: true, placeholder: "#{t('new_folder_name')}...", class: 'base-input w-full', autofocus: true %>
|
<%= f.text_field :name, required: true, placeholder: "#{t('new_folder_name')}...", class: 'base-input w-full', autofocus: true %>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</toggle-visible>
|
</toggle-visible>
|
||||||
<% end %>
|
<% end %>
|
||||||
<div id="general" class="px-5 mb-4">
|
<div id="general" class="px-5 mb-4" style="<%= 'padding-inline: 18px' if turbo_native_app? %>">
|
||||||
<%= render 'access' %>
|
<%= render 'access' %>
|
||||||
<%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-2' }, data: { close_on_submit: false } do |f| %>
|
<%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-2' }, data: { close_on_submit: false } do |f| %>
|
||||||
<toggle-on-submit data-element-id="bcc_saved_alert"></toggle-on-submit>
|
<toggle-on-submit data-element-id="bcc_saved_alert"></toggle-on-submit>
|
||||||
@@ -146,14 +146,14 @@
|
|||||||
<%= render 'templates_code_modal/preferences', class: 'pt-2' %>
|
<%= render 'templates_code_modal/preferences', class: 'pt-2' %>
|
||||||
</div>
|
</div>
|
||||||
<% if show_recipients %>
|
<% if show_recipients %>
|
||||||
<div id="recipients" class="hidden mt-2 mb-4 px-5 pt-1 pb-2">
|
<div id="recipients" class="hidden mt-2 mb-4 px-5 pt-1 pb-2" style="<%= 'padding-inline: 18px' if turbo_native_app? %>">
|
||||||
<native-event data-on="submit" data-name="template-builder:update" class="block">
|
<native-event data-on="submit" data-name="template-builder:update" class="block">
|
||||||
<%= render 'recipients', template: @template %>
|
<%= render 'recipients', template: @template %>
|
||||||
</native-event>
|
</native-event>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if show_api %>
|
<% if show_api %>
|
||||||
<div id="api" class="hidden mt-2 mb-4 px-5">
|
<div id="api" class="hidden mt-2 mb-4 px-5" style="<%= 'padding-inline: 18px' if turbo_native_app? %>">
|
||||||
<div>
|
<div>
|
||||||
<label class="text-sm font-semibold" for="template_id">
|
<label class="text-sm font-semibold" for="template_id">
|
||||||
<%= t('template_id') %>
|
<%= t('template_id') %>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<% multiple_submitters = @template.submitters.to_a.length > 1 %>
|
<% multiple_submitters = @template.submitters.to_a.length > 1 %>
|
||||||
<% enough_defined_submitters = Templates.filter_undefined_submitters(@template.submitters).size < 2 %>
|
<% enough_defined_submitters = Templates.filter_undefined_submitters(@template.submitters).size < 2 %>
|
||||||
<%= render 'shared/turbo_modal_large', title: t('share_link') do %>
|
<%= render 'shared/turbo_modal_large', title: t('share_link') do %>
|
||||||
<div class="<%= 'mt-2' unless turbo_native_android? %> mb-4 px-5">
|
<div class="<%= 'mt-2' unless turbo_native_android? %> <%= 'mb-4' unless turbo_native_app? %> px-5" style="<%= 'padding-inline: 18px' if turbo_native_app? %>">
|
||||||
<% if @template.variables_schema.present? %>
|
<% if @template.variables_schema.present? %>
|
||||||
<div class="flex items-start gap-4 p-4 border border-base-300 rounded-2xl bg-base-100 mt-4">
|
<div class="flex items-start gap-4 p-4 border border-base-300 rounded-2xl bg-base-100 mt-4">
|
||||||
<%= svg_icon('info_circle', class: 'stroke-current shrink-0 h-6 w-6') %>
|
<%= svg_icon('info_circle', class: 'stroke-current shrink-0 h-6 w-6') %>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</toggle-visible>
|
</toggle-visible>
|
||||||
<div id="draw" class="mt-3 <%= 'px-4' if turbo_native_android? %>">
|
<div id="draw" class="mt-3" style="<%= 'padding-inline: 18px' if turbo_native_app? %>">
|
||||||
<%= form_for @user_config, url: user_initials_path, method: :put, data: { turbo_frame: :_top }, html: { autocomplete: :off, enctype: 'multipart/form-data' } do |f| %>
|
<%= form_for @user_config, url: user_initials_path, method: :put, data: { turbo_frame: :_top }, html: { autocomplete: :off, enctype: 'multipart/form-data' } do |f| %>
|
||||||
<signature-form class="relative block">
|
<signature-form class="relative block">
|
||||||
<a class="absolute top-1 right-1 link text-sm" data-target="signature-form.clear" href="#"><%= t('clear') %></a>
|
<a class="absolute top-1 right-1 link text-sm" data-target="signature-form.clear" href="#"><%= t('clear') %></a>
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
</signature-form>
|
</signature-form>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<div id="upload" class="hidden mt-3 <%= 'px-4' if turbo_native_android? %>">
|
<div id="upload" class="hidden mt-3" style="<%= 'padding-inline: 18px' if turbo_native_app? %>">
|
||||||
<%= form_for @user_config, url: user_initials_path, method: :put, data: { turbo_frame: :_top }, html: { autocomplete: :off, enctype: 'multipart/form-data' } do |f| %>
|
<%= form_for @user_config, url: user_initials_path, method: :put, data: { turbo_frame: :_top }, html: { autocomplete: :off, enctype: 'multipart/form-data' } do |f| %>
|
||||||
<file-dropzone data-submit-on-upload="true" class="w-full">
|
<file-dropzone data-submit-on-upload="true" class="w-full">
|
||||||
<label for="file" class="w-full block h-32 relative bg-base-200 hover:bg-base-200/70 rounded-md border border-base-content border-dashed">
|
<label for="file" class="w-full block h-32 relative bg-base-200 hover:bg-base-200/70 rounded-md border border-base-content border-dashed">
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</toggle-visible>
|
</toggle-visible>
|
||||||
<div id="draw" class="mt-3 <%= 'px-4' if turbo_native_android? %>">
|
<div id="draw" class="mt-3" style="<%= 'padding-inline: 18px' if turbo_native_app? %>">
|
||||||
<%= form_for @user_config, url: user_signature_path, method: :put, data: { turbo_frame: :_top }, html: { autocomplete: :off, enctype: 'multipart/form-data' } do |f| %>
|
<%= form_for @user_config, url: user_signature_path, method: :put, data: { turbo_frame: :_top }, html: { autocomplete: :off, enctype: 'multipart/form-data' } do |f| %>
|
||||||
<signature-form class="relative block">
|
<signature-form class="relative block">
|
||||||
<a class="absolute top-1 right-1 link text-sm" data-target="signature-form.clear" href="#"><%= t('clear') %></a>
|
<a class="absolute top-1 right-1 link text-sm" data-target="signature-form.clear" href="#"><%= t('clear') %></a>
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
</signature-form>
|
</signature-form>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<div id="upload" class="hidden mt-3 <%= 'px-4' if turbo_native_android? %>">
|
<div id="upload" class="hidden mt-3" style="<%= 'padding-inline: 18px' if turbo_native_app? %>">
|
||||||
<%= form_for @user_config, url: user_signature_path, method: :put, data: { turbo_frame: :_top }, html: { autocomplete: :off, enctype: 'multipart/form-data' } do |f| %>
|
<%= form_for @user_config, url: user_signature_path, method: :put, data: { turbo_frame: :_top }, html: { autocomplete: :off, enctype: 'multipart/form-data' } do |f| %>
|
||||||
<file-dropzone data-submit-on-upload="true" class="w-full">
|
<file-dropzone data-submit-on-upload="true" class="w-full">
|
||||||
<label for="file" class="w-full block h-32 relative bg-base-200 hover:bg-base-200/70 rounded-md border border-base-content border-dashed">
|
<label for="file" class="w-full block h-32 relative bg-base-200 hover:bg-base-200/70 rounded-md border border-base-content border-dashed">
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<%= form_for user, html: { class: "space-y-4 #{'px-4' if turbo_native_android?}" }, data: { turbo_frame: :_top } do |f| %>
|
<%= form_for user, html: { class: 'space-y-4', style: ('padding-inline: 18px' if turbo_native_app?) }, data: { turbo_frame: :_top } do |f| %>
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
<div class="flex space-x-4">
|
<div class="flex space-x-4">
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ module DocuSeal
|
|||||||
|
|
||||||
config.active_storage.routes_prefix = ''
|
config.active_storage.routes_prefix = ''
|
||||||
|
|
||||||
config.active_storage.draw_routes = ENV['MULTITENANT'] != 'true'
|
config.active_storage.draw_routes = false
|
||||||
|
|
||||||
config.active_storage.analyzers = []
|
config.active_storage.analyzers = []
|
||||||
|
|
||||||
|
|||||||
@@ -166,7 +166,14 @@ Rails.application.configure do
|
|||||||
|
|
||||||
current_user = controller.instance_variable_get(:@current_user)
|
current_user = controller.instance_variable_get(:@current_user)
|
||||||
|
|
||||||
os = DetectBrowserDevice.os(controller.request.user_agent) if ENV['MULTITENANT'] == 'true'
|
if ENV['MULTITENANT'] == 'true'
|
||||||
|
os =
|
||||||
|
if defined?(controller.browser_os)
|
||||||
|
controller.browser_os
|
||||||
|
else
|
||||||
|
DetectBrowserDevice.os(controller.request.user_agent)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
{
|
{
|
||||||
host: controller.request.host,
|
host: controller.request.host,
|
||||||
|
|||||||
@@ -63,26 +63,8 @@ end
|
|||||||
ActiveStorage::LogSubscriber.detach_from(:active_storage) if Rails.env.production?
|
ActiveStorage::LogSubscriber.detach_from(:active_storage) if Rails.env.production?
|
||||||
|
|
||||||
Rails.configuration.to_prepare do
|
Rails.configuration.to_prepare do
|
||||||
ActiveStorage::DiskController.after_action do
|
ActiveStorage::DiskController.after_action(only: :show) do
|
||||||
response.set_header('cache-control', 'public, max-age=31536000') if action_name == 'show'
|
response.set_header('cache-control', 'public, max-age=31536000')
|
||||||
end
|
|
||||||
|
|
||||||
ActiveStorage::Blobs::ProxyController.before_action do
|
|
||||||
response.set_header('Access-Control-Allow-Origin', '*')
|
|
||||||
response.set_header('Access-Control-Allow-Methods', 'GET')
|
|
||||||
response.set_header('Access-Control-Allow-Headers', '*')
|
|
||||||
response.set_header('Access-Control-Max-Age', '1728000')
|
|
||||||
end
|
|
||||||
|
|
||||||
ActiveStorage::Blobs::RedirectController.before_action do
|
|
||||||
response.set_header('Access-Control-Allow-Origin', '*')
|
|
||||||
response.set_header('Access-Control-Allow-Methods', 'GET')
|
|
||||||
response.set_header('Access-Control-Allow-Headers', '*')
|
|
||||||
response.set_header('Access-Control-Max-Age', '1728000')
|
|
||||||
end
|
|
||||||
|
|
||||||
ActiveStorage::DirectUploadsController.before_action do
|
|
||||||
head :forbidden
|
|
||||||
end
|
end
|
||||||
|
|
||||||
LoadActiveStorageConfigs.call
|
LoadActiveStorageConfigs.call
|
||||||
|
|||||||
@@ -830,6 +830,8 @@ en: &en
|
|||||||
click_here_to_update_your_payment_details_and_clear_the_invoice_to_ensure_uninterrupted_service_html: <a href="%{url}" class="link">Click here</a> to update your payment details and clear the invoice to ensure uninterrupted service.
|
click_here_to_update_your_payment_details_and_clear_the_invoice_to_ensure_uninterrupted_service_html: <a href="%{url}" class="link">Click here</a> to update your payment details and clear the invoice to ensure uninterrupted service.
|
||||||
overdue_payment: Overdue Payment
|
overdue_payment: Overdue Payment
|
||||||
your_pro_plan_has_been_suspended_due_to_unpaid_invoices_you_can_update_your_payment_details_to_settle_the_invoice_and_continue_using_docuseal_or_cancel_your_subscription: Your Pro Plan has been suspended due to unpaid invoices. You can update your payment details to settle the invoice and continue using DocuSeal or cancel your subscription.
|
your_pro_plan_has_been_suspended_due_to_unpaid_invoices_you_can_update_your_payment_details_to_settle_the_invoice_and_continue_using_docuseal_or_cancel_your_subscription: Your Pro Plan has been suspended due to unpaid invoices. You can update your payment details to settle the invoice and continue using DocuSeal or cancel your subscription.
|
||||||
|
get_the_docuseal_app_for_a_better_mobile_experience: Get the DocuSeal app for a better mobile experience.
|
||||||
|
install_app: Install app
|
||||||
manage_subscription: Manage Subscription
|
manage_subscription: Manage Subscription
|
||||||
docuseal_version_security_release_is_available: "DocuSeal v%{version} security release is available."
|
docuseal_version_security_release_is_available: "DocuSeal v%{version} security release is available."
|
||||||
click_here_to_view_the_instructions_and_update_your_app_html: '<a href="%{url}" class="link" target="_blank" rel="noopener noreferrer nofollow">Click here</a> to view the instructions and update your app.'
|
click_here_to_view_the_instructions_and_update_your_app_html: '<a href="%{url}" class="link" target="_blank" rel="noopener noreferrer nofollow">Click here</a> to view the instructions and update your app.'
|
||||||
@@ -1046,10 +1048,12 @@ en: &en
|
|||||||
link: Link
|
link: Link
|
||||||
mcp: MCP
|
mcp: MCP
|
||||||
self: Sign Yourself
|
self: Sign Yourself
|
||||||
|
error: Error
|
||||||
submission_event_names:
|
submission_event_names:
|
||||||
send_email_to_html: '<b>Email sent</b> to %{submitter_name}'
|
send_email_to_html: '<b>Email sent</b> to %{submitter_name}'
|
||||||
bounce_email_html: '<b>Email bounced</b> %{submitter_name}'
|
bounce_email_html: '<b>Email bounced</b> %{submitter_name}'
|
||||||
complaint_email_html: '<b>Spam complaint</b> %{submitter_name}'
|
complaint_email_html: '<b>Spam complaint</b> %{submitter_name}'
|
||||||
|
fail_sms_to_html: '<b>SMS failed</b> to %{submitter_name}'
|
||||||
send_reminder_email_to_html: '<b>Reminder email sent</b> to %{submitter_name}'
|
send_reminder_email_to_html: '<b>Reminder email sent</b> to %{submitter_name}'
|
||||||
send_sms_to_html: '<b>SMS sent</b> to %{submitter_name}'
|
send_sms_to_html: '<b>SMS sent</b> to %{submitter_name}'
|
||||||
send_2fa_sms_to_html: '<b>Verification SMS sent</b> to %{submitter_name}'
|
send_2fa_sms_to_html: '<b>Verification SMS sent</b> to %{submitter_name}'
|
||||||
@@ -1988,6 +1992,8 @@ es: &es
|
|||||||
click_here_to_update_your_payment_details_and_clear_the_invoice_to_ensure_uninterrupted_service_html: '<a href="%{url}" class="link">Haz clic aquí</a> para actualizar tus datos de pago y liquidar la factura para garantizar un servicio ininterrumpido.'
|
click_here_to_update_your_payment_details_and_clear_the_invoice_to_ensure_uninterrupted_service_html: '<a href="%{url}" class="link">Haz clic aquí</a> para actualizar tus datos de pago y liquidar la factura para garantizar un servicio ininterrumpido.'
|
||||||
overdue_payment: Pago Atrasado
|
overdue_payment: Pago Atrasado
|
||||||
your_pro_plan_has_been_suspended_due_to_unpaid_invoices_you_can_update_your_payment_details_to_settle_the_invoice_and_continue_using_docuseal_or_cancel_your_subscription: Tu plan Pro ha sido suspendido debido a facturas impagas. Puedes actualizar tus datos de pago para liquidar la factura y seguir usando DocuSeal o cancelar tu suscripción.
|
your_pro_plan_has_been_suspended_due_to_unpaid_invoices_you_can_update_your_payment_details_to_settle_the_invoice_and_continue_using_docuseal_or_cancel_your_subscription: Tu plan Pro ha sido suspendido debido a facturas impagas. Puedes actualizar tus datos de pago para liquidar la factura y seguir usando DocuSeal o cancelar tu suscripción.
|
||||||
|
get_the_docuseal_app_for_a_better_mobile_experience: Descarga la app de DocuSeal para una mejor experiencia móvil.
|
||||||
|
install_app: Instalar app
|
||||||
manage_subscription: Gestionar Suscripción
|
manage_subscription: Gestionar Suscripción
|
||||||
docuseal_version_security_release_is_available: "La versión de seguridad DocuSeal v%{version} está disponible."
|
docuseal_version_security_release_is_available: "La versión de seguridad DocuSeal v%{version} está disponible."
|
||||||
click_here_to_view_the_instructions_and_update_your_app_html: '<a href="%{url}" class="link" target="_blank" rel="noopener noreferrer nofollow">Haz clic aquí</a> para ver las instrucciones y actualizar tu aplicación.'
|
click_here_to_view_the_instructions_and_update_your_app_html: '<a href="%{url}" class="link" target="_blank" rel="noopener noreferrer nofollow">Haz clic aquí</a> para ver las instrucciones y actualizar tu aplicación.'
|
||||||
@@ -2196,10 +2202,12 @@ es: &es
|
|||||||
link: Enlace
|
link: Enlace
|
||||||
mcp: MCP
|
mcp: MCP
|
||||||
self: Firma tú mismo
|
self: Firma tú mismo
|
||||||
|
error: Error
|
||||||
submission_event_names:
|
submission_event_names:
|
||||||
send_email_to_html: '<b>Correo electrónico enviado</b> a %{submitter_name}'
|
send_email_to_html: '<b>Correo electrónico enviado</b> a %{submitter_name}'
|
||||||
bounce_email_html: '<b>Correo electrónico rebotado</b> %{submitter_name}'
|
bounce_email_html: '<b>Correo electrónico rebotado</b> %{submitter_name}'
|
||||||
complaint_email_html: '<b>Queja de spam</b> %{submitter_name}'
|
complaint_email_html: '<b>Queja de spam</b> %{submitter_name}'
|
||||||
|
fail_sms_to_html: '<b>SMS fallido</b> a %{submitter_name}'
|
||||||
send_reminder_email_to_html: '<b>Correo de recordatorio enviado</b> a %{submitter_name}'
|
send_reminder_email_to_html: '<b>Correo de recordatorio enviado</b> a %{submitter_name}'
|
||||||
send_sms_to_html: '<b>SMS enviado</b> a %{submitter_name}'
|
send_sms_to_html: '<b>SMS enviado</b> a %{submitter_name}'
|
||||||
send_2fa_sms_to_html: '<b>SMS de verificación enviado</b> a %{submitter_name}'
|
send_2fa_sms_to_html: '<b>SMS de verificación enviado</b> a %{submitter_name}'
|
||||||
@@ -3152,6 +3160,8 @@ it: &it
|
|||||||
click_here_to_update_your_payment_details_and_clear_the_invoice_to_ensure_uninterrupted_service_html: '<a href="%{url}" class="link">Fai clic qui</a> per aggiornare i tuoi dati di pagamento e saldare la fattura per garantire un servizio ininterrotto.'
|
click_here_to_update_your_payment_details_and_clear_the_invoice_to_ensure_uninterrupted_service_html: '<a href="%{url}" class="link">Fai clic qui</a> per aggiornare i tuoi dati di pagamento e saldare la fattura per garantire un servizio ininterrotto.'
|
||||||
overdue_payment: Pagamento Scaduto
|
overdue_payment: Pagamento Scaduto
|
||||||
your_pro_plan_has_been_suspended_due_to_unpaid_invoices_you_can_update_your_payment_details_to_settle_the_invoice_and_continue_using_docuseal_or_cancel_your_subscription: Il tuo piano Pro è stato sospeso a causa di fatture non pagate. Puoi aggiornare i tuoi dati di pagamento per saldare la fattura e continuare a utilizzare DocuSeal o annullare l'abbonamento.
|
your_pro_plan_has_been_suspended_due_to_unpaid_invoices_you_can_update_your_payment_details_to_settle_the_invoice_and_continue_using_docuseal_or_cancel_your_subscription: Il tuo piano Pro è stato sospeso a causa di fatture non pagate. Puoi aggiornare i tuoi dati di pagamento per saldare la fattura e continuare a utilizzare DocuSeal o annullare l'abbonamento.
|
||||||
|
get_the_docuseal_app_for_a_better_mobile_experience: Scarica l'app DocuSeal per un'esperienza mobile migliore.
|
||||||
|
install_app: Installa app
|
||||||
manage_subscription: Gestisci Abbonamento
|
manage_subscription: Gestisci Abbonamento
|
||||||
docuseal_version_security_release_is_available: "È disponibile il rilascio di sicurezza DocuSeal v%{version}."
|
docuseal_version_security_release_is_available: "È disponibile il rilascio di sicurezza DocuSeal v%{version}."
|
||||||
click_here_to_view_the_instructions_and_update_your_app_html: '<a href="%{url}" class="link" target="_blank" rel="noopener noreferrer nofollow">Fai clic qui</a> per vedere le istruzioni e aggiornare la tua app.'
|
click_here_to_view_the_instructions_and_update_your_app_html: '<a href="%{url}" class="link" target="_blank" rel="noopener noreferrer nofollow">Fai clic qui</a> per vedere le istruzioni e aggiornare la tua app.'
|
||||||
@@ -3360,10 +3370,12 @@ it: &it
|
|||||||
link: Link
|
link: Link
|
||||||
mcp: MCP
|
mcp: MCP
|
||||||
self: Firma te stesso
|
self: Firma te stesso
|
||||||
|
error: Errore
|
||||||
submission_event_names:
|
submission_event_names:
|
||||||
send_email_to_html: '<b>Email inviata</b> a %{submitter_name}'
|
send_email_to_html: '<b>Email inviata</b> a %{submitter_name}'
|
||||||
bounce_email_html: '<b>Email respinta</b> %{submitter_name}'
|
bounce_email_html: '<b>Email respinta</b> %{submitter_name}'
|
||||||
complaint_email_html: '<b>Segnalazione spam</b> %{submitter_name}'
|
complaint_email_html: '<b>Segnalazione spam</b> %{submitter_name}'
|
||||||
|
fail_sms_to_html: '<b>SMS non consegnato</b> a %{submitter_name}'
|
||||||
send_reminder_email_to_html: '<b>E-mail di promemoria inviata</b> a %{submitter_name}'
|
send_reminder_email_to_html: '<b>E-mail di promemoria inviata</b> a %{submitter_name}'
|
||||||
send_sms_to_html: '<b>SMS inviato</b> a %{submitter_name}'
|
send_sms_to_html: '<b>SMS inviato</b> a %{submitter_name}'
|
||||||
send_2fa_sms_to_html: '<b>SMS di verifica inviato</b> a %{submitter_name}'
|
send_2fa_sms_to_html: '<b>SMS di verifica inviato</b> a %{submitter_name}'
|
||||||
@@ -4302,6 +4314,8 @@ fr: &fr
|
|||||||
click_here_to_update_your_payment_details_and_clear_the_invoice_to_ensure_uninterrupted_service_html: <a href="%{url}" class="link">Cliquez ici</a> pour mettre à jour vos informations de paiement et régler la facture afin de garantir la continuité du service.
|
click_here_to_update_your_payment_details_and_clear_the_invoice_to_ensure_uninterrupted_service_html: <a href="%{url}" class="link">Cliquez ici</a> pour mettre à jour vos informations de paiement et régler la facture afin de garantir la continuité du service.
|
||||||
overdue_payment: Paiement en retard
|
overdue_payment: Paiement en retard
|
||||||
your_pro_plan_has_been_suspended_due_to_unpaid_invoices_you_can_update_your_payment_details_to_settle_the_invoice_and_continue_using_docuseal_or_cancel_your_subscription: "Votre offre Pro a été suspendue en raison de factures impayées.\nVous pouvez mettre à jour vos informations de paiement pour régler la facture et continuer à utiliser DocuSeal, ou annuler votre abonnement."
|
your_pro_plan_has_been_suspended_due_to_unpaid_invoices_you_can_update_your_payment_details_to_settle_the_invoice_and_continue_using_docuseal_or_cancel_your_subscription: "Votre offre Pro a été suspendue en raison de factures impayées.\nVous pouvez mettre à jour vos informations de paiement pour régler la facture et continuer à utiliser DocuSeal, ou annuler votre abonnement."
|
||||||
|
get_the_docuseal_app_for_a_better_mobile_experience: Téléchargez l’application DocuSeal pour une meilleure expérience mobile.
|
||||||
|
install_app: Installer l’application
|
||||||
manage_subscription: Gérer l’abonnement
|
manage_subscription: Gérer l’abonnement
|
||||||
docuseal_version_security_release_is_available: "La mise à jour de sécurité DocuSeal v%{version} est disponible."
|
docuseal_version_security_release_is_available: "La mise à jour de sécurité DocuSeal v%{version} est disponible."
|
||||||
click_here_to_view_the_instructions_and_update_your_app_html: '<a href="%{url}" class="link" target="_blank" rel="noopener noreferrer nofollow">Cliquez ici</a> pour voir les instructions et mettre à jour votre application.'
|
click_here_to_view_the_instructions_and_update_your_app_html: '<a href="%{url}" class="link" target="_blank" rel="noopener noreferrer nofollow">Cliquez ici</a> pour voir les instructions et mettre à jour votre application.'
|
||||||
@@ -4507,10 +4521,12 @@ fr: &fr
|
|||||||
link: Lien
|
link: Lien
|
||||||
mcp: MCP
|
mcp: MCP
|
||||||
self: Signer vous-même
|
self: Signer vous-même
|
||||||
|
error: Erreur
|
||||||
submission_event_names:
|
submission_event_names:
|
||||||
send_email_to_html: "<b>E‑mail envoyé</b> à %{submitter_name}"
|
send_email_to_html: "<b>E‑mail envoyé</b> à %{submitter_name}"
|
||||||
bounce_email_html: "<b>E‑mail rejeté</b> %{submitter_name}"
|
bounce_email_html: "<b>E‑mail rejeté</b> %{submitter_name}"
|
||||||
complaint_email_html: "<b>Plainte spam</b> %{submitter_name}"
|
complaint_email_html: "<b>Plainte spam</b> %{submitter_name}"
|
||||||
|
fail_sms_to_html: "<b>SMS non distribué</b> à %{submitter_name}"
|
||||||
send_reminder_email_to_html: "<b>E‑mail de rappel envoyé</b> à %{submitter_name}"
|
send_reminder_email_to_html: "<b>E‑mail de rappel envoyé</b> à %{submitter_name}"
|
||||||
send_sms_to_html: "<b>SMS envoyé</b> à %{submitter_name}"
|
send_sms_to_html: "<b>SMS envoyé</b> à %{submitter_name}"
|
||||||
send_2fa_sms_to_html: "<b>SMS de vérification envoyé</b> à %{submitter_name}"
|
send_2fa_sms_to_html: "<b>SMS de vérification envoyé</b> à %{submitter_name}"
|
||||||
@@ -5462,6 +5478,8 @@ pt: &pt
|
|||||||
click_here_to_update_your_payment_details_and_clear_the_invoice_to_ensure_uninterrupted_service_html: '<a href="%{url}" class="link">Clique aqui</a> para atualizar seus dados de pagamento e quitar a fatura para garantir um serviço ininterrupto.'
|
click_here_to_update_your_payment_details_and_clear_the_invoice_to_ensure_uninterrupted_service_html: '<a href="%{url}" class="link">Clique aqui</a> para atualizar seus dados de pagamento e quitar a fatura para garantir um serviço ininterrupto.'
|
||||||
overdue_payment: Pagamento Atrasado
|
overdue_payment: Pagamento Atrasado
|
||||||
your_pro_plan_has_been_suspended_due_to_unpaid_invoices_you_can_update_your_payment_details_to_settle_the_invoice_and_continue_using_docuseal_or_cancel_your_subscription: Seu plano Pro foi suspenso devido a faturas não pagas. Você pode atualizar seus dados de pagamento para quitar a fatura e continuar usando o DocuSeal ou cancelar sua assinatura.
|
your_pro_plan_has_been_suspended_due_to_unpaid_invoices_you_can_update_your_payment_details_to_settle_the_invoice_and_continue_using_docuseal_or_cancel_your_subscription: Seu plano Pro foi suspenso devido a faturas não pagas. Você pode atualizar seus dados de pagamento para quitar a fatura e continuar usando o DocuSeal ou cancelar sua assinatura.
|
||||||
|
get_the_docuseal_app_for_a_better_mobile_experience: Baixe o app DocuSeal para uma melhor experiência no celular.
|
||||||
|
install_app: Instalar app
|
||||||
manage_subscription: Gerenciar Assinatura
|
manage_subscription: Gerenciar Assinatura
|
||||||
docuseal_version_security_release_is_available: "A versão de segurança DocuSeal v%{version} está disponível."
|
docuseal_version_security_release_is_available: "A versão de segurança DocuSeal v%{version} está disponível."
|
||||||
click_here_to_view_the_instructions_and_update_your_app_html: '<a href="%{url}" class="link" target="_blank" rel="noopener noreferrer nofollow">Clique aqui</a> para ver as instruções e atualizar seu aplicativo.'
|
click_here_to_view_the_instructions_and_update_your_app_html: '<a href="%{url}" class="link" target="_blank" rel="noopener noreferrer nofollow">Clique aqui</a> para ver as instruções e atualizar seu aplicativo.'
|
||||||
@@ -5670,10 +5688,12 @@ pt: &pt
|
|||||||
link: Link
|
link: Link
|
||||||
mcp: MCP
|
mcp: MCP
|
||||||
self: Assine você mesmo
|
self: Assine você mesmo
|
||||||
|
error: Erro
|
||||||
submission_event_names:
|
submission_event_names:
|
||||||
send_email_to_html: '<b>Email enviado</b> para %{submitter_name}'
|
send_email_to_html: '<b>Email enviado</b> para %{submitter_name}'
|
||||||
bounce_email_html: '<b>Email não entregue</b> %{submitter_name}'
|
bounce_email_html: '<b>Email não entregue</b> %{submitter_name}'
|
||||||
complaint_email_html: '<b>Reclamação de spam</b> %{submitter_name}'
|
complaint_email_html: '<b>Reclamação de spam</b> %{submitter_name}'
|
||||||
|
fail_sms_to_html: '<b>SMS não entregue</b> para %{submitter_name}'
|
||||||
send_reminder_email_to_html: '<b>Email de lembrete enviado</b> para %{submitter_name}'
|
send_reminder_email_to_html: '<b>Email de lembrete enviado</b> para %{submitter_name}'
|
||||||
send_sms_to_html: '<b>SMS enviado</b> para %{submitter_name}'
|
send_sms_to_html: '<b>SMS enviado</b> para %{submitter_name}'
|
||||||
send_2fa_sms_to_html: '<b>SMS de verificação enviado</b> para %{submitter_name}'
|
send_2fa_sms_to_html: '<b>SMS de verificação enviado</b> para %{submitter_name}'
|
||||||
@@ -6625,6 +6645,8 @@ de: &de
|
|||||||
click_here_to_update_your_payment_details_and_clear_the_invoice_to_ensure_uninterrupted_service_html: '<a href="%{url}" class="link">Klicken Sie hier</a>, um Ihre Zahlungsdaten zu aktualisieren und die Rechnung zu begleichen, um einen unterbrechungsfreien Service sicherzustellen.'
|
click_here_to_update_your_payment_details_and_clear_the_invoice_to_ensure_uninterrupted_service_html: '<a href="%{url}" class="link">Klicken Sie hier</a>, um Ihre Zahlungsdaten zu aktualisieren und die Rechnung zu begleichen, um einen unterbrechungsfreien Service sicherzustellen.'
|
||||||
overdue_payment: Überfällige Zahlung
|
overdue_payment: Überfällige Zahlung
|
||||||
your_pro_plan_has_been_suspended_due_to_unpaid_invoices_you_can_update_your_payment_details_to_settle_the_invoice_and_continue_using_docuseal_or_cancel_your_subscription: Ihr Pro-Plan wurde aufgrund unbezahlter Rechnungen ausgesetzt. Sie können Ihre Zahlungsdaten aktualisieren, um die Rechnung zu begleichen und DocuSeal weiterhin zu nutzen, oder Ihr Abonnement kündigen.
|
your_pro_plan_has_been_suspended_due_to_unpaid_invoices_you_can_update_your_payment_details_to_settle_the_invoice_and_continue_using_docuseal_or_cancel_your_subscription: Ihr Pro-Plan wurde aufgrund unbezahlter Rechnungen ausgesetzt. Sie können Ihre Zahlungsdaten aktualisieren, um die Rechnung zu begleichen und DocuSeal weiterhin zu nutzen, oder Ihr Abonnement kündigen.
|
||||||
|
get_the_docuseal_app_for_a_better_mobile_experience: Holen Sie sich die DocuSeal-App für ein besseres mobiles Erlebnis.
|
||||||
|
install_app: App installieren
|
||||||
manage_subscription: Abonnement verwalten
|
manage_subscription: Abonnement verwalten
|
||||||
docuseal_version_security_release_is_available: "Das Sicherheitsupdate DocuSeal v%{version} ist verfügbar."
|
docuseal_version_security_release_is_available: "Das Sicherheitsupdate DocuSeal v%{version} ist verfügbar."
|
||||||
click_here_to_view_the_instructions_and_update_your_app_html: '<a href="%{url}" class="link" target="_blank" rel="noopener noreferrer nofollow">Klicken Sie hier</a>, um die Anleitung anzuzeigen und Ihre App zu aktualisieren.'
|
click_here_to_view_the_instructions_and_update_your_app_html: '<a href="%{url}" class="link" target="_blank" rel="noopener noreferrer nofollow">Klicken Sie hier</a>, um die Anleitung anzuzeigen und Ihre App zu aktualisieren.'
|
||||||
@@ -6833,10 +6855,12 @@ de: &de
|
|||||||
link: Link
|
link: Link
|
||||||
mcp: MCP
|
mcp: MCP
|
||||||
self: Selbst unterschreiben
|
self: Selbst unterschreiben
|
||||||
|
error: Fehler
|
||||||
submission_event_names:
|
submission_event_names:
|
||||||
send_email_to_html: '<b>E-Mail gesendet</b> an %{submitter_name}'
|
send_email_to_html: '<b>E-Mail gesendet</b> an %{submitter_name}'
|
||||||
bounce_email_html: '<b>E-Mail unzustellbar</b> %{submitter_name}'
|
bounce_email_html: '<b>E-Mail unzustellbar</b> %{submitter_name}'
|
||||||
complaint_email_html: '<b>Spam-Beschwerde</b> %{submitter_name}'
|
complaint_email_html: '<b>Spam-Beschwerde</b> %{submitter_name}'
|
||||||
|
fail_sms_to_html: '<b>SMS unzustellbar</b> an %{submitter_name}'
|
||||||
send_reminder_email_to_html: '<b>Erinnerungs-E-Mail gesendet</b> an %{submitter_name}'
|
send_reminder_email_to_html: '<b>Erinnerungs-E-Mail gesendet</b> an %{submitter_name}'
|
||||||
send_sms_to_html: '<b>SMS gesendet</b> an %{submitter_name}'
|
send_sms_to_html: '<b>SMS gesendet</b> an %{submitter_name}'
|
||||||
send_2fa_sms_to_html: '<b>Verifizierungs-SMS gesendet</b> an %{submitter_name}'
|
send_2fa_sms_to_html: '<b>Verifizierungs-SMS gesendet</b> an %{submitter_name}'
|
||||||
@@ -8316,6 +8340,8 @@ nl: &nl
|
|||||||
click_here_to_update_your_payment_details_and_clear_the_invoice_to_ensure_uninterrupted_service_html: <a href="%{url}" class="link">Klik hier</a> om uw betaalgegevens bij te werken en de factuur te voldoen om ononderbroken service te garanderen.
|
click_here_to_update_your_payment_details_and_clear_the_invoice_to_ensure_uninterrupted_service_html: <a href="%{url}" class="link">Klik hier</a> om uw betaalgegevens bij te werken en de factuur te voldoen om ononderbroken service te garanderen.
|
||||||
overdue_payment: Achterstallige betaling
|
overdue_payment: Achterstallige betaling
|
||||||
your_pro_plan_has_been_suspended_due_to_unpaid_invoices_you_can_update_your_payment_details_to_settle_the_invoice_and_continue_using_docuseal_or_cancel_your_subscription: Uw Pro-abonnement is opgeschort vanwege onbetaalde facturen. U kunt uw betaalgegevens bijwerken om de factuur te voldoen en DocuSeal te blijven gebruiken of uw abonnement opzeggen.
|
your_pro_plan_has_been_suspended_due_to_unpaid_invoices_you_can_update_your_payment_details_to_settle_the_invoice_and_continue_using_docuseal_or_cancel_your_subscription: Uw Pro-abonnement is opgeschort vanwege onbetaalde facturen. U kunt uw betaalgegevens bijwerken om de factuur te voldoen en DocuSeal te blijven gebruiken of uw abonnement opzeggen.
|
||||||
|
get_the_docuseal_app_for_a_better_mobile_experience: Download de DocuSeal-app voor een betere mobiele ervaring.
|
||||||
|
install_app: App installeren
|
||||||
manage_subscription: Abonnement beheren
|
manage_subscription: Abonnement beheren
|
||||||
docuseal_version_security_release_is_available: "Beveiligingsupdate DocuSeal v%{version} is beschikbaar."
|
docuseal_version_security_release_is_available: "Beveiligingsupdate DocuSeal v%{version} is beschikbaar."
|
||||||
click_here_to_view_the_instructions_and_update_your_app_html: '<a href="%{url}" class="link" target="_blank" rel="noopener noreferrer nofollow">Klik hier</a> om de instructies te bekijken en uw app bij te werken.'
|
click_here_to_view_the_instructions_and_update_your_app_html: '<a href="%{url}" class="link" target="_blank" rel="noopener noreferrer nofollow">Klik hier</a> om de instructies te bekijken en uw app bij te werken.'
|
||||||
@@ -8520,10 +8546,12 @@ nl: &nl
|
|||||||
link: Link
|
link: Link
|
||||||
mcp: MCP
|
mcp: MCP
|
||||||
self: Zelf ondertekenen
|
self: Zelf ondertekenen
|
||||||
|
error: Fout
|
||||||
submission_event_names:
|
submission_event_names:
|
||||||
send_email_to_html: "<b>E-mail verzonden</b> naar %{submitter_name}"
|
send_email_to_html: "<b>E-mail verzonden</b> naar %{submitter_name}"
|
||||||
bounce_email_html: "<b>E-mail geretourneerd</b> %{submitter_name}"
|
bounce_email_html: "<b>E-mail geretourneerd</b> %{submitter_name}"
|
||||||
complaint_email_html: "<b>Spamklacht</b> %{submitter_name}"
|
complaint_email_html: "<b>Spamklacht</b> %{submitter_name}"
|
||||||
|
fail_sms_to_html: "<b>SMS niet afgeleverd</b> naar %{submitter_name}"
|
||||||
send_reminder_email_to_html: "<b>Herinneringsmail verzonden</b> naar %{submitter_name}"
|
send_reminder_email_to_html: "<b>Herinneringsmail verzonden</b> naar %{submitter_name}"
|
||||||
send_sms_to_html: "<b>SMS verzonden</b> naar %{submitter_name}"
|
send_sms_to_html: "<b>SMS verzonden</b> naar %{submitter_name}"
|
||||||
send_2fa_sms_to_html: "<b>Verificatie-SMS verzonden</b> naar %{submitter_name}"
|
send_2fa_sms_to_html: "<b>Verificatie-SMS verzonden</b> naar %{submitter_name}"
|
||||||
|
|||||||
+4
-4
@@ -125,12 +125,12 @@ Rails.application.routes.draw do
|
|||||||
resource :blobs_proxy, only: %i[show], path: '/blobs_proxy/:signed_uuid/*filename',
|
resource :blobs_proxy, only: %i[show], path: '/blobs_proxy/:signed_uuid/*filename',
|
||||||
controller: 'api/active_storage_blobs_proxy'
|
controller: 'api/active_storage_blobs_proxy'
|
||||||
|
|
||||||
if Docuseal.multitenant?
|
if !Docuseal.multitenant? || Rails.env.local?
|
||||||
get '/disk/:encoded_key/*filename' => 'active_storage/disk#show', as: :rails_disk_service if Rails.env.local?
|
get '/disk/:encoded_key/*filename' => 'active_storage/disk#show', as: :rails_disk_service
|
||||||
|
|
||||||
ActiveSupport.run_load_hooks(:multitenant_routes, self)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ActiveSupport.run_load_hooks(:multitenant_routes, self) if Docuseal.multitenant?
|
||||||
|
|
||||||
resources :start_form, only: %i[show update], path: 'd', param: 'slug' do
|
resources :start_form, only: %i[show update], path: 'd', param: 'slug' do
|
||||||
get :completed
|
get :completed
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ module DetectBrowserDevice
|
|||||||
Silk
|
Silk
|
||||||
/ix
|
/ix
|
||||||
|
|
||||||
|
IOS_APP_USER_AGENT_REGEXP = /Hotwire Native iOS/
|
||||||
|
ANDROID_APP_USER_AGENT_REGEXP = /Hotwire Native Android/
|
||||||
|
|
||||||
WINDOWS_USER_AGENT_REGEXP = /
|
WINDOWS_USER_AGENT_REGEXP = /
|
||||||
Windows|
|
Windows|
|
||||||
Win64 |
|
Win64 |
|
||||||
@@ -63,6 +66,42 @@ module DetectBrowserDevice
|
|||||||
NetBSD
|
NetBSD
|
||||||
/ix
|
/ix
|
||||||
|
|
||||||
|
SEARCH_BOT_USER_AGENT_REGEXP = /
|
||||||
|
Googlebot |
|
||||||
|
Google-InspectionTool|
|
||||||
|
Storebot-Google |
|
||||||
|
AdsBot-Google |
|
||||||
|
Mediapartners-Google |
|
||||||
|
bingbot |
|
||||||
|
BingPreview |
|
||||||
|
adidxbot |
|
||||||
|
msnbot |
|
||||||
|
Slurp |
|
||||||
|
DuckDuckBot |
|
||||||
|
Baiduspider |
|
||||||
|
YandexBot |
|
||||||
|
YandexImages |
|
||||||
|
Applebot |
|
||||||
|
PetalBot |
|
||||||
|
SeznamBot |
|
||||||
|
Sogou |
|
||||||
|
Exabot |
|
||||||
|
Qwantify |
|
||||||
|
YisouSpider |
|
||||||
|
Bytespider |
|
||||||
|
AhrefsBot |
|
||||||
|
SemrushBot |
|
||||||
|
MJ12bot |
|
||||||
|
DotBot |
|
||||||
|
GPTBot |
|
||||||
|
OAI-SearchBot |
|
||||||
|
ClaudeBot |
|
||||||
|
Claude-SearchBot |
|
||||||
|
PerplexityBot |
|
||||||
|
CCBot |
|
||||||
|
Amazonbot
|
||||||
|
/ix
|
||||||
|
|
||||||
SDK_USER_AGENT_REGEXP = /\ADocuSeal (?<sdk>Ruby|Python|PHP|Java|C#|JS|Go|CLI) v/i
|
SDK_USER_AGENT_REGEXP = /\ADocuSeal (?<sdk>Ruby|Python|PHP|Java|C#|JS|Go|CLI) v/i
|
||||||
|
|
||||||
def call(user_agent)
|
def call(user_agent)
|
||||||
@@ -74,6 +113,10 @@ module DetectBrowserDevice
|
|||||||
'desktop'
|
'desktop'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def search_bot?(user_agent)
|
||||||
|
SEARCH_BOT_USER_AGENT_REGEXP.match?(user_agent.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
def os(user_agent)
|
def os(user_agent)
|
||||||
return if user_agent.blank?
|
return if user_agent.blank?
|
||||||
|
|
||||||
@@ -82,6 +125,8 @@ module DetectBrowserDevice
|
|||||||
return sdk.downcase if sdk
|
return sdk.downcase if sdk
|
||||||
|
|
||||||
case user_agent
|
case user_agent
|
||||||
|
when IOS_APP_USER_AGENT_REGEXP then 'iosapp'
|
||||||
|
when ANDROID_APP_USER_AGENT_REGEXP then 'andapp'
|
||||||
when WINDOWS_USER_AGENT_REGEXP then 'windows'
|
when WINDOWS_USER_AGENT_REGEXP then 'windows'
|
||||||
when ANDROID_USER_AGENT_REGEXP then 'android'
|
when ANDROID_USER_AGENT_REGEXP then 'android'
|
||||||
when IOS_USER_AGENT_REGEXP then 'ios'
|
when IOS_USER_AGENT_REGEXP then 'ios'
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ module Docuseal
|
|||||||
TWITTER_URL = 'https://twitter.com/docusealco'
|
TWITTER_URL = 'https://twitter.com/docusealco'
|
||||||
TWITTER_HANDLE = '@docusealco'
|
TWITTER_HANDLE = '@docusealco'
|
||||||
CHATGPT_URL = "#{PRODUCT_URL}/chat".freeze
|
CHATGPT_URL = "#{PRODUCT_URL}/chat".freeze
|
||||||
|
APP_STORE_URL = 'https://apps.apple.com/us/app/docuseal-e-signature/id6823564236'
|
||||||
|
GOOGLE_PLAY_URL = 'https://play.google.com/store/apps/details?id=com.docuseal.app'
|
||||||
SUPPORT_EMAIL = 'support@docuseal.com'
|
SUPPORT_EMAIL = 'support@docuseal.com'
|
||||||
HOST = ENV.fetch('HOST', 'localhost')
|
HOST = ENV.fetch('HOST', 'localhost')
|
||||||
AATL_CERT_NAME = 'docuseal_aatl'
|
AATL_CERT_NAME = 'docuseal_aatl'
|
||||||
|
|||||||
@@ -18,4 +18,8 @@ module FilenameUtils
|
|||||||
def dangerous_extension(filename)
|
def dangerous_extension(filename)
|
||||||
ActiveStorage::Filename.wrap(filename).sanitized[DANGEROUS_EXTENSIONS_REGEXP, 1]&.downcase
|
ActiveStorage::Filename.wrap(filename).sanitized[DANGEROUS_EXTENSIONS_REGEXP, 1]&.downcase
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def basename(filename)
|
||||||
|
File.basename(filename, File.extname(filename))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
@@ -469,7 +469,7 @@ module Submissions
|
|||||||
end
|
end
|
||||||
|
|
||||||
events_data = submission.submission_events.sort_by(&:event_timestamp).filter_map do |event|
|
events_data = submission.submission_events.sort_by(&:event_timestamp).filter_map do |event|
|
||||||
next if event.event_type.in?(%w[bounce_email complaint_email])
|
next if event.event_type.in?(%w[bounce_email complaint_email fail_sms])
|
||||||
|
|
||||||
submitter = submission.submitters.find { |e| e.id == event.submitter_id }
|
submitter = submission.submitters.find { |e| e.id == event.submitter_id }
|
||||||
versions = submitter_versions_index[submitter.id] || []
|
versions = submitter_versions_index[submitter.id] || []
|
||||||
|
|||||||
+1
-1
@@ -232,7 +232,7 @@ module Submitters
|
|||||||
def build_document_filename(submitter, blob, filename_format)
|
def build_document_filename(submitter, blob, filename_format)
|
||||||
return blob.filename.to_s if filename_format.blank?
|
return blob.filename.to_s if filename_format.blank?
|
||||||
|
|
||||||
filename = filename_format.gsub('{document.name}', blob.filename.base)
|
filename = filename_format.gsub('{document.name}', FilenameUtils.basename(blob[:filename]))
|
||||||
filename = ReplaceEmailVariables.call(filename, submitter:)
|
filename = ReplaceEmailVariables.call(filename, submitter:)
|
||||||
|
|
||||||
filename = filename.gsub(' - {submission.status}') do
|
filename = filename.gsub(' - {submission.status}') do
|
||||||
|
|||||||
@@ -8,6 +8,13 @@ module Submitters
|
|||||||
methods: %i[status application_key]
|
methods: %i[status application_key]
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
|
EVENT_DATA_KEYS = {
|
||||||
|
'decline_form' => %w[reason],
|
||||||
|
'complete_verification' => %w[firstname lastname method country idcode],
|
||||||
|
'fail_kba' => %w[issues],
|
||||||
|
'fail_sms' => %w[status error_code]
|
||||||
|
}.freeze
|
||||||
|
|
||||||
module_function
|
module_function
|
||||||
|
|
||||||
def call(submitter, with_template: false, with_events: false, with_documents: true, with_urls: false,
|
def call(submitter, with_template: false, with_events: false, with_documents: true, with_urls: false,
|
||||||
@@ -55,7 +62,7 @@ module Submitters
|
|||||||
def serialize_events(events)
|
def serialize_events(events)
|
||||||
events.map do |event|
|
events.map do |event|
|
||||||
event.as_json(only: %i[id submitter_id event_type event_timestamp])
|
event.as_json(only: %i[id submitter_id event_type event_timestamp])
|
||||||
.merge('data' => event.data.slice('reason', 'firstname', 'lastname', 'method', 'country', 'idcode'))
|
.merge('data' => event.data.slice(*EVENT_DATA_KEYS[event.event_type]))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -104,7 +104,10 @@ module Submitters
|
|||||||
|
|
||||||
def build_documents_array(submitter, expires_at: nil)
|
def build_documents_array(submitter, expires_at: nil)
|
||||||
submitter.documents.map do |attachment|
|
submitter.documents.map do |attachment|
|
||||||
{ 'name' => attachment.filename.base, 'url' => rails_storage_proxy_url(attachment, expires_at:) }
|
{
|
||||||
|
'name' => FilenameUtils.basename(attachment.blob[:filename]),
|
||||||
|
'url' => rails_storage_proxy_url(attachment, expires_at:)
|
||||||
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ module Templates
|
|||||||
def create_document!(template, attachment, data, scan)
|
def create_document!(template, attachment, data, scan)
|
||||||
blob = ActiveStorage::Blob.create_and_upload!(
|
blob = ActiveStorage::Blob.create_and_upload!(
|
||||||
io: StringIO.new(data),
|
io: StringIO.new(data),
|
||||||
filename: "#{attachment.filename.base}.#{scan ? 'png' : 'jpg'}",
|
filename: "#{FilenameUtils.basename(attachment.blob[:filename])}.#{scan ? 'png' : 'jpg'}",
|
||||||
metadata: { identified: true, analyzed: true },
|
metadata: { identified: true, analyzed: true },
|
||||||
content_type: scan ? 'image/png' : 'image/jpeg'
|
content_type: scan ? 'image/png' : 'image/jpeg'
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ module Templates
|
|||||||
schema_item =
|
schema_item =
|
||||||
template.schema.find { |item| item['attachment_uuid'] == entry['attachment_uuid'] } ||
|
template.schema.find { |item| item['attachment_uuid'] == entry['attachment_uuid'] } ||
|
||||||
{ 'attachment_uuid' => entry['attachment_uuid'],
|
{ 'attachment_uuid' => entry['attachment_uuid'],
|
||||||
'name' => attachments_index[entry['attachment_uuid']].filename.base }
|
'name' => FilenameUtils.basename(attachments_index[entry['attachment_uuid']].blob[:filename]) }
|
||||||
|
|
||||||
next if entry['pages'].blank?
|
next if entry['pages'].blank?
|
||||||
|
|
||||||
@@ -270,7 +270,7 @@ module Templates
|
|||||||
|
|
||||||
blob = ActiveStorage::Blob.create_and_upload!(
|
blob = ActiveStorage::Blob.create_and_upload!(
|
||||||
io: StringIO.new(data),
|
io: StringIO.new(data),
|
||||||
filename: "#{attachment.filename.base}#{extension}",
|
filename: "#{FilenameUtils.basename(attachment.blob[:filename])}#{extension}",
|
||||||
metadata: { identified: true, analyzed: true },
|
metadata: { identified: true, analyzed: true },
|
||||||
content_type:
|
content_type:
|
||||||
)
|
)
|
||||||
@@ -439,7 +439,7 @@ module Templates
|
|||||||
|
|
||||||
blob = ActiveStorage::Blob.create_and_upload!(
|
blob = ActiveStorage::Blob.create_and_upload!(
|
||||||
io: StringIO.new(data),
|
io: StringIO.new(data),
|
||||||
filename: "#{old_attachment.filename.base}.pdf",
|
filename: "#{FilenameUtils.basename(old_attachment.blob[:filename])}.pdf",
|
||||||
metadata: { identified: true, analyzed: true,
|
metadata: { identified: true, analyzed: true,
|
||||||
pdf: { annotations: }.compact_blank, sha256: }.compact_blank,
|
pdf: { annotations: }.compact_blank, sha256: }.compact_blank,
|
||||||
content_type: Templates::ProcessDocument::PDF_CONTENT_TYPE
|
content_type: Templates::ProcessDocument::PDF_CONTENT_TYPE
|
||||||
|
|||||||
@@ -12,7 +12,10 @@ module Templates
|
|||||||
documents.each_with_index do |document, index|
|
documents.each_with_index do |document, index|
|
||||||
replaced_document_schema = template.schema[index]
|
replaced_document_schema = template.schema[index]
|
||||||
|
|
||||||
template.schema[index] = { attachment_uuid: document.uuid, name: document.filename.base }
|
template.schema[index] = {
|
||||||
|
attachment_uuid: document.uuid,
|
||||||
|
name: FilenameUtils.basename(document.blob[:filename])
|
||||||
|
}
|
||||||
|
|
||||||
if replaced_document_schema
|
if replaced_document_schema
|
||||||
template.fields.each do |field|
|
template.fields.each do |field|
|
||||||
|
|||||||
Reference in new issue
Block a user