mirror of
https://github.com/docusealco/docuseal
synced 2026-11-04 06:42:32 -05:00
Merge from docusealco/wip
This commit is contained in:
98 files changed
+363
-314
No files matched your search
+77
-77
@@ -3,29 +3,29 @@ GEM
|
|||||||
specs:
|
specs:
|
||||||
action_text-trix (2.1.19)
|
action_text-trix (2.1.19)
|
||||||
railties
|
railties
|
||||||
actioncable (8.1.3.1)
|
actioncable (8.1.4)
|
||||||
actionpack (= 8.1.3.1)
|
actionpack (= 8.1.4)
|
||||||
activesupport (= 8.1.3.1)
|
activesupport (= 8.1.4)
|
||||||
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.3.1)
|
actionmailbox (8.1.4)
|
||||||
actionpack (= 8.1.3.1)
|
actionpack (= 8.1.4)
|
||||||
activejob (= 8.1.3.1)
|
activejob (= 8.1.4)
|
||||||
activerecord (= 8.1.3.1)
|
activerecord (= 8.1.4)
|
||||||
activestorage (= 8.1.3.1)
|
activestorage (= 8.1.4)
|
||||||
activesupport (= 8.1.3.1)
|
activesupport (= 8.1.4)
|
||||||
mail (>= 2.8.0)
|
mail (>= 2.8.0)
|
||||||
actionmailer (8.1.3.1)
|
actionmailer (8.1.4)
|
||||||
actionpack (= 8.1.3.1)
|
actionpack (= 8.1.4)
|
||||||
actionview (= 8.1.3.1)
|
actionview (= 8.1.4)
|
||||||
activejob (= 8.1.3.1)
|
activejob (= 8.1.4)
|
||||||
activesupport (= 8.1.3.1)
|
activesupport (= 8.1.4)
|
||||||
mail (>= 2.8.0)
|
mail (>= 2.8.0)
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
actionpack (8.1.3.1)
|
actionpack (8.1.4)
|
||||||
actionview (= 8.1.3.1)
|
actionview (= 8.1.4)
|
||||||
activesupport (= 8.1.3.1)
|
activesupport (= 8.1.4)
|
||||||
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.3.1)
|
actiontext (8.1.4)
|
||||||
action_text-trix (~> 2.1.15)
|
action_text-trix (~> 2.1.15)
|
||||||
actionpack (= 8.1.3.1)
|
actionpack (= 8.1.4)
|
||||||
activerecord (= 8.1.3.1)
|
activerecord (= 8.1.4)
|
||||||
activestorage (= 8.1.3.1)
|
activestorage (= 8.1.4)
|
||||||
activesupport (= 8.1.3.1)
|
activesupport (= 8.1.4)
|
||||||
globalid (>= 0.6.0)
|
globalid (>= 0.6.0)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
actionview (8.1.3.1)
|
actionview (8.1.4)
|
||||||
activesupport (= 8.1.3.1)
|
activesupport (= 8.1.4)
|
||||||
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)
|
||||||
activejob (8.1.3.1)
|
activejob (8.1.4)
|
||||||
activesupport (= 8.1.3.1)
|
activesupport (= 8.1.4)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (8.1.3.1)
|
activemodel (8.1.4)
|
||||||
activesupport (= 8.1.3.1)
|
activesupport (= 8.1.4)
|
||||||
activerecord (8.1.3.1)
|
activerecord (8.1.4)
|
||||||
activemodel (= 8.1.3.1)
|
activemodel (= 8.1.4)
|
||||||
activesupport (= 8.1.3.1)
|
activesupport (= 8.1.4)
|
||||||
timeout (>= 0.4.0)
|
timeout (>= 0.4.0)
|
||||||
activestorage (8.1.3.1)
|
activestorage (8.1.4)
|
||||||
actionpack (= 8.1.3.1)
|
actionpack (= 8.1.4)
|
||||||
activejob (= 8.1.3.1)
|
activejob (= 8.1.4)
|
||||||
activerecord (= 8.1.3.1)
|
activerecord (= 8.1.4)
|
||||||
activesupport (= 8.1.3.1)
|
activesupport (= 8.1.4)
|
||||||
marcel (~> 1.0)
|
marcel (~> 1.0)
|
||||||
activesupport (8.1.3.1)
|
activesupport (8.1.4)
|
||||||
base64
|
base64
|
||||||
bigdecimal
|
bigdecimal
|
||||||
concurrent-ruby (~> 1.0, >= 1.3.1)
|
concurrent-ruby (~> 1.0, >= 1.3.1)
|
||||||
@@ -116,7 +116,7 @@ GEM
|
|||||||
erubi (~> 1.4)
|
erubi (~> 1.4)
|
||||||
parser (>= 2.4)
|
parser (>= 2.4)
|
||||||
smart_properties
|
smart_properties
|
||||||
bigdecimal (4.1.2)
|
bigdecimal (4.1.3)
|
||||||
bindex (0.8.1)
|
bindex (0.8.1)
|
||||||
bootsnap (1.23.0)
|
bootsnap (1.23.0)
|
||||||
msgpack (~> 1.2)
|
msgpack (~> 1.2)
|
||||||
@@ -149,14 +149,14 @@ GEM
|
|||||||
crack (1.0.1)
|
crack (1.0.1)
|
||||||
bigdecimal
|
bigdecimal
|
||||||
rexml
|
rexml
|
||||||
crass (1.0.7)
|
crass (1.0.8)
|
||||||
csv (3.3.5)
|
csv (3.3.5)
|
||||||
csv-safe (3.3.1)
|
csv-safe (3.3.1)
|
||||||
csv (~> 3.0)
|
csv (~> 3.0)
|
||||||
cuprite (0.17)
|
cuprite (0.17)
|
||||||
capybara (~> 3.0)
|
capybara (~> 3.0)
|
||||||
ferrum (~> 0.17.0)
|
ferrum (~> 0.17.0)
|
||||||
date (3.5.1)
|
date (3.6.0)
|
||||||
debug (1.11.1)
|
debug (1.11.1)
|
||||||
irb (~> 1.10)
|
irb (~> 1.10)
|
||||||
reline (>= 0.3.8)
|
reline (>= 0.3.8)
|
||||||
@@ -179,7 +179,7 @@ GEM
|
|||||||
dotenv (3.2.0)
|
dotenv (3.2.0)
|
||||||
drb (2.2.3)
|
drb (2.2.3)
|
||||||
email_typo (0.2.3)
|
email_typo (0.2.3)
|
||||||
erb (6.0.6)
|
erb (6.0.7)
|
||||||
erb_lint (0.9.0)
|
erb_lint (0.9.0)
|
||||||
activesupport
|
activesupport
|
||||||
better_html (>= 2.0.1)
|
better_html (>= 2.0.1)
|
||||||
@@ -195,8 +195,8 @@ GEM
|
|||||||
railties (>= 6.1.0)
|
railties (>= 6.1.0)
|
||||||
faker (3.6.1)
|
faker (3.6.1)
|
||||||
i18n (>= 1.8.11, < 2)
|
i18n (>= 1.8.11, < 2)
|
||||||
faraday (2.14.3)
|
faraday (2.15.1)
|
||||||
faraday-net_http (>= 2.0, < 3.5)
|
faraday-net_http (>= 2.0, < 3.6)
|
||||||
json
|
json
|
||||||
logger
|
logger
|
||||||
faraday-follow_redirects (0.5.0)
|
faraday-follow_redirects (0.5.0)
|
||||||
@@ -264,14 +264,14 @@ GEM
|
|||||||
strscan (>= 3.1.2)
|
strscan (>= 3.1.2)
|
||||||
i18n (1.15.2)
|
i18n (1.15.2)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
io-console (0.8.2)
|
io-console (0.9.5)
|
||||||
irb (1.18.0)
|
irb (1.18.0)
|
||||||
pp (>= 0.6.0)
|
pp (>= 0.6.0)
|
||||||
prism (>= 1.3.0)
|
prism (>= 1.3.0)
|
||||||
rdoc (>= 4.0.0)
|
rdoc (>= 4.0.0)
|
||||||
reline (>= 0.4.2)
|
reline (>= 0.4.2)
|
||||||
jmespath (1.6.2)
|
jmespath (1.6.2)
|
||||||
json (2.21.2)
|
json (3.1.0)
|
||||||
jwt (3.2.0)
|
jwt (3.2.0)
|
||||||
base64
|
base64
|
||||||
language_server-protocol (3.17.0.5)
|
language_server-protocol (3.17.0.5)
|
||||||
@@ -310,17 +310,17 @@ GEM
|
|||||||
drb (~> 2.0)
|
drb (~> 2.0)
|
||||||
prism (~> 1.5)
|
prism (~> 1.5)
|
||||||
msgpack (1.8.4)
|
msgpack (1.8.4)
|
||||||
multi_json (1.19.1)
|
multi_json (1.21.2)
|
||||||
net-http (0.9.1)
|
net-http (0.9.1)
|
||||||
uri (>= 0.11.1)
|
uri (>= 0.11.1)
|
||||||
net-imap (0.6.6)
|
net-imap (0.6.8)
|
||||||
date
|
date
|
||||||
net-protocol
|
net-protocol
|
||||||
net-pop (0.1.2)
|
net-pop (0.1.2)
|
||||||
net-protocol
|
net-protocol
|
||||||
net-protocol (0.2.2)
|
net-protocol (0.4.0)
|
||||||
timeout
|
timeout
|
||||||
net-smtp (0.5.1)
|
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.4-aarch64-linux-gnu)
|
||||||
@@ -361,7 +361,7 @@ GEM
|
|||||||
prettyprint
|
prettyprint
|
||||||
pretender (1.0.0)
|
pretender (1.0.0)
|
||||||
actionpack (>= 7.2)
|
actionpack (>= 7.2)
|
||||||
prettyprint (0.2.0)
|
prettyprint (0.2.1)
|
||||||
prism (1.9.0)
|
prism (1.9.0)
|
||||||
pry (0.16.0)
|
pry (0.16.0)
|
||||||
coderay (~> 1.1)
|
coderay (~> 1.1)
|
||||||
@@ -373,30 +373,30 @@ 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.6)
|
rack (3.2.7)
|
||||||
rack-proxy (0.7.7)
|
rack-proxy (0.7.7)
|
||||||
rack
|
rack
|
||||||
rack-session (2.1.2)
|
rack-session (2.1.2)
|
||||||
base64 (>= 0.1.0)
|
base64 (>= 0.1.0)
|
||||||
rack (>= 3.0.0)
|
rack (>= 3.0.0)
|
||||||
rack-test (2.2.0)
|
rack-test (2.3.0)
|
||||||
rack (>= 1.3)
|
rack (>= 1.3)
|
||||||
rackup (2.3.1)
|
rackup (2.3.1)
|
||||||
rack (>= 3)
|
rack (>= 3)
|
||||||
rails (8.1.3.1)
|
rails (8.1.4)
|
||||||
actioncable (= 8.1.3.1)
|
actioncable (= 8.1.4)
|
||||||
actionmailbox (= 8.1.3.1)
|
actionmailbox (= 8.1.4)
|
||||||
actionmailer (= 8.1.3.1)
|
actionmailer (= 8.1.4)
|
||||||
actionpack (= 8.1.3.1)
|
actionpack (= 8.1.4)
|
||||||
actiontext (= 8.1.3.1)
|
actiontext (= 8.1.4)
|
||||||
actionview (= 8.1.3.1)
|
actionview (= 8.1.4)
|
||||||
activejob (= 8.1.3.1)
|
activejob (= 8.1.4)
|
||||||
activemodel (= 8.1.3.1)
|
activemodel (= 8.1.4)
|
||||||
activerecord (= 8.1.3.1)
|
activerecord (= 8.1.4)
|
||||||
activestorage (= 8.1.3.1)
|
activestorage (= 8.1.4)
|
||||||
activesupport (= 8.1.3.1)
|
activesupport (= 8.1.4)
|
||||||
bundler (>= 1.15.0)
|
bundler (>= 1.15.0)
|
||||||
railties (= 8.1.3.1)
|
railties (= 8.1.4)
|
||||||
rails-dom-testing (2.3.0)
|
rails-dom-testing (2.3.0)
|
||||||
activesupport (>= 5.0.0)
|
activesupport (>= 5.0.0)
|
||||||
minitest
|
minitest
|
||||||
@@ -407,9 +407,9 @@ GEM
|
|||||||
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.3.1)
|
railties (8.1.4)
|
||||||
actionpack (= 8.1.3.1)
|
actionpack (= 8.1.4)
|
||||||
activesupport (= 8.1.3.1)
|
activesupport (= 8.1.4)
|
||||||
irb (~> 1.13)
|
irb (~> 1.13)
|
||||||
rackup (>= 1.0.0)
|
rackup (>= 1.0.0)
|
||||||
rake (>= 12.2)
|
rake (>= 12.2)
|
||||||
@@ -418,11 +418,11 @@ GEM
|
|||||||
zeitwerk (~> 2.6)
|
zeitwerk (~> 2.6)
|
||||||
rainbow (3.1.1)
|
rainbow (3.1.1)
|
||||||
rake (13.4.2)
|
rake (13.4.2)
|
||||||
rbs (4.1.0)
|
rbs (4.2.0)
|
||||||
logger
|
logger
|
||||||
prism (>= 1.6.0)
|
prism (>= 1.6.0)
|
||||||
tsort
|
tsort
|
||||||
rdoc (8.0.0)
|
rdoc (8.1.0)
|
||||||
erb
|
erb
|
||||||
prism (>= 1.6.0)
|
prism (>= 1.6.0)
|
||||||
rbs (>= 4.0.0)
|
rbs (>= 4.0.0)
|
||||||
@@ -430,7 +430,7 @@ GEM
|
|||||||
redis-client (0.29.0)
|
redis-client (0.29.0)
|
||||||
connection_pool
|
connection_pool
|
||||||
regexp_parser (2.11.3)
|
regexp_parser (2.11.3)
|
||||||
reline (0.6.3)
|
reline (0.7.0)
|
||||||
io-console (~> 0.5)
|
io-console (~> 0.5)
|
||||||
representable (3.2.0)
|
representable (3.2.0)
|
||||||
declarative (< 0.1.0)
|
declarative (< 0.1.0)
|
||||||
@@ -466,14 +466,14 @@ GEM
|
|||||||
rspec-mocks (>= 3.13.0, < 5.0.0)
|
rspec-mocks (>= 3.13.0, < 5.0.0)
|
||||||
rspec-support (>= 3.13.0, < 5.0.0)
|
rspec-support (>= 3.13.0, < 5.0.0)
|
||||||
rspec-support (3.13.7)
|
rspec-support (3.13.7)
|
||||||
rubocop (1.86.0)
|
rubocop (1.92.1)
|
||||||
json (~> 2.3)
|
json (>= 2.3)
|
||||||
language_server-protocol (~> 3.17.0.2)
|
language_server-protocol (~> 3.17.0.2)
|
||||||
lint_roller (~> 1.1.0)
|
lint_roller (~> 1.1.0)
|
||||||
parallel (~> 1.10)
|
parallel (>= 1.10)
|
||||||
parser (>= 3.3.0.2)
|
parser (>= 3.3.0.2)
|
||||||
rainbow (>= 2.2.2, < 4.0)
|
rainbow (>= 2.2.2, < 4.0)
|
||||||
regexp_parser (>= 2.9.3, < 3.0)
|
regexp_parser (>= 2.11.3, < 3.0)
|
||||||
rubocop-ast (>= 1.49.0, < 2.0)
|
rubocop-ast (>= 1.49.0, < 2.0)
|
||||||
ruby-progressbar (~> 1.7)
|
ruby-progressbar (~> 1.7)
|
||||||
unicode-display_width (>= 2.4.0, < 4.0)
|
unicode-display_width (>= 2.4.0, < 4.0)
|
||||||
@@ -555,7 +555,7 @@ GEM
|
|||||||
unicode-emoji (~> 4.1)
|
unicode-emoji (~> 4.1)
|
||||||
unicode-emoji (4.2.0)
|
unicode-emoji (4.2.0)
|
||||||
uniform_notifier (1.18.0)
|
uniform_notifier (1.18.0)
|
||||||
uri (1.1.1)
|
uri (1.1.2)
|
||||||
useragent (0.16.11)
|
useragent (0.16.11)
|
||||||
warden (1.2.9)
|
warden (1.2.9)
|
||||||
rack (>= 2.0.9)
|
rack (>= 2.0.9)
|
||||||
@@ -587,7 +587,7 @@ GEM
|
|||||||
xpath (3.2.0)
|
xpath (3.2.0)
|
||||||
nokogiri (~> 1.8)
|
nokogiri (~> 1.8)
|
||||||
yaml (0.4.0)
|
yaml (0.4.0)
|
||||||
zeitwerk (2.8.2)
|
zeitwerk (2.8.3)
|
||||||
zip_kit (6.3.4)
|
zip_kit (6.3.4)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ Out of scope vulnerabilities:
|
|||||||
- CSRF
|
- CSRF
|
||||||
- DNSSEC, CAA, CSP headers
|
- DNSSEC, CAA, CSP headers
|
||||||
- DNS or email security related
|
- DNS or email security related
|
||||||
|
- SSRF
|
||||||
- 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.
|
||||||
@@ -54,14 +54,13 @@ class AccountsController < ApplicationController
|
|||||||
email: true_user.email.sub('@', '+removed@'))
|
email: true_user.email.sub('@', '+removed@'))
|
||||||
true_user.account.update!(archived_at: Time.current)
|
true_user.account.update!(archived_at: Time.current)
|
||||||
|
|
||||||
# rubocop:disable Layout/LineLength
|
# rubocop:disable-next Layout/LineLength
|
||||||
render turbo_stream: turbo_stream.replace(
|
render turbo_stream: turbo_stream.replace(
|
||||||
:account_delete_button,
|
:account_delete_button,
|
||||||
html: helpers.tag.p(I18n.t('your_account_will_be_permanently_deleted_within_2_months_please_contact_us_if_you_want_to_keep_your_account')) +
|
html: helpers.tag.p(I18n.t('your_account_will_be_permanently_deleted_within_2_months_please_contact_us_if_you_want_to_keep_your_account')) +
|
||||||
helpers.tag.br +
|
helpers.tag.br +
|
||||||
helpers.tag.p(I18n.t('your_email_address_has_been_released_immediately_you_can_now_be_added_to_your_company_team_without_waiting_for_the_deletion_period_to_end'))
|
helpers.tag.p(I18n.t('your_email_address_has_been_released_immediately_you_can_now_be_added_to_your_company_team_without_waiting_for_the_deletion_period_to_end'))
|
||||||
)
|
)
|
||||||
# rubocop:enable Layout/LineLength
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ module Api
|
|||||||
before_action :set_noindex_headers
|
before_action :set_noindex_headers
|
||||||
before_action :set_security_headers
|
before_action :set_security_headers
|
||||||
|
|
||||||
# rubocop:disable Metrics
|
# rubocop:disable-next Metrics
|
||||||
def show
|
def show
|
||||||
blob_uuid, purp, exp = ApplicationRecord.signed_id_verifier.verified(params[:signed_uuid])
|
blob_uuid, purp, exp = ApplicationRecord.signed_id_verifier.verified(params[:signed_uuid])
|
||||||
|
|
||||||
@@ -53,7 +53,6 @@ module Api
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
|||||||
@@ -1,53 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Api
|
|
||||||
class ActiveStorageBlobsProxyLegacyController < ApiBaseController
|
|
||||||
include ActiveStorage::Streaming
|
|
||||||
|
|
||||||
skip_before_action :authenticate_user!
|
|
||||||
skip_authorization_check
|
|
||||||
|
|
||||||
before_action :set_cors_headers
|
|
||||||
before_action :set_noindex_headers
|
|
||||||
before_action :set_security_headers
|
|
||||||
|
|
||||||
# rubocop:disable Metrics
|
|
||||||
def show
|
|
||||||
Rollbar.info('Blob legacy') if defined?(Rollbar)
|
|
||||||
|
|
||||||
blob = ActiveStorage::Blob.find_signed(params[:signed_blob_id] || params[:signed_id])
|
|
||||||
|
|
||||||
return head :not_found unless blob
|
|
||||||
|
|
||||||
if FilenameUtils.dangerous_extension(blob.filename)
|
|
||||||
Rollbar.error('Dangerous extension') if defined?(Rollbar)
|
|
||||||
|
|
||||||
return head :unprocessable_content
|
|
||||||
end
|
|
||||||
|
|
||||||
is_permitted = blob.attachments.any? do |a|
|
|
||||||
(current_user && a.record.account.id == current_user.account_id) ||
|
|
||||||
a.record.account.account_configs.any? { |e| e.key == 'legacy_blob_proxy' } ||
|
|
||||||
a.name == 'logo'
|
|
||||||
end
|
|
||||||
|
|
||||||
unless is_permitted
|
|
||||||
Rollbar.error("Blob account not found: #{blob.id}") if defined?(Rollbar)
|
|
||||||
|
|
||||||
return render json: { error: 'Not authenticated' }, status: :unauthorized
|
|
||||||
end
|
|
||||||
|
|
||||||
if request.headers['Range'].present?
|
|
||||||
send_blob_byte_range_data blob, request.headers['Range']
|
|
||||||
else
|
|
||||||
http_cache_forever public: true do
|
|
||||||
response.headers['Accept-Ranges'] = 'bytes'
|
|
||||||
response.headers['Content-Length'] = blob.byte_size.to_s
|
|
||||||
|
|
||||||
send_blob_stream blob, disposition: params[:disposition]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
# rubocop:enable Metrics
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -36,7 +36,7 @@ module Api
|
|||||||
render json: Submitters::SerializeForApi.call(@submitter, with_template: true, with_events: true, params:)
|
render json: Submitters::SerializeForApi.call(@submitter, with_template: true, with_events: true, params:)
|
||||||
end
|
end
|
||||||
|
|
||||||
# rubocop:disable Metrics/MethodLength
|
# rubocop:disable-next Metrics/MethodLength
|
||||||
def update
|
def update
|
||||||
submission = @submitter.submission
|
submission = @submitter.submission
|
||||||
role = submission.template_submitters.find { |e| e['uuid'] == @submitter.uuid }['name']
|
role = submission.template_submitters.find { |e| e['uuid'] == @submitter.uuid }['name']
|
||||||
@@ -84,7 +84,6 @@ module Api
|
|||||||
|
|
||||||
render json: { error: e.message }, status: :unprocessable_content
|
render json: { error: e.message }, status: :unprocessable_content
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics/MethodLength
|
|
||||||
|
|
||||||
def submitter_params
|
def submitter_params
|
||||||
submitter_params = params.key?(:submitter) ? params.require(:submitter) : params
|
submitter_params = params.key?(:submitter) ? params.require(:submitter) : params
|
||||||
@@ -179,11 +178,29 @@ module Api
|
|||||||
submitters = submitters.where(external_id: params[:external_id]) if params[:external_id].present?
|
submitters = submitters.where(external_id: params[:external_id]) if params[:external_id].present?
|
||||||
submitters = submitters.where(slug: params[:slug]) if params[:slug].present?
|
submitters = submitters.where(slug: params[:slug]) if params[:slug].present?
|
||||||
submitters = submitters.where(submission_id: params[:submission_id]) if params[:submission_id].present?
|
submitters = submitters.where(submission_id: params[:submission_id]) if params[:submission_id].present?
|
||||||
submitters = submitters.where(template_id: params[:template_id]) if params[:template_id].present?
|
submitters = filter_submitters_by_template_id(submitters, params) if params[:template_id].present?
|
||||||
|
|
||||||
maybe_filter_by_completed_at(submitters, params)
|
maybe_filter_by_completed_at(submitters, params)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def filter_submitters_by_template_id(submitters, params)
|
||||||
|
return submitters.where(template_id: params[:template_id]) if params[:template_id].is_a?(Array)
|
||||||
|
|
||||||
|
template = Template.find_by(id: params[:template_id])
|
||||||
|
|
||||||
|
return submitters.none if template.nil? || !can?(:read, template)
|
||||||
|
|
||||||
|
if template.account_id == current_user.account_id &&
|
||||||
|
params[:completed_after].blank? && params[:completed_before].blank?
|
||||||
|
account_id_bind = Submitter.predicate_builder.build_bind_attribute('account_id', current_user.account_id)
|
||||||
|
|
||||||
|
submitters = submitters.unscope(where: :account_id)
|
||||||
|
.where((Submitter.arel_table[:account_id] + 0).eq(account_id_bind))
|
||||||
|
end
|
||||||
|
|
||||||
|
submitters.where(template_id: template.id)
|
||||||
|
end
|
||||||
|
|
||||||
def assign_external_id(submitter, attrs)
|
def assign_external_id(submitter, attrs)
|
||||||
submitter.external_id = attrs[:application_key] if attrs.key?(:application_key)
|
submitter.external_id = attrs[:application_key] if attrs.key?(:application_key)
|
||||||
submitter.external_id = attrs[:external_id] if attrs.key?(:external_id)
|
submitter.external_id = attrs[:external_id] if attrs.key?(:external_id)
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ module Mcp
|
|||||||
}
|
}
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
# rubocop:disable-next Metrics/AbcSize, Metrics/MethodLength
|
||||||
def call
|
def call
|
||||||
account = current_user.account
|
account = current_user.account
|
||||||
|
|
||||||
@@ -87,6 +87,5 @@ module Mcp
|
|||||||
edit_url: edit_template_url(@template)
|
edit_url: edit_template_url(@template)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -66,7 +66,7 @@ module Mcp
|
|||||||
}
|
}
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
# rubocop:disable Metrics
|
# rubocop:disable-next Metrics
|
||||||
def call
|
def call
|
||||||
@template = Template.accessible_by(current_ability).find(mcp_params['template_id'])
|
@template = Template.accessible_by(current_ability).find(mcp_params['template_id'])
|
||||||
|
|
||||||
@@ -115,6 +115,5 @@ module Mcp
|
|||||||
rescue Submissions::CreateFromSubmitters::BaseError => e
|
rescue Submissions::CreateFromSubmitters::BaseError => e
|
||||||
render_tool_error(e.message)
|
render_tool_error(e.message)
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class PasswordsController < Devise::PasswordsController
|
class PasswordsController < Devise::PasswordsController
|
||||||
# rubocop:disable Rails/LexicallyScopedActionFilter
|
# rubocop:disable-next Rails/LexicallyScopedActionFilter
|
||||||
skip_before_action :require_no_authentication, only: %i[edit update]
|
skip_before_action :require_no_authentication, only: %i[edit update]
|
||||||
# rubocop:enable Rails/LexicallyScopedActionFilter
|
|
||||||
|
|
||||||
around_action :with_browser_locale
|
around_action :with_browser_locale
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class PreviewDocumentPageController < ActionController::API
|
|||||||
File.open(file_path, File::RDWR | File::CREAT, 0o644) do |file|
|
File.open(file_path, File::RDWR | File::CREAT, 0o644) do |file|
|
||||||
file.flock(File::LOCK_EX)
|
file.flock(File::LOCK_EX)
|
||||||
|
|
||||||
# rubocop:disable Style/ZeroLengthPredicate
|
# rubocop:disable-next Style/ZeroLengthPredicate
|
||||||
if file.size.zero?
|
if file.size.zero?
|
||||||
cleanup_stale_tempfiles
|
cleanup_stale_tempfiles
|
||||||
|
|
||||||
@@ -63,7 +63,6 @@ class PreviewDocumentPageController < ActionController::API
|
|||||||
else
|
else
|
||||||
FileUtils.touch(file_path)
|
FileUtils.touch(file_path)
|
||||||
end
|
end
|
||||||
# rubocop:enable Style/ZeroLengthPredicate
|
|
||||||
|
|
||||||
file.flock(File::LOCK_UN)
|
file.flock(File::LOCK_UN)
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class SendSubmissionEmailController < ApplicationController
|
|||||||
template = Template.find_by!(slug: params[:template_slug])
|
template = Template.find_by!(slug: params[:template_slug])
|
||||||
|
|
||||||
@submitter =
|
@submitter =
|
||||||
Submitter.completed.where(submission: template.submissions).find_by(email: params[:email].to_s.downcase)
|
Submitter.completed.where(template_id: template.id).find_by(email: params[:email].to_s.downcase)
|
||||||
elsif params[:submission_slug]
|
elsif params[:submission_slug]
|
||||||
submission = Submission.find_by!(slug: params[:submission_slug])
|
submission = Submission.find_by!(slug: params[:submission_slug])
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class StartFormController < ApplicationController
|
|||||||
@submitter = find_or_initialize_submitter(@template, submitter_params)
|
@submitter = find_or_initialize_submitter(@template, submitter_params)
|
||||||
|
|
||||||
if @submitter.completed_at?
|
if @submitter.completed_at?
|
||||||
redirect_to start_form_completed_path(@template.slug, submitter_params.compact_blank)
|
redirect_to start_form_completed_path(@template.slug, submitter_params.compact_blank.merge(lang:))
|
||||||
else
|
else
|
||||||
if Templates.filter_undefined_submitters(@template.submitters).size > 1 && @submitter.new_record?
|
if Templates.filter_undefined_submitters(@template.submitters).size > 1 && @submitter.new_record?
|
||||||
@error_message = multiple_submitters_error_message
|
@error_message = multiple_submitters_error_message
|
||||||
@@ -59,7 +59,7 @@ class StartFormController < ApplicationController
|
|||||||
|
|
||||||
Submitters::StartForm.assign_start_form_cookie(@submitter, request)
|
Submitters::StartForm.assign_start_form_cookie(@submitter, request)
|
||||||
|
|
||||||
redirect_to submit_form_path(@submitter.slug)
|
redirect_to submit_form_path(@submitter.slug, lang:)
|
||||||
else
|
else
|
||||||
render :show, status: :unprocessable_content
|
render :show, status: :unprocessable_content
|
||||||
end
|
end
|
||||||
@@ -80,7 +80,7 @@ class StartFormController < ApplicationController
|
|||||||
raise ActionController::RoutingError, I18n.t('not_found') if required_params.any? { |_, v| v.blank? } ||
|
raise ActionController::RoutingError, I18n.t('not_found') if required_params.any? { |_, v| v.blank? } ||
|
||||||
required_params.except('name').compact_blank.blank?
|
required_params.except('name').compact_blank.blank?
|
||||||
|
|
||||||
@submitter = Submitter.where(submission: @template.submissions)
|
@submitter = Submitter.where(template_id: @template.id)
|
||||||
.where.not(completed_at: nil)
|
.where.not(completed_at: nil)
|
||||||
.find_by!(required_params.except('name'))
|
.find_by!(required_params.except('name'))
|
||||||
end
|
end
|
||||||
@@ -150,7 +150,7 @@ class StartFormController < ApplicationController
|
|||||||
return render :show, status: :unprocessable_content if submitter.errors.present?
|
return render :show, status: :unprocessable_content if submitter.errors.present?
|
||||||
|
|
||||||
if Submitters::StartForm.verify_2fa_and_save_submitter(submitter, request, is_new_record: submitter.new_record?)
|
if Submitters::StartForm.verify_2fa_and_save_submitter(submitter, request, is_new_record: submitter.new_record?)
|
||||||
redirect_to submit_form_path(submitter.slug)
|
redirect_to submit_form_path(submitter.slug, lang:)
|
||||||
else
|
else
|
||||||
if defined?(Rollbar) && template.preferences['shared_link_2fa'] != true
|
if defined?(Rollbar) && template.preferences['shared_link_2fa'] != true
|
||||||
Rollbar.info("2FA link requested: #{submitter.id}")
|
Rollbar.info("2FA link requested: #{submitter.id}")
|
||||||
@@ -167,10 +167,14 @@ class StartFormController < ApplicationController
|
|||||||
|
|
||||||
render :error, status: :unprocessable_content
|
render :error, status: :unprocessable_content
|
||||||
rescue Submitters::UnableToSendCode, Submitters::InvalidOtp => e
|
rescue Submitters::UnableToSendCode, Submitters::InvalidOtp => e
|
||||||
redirect_to start_form_path(template.slug, params: submitter_params.merge(email_verification: true)),
|
redirect_to start_form_path(template.slug, lang:, params: submitter_params.merge(email_verification: true)),
|
||||||
alert: e.message
|
alert: e.message
|
||||||
rescue RateLimit::LimitApproached
|
rescue RateLimit::LimitApproached
|
||||||
redirect_to start_form_path(template.slug, params: submitter_params.merge(email_verification: true)),
|
redirect_to start_form_path(template.slug, lang:, params: submitter_params.merge(email_verification: true)),
|
||||||
alert: I18n.t(:too_many_attempts)
|
alert: I18n.t(:too_many_attempts)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def lang
|
||||||
|
params[:lang].presence
|
||||||
|
end
|
||||||
end
|
end
|
||||||
@@ -16,21 +16,21 @@ class StartFormEmail2faSendController < ApplicationController
|
|||||||
.submitters.new(**submitter_params, account_id: @template.account_id)
|
.submitters.new(**submitter_params, account_id: @template.account_id)
|
||||||
|
|
||||||
if @submitter.email.blank?
|
if @submitter.email.blank?
|
||||||
return redirect_to start_form_path(@template.slug), alert: I18n.t(:provide_your_email_to_start)
|
return redirect_to start_form_path(@template.slug, lang:), alert: I18n.t(:provide_your_email_to_start)
|
||||||
end
|
end
|
||||||
|
|
||||||
Submitters.send_shared_link_email_verification_code(@submitter, request:)
|
Submitters.send_shared_link_email_verification_code(@submitter, request:)
|
||||||
|
|
||||||
redir_params = { notice: I18n.t(:code_has_been_resent) } if params[:resend]
|
redir_params = { notice: I18n.t(:code_has_been_resent) } if params[:resend]
|
||||||
|
|
||||||
redirect_to start_form_path(@template.slug, params: submitter_params.merge(email_verification: true)),
|
redirect_to start_form_path(@template.slug, lang:, params: submitter_params.merge(email_verification: true)),
|
||||||
**redir_params
|
**redir_params
|
||||||
rescue Submitters::BouncedEmail => e
|
rescue Submitters::BouncedEmail => e
|
||||||
@error_message = e.message
|
@error_message = e.message
|
||||||
|
|
||||||
render 'start_form/error', status: :unprocessable_content
|
render 'start_form/error', status: :unprocessable_content
|
||||||
rescue Submitters::UnableToSendCode => e
|
rescue Submitters::UnableToSendCode => e
|
||||||
redirect_to start_form_path(@template.slug, params: submitter_params.merge(email_verification: true)),
|
redirect_to start_form_path(@template.slug, lang:, params: submitter_params.merge(email_verification: true)),
|
||||||
alert: e.message
|
alert: e.message
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -66,4 +66,8 @@ class StartFormEmail2faSendController < ApplicationController
|
|||||||
attrs[:email] = Submissions.normalize_email(attrs[:email])
|
attrs[:email] = Submissions.normalize_email(attrs[:email])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def lang
|
||||||
|
params[:lang].presence
|
||||||
|
end
|
||||||
end
|
end
|
||||||
@@ -25,5 +25,7 @@ class SubmissionsExportController < ApplicationController
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def new; end
|
def new
|
||||||
|
render layout: turbo_native_android? ? 'plain' : true
|
||||||
|
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]
|
render params[:name], layout: turbo_native_android? ? 'plain' : true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -20,7 +20,7 @@ class SubmitFormController < ApplicationController
|
|||||||
return render :email_2fa unless Submitters::AuthorizedForForm.pass_email_2fa?(@submitter, request)
|
return render :email_2fa unless Submitters::AuthorizedForForm.pass_email_2fa?(@submitter, request)
|
||||||
|
|
||||||
if @submitter.completed_at? || submission.completed_at?
|
if @submitter.completed_at? || submission.completed_at?
|
||||||
return redirect_to submit_form_completed_path(@submitter.slug)
|
return redirect_to submit_form_completed_path(@submitter.slug, lang:)
|
||||||
end
|
end
|
||||||
|
|
||||||
@form_configs = Submitters::FormConfigs.call(@submitter, CONFIG_KEYS)
|
@form_configs = Submitters::FormConfigs.call(@submitter, CONFIG_KEYS)
|
||||||
@@ -96,7 +96,7 @@ class SubmitFormController < ApplicationController
|
|||||||
|
|
||||||
return if Submitters::AuthorizedForForm.call(@submitter, current_user, request)
|
return if Submitters::AuthorizedForForm.call(@submitter, current_user, request)
|
||||||
|
|
||||||
redirect_to submit_form_path(params[:submit_form_slug])
|
redirect_to submit_form_path(params[:submit_form_slug], lang:)
|
||||||
end
|
end
|
||||||
|
|
||||||
def success; end
|
def success; end
|
||||||
@@ -114,7 +114,7 @@ class SubmitFormController < ApplicationController
|
|||||||
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)
|
||||||
|
|
||||||
redirect_to start_form_path(@submitter.submission.template.slug)
|
redirect_to start_form_path(@submitter.submission.template.slug, lang:)
|
||||||
end
|
end
|
||||||
|
|
||||||
def maybe_render_locked_page
|
def maybe_render_locked_page
|
||||||
@@ -144,4 +144,8 @@ class SubmitFormController < ApplicationController
|
|||||||
ActiveStorage::Attachment.where(record: submission.submitters, name: :attachments)
|
ActiveStorage::Attachment.where(record: submission.submitters, name: :attachments)
|
||||||
.preload(:blob).index_by(&:uuid)
|
.preload(:blob).index_by(&:uuid)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def lang
|
||||||
|
params[:lang].presence
|
||||||
|
end
|
||||||
end
|
end
|
||||||
@@ -20,17 +20,17 @@ class SubmitFormEmail2fasController < ApplicationController
|
|||||||
{ value: @submitter.slug, expires: Submitters::StartForm::COOKIES_TTL.from_now,
|
{ value: @submitter.slug, expires: Submitters::StartForm::COOKIES_TTL.from_now,
|
||||||
**Submitters::StartForm::COOKIES_DEFAULTS }
|
**Submitters::StartForm::COOKIES_DEFAULTS }
|
||||||
|
|
||||||
redirect_to submit_form_path(@submitter.slug)
|
redirect_to submit_form_path(@submitter.slug, lang:)
|
||||||
else
|
else
|
||||||
redirect_to submit_form_path(@submitter.slug, status: :error), alert: I18n.t(:invalid_code)
|
redirect_to submit_form_path(@submitter.slug, status: :error, lang:), alert: I18n.t(:invalid_code)
|
||||||
end
|
end
|
||||||
rescue RateLimit::LimitApproached
|
rescue RateLimit::LimitApproached
|
||||||
redirect_to submit_form_path(@submitter.slug, status: :error), alert: I18n.t(:too_many_attempts)
|
redirect_to submit_form_path(@submitter.slug, status: :error, lang:), alert: I18n.t(:too_many_attempts)
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
if @submitter.submission_events.where(event_type: 'send_2fa_email').exists?(created_at: 15.seconds.ago..)
|
if @submitter.submission_events.where(event_type: 'send_2fa_email').exists?(created_at: 15.seconds.ago..)
|
||||||
return redirect_to submit_form_path(@submitter.slug, status: :error), alert: I18n.t(:rate_limit_exceeded)
|
return redirect_to submit_form_path(@submitter.slug, status: :error, lang:), alert: I18n.t(:rate_limit_exceeded)
|
||||||
end
|
end
|
||||||
|
|
||||||
RateLimit.call("send-email-code-#{@submitter.id}", limit: 2, ttl: 45.seconds, enabled: true)
|
RateLimit.call("send-email-code-#{@submitter.id}", limit: 2, ttl: 45.seconds, enabled: true)
|
||||||
@@ -38,19 +38,24 @@ class SubmitFormEmail2fasController < ApplicationController
|
|||||||
if Docuseal.multitenant? && Submitters.email_bounced_recently?(@submitter.email)
|
if Docuseal.multitenant? && Submitters.email_bounced_recently?(@submitter.email)
|
||||||
Rollbar.warning("Bounced OTP email for submitter: #{@submitter.id}") if defined?(Rollbar)
|
Rollbar.warning("Bounced OTP email for submitter: #{@submitter.id}") if defined?(Rollbar)
|
||||||
|
|
||||||
return redirect_to submit_form_path(@submitter.slug, status: :error), alert: I18n.t(:verification_email_bounced)
|
return redirect_to submit_form_path(@submitter.slug, status: :error, lang:),
|
||||||
|
alert: I18n.t(:verification_email_bounced)
|
||||||
end
|
end
|
||||||
|
|
||||||
SendSubmitterVerificationEmailJob.perform_async('submitter_id' => @submitter.id, 'locale' => I18n.locale.to_s)
|
SendSubmitterVerificationEmailJob.perform_async('submitter_id' => @submitter.id, 'locale' => I18n.locale.to_s)
|
||||||
|
|
||||||
redir_params = params[:resend] ? { alert: I18n.t(:code_has_been_resent) } : {}
|
redir_params = params[:resend] ? { alert: I18n.t(:code_has_been_resent) } : {}
|
||||||
|
|
||||||
redirect_to submit_form_path(@submitter.slug, status: :sent), **redir_params
|
redirect_to submit_form_path(@submitter.slug, status: :sent, lang:), **redir_params
|
||||||
rescue RateLimit::LimitApproached
|
rescue RateLimit::LimitApproached
|
||||||
redirect_to submit_form_path(@submitter.slug, status: :error), alert: I18n.t(:too_many_attempts)
|
redirect_to submit_form_path(@submitter.slug, status: :error, lang:), alert: I18n.t(:too_many_attempts)
|
||||||
end
|
end
|
||||||
|
|
||||||
def load_submitter
|
def load_submitter
|
||||||
@submitter = Submitter.find_by!(slug: params[:submitter_slug])
|
@submitter = Submitter.find_by!(slug: params[:submitter_slug])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def lang
|
||||||
|
params[:lang].presence
|
||||||
|
end
|
||||||
end
|
end
|
||||||
@@ -41,7 +41,9 @@ class TemplateFoldersController < ApplicationController
|
|||||||
render_infinite_scroll(@pagy, @templates, @template_folders) if turbo_infinite_scroll?
|
render_infinite_scroll(@pagy, @templates, @template_folders) if turbo_infinite_scroll?
|
||||||
end
|
end
|
||||||
|
|
||||||
def edit; end
|
def edit
|
||||||
|
render layout: turbo_native_android? ? 'plain' : true
|
||||||
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
if @template_folder != current_account.default_template_folder &&
|
if @template_folder != current_account.default_template_folder &&
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ class TemplatesCloneController < ApplicationController
|
|||||||
authorize!(:create, Template)
|
authorize!(:create, Template)
|
||||||
|
|
||||||
@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
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
class TemplatesFoldersController < ApplicationController
|
class TemplatesFoldersController < ApplicationController
|
||||||
load_and_authorize_resource :template
|
load_and_authorize_resource :template
|
||||||
|
|
||||||
def edit; end
|
def edit
|
||||||
|
render layout: turbo_native_android? ? 'plain' : true
|
||||||
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
authorize!(:update, @template)
|
authorize!(:update, @template)
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ class UserInitialsController < ApplicationController
|
|||||||
before_action :load_user_config
|
before_action :load_user_config
|
||||||
authorize_resource :user_config
|
authorize_resource :user_config
|
||||||
|
|
||||||
def edit; end
|
def edit
|
||||||
|
render layout: turbo_native_android? ? 'plain' : true
|
||||||
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
file = params[:file]
|
file = params[:file]
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ class UserSignaturesController < ApplicationController
|
|||||||
before_action :load_user_config
|
before_action :load_user_config
|
||||||
authorize_resource :user_config
|
authorize_resource :user_config
|
||||||
|
|
||||||
def edit; end
|
def edit
|
||||||
|
render layout: turbo_native_android? ? 'plain' : true
|
||||||
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
file = params[:file]
|
file = params[:file]
|
||||||
|
|||||||
@@ -31,9 +31,13 @@ class UsersController < ApplicationController
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def new; end
|
def new
|
||||||
|
render layout: turbo_native_android? ? 'plain' : true
|
||||||
|
end
|
||||||
|
|
||||||
def edit; end
|
def edit
|
||||||
|
render layout: turbo_native_android? ? 'plain' : true
|
||||||
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
existing_user = User.accessible_by(current_ability).find_by(email: @user.email)
|
existing_user = User.accessible_by(current_ability).find_by(email: @user.email)
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class WebhookSettingsController < ApplicationController
|
|||||||
|
|
||||||
SendTestWebhookRequestJob.perform_async(
|
SendTestWebhookRequestJob.perform_async(
|
||||||
'submitter_id' => submitter.id,
|
'submitter_id' => submitter.id,
|
||||||
'event_uuid' => SecureRandom.uuid,
|
'event_uuid' => SecureRandom.uuid_v7,
|
||||||
'webhook_url_id' => @webhook_url.id
|
'webhook_url_id' => @webhook_url.id
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export default targetable(class extends HTMLElement {
|
|||||||
|
|
||||||
this.input.files = dataTransfer.files
|
this.input.files = dataTransfer.files
|
||||||
|
|
||||||
if (this.input.webkitEntries.length) {
|
if (this.input.webkitEntries?.length) {
|
||||||
this.input.dataset.file = `${dataTransfer.files[0].name}`
|
this.input.dataset.file = `${dataTransfer.files[0].name}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -772,7 +772,7 @@
|
|||||||
class="sticky bottom-0 z-20"
|
class="sticky bottom-0 z-20"
|
||||||
>
|
>
|
||||||
<native-action
|
<native-action
|
||||||
v-if="nativePlatform && withDocumentsList && (isBreakpointLg || isMobile) && sortedDocuments.length && editable"
|
v-if="nativePlatform && withDocumentsList && (isBreakpointLg || isMobile) && editable"
|
||||||
data-placement="drawer"
|
data-placement="drawer"
|
||||||
data-side="leading"
|
data-side="leading"
|
||||||
data-icon="files"
|
data-icon="files"
|
||||||
@@ -782,7 +782,7 @@
|
|||||||
data-view="documents"
|
data-view="documents"
|
||||||
/>
|
/>
|
||||||
<native-action
|
<native-action
|
||||||
v-if="nativePlatform && withFieldsList && isBreakpointLg && sortedDocuments.length && editable"
|
v-if="nativePlatform && withFieldsList && isBreakpointLg && editable"
|
||||||
data-placement="drawer"
|
data-placement="drawer"
|
||||||
data-side="trailing"
|
data-side="trailing"
|
||||||
data-icon="plus"
|
data-icon="plus"
|
||||||
|
|||||||
@@ -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 ? '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' ? '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
|
<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"
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
>{{ t('available_in_pro') }}</a>
|
>{{ t('available_in_pro') }}</a>
|
||||||
</div>
|
</div>
|
||||||
<form @submit.prevent="validateSaveAndClose">
|
<form @submit.prevent="validateSaveAndClose">
|
||||||
<div class="my-4">
|
<div :class="inline && nativePlatform === 'android' ? 'mt-1 mb-4' : 'my-4'">
|
||||||
<div
|
<div
|
||||||
v-for="(condition, cindex) in conditions"
|
v-for="(condition, cindex) in conditions"
|
||||||
:key="cindex"
|
:key="cindex"
|
||||||
@@ -168,7 +168,7 @@
|
|||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'ConditionModal',
|
name: 'ConditionModal',
|
||||||
inject: ['t', 'template', 'withConditions'],
|
inject: ['t', 'template', 'withConditions', 'nativePlatform'],
|
||||||
props: {
|
props: {
|
||||||
item: {
|
item: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
|||||||
@@ -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 ? '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' ? '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
|
<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"
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<label
|
<label
|
||||||
dir="auto"
|
dir="auto"
|
||||||
class="label text-sm"
|
:class="['label text-sm', { 'pt-0 mt-1': inline && nativePlatform === 'android' }]"
|
||||||
for="description_field"
|
for="description_field"
|
||||||
>
|
>
|
||||||
{{ t('description') }}
|
{{ t('description') }}
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'DescriptionModal',
|
name: 'DescriptionModal',
|
||||||
inject: ['t', 'template'],
|
inject: ['t', 'template', 'nativePlatform'],
|
||||||
props: {
|
props: {
|
||||||
field: {
|
field: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
<CropView
|
<CropView
|
||||||
v-if="cropPageItem"
|
v-if="cropPageItem"
|
||||||
class="absolute inset-0 z-10 bg-base-100"
|
class="absolute inset-0 z-10 bg-base-100"
|
||||||
:style="inline ? { paddingTop: '70px' } : null"
|
:style="inline && nativePlatform === 'ios' ? { paddingTop: '70px' } : null"
|
||||||
:template-id="template.id"
|
:template-id="template.id"
|
||||||
:page="cropPageItem"
|
:page="cropPageItem"
|
||||||
:image-url="thumbUrl(cropPageItem)"
|
:image-url="thumbUrl(cropPageItem)"
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
<RedactView
|
<RedactView
|
||||||
v-else-if="redactPageItem"
|
v-else-if="redactPageItem"
|
||||||
class="absolute inset-0 z-10 bg-base-100"
|
class="absolute inset-0 z-10 bg-base-100"
|
||||||
:style="inline ? { paddingTop: '70px' } : null"
|
:style="inline && nativePlatform === 'ios' ? { paddingTop: '70px' } : null"
|
||||||
:template-id="template.id"
|
:template-id="template.id"
|
||||||
:page="redactPageItem"
|
:page="redactPageItem"
|
||||||
:image-url="thumbUrl(redactPageItem)"
|
:image-url="thumbUrl(redactPageItem)"
|
||||||
@@ -63,14 +63,14 @@
|
|||||||
>
|
>
|
||||||
<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 ? { paddingTop: '86px' } : null"
|
:style="inline && nativePlatform === 'ios' ? { paddingTop: '86px' } : null"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-for="(doc, docIndex) in layout"
|
v-for="(doc, docIndex) in layout"
|
||||||
:key="doc.attachmentUuid"
|
:key="doc.attachmentUuid"
|
||||||
:data-uuid="doc.attachmentUuid"
|
:data-uuid="doc.attachmentUuid"
|
||||||
class="relative"
|
class="relative"
|
||||||
:style="inline ? { scrollMarginTop: '86px' } : null"
|
:style="inline && nativePlatform === 'ios' ? { scrollMarginTop: '86px' } : null"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex items-center pb-2"
|
class="flex items-center pb-2"
|
||||||
@@ -191,7 +191,7 @@
|
|||||||
:key="page.id"
|
:key="page.id"
|
||||||
:data-page-id="page.id"
|
:data-page-id="page.id"
|
||||||
class="relative min-w-0 cursor-pointer group"
|
class="relative min-w-0 cursor-pointer group"
|
||||||
:style="inline ? { scrollMarginTop: '86px' } : null"
|
:style="inline && nativePlatform === 'ios' ? { scrollMarginTop: '86px' } : null"
|
||||||
draggable="true"
|
draggable="true"
|
||||||
@click="selectedPageId = page.id"
|
@click="selectedPageId = page.id"
|
||||||
@mousedown="onPageMousedown(page, $event)"
|
@mousedown="onPageMousedown(page, $event)"
|
||||||
@@ -260,7 +260,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="flex-none px-4 border-t pt-3 flex flex-col gap-3 md:w-56 md:border-t-0 md:border-l md:py-4 md:gap-0"
|
class="flex-none px-4 border-t pt-3 flex flex-col gap-3 md:w-56 md:border-t-0 md:border-l md:py-4 md:gap-0"
|
||||||
:class="{ 'pb-3': !inline }"
|
:class="{ 'pb-3': !inline || nativePlatform === 'android' }"
|
||||||
>
|
>
|
||||||
<div class="grid grid-cols-4 gap-2 md:block md:space-y-2">
|
<div class="grid grid-cols-4 gap-2 md:block md:space-y-2">
|
||||||
<button
|
<button
|
||||||
@@ -419,7 +419,7 @@ export default {
|
|||||||
IconEraser,
|
IconEraser,
|
||||||
IconCrop
|
IconCrop
|
||||||
},
|
},
|
||||||
inject: ['t', 'baseFetch'],
|
inject: ['t', 'baseFetch', 'nativePlatform'],
|
||||||
props: {
|
props: {
|
||||||
template: {
|
template: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
|||||||
@@ -608,10 +608,10 @@ export default {
|
|||||||
return !['stamp', 'heading', 'strikethrough'].includes(this.field.type)
|
return !['stamp', 'heading', 'strikethrough'].includes(this.field.type)
|
||||||
},
|
},
|
||||||
showCondition () {
|
showCondition () {
|
||||||
return this.withCondition && (this.withConditions || this.nativePlatform !== 'ios') && !['stamp', 'heading'].includes(this.field.type)
|
return this.withCondition && (this.withConditions || !this.nativePlatform) && !['stamp', 'heading'].includes(this.field.type)
|
||||||
},
|
},
|
||||||
showFormula () {
|
showFormula () {
|
||||||
return (this.field.type === 'number' || this.field.type === 'date' || this.field.type === 'payment' || !!this.field.preferences?.formula) && (this.withFormula || this.nativePlatform !== 'ios')
|
return (this.field.type === 'number' || this.field.type === 'date' || this.field.type === 'payment' || !!this.field.preferences?.formula) && (this.withFormula || !this.nativePlatform)
|
||||||
},
|
},
|
||||||
showRequired () {
|
showRequired () {
|
||||||
return this.withRequired && !['phone', 'stamp', 'verification', 'strikethrough', 'heading'].includes(this.field.type)
|
return this.withRequired && !['phone', 'stamp', 'verification', 'strikethrough', 'heading'].includes(this.field.type)
|
||||||
|
|||||||
@@ -484,7 +484,7 @@
|
|||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
v-if="withCondition && (withConditions || nativePlatform !== 'ios') && field.type != 'stamp' && field.type != 'heading'"
|
v-if="withCondition && (withConditions || !nativePlatform) && field.type != 'stamp' && field.type != 'heading'"
|
||||||
class="field-settings-condition"
|
class="field-settings-condition"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
@@ -500,7 +500,7 @@
|
|||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
v-if="(field.type == 'number' || field.type == 'date' || field.preferences?.formula) && (withFormula || nativePlatform !== 'ios')"
|
v-if="(field.type == 'number' || field.type == 'date' || field.preferences?.formula) && (withFormula || !nativePlatform)"
|
||||||
class="field-settings-formula"
|
class="field-settings-formula"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
|
|||||||
@@ -275,7 +275,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<div
|
<div
|
||||||
v-else-if="type == 'phone' && nativePlatform !== 'ios' && (fieldTypes.length === 0 || fieldTypes.includes(type))"
|
v-else-if="type == 'phone' && !nativePlatform && (fieldTypes.length === 0 || fieldTypes.includes(type))"
|
||||||
class="tooltip tooltip-bottom flex"
|
class="tooltip tooltip-bottom flex"
|
||||||
:class="{'tooltip-bottom-end': withPayment, 'tooltip-bottom': !withPayment }"
|
:class="{'tooltip-bottom-end': withPayment, 'tooltip-bottom': !withPayment }"
|
||||||
:data-tip="t('unlock_sms_verified_phone_number_field_with_paid_plan_use_text_field_for_phone_numbers_without_verification')"
|
:data-tip="t('unlock_sms_verified_phone_number_field_with_paid_plan_use_text_field_for_phone_numbers_without_verification')"
|
||||||
|
|||||||
@@ -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 ? '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' ? '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
|
<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"
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
@click.prevent="$emit('close')"
|
@click.prevent="$emit('close')"
|
||||||
>×</a>
|
>×</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-4">
|
<div :class="inline && nativePlatform === 'android' ? 'mt-1' : 'mt-4'">
|
||||||
<div>
|
<div>
|
||||||
<div class="flex flex-wrap items-center gap-1.5">
|
<div class="flex flex-wrap items-center gap-1.5">
|
||||||
<span>
|
<span>
|
||||||
@@ -200,7 +200,7 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
IconChevronDown
|
IconChevronDown
|
||||||
},
|
},
|
||||||
inject: ['t', 'template'],
|
inject: ['t', 'template', 'nativePlatform'],
|
||||||
props: {
|
props: {
|
||||||
field: {
|
field: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
|||||||
@@ -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 ? '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' ? '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
|
<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"
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
class="link"
|
class="link"
|
||||||
>{{ t('available_in_pro') }}</a>
|
>{{ t('available_in_pro') }}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-wrap mb-2 gap-y-1 pt-1">
|
<div :class="['flex flex-wrap mb-2 gap-y-1', inline && nativePlatform === 'android' ? 'mt-1' : 'pt-1']">
|
||||||
<button
|
<button
|
||||||
v-for="f in fields"
|
v-for="f in fields"
|
||||||
:key="f.uuid"
|
:key="f.uuid"
|
||||||
@@ -152,7 +152,7 @@ export default {
|
|||||||
IconCodePlus,
|
IconCodePlus,
|
||||||
IconMathFunction
|
IconMathFunction
|
||||||
},
|
},
|
||||||
inject: ['t', 'template', 'withFormula'],
|
inject: ['t', 'template', 'withFormula', 'nativePlatform'],
|
||||||
props: {
|
props: {
|
||||||
field: {
|
field: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
|||||||
@@ -203,7 +203,7 @@
|
|||||||
>{{ t('learn_more') }}</a>
|
>{{ t('learn_more') }}</a>
|
||||||
</div>
|
</div>
|
||||||
<li
|
<li
|
||||||
v-if="withFormula || nativePlatform !== 'ios'"
|
v-if="withFormula || !nativePlatform"
|
||||||
class="field-settings-formula mb-1"
|
class="field-settings-formula mb-1"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
@@ -233,7 +233,7 @@
|
|||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
v-if="withCondition && (withConditions || nativePlatform !== 'ios')"
|
v-if="withCondition && (withConditions || !nativePlatform)"
|
||||||
class="field-settings-condition mt-1"
|
class="field-settings-condition mt-1"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
|
|||||||
@@ -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 ? 'px-4 pt-3 pb-6' : 'modal-box pt-4 pb-6 mt-20 w-full'">
|
<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
|
<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"
|
||||||
@@ -63,7 +63,7 @@ import { IconUser, IconInnerShadowTop } from '@tabler/icons-vue'
|
|||||||
export default {
|
export default {
|
||||||
name: 'RevisionsModal',
|
name: 'RevisionsModal',
|
||||||
components: { IconUser, IconInnerShadowTop },
|
components: { IconUser, IconInnerShadowTop },
|
||||||
inject: ['t', 'baseFetch'],
|
inject: ['t', 'baseFetch', 'nativePlatform'],
|
||||||
props: {
|
props: {
|
||||||
template: {
|
template: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ export default {
|
|||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
showCondition () {
|
showCondition () {
|
||||||
return this.withCondition && (this.withConditions || this.nativePlatform !== 'ios')
|
return this.withCondition && (this.withConditions || !this.nativePlatform)
|
||||||
},
|
},
|
||||||
fieldNames: FieldType.computed.fieldNames,
|
fieldNames: FieldType.computed.fieldNames,
|
||||||
fieldLabels: FieldType.computed.fieldLabels
|
fieldLabels: FieldType.computed.fieldLabels
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ class ProcessSubmitterCompletionJob
|
|||||||
|
|
||||||
WebhookUrls.for_account_id(submitter.account_id, %w[form.completed submission.completed]).each do |webhook|
|
WebhookUrls.for_account_id(submitter.account_id, %w[form.completed submission.completed]).each do |webhook|
|
||||||
if webhook.events.include?('form.completed')
|
if webhook.events.include?('form.completed')
|
||||||
event_uuids['form.completed'] ||= SecureRandom.uuid
|
event_uuids['form.completed'] ||= SecureRandom.uuid_v7
|
||||||
|
|
||||||
SendFormCompletedWebhookRequestJob.perform_async('submitter_id' => submitter.id,
|
SendFormCompletedWebhookRequestJob.perform_async('submitter_id' => submitter.id,
|
||||||
'event_uuid' => event_uuids['form.completed'],
|
'event_uuid' => event_uuids['form.completed'],
|
||||||
@@ -109,7 +109,7 @@ class ProcessSubmitterCompletionJob
|
|||||||
|
|
||||||
next unless webhook.events.include?('submission.completed') && is_last
|
next unless webhook.events.include?('submission.completed') && is_last
|
||||||
|
|
||||||
event_uuids['submission.completed'] ||= SecureRandom.uuid
|
event_uuids['submission.completed'] ||= SecureRandom.uuid_v7
|
||||||
|
|
||||||
SendSubmissionCompletedWebhookRequestJob.perform_async('submission_id' => submitter.submission_id,
|
SendSubmissionCompletedWebhookRequestJob.perform_async('submission_id' => submitter.submission_id,
|
||||||
'event_uuid' => event_uuids['submission.completed'],
|
'event_uuid' => event_uuids['submission.completed'],
|
||||||
|
|||||||
@@ -15,7 +15,8 @@
|
|||||||
#
|
#
|
||||||
# Indexes
|
# Indexes
|
||||||
#
|
#
|
||||||
# index_accounts_on_uuid (uuid) UNIQUE
|
# index_accounts_on_created_at (created_at)
|
||||||
|
# index_accounts_on_uuid (uuid) UNIQUE
|
||||||
#
|
#
|
||||||
class Account < ApplicationRecord
|
class Account < ApplicationRecord
|
||||||
attribute :uuid, :string, default: -> { SecureRandom.uuid }
|
attribute :uuid, :string, default: -> { SecureRandom.uuid }
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
# index_webhook_events_on_webhook_url_id_and_id (webhook_url_id,id)
|
# index_webhook_events_on_webhook_url_id_and_id (webhook_url_id,id)
|
||||||
#
|
#
|
||||||
class WebhookEvent < ApplicationRecord
|
class WebhookEvent < ApplicationRecord
|
||||||
attribute :uuid, :string, default: -> { SecureRandom.uuid }
|
attribute :uuid, :string, default: -> { SecureRandom.uuid_v7 }
|
||||||
|
|
||||||
belongs_to :webhook_url, optional: true
|
belongs_to :webhook_url, optional: true
|
||||||
belongs_to :account, optional: true
|
belongs_to :account, optional: true
|
||||||
|
|||||||
@@ -133,7 +133,7 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% account_config = AccountConfig.find_or_initialize_by(account: current_account, key: AccountConfig::ALLOW_TO_DECLINE_KEY) %>
|
<% account_config = AccountConfig.find_or_initialize_by(account: current_account, key: AccountConfig::ALLOW_TO_DECLINE_KEY) %>
|
||||||
<% if can?(:manage, account_config) && (!turbo_native_ios? || !Docuseal.multitenant? || can?(:manage, :disable_decline)) %>
|
<% if can?(:manage, account_config) && (!turbo_native_app? || !Docuseal.multitenant? || can?(:manage, :disable_decline)) %>
|
||||||
<%= form_for account_config, url: account_configs_path, method: :post do |f| %>
|
<%= form_for account_config, url: account_configs_path, method: :post do |f| %>
|
||||||
<%= f.hidden_field :key %>
|
<%= f.hidden_field :key %>
|
||||||
<div class="flex items-center justify-between gap-4 py-2.5">
|
<div class="flex items-center justify-between gap-4 py-2.5">
|
||||||
@@ -156,7 +156,7 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% account_config = AccountConfig.find_or_initialize_by(account: current_account, key: AccountConfig::ALLOW_TO_DELEGATE_KEY) %>
|
<% account_config = AccountConfig.find_or_initialize_by(account: current_account, key: AccountConfig::ALLOW_TO_DELEGATE_KEY) %>
|
||||||
<% if can?(:manage, account_config) && (!turbo_native_ios? || !Docuseal.multitenant? || can?(:manage, :delegate_form)) %>
|
<% if can?(:manage, account_config) && (!turbo_native_app? || !Docuseal.multitenant? || can?(:manage, :delegate_form)) %>
|
||||||
<%= form_for account_config, url: account_configs_path, method: :post do |f| %>
|
<%= form_for account_config, url: account_configs_path, method: :post do |f| %>
|
||||||
<%= f.hidden_field :key %>
|
<%= f.hidden_field :key %>
|
||||||
<div class="flex items-center justify-between gap-4 py-2.5">
|
<div class="flex items-center justify-between gap-4 py-2.5">
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<% unless turbo_native_ios? %>
|
<% unless turbo_native_app? %>
|
||||||
<tr class="group">
|
<tr class="group">
|
||||||
<td>
|
<td>
|
||||||
<div class="flex items-center space-x-1">
|
<div class="flex items-center space-x-1">
|
||||||
|
|||||||
@@ -7,4 +7,21 @@
|
|||||||
-webkit-user-drag: none;
|
-webkit-user-drag: none;
|
||||||
-webkit-touch-callout: none;
|
-webkit-touch-callout: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<% if turbo_native_android? %>
|
||||||
|
input[type="date"] {
|
||||||
|
appearance: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="date"]::-webkit-calendar-picker-indicator {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
div:has(> #account_settings_menu) + * {
|
||||||
|
margin-top: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<% end %>
|
||||||
</style>
|
</style>
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<%= render 'bcc_form', config: @bcc_config %>
|
<%= render 'bcc_form', config: @bcc_config %>
|
||||||
<% unless can?(:manage, :personalization_restricted) || (turbo_native_ios? && !can?(:manage, :email_reminders)) %>
|
<% unless can?(:manage, :personalization_restricted) || (turbo_native_app? && !can?(:manage, :email_reminders)) %>
|
||||||
<div class="flex justify-between items-end mb-4 mt-8">
|
<div class="flex justify-between items-end mb-4 mt-8">
|
||||||
<h2 class="text-2xl md:text-3xl font-bold">
|
<h2 class="text-2xl md:text-3xl font-bold">
|
||||||
<%= t('sign_request_email_reminders') %>
|
<%= t('sign_request_email_reminders') %>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
<%= render 'documents_copy_email_form' %>
|
<%= render 'documents_copy_email_form' %>
|
||||||
<%= render 'submitter_completed_email_form' %>
|
<%= render 'submitter_completed_email_form' %>
|
||||||
</div>
|
</div>
|
||||||
<% if !turbo_native_ios? || can?(:manage, :custom_logo) %>
|
<% if !turbo_native_app? || can?(:manage, :custom_logo) %>
|
||||||
<p class="text-3xl md:text-4xl font-bold mb-4 mt-8">
|
<p class="text-3xl md:text-4xl font-bold mb-4 mt-8">
|
||||||
<%= t('company_logo') %>
|
<%= t('company_logo') %>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
<script type="application/json" id="native_path_configuration"><%= render partial: 'layouts/native_path_configuration', formats: :json %></script>
|
<script type="application/json" id="native_path_configuration"><%= render partial: 'layouts/native_path_configuration', formats: :json %></script>
|
||||||
<% if signed_in? %>
|
<% if signed_in? %>
|
||||||
<native-action data-placement="profile" data-icon="user">
|
<% unless turbo_native_android? %>
|
||||||
<%= link_to t('profile'), settings_profile_index_path %>
|
<native-action data-placement="profile" data-icon="user">
|
||||||
</native-action>
|
<%= link_to t('profile'), settings_profile_index_path %>
|
||||||
<native-action data-placement="profile" data-icon="settings">
|
</native-action>
|
||||||
<%= link_to t('settings'), settings_path %>
|
<native-action data-placement="profile" data-icon="settings">
|
||||||
</native-action>
|
<%= link_to t('settings'), settings_path %>
|
||||||
|
</native-action>
|
||||||
|
<% end %>
|
||||||
<% if current_account.testing? && (can?(:manage, EncryptedConfig) || current_user != true_user) %>
|
<% if current_account.testing? && (can?(:manage, EncryptedConfig) || current_user != true_user) %>
|
||||||
<native-action data-placement="test_mode" data-icon="code" data-label="<%= t('exit_test_mode') %>">
|
<native-action data-placement="test_mode" data-icon="code" data-label="<%= t('exit_test_mode') %>">
|
||||||
<%= button_to '', testing_account_path, method: :delete, form: { data: { turbo_action: 'replace' } } %>
|
<%= button_to '', testing_account_path, method: :delete, form: { data: { turbo_action: 'replace' } } %>
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
<%= link_to t('storage'), settings_storage_index_path, class: 'text-base hover:bg-base-300', data: nav_link_data %>
|
<%= link_to t('storage'), settings_storage_index_path, class: 'text-base hover:bg-base-300', data: nav_link_data %>
|
||||||
</li>
|
</li>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if can?(:read, EncryptedConfig.new(key: 'submitter_invitation_sms', account: current_account)) && true_user == current_user && (!turbo_native_ios? || can?(:manage, :sms_verification)) %>
|
<% if can?(:read, EncryptedConfig.new(key: 'submitter_invitation_sms', account: current_account)) && true_user == current_user && (!turbo_native_app? || can?(:manage, :sms_verification)) %>
|
||||||
<li>
|
<li>
|
||||||
<%= link_to 'SMS', settings_sms_path, class: 'text-base hover:bg-base-300', data: nav_link_data %>
|
<%= link_to 'SMS', settings_sms_path, class: 'text-base hover:bg-base-300', data: nav_link_data %>
|
||||||
</li>
|
</li>
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
</li>
|
</li>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if !Docuseal.demo? && !turbo_native_ios? && can?(:manage, EncryptedConfig) && (current_user != true_user || !current_account.linked_account_account) %>
|
<% if !Docuseal.demo? && !turbo_native_app? && can?(:manage, EncryptedConfig) && (current_user != true_user || !current_account.linked_account_account) %>
|
||||||
<li>
|
<li>
|
||||||
<%= content_for(:pro_link) || link_to(Docuseal.multitenant? ? console_redirect_index_path(redir: "#{Docuseal::CONSOLE_URL}/plans") : "#{Docuseal::CLOUD_URL}/sign_up?#{{ redir: "#{Docuseal::CONSOLE_URL}/on_premises" }.to_query}", class: 'text-base hover:bg-base-300', data: { turbo: false }) do %>
|
<%= content_for(:pro_link) || link_to(Docuseal.multitenant? ? console_redirect_index_path(redir: "#{Docuseal::CONSOLE_URL}/plans") : "#{Docuseal::CLOUD_URL}/sign_up?#{{ redir: "#{Docuseal::CONSOLE_URL}/on_premises" }.to_query}", class: 'text-base hover:bg-base-300', data: { turbo: false }) do %>
|
||||||
<%= t('plans') %>
|
<%= t('plans') %>
|
||||||
@@ -107,7 +107,7 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
</li>
|
</li>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if (!Docuseal.multitenant? || can?(:manage, :saml_sso)) && can?(:read, EncryptedConfig.new(key: 'saml_configs', account: current_account)) && true_user == current_user && (!turbo_native_ios? || can?(:manage, :saml_sso)) %>
|
<% if (!Docuseal.multitenant? || can?(:manage, :saml_sso)) && can?(:read, EncryptedConfig.new(key: 'saml_configs', account: current_account)) && true_user == current_user && (!turbo_native_app? || can?(:manage, :saml_sso)) %>
|
||||||
<li>
|
<li>
|
||||||
<%= link_to 'SSO', settings_sso_index_path, class: 'text-base hover:bg-base-300', data: nav_link_data %>
|
<%= link_to 'SSO', settings_sso_index_path, class: 'text-base hover:bg-base-300', data: nav_link_data %>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
<form action="<%= url_for %>" method="get" class="dropdown dropdown-top hidden md:inline">
|
<form action="<%= url_for %>" method="get" class="dropdown dropdown-top hidden md:inline">
|
||||||
<label tabindex="0" class="btn btn-sm h-10">
|
<% unless turbo_native_app? %>
|
||||||
<%= svg_icon('arrow_sort', class: 'w-5 h-5') %>
|
<label tabindex="0" class="btn btn-sm h-10">
|
||||||
</label>
|
<%= svg_icon('arrow_sort', class: 'w-5 h-5') %>
|
||||||
|
</label>
|
||||||
|
<% end %>
|
||||||
<ul tabindex="0" class="dropdown-content z-[10] menu p-2 shadow bg-base-100 rounded-box mb-1 min-w-48">
|
<ul tabindex="0" class="dropdown-content z-[10] menu p-2 shadow bg-base-100 rounded-box mb-1 min-w-48">
|
||||||
<native-action class="contents" data-menu="<%= t('sort_by') %>" data-menu-icon="arrow_sort" data-icon="sort_descending_numbers" data-selected="<%= selected_order == 'created_at' %>">
|
<native-action class="contents" data-menu="<%= t('sort_by') %>" data-menu-icon="arrow_sort" data-icon="sort_descending_numbers" data-selected="<%= selected_order == 'created_at' %>">
|
||||||
<toggle-cookies data-value="created_at" data-key="dashboard_templates_order">
|
<toggle-cookies data-value="created_at" data-key="dashboard_templates_order">
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<% content_for(:native_modal, 'true') %>
|
<% 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 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 %>">
|
||||||
<%= yield %>
|
<%= yield %>
|
||||||
</native-modal>
|
</native-modal>
|
||||||
</turbo-frame>
|
</turbo-frame>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<%= t('we_sent_a_one_time_verification_code_to_your_email_address_please_enter_the_code_below_to_continue') %>
|
<%= t('we_sent_a_one_time_verification_code_to_your_email_address_please_enter_the_code_below_to_continue') %>
|
||||||
</div>
|
</div>
|
||||||
<%= form_for '', url: @resubmit_submitter ? resubmit_form_path : start_form_path(@template.slug), method: :put, html: { class: 'space-y-4', id: 'code_form' } do |f| %>
|
<%= form_for '', url: @resubmit_submitter ? resubmit_form_path : start_form_path(@template.slug, lang: params[:lang].presence), method: :put, html: { class: 'space-y-4', id: 'code_form' } do |f| %>
|
||||||
<div dir="auto" class="form-control !mt-0">
|
<div dir="auto" class="form-control !mt-0">
|
||||||
<%= f.hidden_field 'resubmit', value: params[:resubmit] %>
|
<%= f.hidden_field 'resubmit', value: params[:resubmit] %>
|
||||||
<%= f.hidden_field 'submitter[name]', value: params[:name] || params.dig(:submitter, :name) %>
|
<%= f.hidden_field 'submitter[name]', value: params[:name] || params.dig(:submitter, :name) %>
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
<% if @resubmit_submitter %>
|
<% if @resubmit_submitter %>
|
||||||
<%= button_to t(:re_send_email), resubmit_form_path, params: { resubmit: @resubmit_submitter.slug }, method: :put, id: 'resend_code', class: 'hidden' %>
|
<%= button_to t(:re_send_email), resubmit_form_path, params: { resubmit: @resubmit_submitter.slug }, method: :put, id: 'resend_code', class: 'hidden' %>
|
||||||
<% else %>
|
<% else %>
|
||||||
<%= button_to t(:re_send_email), start_form_email_2fa_send_index_path, params: { slug: @template.slug, resend: true, submitter: { name: params[:name] || params.dig(:submitter, :name), email: params[:email] || params.dig(:submitter, :email), phone: params[:phone] || params.dig(:submitter, :phone) } }.compact, method: :post, id: 'resend_code', class: 'hidden' %>
|
<%= button_to t(:re_send_email), start_form_email_2fa_send_index_path, params: { slug: @template.slug, resend: true, submitter: { name: params[:name] || params.dig(:submitter, :name), email: params[:email] || params.dig(:submitter, :email), phone: params[:phone] || params.dig(:submitter, :phone) }, lang: params[:lang] }.compact, method: :post, id: 'resend_code', class: 'hidden' %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<% if !@template.archived_at? && !@template.account.archived_at? %>
|
<% if !@template.archived_at? && !@template.account.archived_at? %>
|
||||||
<%= form_for @submitter, url: @resubmit_submitter ? resubmit_form_path : start_form_path(@template.slug), data: { turbo_frame: :_top }, method: :put, html: { class: 'space-y-4' } do |f| %>
|
<%= form_for @submitter, url: @resubmit_submitter ? resubmit_form_path : start_form_path(@template.slug, lang: params[:lang].presence), data: { turbo_frame: :_top }, method: :put, html: { class: 'space-y-4' } do |f| %>
|
||||||
<%= hidden_field_tag :resubmit, @resubmit_submitter.slug if @resubmit_submitter %>
|
<%= hidden_field_tag :resubmit, @resubmit_submitter.slug if @resubmit_submitter %>
|
||||||
<% if @error_message %>
|
<% if @error_message %>
|
||||||
<div class="alert items-start bg-base-100 border border-red-400 text-red-400">
|
<div class="alert items-start bg-base-100 border border-red-400 text-red-400">
|
||||||
|
|||||||
@@ -43,7 +43,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<p class="text-base-content/80 mt-1">
|
<p class="text-base-content/80 mt-1">
|
||||||
<% if event.event_type == 'complete_verification' %>
|
<% if event.event_type == 'complete_verification' %>
|
||||||
<%= t('submission_event_names.complete_verification_by_html', provider: event.data['method'], submitter_name:) %>
|
<% identity_name = [event.data['firstname'], event.data['lastname']].compact_blank.join(' ') %>
|
||||||
|
<%= t('submission_event_names.complete_verification_by_html', provider: event.data['method'], submitter_name: identity_name.presence || submitter_name) %>
|
||||||
<% elsif event.event_type == 'invite_party' && (invited_submitter = @submission.submitters.find { |e| e.uuid == event.data['uuid'] }) && (name = @submission.template_submitters.find { |e| e['uuid'] == event.data['uuid'] }&.dig('name')) %>
|
<% elsif event.event_type == 'invite_party' && (invited_submitter = @submission.submitters.find { |e| e.uuid == event.data['uuid'] }) && (name = @submission.template_submitters.find { |e| e['uuid'] == event.data['uuid'] }&.dig('name')) %>
|
||||||
<%= t('submission_event_names.invite_party_by_html', invited_submitter_name: [invited_submitter.name || invited_submitter.email || invited_submitter.phone, name].join(' '), submitter_name:) %>
|
<%= t('submission_event_names.invite_party_by_html', invited_submitter_name: [invited_submitter.name || invited_submitter.email || invited_submitter.phone, name].join(' '), submitter_name:) %>
|
||||||
<% elsif event.event_type == 'delegate_form' %>
|
<% elsif event.event_type == 'delegate_form' %>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<% unless turbo_native_ios? %>
|
<% unless turbo_native_app? %>
|
||||||
<toggle-on-checked data-names="is_custom_message" class="block">
|
<toggle-on-checked data-names="is_custom_message" class="block">
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= render 'sms_settings/placeholder' %>
|
<%= render 'sms_settings/placeholder' %>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<% unless turbo_native_ios? %>
|
<% unless turbo_native_app? %>
|
||||||
<div class="mt-2 mb-1">
|
<div class="mt-2 mb-1">
|
||||||
<div class="tooltip tooltip-no-touch w-full" data-tip="<%= t('unlock_with_docuseal_pro') %>">
|
<div class="tooltip tooltip-no-touch w-full" data-tip="<%= t('unlock_with_docuseal_pro') %>">
|
||||||
<%= link_to submitter.sent_at? ? t('re_send_sms') : t('send_sms'), Docuseal.multitenant? ? console_redirect_index_path(redir: "#{Docuseal::CONSOLE_URL}/plans") : "#{Docuseal::CLOUD_URL}/sign_up?#{{ redir: "#{Docuseal::CONSOLE_URL}/on_premises" }.to_query}", class: 'btn btn-sm btn-primary text-gray-400 w-full' %>
|
<%= link_to submitter.sent_at? ? t('re_send_sms') : t('send_sms'), Docuseal.multitenant? ? console_redirect_index_path(redir: "#{Docuseal::CONSOLE_URL}/plans") : "#{Docuseal::CLOUD_URL}/sign_up?#{{ redir: "#{Docuseal::CONSOLE_URL}/on_premises" }.to_query}", class: 'btn btn-sm btn-primary text-gray-400 w-full' %>
|
||||||
|
|||||||
@@ -6,14 +6,14 @@
|
|||||||
<% recipient_form_fields = Accounts.load_recipient_form_fields(current_account) if prefillable_fields.blank? %>
|
<% recipient_form_fields = Accounts.load_recipient_form_fields(current_account) if prefillable_fields.blank? %>
|
||||||
<% can_send_emails = Accounts.can_send_emails?(current_account) %>
|
<% can_send_emails = Accounts.can_send_emails?(current_account) %>
|
||||||
<% only_detailed = require_phone_2fa || require_email_2fa || prefillable_fields.present? || recipient_form_fields.present? %>
|
<% only_detailed = require_phone_2fa || require_email_2fa || prefillable_fields.present? || recipient_form_fields.present? %>
|
||||||
<% with_list = @template.variables_schema.blank? && (!turbo_native_ios? || can?(:manage, :bulk_send)) %>
|
<% with_list = @template.variables_schema.blank? && (!turbo_native_app? || can?(:manage, :bulk_send)) %>
|
||||||
<% with_phone = !turbo_native_ios? || can?(:manage, :sms_verification) %>
|
<% with_phone = !turbo_native_app? || can?(:manage, :sms_verification) %>
|
||||||
<% default_tab = 'email' if default_tab == 'phone' && !with_phone %>
|
<% default_tab = 'email' if default_tab == 'phone' && !with_phone %>
|
||||||
<% variables_form = render 'variables_form', schema: @template.variables_schema if @template.variables_schema.present? && @template.variables_schema.any? { |_, v| !v['disabled'] } %>
|
<% variables_form = render 'variables_form', schema: @template.variables_schema if @template.variables_schema.present? && @template.variables_schema.any? { |_, v| !v['disabled'] } %>
|
||||||
<%= render 'shared/turbo_modal_large', title: params[:selfsign] ? t('add_recipients') : t('add_new_recipients') do %>
|
<%= render 'shared/turbo_modal_large', title: params[:selfsign] ? t('add_recipients') : t('add_new_recipients') do %>
|
||||||
<% options = [only_detailed ? nil : [t('via_email'), 'email'], only_detailed || !with_phone ? nil : [t('via_phone'), 'phone'], [t('detailed'), 'detailed'], with_list ? [t('upload_list'), 'list'] : nil].compact %>
|
<% options = [only_detailed ? nil : [t('via_email'), 'email'], only_detailed || !with_phone ? nil : [t('via_phone'), 'phone'], [t('detailed'), 'detailed'], with_list ? [t('upload_list'), 'list'] : nil].compact %>
|
||||||
<% if options.size > 1 %>
|
<% if options.size > 1 %>
|
||||||
<toggle-visible data-element-ids="<%= options.map(&:last).to_json %>" class="relative text-center px-2 block <%= 'mt-4' unless turbo_native_app? %>">
|
<toggle-visible data-element-ids="<%= options.map(&:last).to_json %>" class="relative text-center px-2 block <%= turbo_native_app? ? ('mt-1.5' if turbo_native_android?) : 'mt-4' %> <%= 'max-sm:hidden' if options.one? { |_, value| value != 'list' } %>">
|
||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<% options.each_with_index do |(label, value), index| %>
|
<% options.each_with_index do |(label, value), index| %>
|
||||||
<%= content_tag(value == 'list' ? 'span' : 'toggle-cookies', data: { value:, key: 'add_recipients_tab' }) do %>
|
<%= content_tag(value == 'list' ? 'span' : 'toggle-cookies', data: { value:, key: 'add_recipients_tab' }) do %>
|
||||||
|
|||||||
@@ -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">
|
<div class="space-y-2 <%= 'mt-1.5 px-4' if turbo_native_android? %>">
|
||||||
<%= 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 } do |f| %>
|
<%= form_for '', url: path, method: :get, data: { turbo_frame: :_top }, html: { autocomplete: :off, class: ('px-4' if turbo_native_android?) } 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? %>
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
<div class="flex flex-col md:flex-row gap-2">
|
<div class="flex flex-col md:flex-row gap-2">
|
||||||
<div class="form-control w-full">
|
<div class="form-control w-full">
|
||||||
<%= label_tag 'completed_at_from', t('from'), for: 'date_from', class: 'label text-sm' %>
|
<%= label_tag 'completed_at_from', t('from'), for: 'date_from', class: 'label text-sm' %>
|
||||||
<%= date_field_tag 'completed_at_from', params[:completed_at_from], id: 'date_from', class: 'base-input !h-10', autocomplete: 'off' %>
|
<%= date_field_tag 'completed_at_from', params[:completed_at_from], id: 'date_from', class: "base-input !h-10 #{'w-full' if turbo_native_android?}", autocomplete: 'off' %>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-control w-full">
|
<div class="form-control w-full">
|
||||||
<%= label_tag 'completed_at_to', t('to'), for: 'date_to', class: 'label text-sm' %>
|
<%= label_tag 'completed_at_to', t('to'), for: 'date_to', class: 'label text-sm' %>
|
||||||
<%= date_field_tag 'completed_at_to', params[:completed_at_to], id: 'date_to', class: 'base-input !h-10', autocomplete: 'off' %>
|
<%= date_field_tag 'completed_at_to', params[:completed_at_to], id: 'date_to', class: "base-input !h-10 #{'w-full' if turbo_native_android?}", autocomplete: 'off' %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<%= render 'date_buttons' %>
|
<%= render 'date_buttons' %>
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
<div class="flex flex-col md:flex-row gap-2">
|
<div class="flex flex-col md:flex-row gap-2">
|
||||||
<div class="form-control w-full">
|
<div class="form-control w-full">
|
||||||
<%= label_tag 'created_at_from', t('from'), for: 'date_from', class: 'label text-sm' %>
|
<%= label_tag 'created_at_from', t('from'), for: 'date_from', class: 'label text-sm' %>
|
||||||
<%= date_field_tag 'created_at_from', params[:created_at_from], id: 'date_from', class: 'base-input !h-10', autocomplete: 'off' %>
|
<%= date_field_tag 'created_at_from', params[:created_at_from], id: 'date_from', class: "base-input !h-10 #{'w-full' if turbo_native_android?}", autocomplete: 'off' %>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-control w-full">
|
<div class="form-control w-full">
|
||||||
<%= label_tag 'created_at_to', t('to'), for: 'date_to', class: 'label text-sm' %>
|
<%= label_tag 'created_at_to', t('to'), for: 'date_to', class: 'label text-sm' %>
|
||||||
<%= date_field_tag 'created_at_to', params[:created_at_to], id: 'date_to', class: 'base-input !h-10', autocomplete: 'off' %>
|
<%= date_field_tag 'created_at_to', params[:created_at_to], id: 'date_to', class: "base-input !h-10 #{'w-full' if turbo_native_android?}", autocomplete: 'off' %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<%= render 'date_buttons' %>
|
<%= render 'date_buttons' %>
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
<%= form_for '', url: submit_form_email_2fa_path, method: :post, html: { class: 'space-y-4', id: 'code_form' } do |f| %>
|
<%= form_for '', url: submit_form_email_2fa_path, method: :post, html: { class: 'space-y-4', id: 'code_form' } do |f| %>
|
||||||
<div dir="auto" class="form-control !mt-0">
|
<div dir="auto" class="form-control !mt-0">
|
||||||
<%= f.hidden_field :submitter_slug, value: @submitter.slug %>
|
<%= f.hidden_field :submitter_slug, value: @submitter.slug %>
|
||||||
|
<%= f.hidden_field :lang, value: params[:lang] if params[:lang].present? %>
|
||||||
<%= f.text_field :one_time_code, required: true, inputmode: 'numeric', class: 'base-input text-center', placeholder: 'XXXXXX' %>
|
<%= f.text_field :one_time_code, required: true, inputmode: 'numeric', class: 'base-input text-center', placeholder: 'XXXXXX' %>
|
||||||
<div class="flex justify-between items-center mt-1">
|
<div class="flex justify-between items-center mt-1">
|
||||||
<span>
|
<span>
|
||||||
@@ -55,7 +56,7 @@
|
|||||||
<%= f.button button_title(title: t('submit')), class: 'base-button' %>
|
<%= f.button button_title(title: t('submit')), class: 'base-button' %>
|
||||||
</toggle-submit>
|
</toggle-submit>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= button_to t(:re_send_email), submit_form_email_2fa_path, params: { submitter_slug: @submitter.slug, resend: true }, method: :put, form: { id: 'resend_code_form', class: 'hidden' } %>
|
<%= button_to t(:re_send_email), submit_form_email_2fa_path, params: { submitter_slug: @submitter.slug, resend: true, lang: params[:lang] }.compact_blank, method: :put, form: { id: 'resend_code_form', class: 'hidden' } %>
|
||||||
<% else %>
|
<% else %>
|
||||||
<% if params[:t] %>
|
<% if params[:t] %>
|
||||||
<fetch-form data-onload="true">
|
<fetch-form data-onload="true">
|
||||||
@@ -63,7 +64,7 @@
|
|||||||
</fetch-form>
|
</fetch-form>
|
||||||
<% end %>
|
<% end %>
|
||||||
<toggle-submit dir="auto" class="form-control">
|
<toggle-submit dir="auto" class="form-control">
|
||||||
<%= button_to button_title(title: t('send_verification_code')), submit_form_email_2fa_path, params: { submitter_slug: @submitter.slug }, method: :put, class: 'base-button w-full' %>
|
<%= button_to button_title(title: t('send_verification_code')), submit_form_email_2fa_path, params: { submitter_slug: @submitter.slug, lang: params[:lang] }.compact_blank, method: :put, class: 'base-button w-full' %>
|
||||||
</toggle-submit>
|
</toggle-submit>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% else %>
|
<% else %>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<%= 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 } do |f| %>
|
<%= 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| %>
|
||||||
<div class="form-control 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>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
|
|||||||
@@ -5,7 +5,9 @@
|
|||||||
<% is_show_header = submissions_count != 0 || params[:q].present? || params[:status].present? || filter_params.present? %>
|
<% is_show_header = submissions_count != 0 || params[:q].present? || params[:status].present? || filter_params.present? %>
|
||||||
<%= render 'title', template: @template, with_export: is_show_header %>
|
<%= render 'title', template: @template, with_export: is_show_header %>
|
||||||
<% if turbo_native_app? %>
|
<% if turbo_native_app? %>
|
||||||
<native-action data-placement="search" data-native="search" data-label="<%= t('search') %>" data-url="<%= search_index_path(filter_params.to_h.merge({ 'scope' => 'submissions', 'template_id' => @template.id, 'archived' => ('true' if @template.archived_at?) }.compact)) %>"></native-action>
|
<% if !turbo_native_android? || submissions_count >= 5 || params[:q].present? || params[:status].present? || filter_params.present? %>
|
||||||
|
<native-action data-placement="search" data-native="search" data-label="<%= t('search') %>" data-url="<%= search_index_path(filter_params.to_h.merge({ 'scope' => 'submissions', 'template_id' => @template.id, 'archived' => ('true' if @template.archived_at?) }.compact)) %>"></native-action>
|
||||||
|
<% end %>
|
||||||
<% if !@template.archived_at? && can?(:create, Submission) %>
|
<% if !@template.archived_at? && can?(:create, Submission) %>
|
||||||
<native-action data-placement="footer" data-icon="send" data-haptic="true" data-label="<%= t('send_to_recipients') %>">
|
<native-action data-placement="footer" data-icon="send" data-haptic="true" data-label="<%= t('send_to_recipients') %>">
|
||||||
<a href="<%= new_template_submission_path(@template) %>" data-turbo-frame="modal" data-native-modal="<%= 'medium' if @template.submitters.size < 3 %>"></a>
|
<a href="<%= new_template_submission_path(@template) %>" data-turbo-frame="modal" data-native-modal="<%= 'medium' if @template.submitters.size < 3 %>"></a>
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
<%= form_for @template, url: template_clone_index_path(@base_template), data: { turbo_frame: :_top }, html: { autocomplete: :off } do |f| %>
|
<%= 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| %>
|
||||||
<% 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 %>
|
||||||
<% if (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? %>
|
||||||
<div class="form-control -mb-2 mt-2">
|
<% if with_accounts %>
|
||||||
|
<div class="form-control -mb-2 <%= turbo_native_android? ? 'mt-1.5' : 'mt-2' %>">
|
||||||
<%= select_tag :account_id, options_for_select([current_account, *accounts.order(:name)].uniq.map { |e| [e.name, e.id] }, current_account.id), required: true, class: 'base-select' %>
|
<%= select_tag :account_id, options_for_select([current_account, *accounts.order(:name)].uniq.map { |e| [e.name, e.id] }, current_account.id), required: true, class: 'base-select' %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<div class="form-control mt-4">
|
<div class="form-control <%= turbo_native_android? && !with_accounts ? 'mt-1.5' : 'mt-4' %>">
|
||||||
<%= f.text_field :name, required: true, placeholder: t('document_name'), class: 'base-input', dir: 'auto' %>
|
<%= f.text_field :name, required: true, placeholder: t('document_name'), class: 'base-input', dir: 'auto' %>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-3 mb-4 flex items-center justify-between">
|
<div class="mt-3 mb-4 flex items-center justify-between">
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<% unless turbo_native_ios? %>
|
<% unless turbo_native_app? %>
|
||||||
<div class="alert">
|
<div class="alert">
|
||||||
<%= svg_icon('info_circle', class: 'w-6 h-6') %>
|
<%= svg_icon('info_circle', class: 'w-6 h-6') %>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -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 } do |f| %>
|
<%= 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| %>
|
||||||
<%= 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: "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 px-4' : 'mt-6'} #{'hidden' if with_subfolder}" } 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 %>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<% options << [t('recipients'), 'recipients'] if show_recipients %>
|
<% options << [t('recipients'), 'recipients'] if show_recipients %>
|
||||||
<% options << [safe_join([tag.span('API', class: 'md:hidden'), tag.span(t('api_and_embedding'), class: 'hidden md:inline')]), 'api'] if show_api %>
|
<% options << [safe_join([tag.span('API', class: 'md:hidden'), tag.span(t('api_and_embedding'), class: 'hidden md:inline')]), 'api'] if show_api %>
|
||||||
<% if options.size > 1 %>
|
<% if options.size > 1 %>
|
||||||
<toggle-visible data-element-ids="<%= options.map(&:last).to_json %>" class="relative text-center block <%= 'mt-3' unless turbo_native_app? %>">
|
<toggle-visible data-element-ids="<%= options.map(&:last).to_json %>" class="relative text-center block <%= turbo_native_app? ? ('mt-1.5' if turbo_native_android?) : 'mt-3' %>">
|
||||||
<div class="join">
|
<div class="join">
|
||||||
<% options.each_with_index do |(label, value), index| %>
|
<% options.each_with_index do |(label, value), index| %>
|
||||||
<span>
|
<span>
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
<% 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 mb-4 px-5">
|
<div class="<%= 'mt-2' unless turbo_native_android? %> mb-4 px-5">
|
||||||
<% 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') %>
|
||||||
<div><%= t('dynamic_template_with_variables_cannot_be_used_via_shared_link') %></div>
|
<div><%= t('dynamic_template_with_variables_cannot_be_used_via_shared_link') %></div>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= form_for @template, url: template_share_link_path(@template), method: :post, html: { id: 'shared_link_form', autocomplete: 'off', class: 'mt-3' }, data: { close_on_submit: false } do |f| %>
|
<%= form_for @template, url: template_share_link_path(@template), method: :post, html: { id: 'shared_link_form', autocomplete: 'off', class: turbo_native_android? ? 'mt-1' : 'mt-3' }, data: { close_on_submit: false } do |f| %>
|
||||||
<% if @template.preferences&.dig('require_email_2fa') || @template.preferences&.dig('require_phone_2fa') %>
|
<% if @template.preferences&.dig('require_email_2fa') || @template.preferences&.dig('require_phone_2fa') %>
|
||||||
<label for="template_shared_link" class="tooltip tooltip-bottom tooltip-no-touch flex items-center my-4 justify-between gap-4 p-4 border border-base-300 rounded-2xl bg-base-100" data-tip="<%= t(:templates_that_require_email_or_phone_2fa_cannot_be_used_via_a_shared_link) %>">
|
<label for="template_shared_link" class="tooltip tooltip-bottom tooltip-no-touch flex items-center <%= turbo_native_android? ? 'mb-4' : 'my-4' %> justify-between gap-4 p-4 border border-base-300 rounded-2xl bg-base-100" data-tip="<%= t(:templates_that_require_email_or_phone_2fa_cannot_be_used_via_a_shared_link) %>">
|
||||||
<span><%= t('enable_shared_link') %></span>
|
<span><%= t('enable_shared_link') %></span>
|
||||||
<%= check_box_tag 'shared_link', 'true', false, disabled: true, class: 'toggle' %>
|
<%= check_box_tag 'shared_link', 'true', false, disabled: true, class: 'toggle' %>
|
||||||
</label>
|
</label>
|
||||||
<% else %>
|
<% else %>
|
||||||
<label for="template_shared_link" class="flex items-center my-4 justify-between gap-4 p-4 border border-base-300 rounded-2xl bg-base-100">
|
<label for="template_shared_link" class="flex items-center <%= turbo_native_android? ? 'mb-4' : 'my-4' %> justify-between gap-4 p-4 border border-base-300 rounded-2xl bg-base-100">
|
||||||
<span><%= t('enable_shared_link') %></span>
|
<span><%= t('enable_shared_link') %></span>
|
||||||
<submit-form data-on="change" class="flex">
|
<submit-form data-on="change" class="flex">
|
||||||
<%= f.check_box :shared_link, { disabled: !can?(:update, @template) || @template.variables_schema.present?, class: 'toggle' }, 'true', 'false' %>
|
<%= f.check_box :shared_link, { disabled: !can?(:update, @template) || @template.variables_schema.present?, class: 'toggle' }, 'true', 'false' %>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<% if can?(:update, @template) %>
|
<% if can?(:update, @template) %>
|
||||||
<toggle-submit class="block">
|
<toggle-submit class="block">
|
||||||
<%= button_to button_title(title: t('enable_shared_link'), icon: svg_icon('lock_open', class: 'w-6 h-6')), template_share_link_path(@template), params: { template: { shared_link: true }, redir: template_share_link_qr_path(@template) }, method: :post, data: { turbo: false }, class: 'base-button w-full' %>
|
<%= button_to button_title(title: t('enable_shared_link'), icon: svg_icon('lock_open', class: 'w-6 h-6')), template_share_link_path(@template), params: { template: { shared_link: true }, redir: template_share_link_qr_path(@template) }, method: :post, class: 'base-button w-full' %>
|
||||||
</toggle-submit>
|
</toggle-submit>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<%= render 'shared/turbo_modal', title: t('update_initials') do %>
|
<%= render 'shared/turbo_modal', title: t('update_initials') do %>
|
||||||
<% options = [[t('draw'), 'draw'], [t('upload'), 'upload']] %>
|
<% options = [[t('draw'), 'draw'], [t('upload'), 'upload']] %>
|
||||||
<toggle-visible data-element-ids="<%= options.map(&:last).to_json %>" class="relative text-center block <%= 'mt-4' unless turbo_native_app? %>">
|
<toggle-visible data-element-ids="<%= options.map(&:last).to_json %>" class="relative text-center block <%= turbo_native_app? ? ('mt-1.5' if turbo_native_android?) : 'mt-4' %>">
|
||||||
<div class="join">
|
<div class="join">
|
||||||
<% options.each_with_index do |(label, value), index| %>
|
<% options.each_with_index do |(label, value), index| %>
|
||||||
<span>
|
<span>
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</toggle-visible>
|
</toggle-visible>
|
||||||
<div id="draw" class="mt-3">
|
<div id="draw" class="mt-3 <%= 'px-4' if turbo_native_android? %>">
|
||||||
<%= 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">
|
<div id="upload" class="hidden mt-3 <%= 'px-4' if turbo_native_android? %>">
|
||||||
<%= 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">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<%= render 'shared/turbo_modal', title: t('update_signature') do %>
|
<%= render 'shared/turbo_modal', title: t('update_signature') do %>
|
||||||
<% options = [[t('draw'), 'draw'], [t('upload'), 'upload']] %>
|
<% options = [[t('draw'), 'draw'], [t('upload'), 'upload']] %>
|
||||||
<toggle-visible data-element-ids="<%= options.map(&:last).to_json %>" class="relative text-center block <%= 'mt-4' unless turbo_native_app? %>">
|
<toggle-visible data-element-ids="<%= options.map(&:last).to_json %>" class="relative text-center block <%= turbo_native_app? ? ('mt-1.5' if turbo_native_android?) : 'mt-4' %>">
|
||||||
<div class="join">
|
<div class="join">
|
||||||
<% options.each_with_index do |(label, value), index| %>
|
<% options.each_with_index do |(label, value), index| %>
|
||||||
<span>
|
<span>
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</toggle-visible>
|
</toggle-visible>
|
||||||
<div id="draw" class="mt-3">
|
<div id="draw" class="mt-3 <%= 'px-4' if turbo_native_android? %>">
|
||||||
<%= 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">
|
<div id="upload" class="hidden mt-3 <%= 'px-4' if turbo_native_android? %>">
|
||||||
<%= 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' }, data: { turbo_frame: :_top } do |f| %>
|
<%= form_for user, html: { class: "space-y-4 #{'px-4' if turbo_native_android?}" }, 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">
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% unless turbo_native_ios? %>
|
<% unless turbo_native_app? %>
|
||||||
<a class="text-sm mt-3 px-4 py-2 bg-base-300 rounded-full block" target="_blank" href="<%= Docuseal.multitenant? ? console_redirect_index_path(redir: "#{Docuseal::CONSOLE_URL}/plans") : "#{Docuseal::CLOUD_URL}/sign_up?#{{ redir: "#{Docuseal::CONSOLE_URL}/on_premises" }.to_query}" %>">
|
<a class="text-sm mt-3 px-4 py-2 bg-base-300 rounded-full block" target="_blank" href="<%= Docuseal.multitenant? ? console_redirect_index_path(redir: "#{Docuseal::CONSOLE_URL}/plans") : "#{Docuseal::CLOUD_URL}/sign_up?#{{ redir: "#{Docuseal::CONSOLE_URL}/on_premises" }.to_query}" %>">
|
||||||
<%= svg_icon('info_circle', class: 'w-4 h-4 inline align-text-bottom') %>
|
<%= svg_icon('info_circle', class: 'w-4 h-4 inline align-text-bottom') %>
|
||||||
<%= t('unlock_more_user_roles_with_docuseal_pro') %>
|
<%= t('unlock_more_user_roles_with_docuseal_pro') %>
|
||||||
|
|||||||
@@ -103,7 +103,22 @@ Rails.application.configure do
|
|||||||
config.active_support.report_deprecations = false
|
config.active_support.report_deprecations = false
|
||||||
|
|
||||||
# Use default logging formatter so that PID and timestamp are not suppressed.
|
# Use default logging formatter so that PID and timestamp are not suppressed.
|
||||||
config.log_formatter = Logger::Formatter.new
|
json_formatter = Logger::Formatter.new
|
||||||
|
json_formatter.define_singleton_method(:call) do |severity, time, _progname, msg|
|
||||||
|
data = { ts: time.utc.iso8601(3), pid: Process.pid, lvl: severity }
|
||||||
|
data[:tags] = current_tags.join(',') if current_tags.any?
|
||||||
|
|
||||||
|
if msg.is_a?(Hash)
|
||||||
|
data.merge!(msg)
|
||||||
|
else
|
||||||
|
data[:msg] = msg2str(msg)
|
||||||
|
end
|
||||||
|
|
||||||
|
"#{data.to_json}\n"
|
||||||
|
end
|
||||||
|
json_formatter.define_singleton_method(:tags_text) { '' }
|
||||||
|
|
||||||
|
config.log_formatter = ENV['LOG_FORMATTER'] == 'json' ? json_formatter : Logger::Formatter.new
|
||||||
|
|
||||||
# Use a different logger for distributed setups.
|
# Use a different logger for distributed setups.
|
||||||
# require "syslog/logger"
|
# require "syslog/logger"
|
||||||
@@ -129,7 +144,12 @@ Rails.application.configure do
|
|||||||
config.lograge.enabled = true
|
config.lograge.enabled = true
|
||||||
config.lograge.base_controller_class = ['ActionController::API', 'ActionController::Base']
|
config.lograge.base_controller_class = ['ActionController::API', 'ActionController::Base']
|
||||||
|
|
||||||
config.lograge.formatter = ->(data) { data.except(:path, :location).to_json }
|
config.lograge.formatter =
|
||||||
|
if ENV['LOG_FORMATTER'] == 'json'
|
||||||
|
->(data) { data.except(:path, :location) }
|
||||||
|
else
|
||||||
|
->(data) { data.except(:path, :location).to_json }
|
||||||
|
end
|
||||||
|
|
||||||
config.lograge.custom_payload do |controller|
|
config.lograge.custom_payload do |controller|
|
||||||
params =
|
params =
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ ActiveSupport.on_load(:active_storage_attachment) do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# rubocop:disable Metrics/BlockLength
|
# rubocop:disable-next Metrics/BlockLength
|
||||||
ActiveSupport.on_load(:active_storage_blob) do
|
ActiveSupport.on_load(:active_storage_blob) do
|
||||||
attribute :uuid, :string, default: -> { SecureRandom.uuid }
|
attribute :uuid, :string, default: -> { SecureRandom.uuid }
|
||||||
attribute :io_data, :string, default: ''
|
attribute :io_data, :string, default: ''
|
||||||
@@ -59,7 +59,6 @@ ActiveSupport.on_load(:active_storage_blob) do
|
|||||||
service.delete(key)
|
service.delete(key)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics/BlockLength
|
|
||||||
|
|
||||||
ActiveStorage::LogSubscriber.detach_from(:active_storage) if Rails.env.production?
|
ActiveStorage::LogSubscriber.detach_from(:active_storage) if Rails.env.production?
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ end
|
|||||||
#
|
#
|
||||||
# Use this hook to configure devise mailer, warden hooks and so forth.
|
# Use this hook to configure devise mailer, warden hooks and so forth.
|
||||||
# Many of these configuration options can be set straight in your model.
|
# Many of these configuration options can be set straight in your model.
|
||||||
# rubocop:disable Metrics/BlockLength
|
# rubocop:disable-next Metrics/BlockLength
|
||||||
Devise.setup do |config|
|
Devise.setup do |config|
|
||||||
config.warden do |manager|
|
config.warden do |manager|
|
||||||
manager.default_strategies(scope: :user).unshift(:two_factor_authenticatable)
|
manager.default_strategies(scope: :user).unshift(:two_factor_authenticatable)
|
||||||
@@ -336,4 +336,3 @@ Devise.setup do |config|
|
|||||||
|
|
||||||
ActiveSupport.run_load_hooks(:devise_config, config)
|
ActiveSupport.run_load_hooks(:devise_config, config)
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics/BlockLength
|
|
||||||
@@ -10,9 +10,8 @@ ActionView::Base.field_error_proc = proc do |html_tag, instance|
|
|||||||
|
|
||||||
parsed_html_tag = Nokogiri::HTML::DocumentFragment.parse(html_tag)
|
parsed_html_tag = Nokogiri::HTML::DocumentFragment.parse(html_tag)
|
||||||
parsed_html_tag.children.add_class 'input-error'
|
parsed_html_tag.children.add_class 'input-error'
|
||||||
# rubocop:disable Rails/OutputSafety
|
# rubocop:disable-next Rails/OutputSafety
|
||||||
html_tag = parsed_html_tag.to_s.html_safe
|
html_tag = parsed_html_tag.to_s.html_safe
|
||||||
# rubocop:enable Rails/OutputSafety
|
|
||||||
|
|
||||||
result = html_tag
|
result = html_tag
|
||||||
|
|
||||||
|
|||||||
@@ -72,9 +72,8 @@ module HexaPDF
|
|||||||
def terminal_field?
|
def terminal_field?
|
||||||
kids = self[:Kids]
|
kids = self[:Kids]
|
||||||
|
|
||||||
# rubocop:disable Rails/Blank
|
# rubocop:disable-next Rails/Blank
|
||||||
kids.nil? || kids.empty? || kids.none? { |kid| kid&.key?(:T) }
|
kids.nil? || kids.empty? || kids.none? { |kid| kid&.key?(:T) }
|
||||||
# rubocop:enable Rails/Blank
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -12,3 +12,7 @@ if !ENV['SIDEKIQ_BASIC_AUTH_PASSWORD'].to_s.empty? && defined?(Sidekiq::Web)
|
|||||||
end
|
end
|
||||||
|
|
||||||
Sidekiq.strict_args!
|
Sidekiq.strict_args!
|
||||||
|
|
||||||
|
Sidekiq.configure_server do |config|
|
||||||
|
config.logger.formatter = Sidekiq::Logger::Formatters::JSON.new if ENV['LOG_FORMATTER'] == 'json'
|
||||||
|
end
|
||||||
@@ -2,9 +2,8 @@
|
|||||||
|
|
||||||
class AddIsFirstToCompletedSubmitters < ActiveRecord::Migration[8.0]
|
class AddIsFirstToCompletedSubmitters < ActiveRecord::Migration[8.0]
|
||||||
def change
|
def change
|
||||||
# rubocop:disable Rails/ThreeStateBooleanColumn
|
# rubocop:disable-next Rails/ThreeStateBooleanColumn
|
||||||
add_column :completed_submitters, :is_first, :boolean
|
add_column :completed_submitters, :is_first, :boolean
|
||||||
# rubocop:enable Rails/ThreeStateBooleanColumn
|
|
||||||
|
|
||||||
add_index :completed_submitters, %i[account_id completed_at],
|
add_index :completed_submitters, %i[account_id completed_at],
|
||||||
where: 'is_first = TRUE',
|
where: 'is_first = TRUE',
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddAccountsCreatedAtIndex < ActiveRecord::Migration[8.1]
|
||||||
|
def change
|
||||||
|
add_index :accounts, :created_at, if_not_exists: true
|
||||||
|
end
|
||||||
|
end
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddSubmissionEventsAccountEventTypeCreatedAtIndex < ActiveRecord::Migration[8.1]
|
||||||
|
def change
|
||||||
|
return unless ENV['MULTITENANT'] == 'true'
|
||||||
|
|
||||||
|
add_index :submission_events, %i[account_id created_at],
|
||||||
|
where: "event_type = 'start_kba'",
|
||||||
|
if_not_exists: true,
|
||||||
|
name: 'index_submission_events_on_account_created_at_start_kba'
|
||||||
|
end
|
||||||
|
end
|
||||||
+3
-1
@@ -10,7 +10,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema[8.1].define(version: 2026_10_25_120002) do
|
ActiveRecord::Schema[8.1].define(version: 2026_11_02_120000) do
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "btree_gin"
|
enable_extension "btree_gin"
|
||||||
enable_extension "pg_catalog.plpgsql"
|
enable_extension "pg_catalog.plpgsql"
|
||||||
@@ -62,6 +62,7 @@ ActiveRecord::Schema[8.1].define(version: 2026_10_25_120002) do
|
|||||||
t.string "timezone", null: false
|
t.string "timezone", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
t.string "uuid", null: false
|
t.string "uuid", null: false
|
||||||
|
t.index ["created_at"], name: "index_accounts_on_created_at"
|
||||||
t.index ["uuid"], name: "index_accounts_on_uuid", unique: true
|
t.index ["uuid"], name: "index_accounts_on_uuid", unique: true
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -361,6 +362,7 @@ ActiveRecord::Schema[8.1].define(version: 2026_10_25_120002) do
|
|||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
t.index ["account_id", "created_at"], name: "index_submissions_events_on_sms_event_types", where: "((event_type)::text = ANY (ARRAY[('send_sms'::character varying)::text, ('send_2fa_sms'::character varying)::text]))"
|
t.index ["account_id", "created_at"], name: "index_submissions_events_on_sms_event_types", where: "((event_type)::text = ANY (ARRAY[('send_sms'::character varying)::text, ('send_2fa_sms'::character varying)::text]))"
|
||||||
t.index ["account_id"], name: "index_submission_events_on_account_id"
|
t.index ["account_id"], name: "index_submission_events_on_account_id"
|
||||||
|
t.index ["account_id", "created_at"], name: "index_submission_events_on_account_created_at_start_kba", where: "((event_type)::text = 'start_kba'::text)"
|
||||||
t.index ["created_at"], name: "index_submission_events_on_created_at"
|
t.index ["created_at"], name: "index_submission_events_on_created_at"
|
||||||
t.index ["submission_id"], name: "index_submission_events_on_submission_id"
|
t.index ["submission_id"], name: "index_submission_events_on_submission_id"
|
||||||
t.index ["submitter_id"], name: "index_submission_events_on_submitter_id"
|
t.index ["submitter_id"], name: "index_submission_events_on_submitter_id"
|
||||||
|
|||||||
+1
-1
@@ -160,7 +160,7 @@ module Accounts
|
|||||||
def normalize_timezone(timezone)
|
def normalize_timezone(timezone)
|
||||||
tzinfo = TZInfo::Timezone.get(ActiveSupport::TimeZone::MAPPING[timezone] || timezone)
|
tzinfo = TZInfo::Timezone.get(ActiveSupport::TimeZone::MAPPING[timezone] || timezone)
|
||||||
|
|
||||||
::ActiveSupport::TimeZone.all.find { |e| e.tzinfo == tzinfo }&.name || timezone
|
::ActiveSupport::TimeZone.all.find { |e| e.tzinfo.canonical_zone == tzinfo.canonical_zone }&.name || timezone
|
||||||
rescue TZInfo::InvalidTimezoneIdentifier
|
rescue TZInfo::InvalidTimezoneIdentifier
|
||||||
'UTC'
|
'UTC'
|
||||||
end
|
end
|
||||||
|
|||||||
+2
-2
@@ -111,7 +111,7 @@ module LoadIco
|
|||||||
and_scanline_stride = 0
|
and_scanline_stride = 0
|
||||||
if has_and_mask
|
if has_and_mask
|
||||||
and_mask_data_offset = xor_mask_data_offset + (image_pixel_height * xor_scanline_stride)
|
and_mask_data_offset = xor_mask_data_offset + (image_pixel_height * xor_scanline_stride)
|
||||||
and_scanline_stride = (((dib_width * 1) + 31) / 32) * 4
|
and_scanline_stride = ((dib_width + 31) / 32) * 4
|
||||||
end
|
end
|
||||||
|
|
||||||
flat_rgba_pixels = []
|
flat_rgba_pixels = []
|
||||||
@@ -128,7 +128,7 @@ module LoadIco
|
|||||||
if has_and_mask
|
if has_and_mask
|
||||||
dib_io.seek(and_mask_data_offset + (y_dib_row * and_scanline_stride))
|
dib_io.seek(and_mask_data_offset + (y_dib_row * and_scanline_stride))
|
||||||
and_mask_scanline_bytes = dib_io.read(and_scanline_stride)
|
and_mask_scanline_bytes = dib_io.read(and_scanline_stride)
|
||||||
min_and_bytes_needed = ((dib_width * 1) + 7) / 8
|
min_and_bytes_needed = (dib_width + 7) / 8
|
||||||
return nil unless and_mask_scanline_bytes && and_mask_scanline_bytes.bytesize >= min_and_bytes_needed
|
return nil unless and_mask_scanline_bytes && and_mask_scanline_bytes.bytesize >= min_and_bytes_needed
|
||||||
|
|
||||||
(0...dib_width).each do |x_pixel|
|
(0...dib_width).each do |x_pixel|
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ module MarkdownToHtml
|
|||||||
html.presence || '<p></p>'
|
html.presence || '<p></p>'
|
||||||
end
|
end
|
||||||
|
|
||||||
# rubocop:disable Metrics
|
# rubocop:disable-next Metrics
|
||||||
def parse_inline(text)
|
def parse_inline(text)
|
||||||
context = []
|
context = []
|
||||||
out = ''
|
out = ''
|
||||||
@@ -128,5 +128,4 @@ module MarkdownToHtml
|
|||||||
|
|
||||||
(out + text[last..].to_s + flush.call).gsub('<a>', '[')
|
(out + text[last..].to_s + flush.call).gsub('<a>', '[')
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics
|
|
||||||
end
|
end
|
||||||
+2
-4
@@ -86,7 +86,7 @@ class Pdfium
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# rubocop:disable Naming/ClassAndModuleCamelCase
|
# rubocop:disable-next Naming/ClassAndModuleCamelCase
|
||||||
class FPDF_LIBRARY_CONFIG < FFI::Struct
|
class FPDF_LIBRARY_CONFIG < FFI::Struct
|
||||||
layout :version, :int,
|
layout :version, :int,
|
||||||
:m_pUserFontPaths, :pointer,
|
:m_pUserFontPaths, :pointer,
|
||||||
@@ -95,7 +95,6 @@ class Pdfium
|
|||||||
:m_pPlatform, :pointer,
|
:m_pPlatform, :pointer,
|
||||||
:m_RendererType, :int
|
:m_RendererType, :int
|
||||||
end
|
end
|
||||||
# rubocop:enable Naming/ClassAndModuleCamelCase
|
|
||||||
|
|
||||||
attach_function :FPDF_InitLibraryWithConfig, [:pointer], :void
|
attach_function :FPDF_InitLibraryWithConfig, [:pointer], :void
|
||||||
attach_function :FPDF_DestroyLibrary, [], :void
|
attach_function :FPDF_DestroyLibrary, [], :void
|
||||||
@@ -234,7 +233,7 @@ class Pdfium
|
|||||||
typedef :int, :FPDF_BOOL
|
typedef :int, :FPDF_BOOL
|
||||||
typedef :pointer, :IPDF_JSPLATFORM
|
typedef :pointer, :IPDF_JSPLATFORM
|
||||||
|
|
||||||
# rubocop:disable Naming/ClassAndModuleCamelCase
|
# rubocop:disable-next Naming/ClassAndModuleCamelCase
|
||||||
class FPDF_FORMFILLINFO_V2 < FFI::Struct
|
class FPDF_FORMFILLINFO_V2 < FFI::Struct
|
||||||
layout :version, :int,
|
layout :version, :int,
|
||||||
:Release, :pointer,
|
:Release, :pointer,
|
||||||
@@ -272,7 +271,6 @@ class Pdfium
|
|||||||
:FFI_OnFocusChange, :pointer,
|
:FFI_OnFocusChange, :pointer,
|
||||||
:FFI_DoURIActionWithKeyboardModifier, :pointer
|
:FFI_DoURIActionWithKeyboardModifier, :pointer
|
||||||
end
|
end
|
||||||
# rubocop:enable Naming/ClassAndModuleCamelCase
|
|
||||||
|
|
||||||
attach_function :FPDFDOC_InitFormFillEnvironment, %i[FPDF_DOCUMENT pointer], :FPDF_FORMHANDLE
|
attach_function :FPDFDOC_InitFormFillEnvironment, %i[FPDF_DOCUMENT pointer], :FPDF_FORMHANDLE
|
||||||
attach_function :FPDFDOC_ExitFormFillEnvironment, [:FPDF_FORMHANDLE], :void
|
attach_function :FPDFDOC_ExitFormFillEnvironment, [:FPDF_FORMHANDLE], :void
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
require 'puma/plugin'
|
require 'puma/plugin'
|
||||||
|
|
||||||
# rubocop:disable Metrics
|
# rubocop:disable-next Metrics
|
||||||
Puma::Plugin.create do
|
Puma::Plugin.create do
|
||||||
def start(launcher)
|
def start(launcher)
|
||||||
return if ENV['LOCAL_REDIS_URL'].to_s.empty?
|
return if ENV['LOCAL_REDIS_URL'].to_s.empty?
|
||||||
@@ -68,4 +68,3 @@ Puma::Plugin.create do
|
|||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics
|
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
require 'puma/plugin'
|
require 'puma/plugin'
|
||||||
require 'redis_client'
|
require 'redis_client'
|
||||||
|
|
||||||
# rubocop:disable Metrics
|
# rubocop:disable-next Metrics
|
||||||
Puma::Plugin.create do
|
Puma::Plugin.create do
|
||||||
def config(cfg)
|
def config(cfg)
|
||||||
return if cfg.instance_variable_get(:@options)[:workers] <= 0
|
return if cfg.instance_variable_get(:@options)[:workers] <= 0
|
||||||
@@ -73,4 +73,3 @@ Puma::Plugin.create do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics
|
|
||||||
@@ -32,7 +32,7 @@ module ReplaceEmailVariables
|
|||||||
|
|
||||||
module_function
|
module_function
|
||||||
|
|
||||||
# rubocop:disable Metrics
|
# rubocop:disable-next Metrics
|
||||||
def call(text, submitter:, tracking_event_type: 'click_email', html_escape: false, sig: nil)
|
def call(text, submitter:, tracking_event_type: 'click_email', html_escape: false, sig: nil)
|
||||||
text = replace(text, TEMPLATE_NAME, html_escape:) do
|
text = replace(text, TEMPLATE_NAME, html_escape:) do
|
||||||
(submitter.template || submitter.submission.template || submitter.submission).name
|
(submitter.template || submitter.submission.template || submitter.submission).name
|
||||||
@@ -94,7 +94,6 @@ module ReplaceEmailVariables
|
|||||||
|
|
||||||
text.tr(ESCAPED_BRACES, '{}')
|
text.tr(ESCAPED_BRACES, '{}')
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics
|
|
||||||
|
|
||||||
def build_documents_links_text(submitter, sig = nil)
|
def build_documents_links_text(submitter, sig = nil)
|
||||||
url_options = build_url_options_for(submitter)
|
url_options = build_url_options_for(submitter)
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ module SendWebhookRequest
|
|||||||
|
|
||||||
module_function
|
module_function
|
||||||
|
|
||||||
# rubocop:disable Metrics/AbcSize
|
# rubocop:disable-next Metrics/AbcSize
|
||||||
def call(webhook_url, event_uuid:, event_type:, record:, data:, attempt: 0)
|
def call(webhook_url, event_uuid:, event_type:, record:, data:, attempt: 0)
|
||||||
uri = parse_uri(webhook_url.url)
|
uri = parse_uri(webhook_url.url)
|
||||||
|
|
||||||
@@ -53,7 +53,6 @@ module SendWebhookRequest
|
|||||||
rescue Faraday::Error => e
|
rescue Faraday::Error => e
|
||||||
handle_error(webhook_event, attempt:, error_message: e.message&.truncate(100))
|
handle_error(webhook_event, attempt:, error_message: e.message&.truncate(100))
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics/AbcSize
|
|
||||||
|
|
||||||
def parse_uri(url)
|
def parse_uri(url)
|
||||||
URI(url)
|
URI(url)
|
||||||
|
|||||||
@@ -487,8 +487,11 @@ module Submissions
|
|||||||
|
|
||||||
text =
|
text =
|
||||||
if event.event_type == 'complete_verification'
|
if event.event_type == 'complete_verification'
|
||||||
I18n.t('submission_event_names.complete_verification_by_html', provider: event.data['method'],
|
identity_name = [event.data['firstname'], event.data['lastname']].compact_blank.join(' ')
|
||||||
submitter_name:)
|
identity_name = TextUtils.maybe_rtl_reverse(identity_name) if identity_name.present?
|
||||||
|
|
||||||
|
I18n.t('submission_event_names.complete_verification_by_html',
|
||||||
|
provider: event.data['method'], submitter_name: identity_name.presence || submitter_name)
|
||||||
elsif event.event_type == 'invite_party' &&
|
elsif event.event_type == 'invite_party' &&
|
||||||
(invited_submitter = submission.submitters.find { |e| e.uuid == event.data['uuid'] }) &&
|
(invited_submitter = submission.submitters.find { |e| e.uuid == event.data['uuid'] }) &&
|
||||||
(name = submission.template_submitters.find { |e| e['uuid'] == event.data['uuid'] }&.dig('name'))
|
(name = submission.template_submitters.find { |e| e['uuid'] == event.data['uuid'] }&.dig('name'))
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ module Submissions
|
|||||||
|
|
||||||
module_function
|
module_function
|
||||||
|
|
||||||
# rubocop:disable Metrics
|
# rubocop:disable-next Metrics
|
||||||
def call(submission, submitters = nil, params = {}, with_events: true, with_documents: true, with_values: true,
|
def call(submission, submitters = nil, params = {}, with_events: true, with_documents: true, with_values: true,
|
||||||
expires_at: Accounts.link_expires_at(Account.new(id: submission.account_id)))
|
expires_at: Accounts.link_expires_at(Account.new(id: submission.account_id)))
|
||||||
submitters ||= submission.submitters.preload(documents_attachments: :blob, attachments_attachments: :blob)
|
submitters ||= submission.submitters.preload(documents_attachments: :blob, attachments_attachments: :blob)
|
||||||
@@ -62,7 +62,6 @@ module Submissions
|
|||||||
|
|
||||||
json
|
json
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics
|
|
||||||
|
|
||||||
def build_status(submission, submitters)
|
def build_status(submission, submitters)
|
||||||
if submitters.any?(&:declined_at?)
|
if submitters.any?(&:declined_at?)
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ module Submissions
|
|||||||
signature[:SubFilter] = :'ETSI.RFC3161'
|
signature[:SubFilter] = :'ETSI.RFC3161'
|
||||||
end
|
end
|
||||||
|
|
||||||
# rubocop:disable Metrics
|
# rubocop:disable-next Metrics
|
||||||
def sign(io, byte_range)
|
def sign(io, byte_range)
|
||||||
digest = OpenSSL::Digest.new(HASH_ALGORITHM)
|
digest = OpenSSL::Digest.new(HASH_ALGORITHM)
|
||||||
|
|
||||||
@@ -59,7 +59,6 @@ module Submissions
|
|||||||
|
|
||||||
OpenSSL::ASN1::GeneralizedTime.new(Time.now.utc).to_der
|
OpenSSL::ASN1::GeneralizedTime.new(Time.now.utc).to_der
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics
|
|
||||||
|
|
||||||
def build_payload(digest)
|
def build_payload(digest)
|
||||||
req = OpenSSL::Timestamp::Request.new
|
req = OpenSSL::Timestamp::Request.new
|
||||||
|
|||||||
+1
-2
@@ -197,7 +197,7 @@ module Submitters
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# rubocop:disable Metrics
|
# rubocop:disable-next Metrics
|
||||||
def current_submitter_order?(submitter)
|
def current_submitter_order?(submitter)
|
||||||
submission = submitter.submission
|
submission = submitter.submission
|
||||||
|
|
||||||
@@ -228,7 +228,6 @@ module Submitters
|
|||||||
submitter.nil? || submitter.viewer? || submitter.completed_at?
|
submitter.nil? || submitter.viewer? || submitter.completed_at?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics
|
|
||||||
|
|
||||||
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?
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ module Submitters
|
|||||||
|
|
||||||
module_function
|
module_function
|
||||||
|
|
||||||
# rubocop:disable Metrics
|
# rubocop:disable-next Metrics
|
||||||
def call(template, values, submitter_name: nil, role_names: nil, for_submitter: nil, throw_errors: false,
|
def call(template, values, submitter_name: nil, role_names: nil, for_submitter: nil, throw_errors: false,
|
||||||
add_fields: false, purpose: nil)
|
add_fields: false, purpose: nil)
|
||||||
fields =
|
fields =
|
||||||
@@ -85,7 +85,6 @@ module Submitters
|
|||||||
|
|
||||||
[normalized_values, attachments, new_fields]
|
[normalized_values, attachments, new_fields]
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics
|
|
||||||
|
|
||||||
def normalize_value(field, value)
|
def normalize_value(field, value)
|
||||||
if field['type'] == 'checkbox'
|
if field['type'] == 'checkbox'
|
||||||
|
|||||||
@@ -384,7 +384,7 @@ module Submitters
|
|||||||
end.exclude?(false)
|
end.exclude?(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
# rubocop:disable Metrics
|
# rubocop:disable-next Metrics
|
||||||
def check_field_condition(condition, submitter_values, fields_uuid_index)
|
def check_field_condition(condition, submitter_values, fields_uuid_index)
|
||||||
value = submitter_values[condition['field_uuid']]
|
value = submitter_values[condition['field_uuid']]
|
||||||
field = fields_uuid_index[condition['field_uuid']]
|
field = fields_uuid_index[condition['field_uuid']]
|
||||||
@@ -437,7 +437,6 @@ module Submitters
|
|||||||
true
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics
|
|
||||||
|
|
||||||
def replace_default_variables(value, attrs, submission, with_time: false, field: nil)
|
def replace_default_variables(value, attrs, submission, with_time: false, field: nil)
|
||||||
return value if value.in?([true, false]) || value.is_a?(Numeric) || value.is_a?(Array)
|
return value if value.in?([true, false]) || value.is_a?(Numeric) || value.is_a?(Array)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ module Templates
|
|||||||
module ReplaceAttachments
|
module ReplaceAttachments
|
||||||
module_function
|
module_function
|
||||||
|
|
||||||
# rubocop:disable Metrics
|
# rubocop:disable-next Metrics
|
||||||
def call(template, params = {}, extract_fields: false)
|
def call(template, params = {}, extract_fields: false)
|
||||||
documents, = Templates::CreateAttachments.call(template, params, extract_fields:)
|
documents, = Templates::CreateAttachments.call(template, params, extract_fields:)
|
||||||
submitter = template.submitters.first
|
submitter = template.submitters.first
|
||||||
@@ -60,6 +60,5 @@ module Templates
|
|||||||
|
|
||||||
documents
|
documents
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
+1
-1
@@ -54,7 +54,7 @@ module WebhookUrls
|
|||||||
webhook_urls = for_account_id(account_id, event_type)
|
webhook_urls = for_account_id(account_id, event_type)
|
||||||
|
|
||||||
account_records.each do |record|
|
account_records.each do |record|
|
||||||
event_uuid = SecureRandom.uuid
|
event_uuid = SecureRandom.uuid_v7
|
||||||
|
|
||||||
webhook_urls.each do |webhook_url|
|
webhook_urls.each do |webhook_url|
|
||||||
next unless webhook_url.events.include?(event_type)
|
next unless webhook_url.events.include?(event_type)
|
||||||
|
|||||||
Reference in new issue
Block a user