Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ae891932c5 | |||
| a8b5e00814 | |||
| e98432d7e4 | |||
| 29ff58ed98 | |||
| a621575ffc | |||
| d7c7efc203 | |||
| 4f013ca927 | |||
| d9823feef7 | |||
| 676d775544 | |||
| 840ad17258 | |||
| ce0cd09b70 | |||
| bb752fbc00 | |||
| c71fb04404 | |||
| e856cf8787 | |||
| 71aae65bc6 | |||
| 7a33444f9b | |||
| e12ec9d986 | |||
| 94d1fb7dcb | |||
| 6e43a42274 | |||
| 0e0aa0259e | |||
| 75ab6d39ef | |||
| 6f84d84f96 | |||
| cf46593e9b | |||
| 1808346348 | |||
| ea59a68499 | |||
| cba2d02990 | |||
| e92fc0d3e1 | |||
| f1eaa77092 | |||
| 5934bdec55 | |||
| 7a7d3c6ee3 | |||
| cb2f58c04c | |||
| a1c117f1ca |
@@ -1,27 +1,14 @@
|
||||
name: Build Docker Images
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: Version
|
||||
type: string
|
||||
required: true
|
||||
image:
|
||||
description: QEMU image
|
||||
type: string
|
||||
required: false
|
||||
default: tonistiigi/binfmt:latest
|
||||
os:
|
||||
description: OS
|
||||
type: string
|
||||
required: false
|
||||
default: ubuntu-24.04-arm
|
||||
push:
|
||||
tags:
|
||||
- "*.*.*"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ inputs.os }}
|
||||
timeout-minutes: 20
|
||||
runs-on: ubuntu-24.04-arm
|
||||
timeout-minutes: 30
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
@@ -34,18 +21,16 @@ jobs:
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: docuseal/docuseal
|
||||
tags: latest,${{ inputs.version }}
|
||||
tags: type=semver,pattern={{version}}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
with:
|
||||
image: ${{ inputs.image }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Create .version file
|
||||
run: echo ${{ inputs.version }} > .version
|
||||
run: echo ${{ github.ref_name }} > .version
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
|
||||
@@ -9,7 +9,7 @@ RUN apk --no-cache add fontforge wget && \
|
||||
wget https://cdn.jsdelivr.net/gh/notofonts/notofonts.github.io/fonts/NotoSansSymbols2/hinted/ttf/NotoSansSymbols2-Regular.ttf && \
|
||||
wget https://github.com/Maxattax97/gnu-freefont/raw/master/ttf/FreeSans.ttf && \
|
||||
wget https://github.com/impallari/DancingScript/raw/master/OFL.txt && \
|
||||
wget -O /model.onnx "https://github.com/docusealco/fields-detection/releases/download/1.0.0/model_704_int8.onnx" && \
|
||||
wget -O /model.onnx "https://github.com/docusealco/fields-detection/releases/download/1.1.0/model_704_int8.onnx" && \
|
||||
wget -O pdfium-linux.tgz "https://github.com/docusealco/pdfium-binaries/releases/latest/download/pdfium-linux-$(uname -m | sed 's/x86_64/x64/;s/aarch64/arm64/').tgz" && \
|
||||
mkdir -p /pdfium-linux && \
|
||||
tar -xzf pdfium-linux.tgz -C /pdfium-linux
|
||||
@@ -90,7 +90,7 @@ COPY --from=download /model.onnx /app/tmp/model.onnx
|
||||
COPY --from=webpack /app/public/packs ./public/packs
|
||||
|
||||
RUN ln -s /fonts /app/public/fonts
|
||||
RUN bundle exec bootsnap precompile --gemfile app/ lib/
|
||||
RUN bundle exec bootsnap precompile -j 1 --gemfile app/ lib/
|
||||
|
||||
WORKDIR /data/docuseal
|
||||
ENV WORKDIR=/data/docuseal
|
||||
|
||||
@@ -37,7 +37,7 @@ module Api
|
||||
rescue Submitters::MaliciousFileExtension => e
|
||||
Rollbar.error(e) if defined?(Rollbar)
|
||||
|
||||
render json: { error: e.message }, status: :unprocessable_entity
|
||||
render json: { error: e.message }, status: :unprocessable_content
|
||||
end
|
||||
|
||||
def build_new_cookie_signatures_json(submitter, attachment)
|
||||
|
||||
@@ -182,13 +182,13 @@ module Api
|
||||
def submissions_params
|
||||
permitted_attrs = [
|
||||
:send_email, :send_sms, :bcc_completed, :completed_redirect_url, :reply_to, :go_to_last,
|
||||
:require_phone_2fa, :expire_at, :name,
|
||||
:require_phone_2fa, :require_email_2fa, :expire_at, :name,
|
||||
{
|
||||
variables: {},
|
||||
message: %i[subject body],
|
||||
submitters: [[:send_email, :send_sms, :completed_redirect_url, :uuid, :name, :email, :role,
|
||||
:completed, :phone, :application_key, :external_id, :reply_to, :go_to_last,
|
||||
:require_phone_2fa, :order,
|
||||
:require_phone_2fa, :require_email_2fa, :order, :invite_by,
|
||||
{ metadata: {}, values: {}, roles: [], readonly_fields: [], message: %i[subject body],
|
||||
fields: [:name, :uuid, :default_value, :value, :title, :description,
|
||||
:readonly, :required, :validation_pattern, :invalid_message,
|
||||
|
||||
@@ -84,7 +84,7 @@ module Api
|
||||
|
||||
submitter_params.permit(
|
||||
:send_email, :send_sms, :reply_to, :completed_redirect_url, :uuid, :name, :email, :role,
|
||||
:completed, :phone, :application_key, :external_id, :go_to_last, :require_phone_2fa,
|
||||
:completed, :phone, :application_key, :external_id, :go_to_last, :require_phone_2fa, :require_email_2fa,
|
||||
{ metadata: {}, values: {}, readonly_fields: [], message: %i[subject body],
|
||||
fields: [[:name, :uuid, :default_value, :value, :required,
|
||||
:readonly, :validation_pattern, :invalid_message,
|
||||
|
||||
@@ -5,6 +5,8 @@ class PasswordsController < Devise::PasswordsController
|
||||
skip_before_action :require_no_authentication, only: %i[edit update]
|
||||
# rubocop:enable Rails/LexicallyScopedActionFilter
|
||||
|
||||
around_action :with_browser_locale
|
||||
|
||||
class Current < ActiveSupport::CurrentAttributes
|
||||
attribute :user
|
||||
end
|
||||
|
||||
@@ -16,7 +16,9 @@ class StartFormController < ApplicationController
|
||||
COOKIES_DEFAULTS = { httponly: true, secure: Rails.env.production? }.freeze
|
||||
|
||||
def show
|
||||
raise ActionController::RoutingError, I18n.t('not_found') if @template.preferences['require_phone_2fa']
|
||||
if @template.preferences['require_phone_2fa'] || @template.preferences['require_email_2fa']
|
||||
raise ActionController::RoutingError, I18n.t('not_found')
|
||||
end
|
||||
|
||||
if @template.shared_link?
|
||||
@submitter = @template.submissions.new(account_id: @template.account_id)
|
||||
|
||||
@@ -10,6 +10,7 @@ class SubmissionEventsController < ApplicationController
|
||||
'api_complete_form' => 'check',
|
||||
'send_reminder_email' => 'mail_forward',
|
||||
'send_2fa_sms' => '2fa',
|
||||
'send_2fa_email' => '2fa',
|
||||
'send_sms' => 'send',
|
||||
'phone_verified' => 'phone_check',
|
||||
'email_verified' => 'email_check',
|
||||
|
||||
@@ -12,6 +12,14 @@ class SubmissionsController < ApplicationController
|
||||
authorize!(:create, Submission)
|
||||
end
|
||||
|
||||
FIELD_ICONS = {
|
||||
'text' => 'text_size', 'signature' => 'writing_sign', 'date' => 'calendar_event',
|
||||
'number' => 'square_number_1', 'image' => 'photo', 'initials' => 'letter_case_upper',
|
||||
'file' => 'paperclip', 'select' => 'select', 'checkbox' => 'checkbox', 'radio' => 'circle_dot',
|
||||
'stamp' => 'rubber_stamp', 'cells' => 'columns_3', 'multiple' => 'checks', 'phone' => 'phone_check',
|
||||
'payment' => 'credit_card', 'verification' => 'id'
|
||||
}.freeze
|
||||
|
||||
def show
|
||||
@submission = Submissions.preload_with_pages(@submission)
|
||||
|
||||
|
||||
@@ -53,8 +53,11 @@ class SubmissionsPreviewController < ApplicationController
|
||||
|
||||
def use_signature?(submission)
|
||||
return false if current_user && can?(:read, submission)
|
||||
return true if submission.submitters.any? { |e| e.preferences['require_phone_2fa'] }
|
||||
return true if submission.submitters.any? do |e|
|
||||
e.preferences['require_phone_2fa'] || e.preferences['require_email_2fa']
|
||||
end
|
||||
return true if submission.template&.preferences&.dig('require_phone_2fa')
|
||||
return true if submission.template&.preferences&.dig('require_email_2fa')
|
||||
|
||||
!submission_valid_ttl?(submission)
|
||||
end
|
||||
|
||||
@@ -17,6 +17,7 @@ class SubmitFormController < ApplicationController
|
||||
submission = @submitter.submission
|
||||
|
||||
return redirect_to submit_form_completed_path(@submitter.slug) if @submitter.completed_at?
|
||||
return render :email_2fa if require_email_2fa?(@submitter)
|
||||
|
||||
@form_configs = Submitters::FormConfigs.call(@submitter, CONFIG_KEYS)
|
||||
|
||||
@@ -47,6 +48,11 @@ class SubmitFormController < ApplicationController
|
||||
end
|
||||
|
||||
def update
|
||||
if require_email_2fa?(@submitter)
|
||||
return render json: { error: I18n.t('verification_required_refresh_the_page_and_pass_2fa') },
|
||||
status: :unprocessable_content
|
||||
end
|
||||
|
||||
if @submitter.completed_at?
|
||||
return render json: { error: I18n.t('form_has_been_completed_already') }, status: :unprocessable_content
|
||||
end
|
||||
@@ -77,6 +83,8 @@ class SubmitFormController < ApplicationController
|
||||
|
||||
def completed
|
||||
raise ActionController::RoutingError, I18n.t('not_found') if @submitter.account.archived_at?
|
||||
|
||||
redirect_to submit_form_path(params[:submit_form_slug]) if require_email_2fa?(@submitter)
|
||||
end
|
||||
|
||||
def success; end
|
||||
@@ -109,4 +117,12 @@ class SubmitFormController < ApplicationController
|
||||
ActiveStorage::Attachment.where(record: submission.submitters, name: :attachments)
|
||||
.preload(:blob).index_by(&:uuid)
|
||||
end
|
||||
|
||||
def require_email_2fa?(submitter)
|
||||
return false if submitter.submission.template&.preferences&.dig('require_email_2fa') != true &&
|
||||
submitter.preferences['require_email_2fa'] != true
|
||||
return false if cookies.encrypted[:email_2fa_slug] == submitter.slug
|
||||
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class SubmitFormEmail2fasController < ApplicationController
|
||||
around_action :with_browser_locale
|
||||
|
||||
skip_before_action :authenticate_user!
|
||||
skip_authorization_check
|
||||
|
||||
before_action :load_submitter
|
||||
|
||||
COOKIES_TTL = 12.hours
|
||||
COOKIES_DEFAULTS = { httponly: true, secure: Rails.env.production? }.freeze
|
||||
|
||||
def create
|
||||
RateLimit.call("verify-2fa-code-#{@submitter.id}", limit: 2, ttl: 45.seconds, enabled: true)
|
||||
|
||||
value = [@submitter.email.downcase.strip, @submitter.slug].join(':')
|
||||
|
||||
if EmailVerificationCodes.verify(params[:one_time_code].to_s.gsub(/\D/, ''), value)
|
||||
SubmissionEvents.create_with_tracking_data(@submitter, 'email_verified', request, { email: @submitter.email })
|
||||
|
||||
cookies.encrypted[:email_2fa_slug] =
|
||||
{ value: @submitter.slug, expires: COOKIES_TTL.from_now, **COOKIES_DEFAULTS }
|
||||
|
||||
redirect_to submit_form_path(@submitter.slug)
|
||||
else
|
||||
redirect_to submit_form_path(@submitter.slug, status: :error), alert: I18n.t(:invalid_code)
|
||||
end
|
||||
rescue RateLimit::LimitApproached
|
||||
redirect_to submit_form_path(@submitter.slug, status: :error), alert: I18n.t(:too_many_attempts)
|
||||
end
|
||||
|
||||
def update
|
||||
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)
|
||||
end
|
||||
|
||||
RateLimit.call("send-email-code-#{@submitter.id}", limit: 2, ttl: 45.seconds, enabled: true)
|
||||
|
||||
SendSubmitterVerificationEmailJob.perform_async('submitter_id' => @submitter.id, 'locale' => I18n.locale.to_s)
|
||||
|
||||
redir_params = params[:resend] ? { alert: I18n.t(:code_has_been_resent) } : {}
|
||||
|
||||
redirect_to submit_form_path(@submitter.slug, status: :sent), **redir_params
|
||||
rescue RateLimit::LimitApproached
|
||||
redirect_to submit_form_path(@submitter.slug, status: :error), alert: I18n.t(:too_many_attempts)
|
||||
end
|
||||
|
||||
def load_submitter
|
||||
@submitter = Submitter.find_by!(slug: params[:submitter_slug])
|
||||
end
|
||||
end
|
||||
@@ -54,7 +54,7 @@ class TemplatesPreferencesController < ApplicationController
|
||||
documents_copy_email_attach_documents documents_copy_email_reply_to
|
||||
completed_notification_email_attach_documents
|
||||
completed_redirect_url validate_unique_submitters
|
||||
require_all_submitters submitters_order require_phone_2fa
|
||||
require_all_submitters submitters_order require_phone_2fa require_email_2fa
|
||||
default_expire_at_duration shared_link_2fa default_expire_at request_email_enabled
|
||||
completed_notification_email_subject completed_notification_email_body
|
||||
completed_notification_email_enabled completed_notification_email_attach_audit] +
|
||||
|
||||
@@ -54,7 +54,8 @@ class UsersController < ApplicationController
|
||||
def update
|
||||
return redirect_to settings_users_path, notice: I18n.t('unable_to_update_user') if Docuseal.demo?
|
||||
|
||||
attrs = user_params.compact_blank.merge(user_params.slice(:archived_at))
|
||||
attrs = user_params.compact_blank
|
||||
attrs = attrs.merge(user_params.slice(:archived_at)) if current_ability.can?(:create, @user)
|
||||
|
||||
if params.dig(:user, :account_id).present?
|
||||
account = Account.accessible_by(current_ability).find(params.dig(:user, :account_id))
|
||||
|
||||
@@ -133,6 +133,12 @@
|
||||
name="_method"
|
||||
type="hidden"
|
||||
>
|
||||
<input
|
||||
v-if="validate === false"
|
||||
value="false"
|
||||
name="validate"
|
||||
type="hidden"
|
||||
>
|
||||
<div class="md:mt-4">
|
||||
<div v-if="['cells', 'text'].includes(currentField.type)">
|
||||
<TextStep
|
||||
@@ -351,8 +357,6 @@
|
||||
class="base-checkbox !h-7 !w-7"
|
||||
:required="field.required"
|
||||
:checked="!!values[field.uuid]"
|
||||
@invalid="$event.target.setCustomValidity(t('please_check_the_box_to_continue'))"
|
||||
@change="$event.target.setCustomValidity($event.target.validity.valueMissing ? t('please_check_the_box_to_continue') : '')"
|
||||
@click="[scrollIntoField(field), values[field.uuid] = !values[field.uuid]]"
|
||||
>
|
||||
<span
|
||||
@@ -533,7 +537,7 @@
|
||||
/>
|
||||
<div
|
||||
v-if="stepFields.length < 80"
|
||||
class="flex justify-center mt-3 sm:mt-4 mb-0 sm:mb-1"
|
||||
class="flex justify-center mt-3 sm:mt-4 mb-0 sm:mb-1 select-none"
|
||||
>
|
||||
<div class="flex items-center flex-wrap steps-progress">
|
||||
<a
|
||||
@@ -718,6 +722,11 @@ export default {
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
validate: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true
|
||||
},
|
||||
withDisclosure: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
|
||||
@@ -13,7 +13,7 @@ const en = {
|
||||
esignature_disclosure: 'eSignature Disclosure',
|
||||
signature: 'Signature',
|
||||
initials: 'Initials',
|
||||
drawn_signature_on_a_touchscreen_device: 'Drawn signature on a touchscreen device',
|
||||
sign_on_the_touchscreen: 'Sign on the touchscreen',
|
||||
approved: 'Approved',
|
||||
reviewed: 'Reviewed',
|
||||
other: 'Other',
|
||||
@@ -120,7 +120,7 @@ const es = {
|
||||
select_a_reason: 'Selecciona una razón',
|
||||
value_is_invalid: 'El valor no es válido',
|
||||
verification_code_is_invalid: 'El código de verificación no es válido',
|
||||
drawn_signature_on_a_touchscreen_device: 'Firma dibujada en un dispositivo con pantalla táctil',
|
||||
sign_on_the_touchscreen: 'Firmar en pantalla táctil',
|
||||
scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: 'Escanea el código QR con la aplicación de la cámara para abrir el formulario en el móvil y dibujar tu firma',
|
||||
by_clicking_you_agree_to_the: 'Al hacer clic en "{button}", usted acepta el',
|
||||
electronic_signature_disclosure: 'Divulgación de Firma Electrónica',
|
||||
@@ -221,7 +221,7 @@ const it = {
|
||||
select_a_reason: 'Seleziona una ragione',
|
||||
value_is_invalid: 'Il valore non è valido',
|
||||
verification_code_is_invalid: 'Il codice di verifica non è valido',
|
||||
drawn_signature_on_a_touchscreen_device: 'Firma disegnata su un dispositivo con schermo tattile',
|
||||
sign_on_the_touchscreen: 'Firma su schermo tattile',
|
||||
scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: "Scansiona il codice QR con l'app della fotocamera per aprire il modulo sul cellulare e disegnare la tua firma",
|
||||
by_clicking_you_agree_to_the: 'Cliccando su "{button}", accetti il',
|
||||
electronic_signature_disclosure: 'Divulgazione della Firma Elettronica',
|
||||
@@ -316,7 +316,7 @@ const de = {
|
||||
esignature_disclosure: 'Hinweis zur eSignatur',
|
||||
signature: 'Unterschrift',
|
||||
initials: 'Initialen',
|
||||
drawn_signature_on_a_touchscreen_device: 'Auf einem Touchscreen-Gerät gezeichnete Unterschrift',
|
||||
sign_on_the_touchscreen: 'Auf Touchscreen signieren',
|
||||
approved: 'Genehmigt',
|
||||
reviewed: 'Geprüft',
|
||||
other: 'Sonstiges',
|
||||
@@ -417,7 +417,7 @@ const fr = {
|
||||
esignature_disclosure: 'Déclaration eSignature',
|
||||
signature: 'Signature',
|
||||
initials: 'Initiales',
|
||||
drawn_signature_on_a_touchscreen_device: 'Signature dessinée sur un appareil à écran tactile',
|
||||
sign_on_the_touchscreen: 'Signer sur écran tactile',
|
||||
approved: 'Approuvé',
|
||||
reviewed: 'Révisé',
|
||||
other: 'Autre',
|
||||
@@ -524,7 +524,7 @@ const pl = {
|
||||
select_a_reason: 'Wybierz powód',
|
||||
value_is_invalid: 'Wartość jest nieprawidłowa',
|
||||
verification_code_is_invalid: 'Kod weryfikacyjny jest nieprawidłowy',
|
||||
drawn_signature_on_a_touchscreen_device: 'Podpis odręczny na urządzeniu z ekranem dotykowym',
|
||||
sign_on_the_touchscreen: 'Podpisz na ekranie dotykowym',
|
||||
scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: 'Zeskanuj kod QR za pomocą aplikacji aparatu, aby otworzyć formularz na telefonie i narysować swój podpis',
|
||||
by_clicking_you_agree_to_the: 'Klikając na "{button}", zgadzasz się na',
|
||||
electronic_signature_disclosure: 'Ujawnienie Elektronicznej Sygnatury',
|
||||
@@ -625,7 +625,7 @@ const uk = {
|
||||
select_a_reason: 'Виберіть причину',
|
||||
value_is_invalid: 'Значення є неправильним',
|
||||
verification_code_is_invalid: 'Код підтвердження є неправильним',
|
||||
drawn_signature_on_a_touchscreen_device: 'Підпис на сенсорному пристрої',
|
||||
sign_on_the_touchscreen: 'Підписати на сенсорному екрані',
|
||||
scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: 'Скануйте QR-код за допомогою програми камери, щоб відкрити форму на мобільному пристрої та намалювати свій підпис',
|
||||
by_clicking_you_agree_to_the: 'Натиснувши на "{button}", ви погоджуєтеся з',
|
||||
electronic_signature_disclosure: 'Розголошення Електронного Підпису',
|
||||
@@ -726,7 +726,7 @@ const cs = {
|
||||
select_a_reason: 'Vyberte důvod',
|
||||
value_is_invalid: 'Hodnota je neplatná',
|
||||
verification_code_is_invalid: 'Ověřovací kód je neplatný',
|
||||
drawn_signature_on_a_touchscreen_device: 'Namalovaný podpis na dotykovém zařízení',
|
||||
sign_on_the_touchscreen: 'Podepsat na dotykové obrazovce',
|
||||
scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: 'Naskenujte QR kód pomocí aplikace fotoaparátu, abyste otevřeli formulář na mobilním zařízení a nakreslili svůj podpis',
|
||||
by_clicking_you_agree_to_the: 'Kliknutím na "{button}" souhlasíte s',
|
||||
electronic_signature_disclosure: 'Zveřejněním Elektronického Podpisu',
|
||||
@@ -827,7 +827,7 @@ const pt = {
|
||||
select_a_reason: 'Selecione um motivo',
|
||||
value_is_invalid: 'Valor é inválido',
|
||||
verification_code_is_invalid: 'Código de verificação é inválido',
|
||||
drawn_signature_on_a_touchscreen_device: 'Assinatura desenhada em um dispositivo com tela sensível ao toque',
|
||||
sign_on_the_touchscreen: 'Assinar na tela sensível',
|
||||
scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: 'Escaneie o código QR com o aplicativo da câmera para abrir o formulário no celular e desenhar sua assinatura',
|
||||
by_clicking_you_agree_to_the: 'Ao clicar em "{button}", você concorda com o',
|
||||
electronic_signature_disclosure: 'Divulgação de Assinatura Eletrônica',
|
||||
@@ -928,7 +928,7 @@ const he = {
|
||||
select_a_reason: 'בחר סיבה',
|
||||
value_is_invalid: 'ערך לא תקין',
|
||||
verification_code_is_invalid: 'קוד האימות אינו תקין',
|
||||
drawn_signature_on_a_touchscreen_device: 'חתימה שנוצרה במכשיר עם מסך מגע',
|
||||
sign_on_the_touchscreen: 'חתום על מסך המגע',
|
||||
scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: 'סרוק את קוד ה-QR באמצעות אפליקציית המצלמה כדי לפתוח את הטופס במובייל ולצייר את החתימה שלך',
|
||||
by_clicking_you_agree_to_the: 'על ידי לחיצה על "{button}", אתה מסכים ל',
|
||||
electronic_signature_disclosure: 'חשיפת חתימה אלקטרונית',
|
||||
@@ -1029,7 +1029,7 @@ const nl = {
|
||||
select_a_reason: 'Selecteer een reden',
|
||||
value_is_invalid: 'Waarde is ongeldig',
|
||||
verification_code_is_invalid: 'Verificatiecode is ongeldig',
|
||||
drawn_signature_on_a_touchscreen_device: 'Getekende handtekening op een apparaat met een touchscreen',
|
||||
sign_on_the_touchscreen: 'Onderteken op touchscreen',
|
||||
scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: 'Scan de QR-code met de camera-app om het formulier op mobiel te openen en uw handtekening te tekenen',
|
||||
by_clicking_you_agree_to_the: 'Door op "{button}" te klikken, gaat u akkoord met de',
|
||||
electronic_signature_disclosure: 'Openbaarmaking van Elektronische Handtekening',
|
||||
@@ -1131,7 +1131,7 @@ const ar = {
|
||||
value_is_invalid: 'القيمة غير صالحة',
|
||||
verification_code_is_invalid: 'رمز التحقق غير صالح',
|
||||
already_paid: 'تم الدفع بالفعل',
|
||||
drawn_signature_on_a_touchscreen_device: 'توقيع مرسوم على جهاز بشاشة تعمل باللمس',
|
||||
sign_on_the_touchscreen: 'وقع على شاشة اللمس',
|
||||
scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: 'امسح رمز الاستجابة السريعة باستخدام تطبيق الكاميرا لفتح النموذج على الهاتف المحمول ورسم توقيعك',
|
||||
by_clicking_you_agree_to_the: 'بالنقر فوق "{button}"، أنت توافق على',
|
||||
electronic_signature_disclosure: 'كشف التوقيع الإلكتروني',
|
||||
@@ -1229,7 +1229,7 @@ const ko = {
|
||||
reviewed_by: '검토자',
|
||||
authored_by: '작성자',
|
||||
select_a_reason: '이유 선택',
|
||||
drawn_signature_on_a_touchscreen_device: '터치스크린 장치에서 그린 서명',
|
||||
sign_on_the_touchscreen: '터치스크린에서 서명',
|
||||
scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: '카메라 앱으로 QR 코드를 스캔하여 모바일에서 양식을 열고 서명을 그리세요',
|
||||
by_clicking_you_agree_to_the: '"{button}"를 클릭함으로써, 다음에 동의하게 됩니다',
|
||||
electronic_signature_disclosure: '전자 서명 공개',
|
||||
@@ -1326,7 +1326,7 @@ const ja = {
|
||||
esignature_disclosure: '電子署名開示',
|
||||
signature: '署名',
|
||||
initials: 'イニシャル',
|
||||
drawn_signature_on_a_touchscreen_device: 'タッチスクリーンデバイスで描かれた署名',
|
||||
sign_on_the_touchscreen: 'タッチスクリーンで署名',
|
||||
approved: '承認済み',
|
||||
reviewed: '確認済み',
|
||||
other: 'その他',
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<div class="space-x-2 flex flex-none">
|
||||
<span
|
||||
v-if="isDrawInitials"
|
||||
class="tooltip"
|
||||
class="md:tooltip"
|
||||
:data-tip="t('type_initial')"
|
||||
>
|
||||
<a
|
||||
@@ -36,7 +36,7 @@
|
||||
</span>
|
||||
<span
|
||||
v-else
|
||||
class="tooltip ml-2"
|
||||
class="md:tooltip ml-2"
|
||||
:data-tip="t('draw_initials')"
|
||||
>
|
||||
<a
|
||||
@@ -52,7 +52,7 @@
|
||||
</a>
|
||||
</span>
|
||||
<span
|
||||
class="tooltip"
|
||||
class="md:tooltip"
|
||||
:data-tip="t('click_to_upload')"
|
||||
>
|
||||
<label class="btn btn-outline btn-sm font-medium inline-flex flex-nowrap upload-image-button">
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<div class="space-x-2 flex flex-none">
|
||||
<span
|
||||
v-if="isTextSignature && format !== 'typed_or_upload' && format !== 'typed' && format !== 'upload'"
|
||||
class="tooltip"
|
||||
class="md:tooltip"
|
||||
:data-tip="t('draw_signature')"
|
||||
>
|
||||
<a
|
||||
@@ -39,7 +39,7 @@
|
||||
</span>
|
||||
<span
|
||||
v-else-if="withTypedSignature && format !== 'drawn_or_upload' && format !== 'typed_or_upload' && format !== 'typed' && format !== 'drawn' && format !== 'upload'"
|
||||
class="tooltip ml-2"
|
||||
class="md:tooltip ml-2"
|
||||
:class="{ 'hidden sm:inline': modelValue || computedPreviousValue }"
|
||||
:data-tip="t('type_text')"
|
||||
>
|
||||
@@ -57,7 +57,7 @@
|
||||
</span>
|
||||
<span
|
||||
v-if="format !== 'typed' && format !== 'drawn' && format !== 'upload' && format !== 'drawn_or_typed'"
|
||||
class="tooltip"
|
||||
class="md:tooltip"
|
||||
:class="{ 'hidden sm:inline': modelValue || computedPreviousValue }"
|
||||
:data-tip="t('take_photo')"
|
||||
>
|
||||
@@ -86,8 +86,8 @@
|
||||
</a>
|
||||
<span
|
||||
v-if="withQrButton && !modelValue && !computedPreviousValue && format !== 'typed_or_upload' && format !== 'typed' && format !== 'upload'"
|
||||
class="tooltip before:translate-x-[-90%]"
|
||||
:data-tip="t('drawn_signature_on_a_touchscreen_device')"
|
||||
class="md:tooltip before:translate-x-[-90%]"
|
||||
:data-tip="t('sign_on_the_touchscreen')"
|
||||
>
|
||||
<a
|
||||
href="#"
|
||||
@@ -142,7 +142,7 @@
|
||||
/>
|
||||
<div
|
||||
v-else
|
||||
class="relative"
|
||||
class="relative select-none"
|
||||
>
|
||||
<div
|
||||
v-if="!modelValue && !computedPreviousValue && !isShowQr && !isTextSignature && isSignatureStarted"
|
||||
@@ -176,7 +176,7 @@
|
||||
class="top-0 bottom-0 right-0 left-0 absolute bg-base-content/10 rounded-2xl"
|
||||
>
|
||||
<div
|
||||
class="absolute top-1.5 right-1.5 tooltip"
|
||||
class="absolute top-1.5 right-1.5 md:tooltip"
|
||||
>
|
||||
<a
|
||||
href="#"
|
||||
@@ -281,7 +281,7 @@
|
||||
<div
|
||||
v-else-if="withDisclosure"
|
||||
dir="auto"
|
||||
class="text-base-content/60 text-xs text-center w-full mt-1"
|
||||
class="text-base-content/60 text-xs text-center w-full mt-1 select-none"
|
||||
>
|
||||
{{ t('by_clicking_you_agree_to_the').replace('{button}', buttonText.charAt(0).toUpperCase() + buttonText.slice(1)) }} <a
|
||||
href="https://www.docuseal.com/esign-disclosure"
|
||||
|
||||
@@ -49,7 +49,12 @@
|
||||
</li>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div
|
||||
v-if="fieldTypes.length && submitterDefaultFields.length"
|
||||
class="bg-base-300"
|
||||
style="height: 1px; margin-top: 1px; margin-bottom: 1px"
|
||||
/>
|
||||
<template v-if="fieldTypes.length || !submitterDefaultFields.length">
|
||||
<template
|
||||
v-for="(icon, type) in fieldIconsSorted"
|
||||
:key="type"
|
||||
|
||||
@@ -4,7 +4,9 @@ class ProcessSubmissionExpiredJob
|
||||
include Sidekiq::Job
|
||||
|
||||
def perform(params = {})
|
||||
submission = Submission.find(params['submission_id'])
|
||||
submission = Submission.find_by(id: params['submission_id'])
|
||||
|
||||
return unless submission
|
||||
|
||||
return if submission.archived_at?
|
||||
return if submission.template&.archived_at?
|
||||
|
||||
@@ -8,8 +8,13 @@ class SendFormCompletedWebhookRequestJob
|
||||
MAX_ATTEMPTS = 12
|
||||
|
||||
def perform(params = {})
|
||||
submitter = Submitter.find(params['submitter_id'])
|
||||
webhook_url = WebhookUrl.find(params['webhook_url_id'])
|
||||
submitter = Submitter.find_by(id: params['submitter_id'])
|
||||
|
||||
return unless submitter
|
||||
|
||||
webhook_url = WebhookUrl.find_by(id: params['webhook_url_id'])
|
||||
|
||||
return unless webhook_url
|
||||
|
||||
attempt = params['attempt'].to_i
|
||||
|
||||
|
||||
@@ -8,8 +8,13 @@ class SendFormDeclinedWebhookRequestJob
|
||||
MAX_ATTEMPTS = 10
|
||||
|
||||
def perform(params = {})
|
||||
submitter = Submitter.find(params['submitter_id'])
|
||||
webhook_url = WebhookUrl.find(params['webhook_url_id'])
|
||||
submitter = Submitter.find_by(id: params['submitter_id'])
|
||||
|
||||
return unless submitter
|
||||
|
||||
webhook_url = WebhookUrl.find_by(id: params['webhook_url_id'])
|
||||
|
||||
return unless webhook_url
|
||||
|
||||
attempt = params['attempt'].to_i
|
||||
|
||||
|
||||
@@ -8,8 +8,13 @@ class SendFormStartedWebhookRequestJob
|
||||
MAX_ATTEMPTS = 10
|
||||
|
||||
def perform(params = {})
|
||||
submitter = Submitter.find(params['submitter_id'])
|
||||
webhook_url = WebhookUrl.find(params['webhook_url_id'])
|
||||
submitter = Submitter.find_by(id: params['submitter_id'])
|
||||
|
||||
return unless submitter
|
||||
|
||||
webhook_url = WebhookUrl.find_by(id: params['webhook_url_id'])
|
||||
|
||||
return unless webhook_url
|
||||
|
||||
attempt = params['attempt'].to_i
|
||||
|
||||
|
||||
@@ -8,8 +8,13 @@ class SendFormViewedWebhookRequestJob
|
||||
MAX_ATTEMPTS = 10
|
||||
|
||||
def perform(params = {})
|
||||
submitter = Submitter.find(params['submitter_id'])
|
||||
webhook_url = WebhookUrl.find(params['webhook_url_id'])
|
||||
submitter = Submitter.find_by(id: params['submitter_id'])
|
||||
|
||||
return unless submitter
|
||||
|
||||
webhook_url = WebhookUrl.find_by(id: params['webhook_url_id'])
|
||||
|
||||
return unless webhook_url
|
||||
|
||||
attempt = params['attempt'].to_i
|
||||
|
||||
|
||||
@@ -8,8 +8,13 @@ class SendSubmissionArchivedWebhookRequestJob
|
||||
MAX_ATTEMPTS = 10
|
||||
|
||||
def perform(params = {})
|
||||
submission = Submission.find(params['submission_id'])
|
||||
webhook_url = WebhookUrl.find(params['webhook_url_id'])
|
||||
submission = Submission.find_by(id: params['submission_id'])
|
||||
|
||||
return unless submission
|
||||
|
||||
webhook_url = WebhookUrl.find_by(id: params['webhook_url_id'])
|
||||
|
||||
return unless webhook_url
|
||||
|
||||
attempt = params['attempt'].to_i
|
||||
|
||||
|
||||
@@ -8,8 +8,13 @@ class SendSubmissionCompletedWebhookRequestJob
|
||||
MAX_ATTEMPTS = 10
|
||||
|
||||
def perform(params = {})
|
||||
submission = Submission.find(params['submission_id'])
|
||||
webhook_url = WebhookUrl.find(params['webhook_url_id'])
|
||||
submission = Submission.find_by(id: params['submission_id'])
|
||||
|
||||
return unless submission
|
||||
|
||||
webhook_url = WebhookUrl.find_by(id: params['webhook_url_id'])
|
||||
|
||||
return unless webhook_url
|
||||
|
||||
attempt = params['attempt'].to_i
|
||||
|
||||
|
||||
@@ -8,8 +8,13 @@ class SendSubmissionCreatedWebhookRequestJob
|
||||
MAX_ATTEMPTS = 10
|
||||
|
||||
def perform(params = {})
|
||||
submission = Submission.find(params['submission_id'])
|
||||
webhook_url = WebhookUrl.find(params['webhook_url_id'])
|
||||
submission = Submission.find_by(id: params['submission_id'])
|
||||
|
||||
return unless submission
|
||||
|
||||
webhook_url = WebhookUrl.find_by(id: params['webhook_url_id'])
|
||||
|
||||
return unless webhook_url
|
||||
|
||||
attempt = params['attempt'].to_i
|
||||
|
||||
|
||||
@@ -8,8 +8,13 @@ class SendSubmissionExpiredWebhookRequestJob
|
||||
MAX_ATTEMPTS = 10
|
||||
|
||||
def perform(params = {})
|
||||
submission = Submission.find(params['submission_id'])
|
||||
webhook_url = WebhookUrl.find(params['webhook_url_id'])
|
||||
submission = Submission.find_by(id: params['submission_id'])
|
||||
|
||||
return unless submission
|
||||
|
||||
webhook_url = WebhookUrl.find_by(id: params['webhook_url_id'])
|
||||
|
||||
return unless webhook_url
|
||||
|
||||
attempt = params['attempt'].to_i
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class SendSubmitterVerificationEmailJob
|
||||
include Sidekiq::Job
|
||||
|
||||
def perform(params = {})
|
||||
submitter = Submitter.find(params['submitter_id'])
|
||||
|
||||
locale = params['locale'].presence || submitter.account.locale
|
||||
|
||||
SubmitterMailer.otp_verification_email(submitter, locale:).deliver_now!
|
||||
|
||||
SubmissionEvent.create!(submitter_id: params['submitter_id'],
|
||||
event_type: 'send_2fa_email',
|
||||
data: { email: submitter.email })
|
||||
end
|
||||
end
|
||||
@@ -8,8 +8,13 @@ class SendTemplateCreatedWebhookRequestJob
|
||||
MAX_ATTEMPTS = 10
|
||||
|
||||
def perform(params = {})
|
||||
template = Template.find(params['template_id'])
|
||||
webhook_url = WebhookUrl.find(params['webhook_url_id'])
|
||||
template = Template.find_by(id: params['template_id'])
|
||||
|
||||
return unless template
|
||||
|
||||
webhook_url = WebhookUrl.find_by(id: params['webhook_url_id'])
|
||||
|
||||
return unless webhook_url
|
||||
|
||||
attempt = params['attempt'].to_i
|
||||
|
||||
|
||||
@@ -8,8 +8,13 @@ class SendTemplateUpdatedWebhookRequestJob
|
||||
MAX_ATTEMPTS = 10
|
||||
|
||||
def perform(params = {})
|
||||
template = Template.find(params['template_id'])
|
||||
webhook_url = WebhookUrl.find(params['webhook_url_id'])
|
||||
template = Template.find_by(id: params['template_id'])
|
||||
|
||||
return unless template
|
||||
|
||||
webhook_url = WebhookUrl.find_by(id: params['webhook_url_id'])
|
||||
|
||||
return unless webhook_url
|
||||
|
||||
attempt = params['attempt'].to_i
|
||||
|
||||
|
||||
@@ -8,10 +8,13 @@ class SendTestWebhookRequestJob
|
||||
USER_AGENT = 'DocuSeal.com Webhook'
|
||||
|
||||
def perform(params = {})
|
||||
submitter = Submitter.find(params['submitter_id'])
|
||||
webhook_url = WebhookUrl.find(params['webhook_url_id'])
|
||||
submitter = Submitter.find_by(id: params['submitter_id'])
|
||||
|
||||
return unless webhook_url && submitter
|
||||
return unless submitter
|
||||
|
||||
webhook_url = WebhookUrl.find_by(id: params['webhook_url_id'])
|
||||
|
||||
return unless webhook_url
|
||||
|
||||
Faraday.post(webhook_url.url,
|
||||
{
|
||||
|
||||
@@ -144,6 +144,17 @@ class SubmitterMailer < ApplicationMailer
|
||||
end
|
||||
end
|
||||
|
||||
def otp_verification_email(submitter, locale: nil)
|
||||
@submitter = submitter
|
||||
@otp_code = EmailVerificationCodes.generate([submitter.email.downcase.strip, submitter.slug].join(':'))
|
||||
|
||||
assign_message_metadata('otp_verification_email', submitter)
|
||||
|
||||
I18n.with_locale(locale || submitter.account.locale) do
|
||||
mail(to: submitter.email, subject: I18n.t('email_verification'))
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def build_submitter_reply_to(submitter, email_config: nil, documents_copy_email: nil)
|
||||
|
||||
@@ -48,6 +48,7 @@ class SubmissionEvent < ApplicationRecord
|
||||
send_reminder_email: 'send_reminder_email',
|
||||
send_sms: 'send_sms',
|
||||
send_2fa_sms: 'send_2fa_sms',
|
||||
send_2fa_email: 'send_2fa_email',
|
||||
open_email: 'open_email',
|
||||
click_email: 'click_email',
|
||||
click_sms: 'click_sms',
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
<p>Hello <%= @resource.email %>!</p>
|
||||
<p>Someone has requested a link to change your password. You can do this through the link below.</p>
|
||||
<p><%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %></p>
|
||||
<p>If you didn't request this, please ignore this email.</p>
|
||||
<p>Your password won't change until you access the link above and create a new one.</p>
|
||||
<p><%= @resource.first_name.present? ? t('hello_name', name: @resource.first_name) : t('hi_there') %>,</p>
|
||||
<p><%= t('you_requested_to_reset_your_password_use_the_link_below_to_continue') %>:</p>
|
||||
<p><%= link_to t('change_my_password'), edit_password_url(@resource, reset_password_token: @token) %></p>
|
||||
<p><%= t('your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one') %></p>
|
||||
<p><%= t('if_you_didnt_request_this_you_can_ignore_this_email') %></p>
|
||||
<p>
|
||||
<%= t('thanks') %>,<br>
|
||||
<%= Docuseal.product_name %>
|
||||
</p>
|
||||
<% content_for(:remove_attribution, true) %>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M4 5m0 2a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2z"></path>
|
||||
<path d="M16 3l0 4"></path>
|
||||
<path d="M8 3l0 4"></path>
|
||||
<path d="M4 11l16 0"></path>
|
||||
<path d="M8 15h2v2h-2z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 450 B |
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M9 11l3 3l8 -8"></path>
|
||||
<path d="M20 12v6a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2h9"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 346 B |
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M7 12l5 5l10 -10"></path>
|
||||
<path d="M2 12l5 5m5 -5l5 -5"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 303 B |
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M3 3m0 1a1 1 0 0 1 1 -1h16a1 1 0 0 1 1 1v16a1 1 0 0 1 -1 1h-16a1 1 0 0 1 -1 -1zm6 -1v18m6 -18v18"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 343 B |
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M3 5m0 3a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v8a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3z"></path>
|
||||
<path d="M3 10l18 0"></path>
|
||||
<path d="M7 15l.01 0"></path>
|
||||
<path d="M11 15l2 0"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 419 B |
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M3 4m0 3a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v10a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3z"></path>
|
||||
<path d="M9 10m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0"></path>
|
||||
<path d="M15 8l2 0"></path>
|
||||
<path d="M15 12l2 0"></path>
|
||||
<path d="M7 16l10 0"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 478 B |
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M3 19v-10.5a3.5 3.5 0 0 1 7 0v10.5"></path>
|
||||
<path d="M3 13h7"></path>
|
||||
<path d="M14 19v-10.5a3.5 3.5 0 0 1 7 0v10.5"></path>
|
||||
<path d="M14 13h7"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 394 B |
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M15 8h.01"></path>
|
||||
<path d="M3 6a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v12a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3v-12z"></path>
|
||||
<path d="M3 16l5 -5c.928 -.893 2.072 -.893 3 0l5 5"></path>
|
||||
<path d="M14 14l1 -1c.928 -.893 2.072 -.893 3 0l3 3"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 481 B |
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M21 17.85h-18c0 -4.05 1.421 -4.05 3.79 -4.05c5.21 0 1.21 -4.59 1.21 -6.8a4 4 0 1 1 8 0c0 2.21 -4 6.8 1.21 6.8c2.369 0 3.79 0 3.79 4.05z"></path>
|
||||
<path d="M5 21h14"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 411 B |
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M3 3m0 2a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v14a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2z"></path>
|
||||
<path d="M9 11l3 3l3 -3"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 361 B |
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M3 3m0 2a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v14a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2z"></path>
|
||||
<path d="M10 10l2 -2v8"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 360 B |
@@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M3 7v-2h13v2"></path>
|
||||
<path d="M10 5v14"></path>
|
||||
<path d="M12 19h-4"></path>
|
||||
<path d="M15 13v-1h6v1"></path>
|
||||
<path d="M18 12v7"></path>
|
||||
<path d="M17 19h2"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 410 B |
@@ -1,6 +1,6 @@
|
||||
<a target="_blank" href="<%= Docuseal::GITHUB_URL %>" rel="noopener noreferrer nofollow" class="relative flex items-center rounded-full px-2 py-0.5 text-xs leading-4 mt-1 text-base-content border border-base-300 tooltip tooltip-bottom" data-tip="Give a star on GitHub">
|
||||
<span class="flex items-center justify-between space-x-0.5 font-medium">
|
||||
<%= svg_icon('start', class: 'h-3 w-3') %>
|
||||
<span>10k</span>
|
||||
<span>11k</span>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<div class="grid <%= 'md:grid-cols-2 gap-1' if submitters.size == 1 %>">
|
||||
<submitters-autocomplete data-field="email">
|
||||
<linked-input data-target-id="<%= "detailed_email_#{item['linked_to_uuid']}" if item['linked_to_uuid'].present? %>">
|
||||
<input type="email" multiple name="submission[1][submitters][][email]" autocomplete="off" class="base-input !h-10 mt-1.5 w-full" placeholder="<%= "#{t('email')} (#{t('optional')})" %>" value="<%= item['email'].presence || ((params[:selfsign] && index.zero?) || item['is_requester'] ? current_user.email : '') %>" id="detailed_email_<%= item['uuid'] %>">
|
||||
<%= tag.input type: 'email', multiple: true, name: 'submission[1][submitters][][email]', autocomplete: 'off', class: 'base-input !h-10 mt-1.5 w-full', placeholder: (local_assigns[:require_email_2fa] == true ? t(:email) : "#{t('email')} (#{t('optional')})"), value: item['email'].presence || ((params[:selfsign] && index.zero?) || item['is_requester'] ? current_user.email : ''), id: "detailed_email_#{item['uuid']}", required: local_assigns[:require_email_2fa] == true %>
|
||||
</linked-input>
|
||||
</submitters-autocomplete>
|
||||
<% has_phone_field = true %>
|
||||
|
||||
@@ -50,12 +50,13 @@
|
||||
<%= svg_icon('check', class: "aspect-square #{area['w'] > area['h'] ? '!w-auto !h-full' : '!w-full !h-auto'}") %>
|
||||
</div>
|
||||
<% elsif field['type'].in?(%w[multiple radio]) && area['option_uuid'] %>
|
||||
<% option = field['options']&.find { |o| o['uuid'] == area['option_uuid'] } %>
|
||||
<% option_name = option['value'].presence || "Option #{field['options'].index(option) + 1}" %>
|
||||
<% if option && Array.wrap(value).include?(option_name) %>
|
||||
<div class="w-full flex items-center justify-center">
|
||||
<%= svg_icon('check', class: "aspect-square #{area['w'] > area['h'] ? '!w-auto !h-full' : '!w-full !h-auto'}") %>
|
||||
</div>
|
||||
<% if (option = field['options']&.find { |o| o['uuid'] == area['option_uuid'] }) %>
|
||||
<% option_name = option['value'].presence || "Option #{field['options'].index(option) + 1}" %>
|
||||
<% if Array.wrap(value).include?(option_name) %>
|
||||
<div class="w-full flex items-center justify-center">
|
||||
<%= svg_icon('check', class: "aspect-square #{area['w'] > area['h'] ? '!w-auto !h-full' : '!w-full !h-auto'}") %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% elsif field['type'] == 'cells' && area['cell_w'].to_f > 0.0 %>
|
||||
<% cell_width = area['cell_w'] / area['w'] * 100 %>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<% require_phone_2fa = @template.preferences['require_phone_2fa'] == true %>
|
||||
<% require_email_2fa = @template.preferences['require_email_2fa'] == true %>
|
||||
<% prefillable_fields = @template.fields.select { |f| f['prefillable'] } %>
|
||||
<% only_detailed = require_phone_2fa || prefillable_fields.present? %>
|
||||
<% only_detailed = require_phone_2fa || require_email_2fa || prefillable_fields.present? %>
|
||||
<%= 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 ? nil : [t('via_phone'), 'phone'], [t('detailed'), 'detailed'], [t('upload_list'), 'list']].compact %>
|
||||
<toggle-visible data-element-ids="<%= options.map(&:last).to_json %>" class="relative text-center px-2 mt-4 block">
|
||||
@@ -25,7 +26,7 @@
|
||||
</div>
|
||||
<% end %>
|
||||
<div id="detailed" class="<%= 'hidden' unless only_detailed %>">
|
||||
<%= render 'detailed_form', template: @template, require_phone_2fa:, prefillable_fields: %>
|
||||
<%= render 'detailed_form', template: @template, require_phone_2fa:, require_email_2fa:, prefillable_fields: %>
|
||||
</div>
|
||||
<div id="list" class="hidden">
|
||||
<%= render 'list_form', template: @template %>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<% font_scale = 1040.0 / PdfUtils::US_LETTER_W %>
|
||||
<% configs = AccountConfig.where(account_id: @submission.account_id, key: [AccountConfig::COMBINE_PDF_RESULT_KEY, AccountConfig::WITH_SIGNATURE_ID, AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY, AccountConfig::WITH_SIGNATURE_ID_REASON_KEY]) %>
|
||||
<% with_signature_id = configs.find { |e| e.key == AccountConfig::WITH_SIGNATURE_ID }&.value == true %>
|
||||
<% is_combined_enabled = configs.find { |e| e.key == AccountConfig::COMBINE_PDF_RESULT_KEY }&.value == true %>
|
||||
<% is_combined_enabled = configs.find { |e| e.key == AccountConfig::COMBINE_PDF_RESULT_KEY }&.value == true && !@submission.template_fields&.any? { |f| f['type'] == 'verification' } %>
|
||||
<% with_submitter_timezone = configs.find { |e| e.key == AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY }&.value == true %>
|
||||
<% with_signature_id_reason = configs.find { |e| e.key == AccountConfig::WITH_SIGNATURE_ID_REASON_KEY }&.value != false %>
|
||||
<div style="max-width: 1600px" class="mx-auto pl-4">
|
||||
@@ -93,8 +93,10 @@
|
||||
<div class="pr-3.5 pl-0.5">
|
||||
<% fields_index = Templates.build_field_areas_index(@submission.template_fields || @submission.template.fields) %>
|
||||
<% submitters_index = @submission.submitters.index_by(&:uuid) %>
|
||||
<% submitters_order_index = nil %>
|
||||
<% attachments_index = ActiveStorage::Attachment.where(record: @submission.submitters, name: :attachments).preload(:blob).index_by(&:uuid) %>
|
||||
<% page_blob_struct = Struct.new(:url, :metadata, keyword_init: true) %>
|
||||
<% bg_classes = %w[bg-red-100 bg-sky-100 bg-emerald-100 bg-yellow-100 bg-purple-100 bg-pink-100 bg-cyan-100 bg-orange-100 bg-lime-100 bg-indigo-100] %>
|
||||
<% schema.each do |item| %>
|
||||
<% document = @submission.schema_documents.find { |e| e.uuid == item['attachment_uuid'] } %>
|
||||
<% document_annots_index = document.metadata.dig('pdf', 'annotations')&.group_by { |e| e['page'] } || {} %>
|
||||
@@ -111,19 +113,29 @@
|
||||
<% fields_index.dig(document.uuid, index)&.each do |(area, field)| %>
|
||||
<% value = values[field['uuid']].presence || (field['default_value'] != '{{date}}' && field['readonly'] == true && field['conditions'].blank? && field['default_value'].present? ? Submitters::SubmitValues.template_default_value_for_submitter(field['default_value'], @submission.submitters.find { |e| e.uuid == field['submitter_uuid'] }, with_time: false) : nil) %>
|
||||
<% value ||= field['default_value'] if field['type'] == 'heading' %>
|
||||
<% next if value.blank? %>
|
||||
<% submitter = submitters_index[field['submitter_uuid']] %>
|
||||
<% if (mask = field.dig('preferences', 'mask').presence) && signed_in? && can?(:read, @submission) %>
|
||||
<span class="group">
|
||||
<span class="hidden group-hover:inline">
|
||||
<%= render 'submissions/value', font_scale:, area:, field:, attachments_index:, value:, locale: @submission.account.locale, timezone: @submission.account.timezone, submitter:, with_signature_id: %>
|
||||
<% if value.present? %>
|
||||
<% if (mask = field.dig('preferences', 'mask').presence) && signed_in? && can?(:read, @submission) %>
|
||||
<span class="group">
|
||||
<span class="hidden group-hover:inline">
|
||||
<%= render 'submissions/value', font_scale:, area:, field:, attachments_index:, value:, locale: @submission.account.locale, timezone: @submission.account.timezone, submitter:, with_signature_id: %>
|
||||
</span>
|
||||
<span class="group-hover:hidden">
|
||||
<%= render 'submissions/value', font_scale:, area:, field:, attachments_index:, value: Array.wrap(value).map { |e| TextUtils.mask_value(e, mask) }.join(', '), locale: @submission.account.locale, timezone: @submission.account.timezone, submitter:, with_signature_id: %>
|
||||
</span>
|
||||
</span>
|
||||
<span class="group-hover:hidden">
|
||||
<%= render 'submissions/value', font_scale:, area:, field:, attachments_index:, value: Array.wrap(value).map { |e| TextUtils.mask_value(e, mask) }.join(', '), locale: @submission.account.locale, timezone: @submission.account.timezone, submitter:, with_signature_id: %>
|
||||
</span>
|
||||
</span>
|
||||
<% else %>
|
||||
<%= render 'submissions/value', page_width: width, page_height: height, font_scale:, area:, field:, attachments_index:, value: mask.present? ? Array.wrap(value).map { |e| TextUtils.mask_value(e, mask) }.join(', ') : value, locale: @submission.account.locale, timezone: @submission.account.timezone, submitter:, with_signature_id:, with_submitter_timezone:, with_signature_id_reason: %>
|
||||
<% else %>
|
||||
<%= render 'submissions/value', page_width: width, page_height: height, font_scale:, area:, field:, attachments_index:, value: mask.present? ? Array.wrap(value).map { |e| TextUtils.mask_value(e, mask) }.join(', ') : value, locale: @submission.account.locale, timezone: @submission.account.timezone, submitter:, with_signature_id:, with_submitter_timezone:, with_signature_id_reason: %>
|
||||
<% end %>
|
||||
<% elsif field['readonly'] != true && submitter && !submitter.completed_at? %>
|
||||
<% submitters_order_index ||= (@submission.template_submitters || @submission.template.submitters).each_with_index.to_h { |s, i| [s['uuid'], i] } %>
|
||||
<% submitter_index = submitters_order_index[submitter.uuid] %>
|
||||
<% bg_class = bg_classes[submitter_index % bg_classes.size] %>
|
||||
<div class="absolute overflow-visible" style="width: <%= area['w'] * 100 %>%; height: <%= area['h'] * 100 %>%; left: <%= area['x'] * 100 %>%; top: <%= area['y'] * 100 %>%;">
|
||||
<div class="flex h-full w-full bg-opacity-80 justify-center items-center <%= bg_class %>">
|
||||
<%= svg_icon(SubmissionsController::FIELD_ICONS[field['type']], class: 'max-h-10 w-full h-full stroke-2 opacity-50') %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
<% content_for(:html_title, "#{@submitter.submission.name || @submitter.submission.template.name} | DocuSeal") %>
|
||||
<% I18n.with_locale(@submitter.account.locale) do %>
|
||||
<% content_for(:html_description, t('account_name_has_invited_you_to_fill_and_sign_documents_online_effortlessly_with_a_secure_fast_and_user_friendly_digital_document_signing_solution', account_name: @submitter.account.name)) %>
|
||||
<% end %>
|
||||
<div class="max-w-md mx-auto px-2 mt-12 mb-4">
|
||||
<div class="space-y-6 mx-auto">
|
||||
<div class="space-y-6">
|
||||
<div class="flex items-center justify-center">
|
||||
<%= render 'start_form/banner' %>
|
||||
</div>
|
||||
<div class="flex items-center bg-base-200 rounded-xl p-4 mb-4">
|
||||
<div class="flex items-center">
|
||||
<div class="mr-3">
|
||||
<%= svg_icon('writing_sign', class: 'w-10 h-10') %>
|
||||
</div>
|
||||
<div>
|
||||
<p dir="auto" class="text-lg font-bold mb-1"><%= @submitter.submission.name || @submitter.submission.template.name %></p>
|
||||
<% last_submitter = @submitter.submission.submitters.completed.order(:completed_at).last %>
|
||||
<% if last_submitter %>
|
||||
<p dir="auto" class="text-sm">
|
||||
<%= t(last_submitter.with_signature_fields? ? 'signed_on_time' : 'completed_on_time', time: l(last_submitter.completed_at.to_date, format: :long)) %>
|
||||
</p>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% if @submitter.email.present? %>
|
||||
<div>
|
||||
<%= t('the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html', email: TextUtils.mask_email(@submitter.email, 2)) %>
|
||||
</div>
|
||||
<% if params[:status] == 'sent' || params[:status] == 'error' %>
|
||||
<%= 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">
|
||||
<%= f.hidden_field :submitter_slug, value: @submitter.slug %>
|
||||
<%= f.text_field :one_time_code, required: true, class: 'base-input text-center', placeholder: 'XXX-XXX' %>
|
||||
<div class="flex justify-between items-center mt-1">
|
||||
<span>
|
||||
<% if flash[:alert] %>
|
||||
<span class="text-red-500">
|
||||
<%= flash[:alert] %>
|
||||
</span>
|
||||
<% end %>
|
||||
<% if flash[:notice] %>
|
||||
<%= flash[:notice] %>
|
||||
<% end %>
|
||||
</span>
|
||||
<span>
|
||||
<label for="resend_code" id="resend_label" class="link"><%= t(:re_send_email) %></label>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<toggle-submit dir="auto" class="form-control">
|
||||
<%= f.button button_title(title: t('submit')), class: 'base-button' %>
|
||||
</toggle-submit>
|
||||
<% end %>
|
||||
<%= button_to t(:re_send_email), submit_form_email_2fa_path, params: { submitter_slug: @submitter.slug, resend: true }, method: :put, id: 'resend_code', class: 'hidden' %>
|
||||
<% else %>
|
||||
<% if params[:t] %>
|
||||
<fetch-form data-onload="true">
|
||||
<%= button_to '', api_submitter_email_clicks_path, params: { submitter_slug: @submitter.slug, t: params[:t] }, method: :post, class: 'hidden' %>
|
||||
</fetch-form>
|
||||
<% end %>
|
||||
<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' %>
|
||||
</toggle-submit>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<div><%= t('please_contact_the_requester_to_specify_your_email_for_two_factor_authentication') %></div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
<p><%= t('your_verification_code_to_access_the_name', name: @submitter.submission.name || @submitter.submission.template.name) %></p>
|
||||
<p><b><%= @otp_code %></b></p>
|
||||
<p><%= t('please_reply_to_this_email_if_you_didnt_request_this') %></p>
|
||||
@@ -67,7 +67,7 @@
|
||||
<%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-1' }, data: { close_on_submit: false } do |f| %>
|
||||
<toggle-on-submit data-element-id="form_saved_alert"></toggle-on-submit>
|
||||
<% configs = AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::SUBMITTER_COMPLETED_EMAIL_KEY).value %>
|
||||
<%= f.fields_for :preferences, Struct.new(:completed_redirect_url, :completed_message, :require_phone_2fa).new(@template.preferences['completed_redirect_url'].presence, Struct.new(:title, :body).new(*(@template.preferences['completed_message'] || {}).values_at('title', 'body')), @template.preferences['require_phone_2fa'] == true) do |ff| %>
|
||||
<%= f.fields_for :preferences, Struct.new(:completed_redirect_url, :completed_message, :require_phone_2fa, :require_email_2fa).new(@template.preferences['completed_redirect_url'].presence, Struct.new(:title, :body).new(*(@template.preferences['completed_message'] || {}).values_at('title', 'body')), @template.preferences['require_phone_2fa'] == true, @template.preferences['require_email_2fa'] == true) do |ff| %>
|
||||
<div class="form-control mb-2">
|
||||
<%= ff.label :completed_redirect_url, t('redirect_on_completion_url'), class: 'label' %>
|
||||
<%= ff.url_field :completed_redirect_url, required: false, class: 'base-input', dir: 'auto' %>
|
||||
@@ -81,6 +81,14 @@
|
||||
</div>
|
||||
<% end %>
|
||||
<%= render 'templates_preferences/form_fields', ff: %>
|
||||
<div class="flex items-center justify-between py-2.5 px-1 mb-2">
|
||||
<span>
|
||||
<%= t('require_email_2fa_to_open') %>
|
||||
</span>
|
||||
<submit-form data-on="change" class="flex">
|
||||
<%= ff.check_box :require_email_2fa, { checked: ff.object.require_email_2fa == true, class: 'toggle' }, 'true', 'false' %>
|
||||
</submit-form>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="form-control pt-2">
|
||||
<%= f.button button_title(title: t('save'), disabled_with: t('saving')), class: 'base-button' %>
|
||||
|
||||
@@ -3,12 +3,19 @@
|
||||
<%= render 'shared/turbo_modal_large', title: t('share_link') do %>
|
||||
<div class="mt-2 mb-4 px-5">
|
||||
<%= 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| %>
|
||||
<label for="template_shared_link" class="flex items-center my-4 justify-between gap-1 alert bg-base-100 border-base-300">
|
||||
<span><%= t('enable_shared_link') %></span>
|
||||
<submit-form data-on="change" class="flex">
|
||||
<%= f.check_box :shared_link, { disabled: !can?(:update, @template), class: 'toggle' }, 'true', 'false' %>
|
||||
</submit-form>
|
||||
</label>
|
||||
<% if @template.preferences&.dig('require_email_2fa') || @template.preferences&.dig('require_phone_2fa') %>
|
||||
<label for="template_shared_link" class="tooltip tooltip-bottom flex items-center my-4 justify-between gap-1 alert bg-base-100 border-base-300" data-tip="<%= t(:templates_that_require_email_or_phone_2fa_cannot_be_used_via_a_shared_link) %>">
|
||||
<span><%= t('enable_shared_link') %></span>
|
||||
<%= check_box_tag 'shared_link', 'true', false, disabled: true, class: 'toggle' %>
|
||||
</label>
|
||||
<% else %>
|
||||
<label for="template_shared_link" class="flex items-center my-4 justify-between gap-1 alert bg-base-100 border-base-300">
|
||||
<span><%= t('enable_shared_link') %></span>
|
||||
<submit-form data-on="change" class="flex">
|
||||
<%= f.check_box :shared_link, { disabled: !can?(:update, @template), class: 'toggle' }, 'true', 'false' %>
|
||||
</submit-form>
|
||||
</label>
|
||||
<% end %>
|
||||
<div class="flex gap-2 mt-3">
|
||||
<input id="embedding_url" type="text" value="<%= start_form_url(slug: @template.slug) %>" class="base-input w-full" autocomplete="off" readonly>
|
||||
<check-on-click data-element-id="template_shared_link">
|
||||
@@ -31,48 +38,50 @@
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="collapse collapse-arrow join-item mt-4">
|
||||
<input id="accordion_checkbox" type="checkbox" name="accordion" class="min-h-0">
|
||||
<div class="collapse-title min-h-0 after:!right-3 p-1">
|
||||
<%= t('advanced_settings') %>
|
||||
</div>
|
||||
<div class="collapse-content !p-0">
|
||||
<%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-4 pt-4 border-t border-base-300' }, data: { close_on_submit: false } do |f| %>
|
||||
<% link_form_fields = @template.preferences.fetch('link_form_fields', ['email']) %>
|
||||
<label class="pl-1"><%= t('link_form_fields') %></label>
|
||||
<required-checkbox-group class="flex flex-col md:flex-row items-center gap-2 w-full mt-2">
|
||||
<% %w[name email phone].each do |field| %>
|
||||
<%= label_tag "link_form_fields_#{field}", t(field), class: 'relative flex w-full md:w-1/3 items-center h-14 border-base-300 py-3.5 border rounded-xl' do %>
|
||||
<%= check_box_tag 'template[preferences][link_form_fields][]', field, link_form_fields.include?(field), class: 'absolute !animate-none checkbox left-3', id: "link_form_fields_#{field}" %>
|
||||
<span class="font-medium w-full text-center"><%= t(field) %></span>
|
||||
<% if @template.preferences&.dig('require_email_2fa') != true && @template.preferences&.dig('require_phone_2fa') != true %>
|
||||
<div class="collapse collapse-arrow join-item mt-4">
|
||||
<input id="accordion_checkbox" type="checkbox" name="accordion" class="min-h-0">
|
||||
<div class="collapse-title min-h-0 after:!right-3 p-1">
|
||||
<%= t('advanced_settings') %>
|
||||
</div>
|
||||
<div class="collapse-content !p-0">
|
||||
<%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-4 pt-4 border-t border-base-300' }, data: { close_on_submit: false } do |f| %>
|
||||
<% link_form_fields = @template.preferences.fetch('link_form_fields', ['email']) %>
|
||||
<label class="pl-1"><%= t('link_form_fields') %></label>
|
||||
<required-checkbox-group class="flex flex-col md:flex-row items-center gap-2 w-full mt-2">
|
||||
<% %w[name email phone].each do |field| %>
|
||||
<%= label_tag "link_form_fields_#{field}", t(field), class: 'relative flex w-full md:w-1/3 items-center h-14 border-base-300 py-3.5 border rounded-xl' do %>
|
||||
<%= check_box_tag 'template[preferences][link_form_fields][]', field, link_form_fields.include?(field), class: 'absolute !animate-none checkbox left-3', id: "link_form_fields_#{field}" %>
|
||||
<span class="font-medium w-full text-center"><%= t(field) %></span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</required-checkbox-group>
|
||||
<% end %>
|
||||
<% if multiple_submitters && enough_defined_submitters %>
|
||||
<div class="collapse collapse-arrow join-item border border-base-300 mt-4">
|
||||
<input type="checkbox" name="accordion" class="min-h-0">
|
||||
<div class="collapse-title py-4 min-h-0">
|
||||
<%= t('default_parties') %>
|
||||
</div>
|
||||
<div class="collapse-content !pb-0">
|
||||
<%= render 'templates_preferences/recipients', template: @template, close_on_submit: false, with_toggles: false, with_submission_requester: false %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% if Docuseal.multitenant? || Accounts.can_send_emails?(current_account) %>
|
||||
<%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-4' }, data: { close_on_submit: false } do |f| %>
|
||||
<%= f.fields_for :preferences, Struct.new(:shared_link_2fa).new(@template.preferences['shared_link_2fa'] == true) do |ff| %>
|
||||
<label for="template_preferences_shared_link_2fa" class="flex items-center mt-4 h-14 justify-between gap-1 alert bg-base-100 border-base-300">
|
||||
<span><%= t('request_email_otp_verification_with_shared_link') %></span>
|
||||
<submit-form data-on="change" class="flex">
|
||||
<%= ff.check_box :shared_link_2fa, { checked: ff.object.shared_link_2fa == true, disabled: !can?(:update, @template), class: 'toggle' }, 'true', 'false' %>
|
||||
</submit-form>
|
||||
</label>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</required-checkbox-group>
|
||||
<% end %>
|
||||
<% if multiple_submitters && enough_defined_submitters %>
|
||||
<div class="collapse collapse-arrow join-item border border-base-300 mt-4">
|
||||
<input type="checkbox" name="accordion" class="min-h-0">
|
||||
<div class="collapse-title py-4 min-h-0">
|
||||
<%= t('default_parties') %>
|
||||
</div>
|
||||
<div class="collapse-content !pb-0">
|
||||
<%= render 'templates_preferences/recipients', template: @template, close_on_submit: false, with_toggles: false, with_submission_requester: false %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% if Docuseal.multitenant? || Accounts.can_send_emails?(current_account) %>
|
||||
<%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-4' }, data: { close_on_submit: false } do |f| %>
|
||||
<%= f.fields_for :preferences, Struct.new(:shared_link_2fa).new(@template.preferences['shared_link_2fa'] == true) do |ff| %>
|
||||
<label for="template_preferences_shared_link_2fa" class="flex items-center mt-4 h-14 justify-between gap-1 alert bg-base-100 border-base-300">
|
||||
<span><%= t('request_email_otp_verification_with_shared_link') %></span>
|
||||
<submit-form data-on="change" class="flex">
|
||||
<%= ff.check_box :shared_link_2fa, { checked: ff.object.shared_link_2fa == true, disabled: !can?(:update, @template), class: 'toggle' }, 'true', 'false' %>
|
||||
</submit-form>
|
||||
</label>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
@@ -12,15 +12,24 @@
|
||||
<% end %>
|
||||
</h1>
|
||||
<div class="flex flex-col md:flex-row gap-y-2 gap-x-4 md:items-center">
|
||||
<% if params[:status].blank? && can?(:create, User.new(account: current_account)) %>
|
||||
<%= render 'users/extra_buttons' %>
|
||||
<% if content_for(:add_user_button) %>
|
||||
<%= content_for(:add_user_button) %>
|
||||
<% else %>
|
||||
<%= link_to new_user_path, class: 'btn btn-primary btn-md gap-2 w-full md:w-fit', data: { turbo_frame: 'modal' } do %>
|
||||
<%= svg_icon('plus', class: 'w-6 h-6') %>
|
||||
<span><%= t('new_user') %></span>
|
||||
<% if params[:status].blank? %>
|
||||
<% if can?(:create, User.new(account: current_account)) %>
|
||||
<%= render 'users/extra_buttons' %>
|
||||
<% if content_for(:add_user_button) %>
|
||||
<%= content_for(:add_user_button) %>
|
||||
<% else %>
|
||||
<%= link_to new_user_path, class: 'btn btn-primary btn-md gap-2 w-full md:w-fit', data: { turbo_frame: 'modal' } do %>
|
||||
<%= svg_icon('plus', class: 'w-6 h-6') %>
|
||||
<span><%= t('new_user') %></span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<div class="tooltip" data-tip="<%= t('contact_your_administrator_to_add_new_users') %>">
|
||||
<%= link_to '#', class: 'btn btn-primary btn-md gap-2 w-full md:w-fit btn-disabled', data: { turbo_frame: 'modal' } do %>
|
||||
<%= svg_icon('plus', class: 'w-6 h-6') %>
|
||||
<span><%= t('new_user') %></span>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -79,7 +88,7 @@
|
||||
<%= t('remove') %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% if params[:status] == 'archived' && can?(:manage, user) && user != current_user && user.archived_at? %>
|
||||
<% if params[:status] == 'archived' && can?(:create, user) && user != current_user && user.archived_at? %>
|
||||
<%= button_to user_path(user), method: :put, params: { user: { archived_at: nil } }, class: 'btn btn-outline btn-xs', title: t('unarchive'), data: { turbo_confirm: t('are_you_sure_') } do %>
|
||||
<%= t('unarchive') %>
|
||||
<% end %>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"ignored_warnings": [
|
||||
{
|
||||
"fingerprint": "bbd1bdad94998e53a48921859065e06cd1595502d4dc40362afcaa90307b591a",
|
||||
"fingerprint": "de39648cd3f79d51e95e45f05fc77da49b0ad68bf80458061151016c0ef78208",
|
||||
"note": "Permitted parameters are necessary for creating submitters via API"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
ActiveSupport.on_load(:active_job) do
|
||||
ActiveJob::LogSubscriber.class_eval do
|
||||
def args_info(_job)
|
||||
''
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -17,7 +17,10 @@ module Devise
|
||||
assign_message_metadata(action, record)
|
||||
|
||||
initialize_from_record(record)
|
||||
mail(headers_for(action, opts), &)
|
||||
|
||||
I18n.with_locale(record.account.locale) do
|
||||
mail(headers_for(action, opts), &)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -25,6 +25,7 @@ en: &en
|
||||
upload_a_new_document: Upload a New Document
|
||||
billing: Billing
|
||||
hi_there: Hi there
|
||||
templates_that_require_email_or_phone_2fa_cannot_be_used_via_a_shared_link: Templates that require email or phone 2FA cannot be used via a shared link.
|
||||
pro: Pro
|
||||
thanks: Thanks
|
||||
private: Private
|
||||
@@ -32,6 +33,7 @@ en: &en
|
||||
enabled: Enabled
|
||||
disabled: Disabled
|
||||
party: Party
|
||||
make_owner: Make Owner
|
||||
use_direct_file_attachment_links_in_the_documents: Use direct file attachment links in the documents
|
||||
click_here_to_send_a_reset_password_email_html: '<label class="link" for="resend_password_button">Click here</label> to send a reset password email.'
|
||||
edit_order: Edit Order
|
||||
@@ -861,11 +863,20 @@ en: &en
|
||||
reports: Reports
|
||||
completed_submissions: Completed submissions
|
||||
sms: SMS
|
||||
require_email_2fa_to_open: Require email 2FA to open
|
||||
verification_required_refresh_the_page_and_pass_2fa: Verification required, refresh the page and pass 2FA.
|
||||
the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: The sender has requested two-factor authentication via a one-time password sent to your <b>%{email}</b> email.
|
||||
please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: Please contact the requester to specify your email for two-factor authentication.
|
||||
rate_limit_exceeded: Rate limit exceeded
|
||||
a_confirmation_email_has_been_sent_to_the_new_email_address: A confirmation email has been sent to the new email address.
|
||||
email_address_is_awaiting_confirmation_follow_the_link_in_the_email_to_confirm: "%{email} email address is awaiting confirmation. Follow the link in the email to confirm."
|
||||
please_confirm_your_email_address_using_the_link_below_: 'Please confirm your email address using the link below:'
|
||||
confirm_email: Confirm email
|
||||
unconfirmed: Unconfirmed
|
||||
you_requested_to_reset_your_password_use_the_link_below_to_continue: You requested to reset your password. Use the link below to continue
|
||||
if_you_didnt_request_this_you_can_ignore_this_email: "If you didn't request this, please ignore this email."
|
||||
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Your password won't change until you open the link above and set a new one."
|
||||
too_many_requests_try_again_later: Too many requests, try again later.
|
||||
devise:
|
||||
confirmations:
|
||||
confirmed: Your email address has been successfully confirmed.
|
||||
@@ -887,6 +898,7 @@ en: &en
|
||||
send_reminder_email_to_html: '<b>Reminder email sent</b> to %{submitter_name}'
|
||||
send_sms_to_html: '<b>SMS sent</b> to %{submitter_name}'
|
||||
send_2fa_sms_to_html: '<b>Verification SMS sent</b> to %{submitter_name}'
|
||||
send_2fa_email_to_html: '<b>Verification email sent</b> to %{submitter_name}'
|
||||
open_email_by_html: '<b>Email opened</b> by %{submitter_name}'
|
||||
click_email_by_html: '<b>Email link clicked</b> by %{submitter_name}'
|
||||
click_sms_by_html: '<b>SMS link clicked</b> by %{submitter_name}'
|
||||
@@ -980,6 +992,8 @@ en: &en
|
||||
range_without_total: "%{from}-%{to} events"
|
||||
|
||||
es: &es
|
||||
templates_that_require_email_or_phone_2fa_cannot_be_used_via_a_shared_link: Las plantillas que requieren autenticación en dos pasos por correo electrónico o teléfono no se pueden usar mediante un enlace compartido.
|
||||
make_owner: Hacer propietario
|
||||
billing: Facturación
|
||||
add_from_google_drive: Agregar desde Google Drive
|
||||
or_add_from: O agregar desde
|
||||
@@ -1821,11 +1835,20 @@ es: &es
|
||||
reports: Informes
|
||||
completed_submissions: Envíos completados
|
||||
sms: SMS
|
||||
require_email_2fa_to_open: Requerir 2FA por correo electrónico para abrir
|
||||
verification_required_refresh_the_page_and_pass_2fa: Verificación requerida, actualiza la página y completa la autenticación de dos factores.
|
||||
the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: El remitente ha solicitado autenticación de dos factores mediante una contraseña de un solo uso enviada a tu correo electrónico <b>%{email}</b>.
|
||||
please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: Por favor, contacta al remitente para especificar tu correo electrónico para la autenticación de dos factores.
|
||||
rate_limit_exceeded: Límite de velocidad excedido
|
||||
a_confirmation_email_has_been_sent_to_the_new_email_address: Se ha enviado un correo electrónico de confirmación a la nueva dirección de correo electrónico.
|
||||
email_address_is_awaiting_confirmation_follow_the_link_in_the_email_to_confirm: "%{email} está pendiente de confirmación. Sigue el enlace en el correo para confirmarla."
|
||||
please_confirm_your_email_address_using_the_link_below_: 'Por favor, confirma tu dirección de correo electrónico utilizando el enlace a continuación:'
|
||||
confirm_email: Confirmar correo
|
||||
unconfirmed: No confirmado
|
||||
you_requested_to_reset_your_password_use_the_link_below_to_continue: Solicitaste restablecer tu contraseña. Usa el enlace a continuación para continuar.
|
||||
if_you_didnt_request_this_you_can_ignore_this_email: "Si no solicitaste esto, puedes ignorar este correo electrónico."
|
||||
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Tu contraseña no cambiará hasta que abras el enlace anterior y establezcas una nueva."
|
||||
too_many_requests_try_again_later: Demasiadas solicitudes. Intenta de nuevo más tarde.
|
||||
devise:
|
||||
confirmations:
|
||||
confirmed: Tu dirección de correo electrónico ha sido confirmada correctamente.
|
||||
@@ -1847,6 +1870,7 @@ es: &es
|
||||
send_reminder_email_to_html: '<b>Correo de recordatorio enviado</b> a %{submitter_name}'
|
||||
send_sms_to_html: '<b>SMS enviado</b> a %{submitter_name}'
|
||||
send_2fa_sms_to_html: '<b>SMS de verificación enviado</b> a %{submitter_name}'
|
||||
send_2fa_email_to_html: '<b>Correo electrónico de verificación enviado</b> a %{submitter_name}'
|
||||
open_email_by_html: '<b>Correo electrónico abierto</b> por %{submitter_name}'
|
||||
click_email_by_html: '<b>Enlace del correo electrónico clicado</b> por %{submitter_name}'
|
||||
click_sms_by_html: '<b>Enlace del SMS clicado</b> por %{submitter_name}'
|
||||
@@ -1940,6 +1964,8 @@ es: &es
|
||||
range_without_total: "%{from}-%{to} eventos"
|
||||
|
||||
it: &it
|
||||
templates_that_require_email_or_phone_2fa_cannot_be_used_via_a_shared_link: I modelli che richiedono 2FA via email o telefono non possono essere utilizzati tramite un link condiviso.
|
||||
make_owner: Rendi proprietario
|
||||
billing: Fatturazione
|
||||
add_from_google_drive: Aggiungi da Google Drive
|
||||
or_add_from: Oppure aggiungi da
|
||||
@@ -2782,11 +2808,20 @@ it: &it
|
||||
reports: Rapporti
|
||||
completed_submissions: Invii completati
|
||||
sms: SMS
|
||||
require_email_2fa_to_open: Richiedi 2FA email per aprire
|
||||
verification_required_refresh_the_page_and_pass_2fa: Verifica richiesta, aggiorna la pagina e completa l'autenticazione a due fattori.
|
||||
the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: Il mittente ha richiesto l'autenticazione a due fattori tramite una password monouso inviata al tuo indirizzo email <b>%{email}</b>.
|
||||
please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: Si prega di contattare il mittente per specificare il tuo indirizzo email per l'autenticazione a due fattori.
|
||||
rate_limit_exceeded: Limite di velocità superato
|
||||
a_confirmation_email_has_been_sent_to_the_new_email_address: È stata inviata un'email di conferma al nuovo indirizzo email.
|
||||
email_address_is_awaiting_confirmation_follow_the_link_in_the_email_to_confirm: "%{email} è in attesa di conferma. Segui il link nell'email per confermare."
|
||||
please_confirm_your_email_address_using_the_link_below_: 'Conferma il tuo indirizzo email utilizzando il link qui sotto:'
|
||||
confirm_email: Conferma email
|
||||
unconfirmed: Non confermato
|
||||
you_requested_to_reset_your_password_use_the_link_below_to_continue: Hai richiesto di reimpostare la tua password. Usa il link qui sotto per continuare.
|
||||
if_you_didnt_request_this_you_can_ignore_this_email: "Se non hai richiesto questo, puoi ignorare questa email."
|
||||
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "La tua password non cambierà finché non apri il link sopra e ne imposti una nuova."
|
||||
too_many_requests_try_again_later: Troppe richieste. Riprova più tardi.
|
||||
devise:
|
||||
confirmations:
|
||||
confirmed: Il tuo indirizzo email è stato confermato con successo.
|
||||
@@ -2808,6 +2843,7 @@ it: &it
|
||||
send_reminder_email_to_html: '<b>E-mail di promemoria inviato</b> a %{submitter_name}'
|
||||
send_sms_to_html: '<b>SMS inviato</b> a %{submitter_name}'
|
||||
send_2fa_sms_to_html: '<b>SMS di verifica inviato</b> a %{submitter_name}'
|
||||
send_2fa_email_to_html: '<b>Email di verifica inviata</b> a %{submitter_name}'
|
||||
open_email_by_html: '<b>E-mail aperta</b> da %{submitter_name}'
|
||||
click_email_by_html: "<b>Link dell'e-mail cliccato</b> da %{submitter_name}"
|
||||
click_sms_by_html: "<b>Link dell'SMS cliccato</b> da %{submitter_name}"
|
||||
@@ -2901,6 +2937,8 @@ it: &it
|
||||
range_without_total: "%{from}-%{to} eventi"
|
||||
|
||||
fr: &fr
|
||||
templates_that_require_email_or_phone_2fa_cannot_be_used_via_a_shared_link: Les modèles nécessitant une authentification à deux facteurs par e-mail ou téléphone ne peuvent pas être utilisés via un lien partagé.
|
||||
make_owner: Rendre propriétaire
|
||||
billing: Facturation
|
||||
add_from_google_drive: Ajouter depuis Google Drive
|
||||
or_add_from: Ou ajouter depuis
|
||||
@@ -3739,11 +3777,20 @@ fr: &fr
|
||||
reports: Rapports
|
||||
completed_submissions: Soumissions terminées
|
||||
sms: SMS
|
||||
require_email_2fa_to_open: Exiger la 2FA par e‑mail pour ouvrir
|
||||
verification_required_refresh_the_page_and_pass_2fa: Vérification requise, actualisez la page et effectuez l'authentification à deux facteurs.
|
||||
the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: L'expéditeur a demandé l'authentification à deux facteurs par mot de passe à usage unique envoyé à votre adresse e-mail <b>%{email}</b>.
|
||||
please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: Veuillez contacter l'expéditeur pour spécifier votre adresse e-mail pour l'authentification à deux facteurs.
|
||||
rate_limit_exceeded: Limite de débit dépassée
|
||||
a_confirmation_email_has_been_sent_to_the_new_email_address: Un e-mail de confirmation a été envoyé à la nouvelle adresse e-mail.
|
||||
email_address_is_awaiting_confirmation_follow_the_link_in_the_email_to_confirm: "%{email} est en attente de confirmation. Suivez le lien dans l'e-mail pour la confirmer."
|
||||
please_confirm_your_email_address_using_the_link_below_: 'Veuillez confirmer votre adresse e-mail en utilisant le lien ci-dessous :'
|
||||
confirm_email: "Confirmer l'e-mail"
|
||||
unconfirmed: Non confirmé
|
||||
you_requested_to_reset_your_password_use_the_link_below_to_continue: Vous avez demandé à réinitialiser votre mot de passe. Utilisez le lien ci-dessous pour continuer.
|
||||
if_you_didnt_request_this_you_can_ignore_this_email: "Si vous n'avez pas fait cette demande, veuillez ignorer cet e-mail."
|
||||
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Votre mot de passe ne changera pas tant que vous n’aurez pas ouvert le lien ci-dessus et défini un nouveau mot de passe."
|
||||
too_many_requests_try_again_later: Trop de demandes. Réessayez plus tard.
|
||||
devise:
|
||||
confirmations:
|
||||
confirmed: Votre adresse e-mail a été confirmée avec succès.
|
||||
@@ -3765,6 +3812,7 @@ fr: &fr
|
||||
send_reminder_email_to_html: "<b>E‑mail de rappel envoyé</b> à %{submitter_name}"
|
||||
send_sms_to_html: "<b>SMS envoyé</b> à %{submitter_name}"
|
||||
send_2fa_sms_to_html: "<b>SMS de vérification envoyé</b> à %{submitter_name}"
|
||||
send_2fa_email_to_html: "<b>E‑mail de vérification envoyé</b> à %{submitter_name}"
|
||||
open_email_by_html: "<b>E‑mail ouvert</b> par %{submitter_name}"
|
||||
click_email_by_html: "<b>Lien e‑mail cliqué</b> par %{submitter_name}"
|
||||
click_sms_by_html: "<b>Lien SMS cliqué</b> par %{submitter_name}"
|
||||
@@ -3858,6 +3906,8 @@ fr: &fr
|
||||
range_without_total: "%{from}-%{to} événements"
|
||||
|
||||
pt: &pt
|
||||
templates_that_require_email_or_phone_2fa_cannot_be_used_via_a_shared_link: Modelos que exigem 2FA por e-mail ou telefone não podem ser usados por meio de um link compartilhado.
|
||||
make_owner: Tornar proprietário
|
||||
billing: Pagamentos
|
||||
add_from_google_drive: Adicionar do Google Drive
|
||||
or_add_from: Ou adicionar de
|
||||
@@ -4699,11 +4749,20 @@ pt: &pt
|
||||
reports: Relatórios
|
||||
completed_submissions: Envios concluídos
|
||||
sms: SMS
|
||||
require_email_2fa_to_open: Exigir 2FA por e-mail para abrir
|
||||
verification_required_refresh_the_page_and_pass_2fa: Verificação necessária, atualize a página e conclua a autenticação de dois fatores.
|
||||
the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: O remetente solicitou autenticação de dois fatores por meio de uma senha de uso único enviada para o seu e-mail <b>%{email}</b>.
|
||||
please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: Por favor, entre em contato com o remetente para especificar seu e-mail para autenticação de dois fatores.
|
||||
rate_limit_exceeded: Limite de taxa excedido
|
||||
a_confirmation_email_has_been_sent_to_the_new_email_address: Um e-mail de confirmação foi enviado para o novo endereço de e-mail.
|
||||
email_address_is_awaiting_confirmation_follow_the_link_in_the_email_to_confirm: "%{email} está aguardando confirmação. Siga o link enviado para esse endereço de e-mail para confirmar."
|
||||
please_confirm_your_email_address_using_the_link_below_: 'Por favor, confirme seu endereço de e-mail usando o link abaixo:'
|
||||
confirm_email: Confirmar e-mail
|
||||
unconfirmed: Não confirmado
|
||||
you_requested_to_reset_your_password_use_the_link_below_to_continue: Você solicitou a redefinição da sua senha. Use o link abaixo para continuar.
|
||||
if_you_didnt_request_this_you_can_ignore_this_email: "Se você não solicitou isso, pode ignorar este e-mail."
|
||||
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Sua senha não será alterada até que você abra o link acima e defina uma nova."
|
||||
too_many_requests_try_again_later: Muitas solicitações. Tente novamente mais tarde.
|
||||
devise:
|
||||
confirmations:
|
||||
confirmed: Seu endereço de e-mail foi confirmado com sucesso.
|
||||
@@ -4725,6 +4784,7 @@ pt: &pt
|
||||
send_reminder_email_to_html: '<b>Email de lembrete enviado</b> para %{submitter_name}'
|
||||
send_sms_to_html: '<b>SMS enviado</b> para %{submitter_name}'
|
||||
send_2fa_sms_to_html: '<b>SMS de verificação enviado</b> para %{submitter_name}'
|
||||
send_2fa_email_to_html: '<b>Email de verificação enviado</b> para %{submitter_name}'
|
||||
open_email_by_html: '<b>E-mail aberto</b> por %{submitter_name}'
|
||||
click_email_by_html: '<b>Link do e-mail clicado</b> por %{submitter_name}'
|
||||
click_sms_by_html: '<b>Link do SMS clicado</b> por %{submitter_name}'
|
||||
@@ -4818,6 +4878,8 @@ pt: &pt
|
||||
range_without_total: "%{from}-%{to} eventos"
|
||||
|
||||
de: &de
|
||||
templates_that_require_email_or_phone_2fa_cannot_be_used_via_a_shared_link: Vorlagen, die eine Zwei-Faktor-Authentifizierung per E-Mail oder Telefon erfordern, können nicht über einen geteilten Link verwendet werden.
|
||||
make_owner: Eigentümer machen
|
||||
billing: Abrechnung
|
||||
add_from_google_drive: Aus Google Drive hinzufügen
|
||||
or_add_from: Oder hinzufügen aus
|
||||
@@ -5659,11 +5721,20 @@ de: &de
|
||||
reports: Berichte
|
||||
completed_submissions: Abgeschlossene Übermittlungen
|
||||
sms: SMS
|
||||
require_email_2fa_to_open: E-Mail-2FA erforderlich, um zu öffnen
|
||||
verification_required_refresh_the_page_and_pass_2fa: Verifikation erforderlich. Aktualisieren Sie die Seite und führen Sie die Zwei-Faktor-Authentifizierung durch.
|
||||
the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: Der Absender hat die Zwei-Faktor-Authentifizierung per Einmalpasswort angefordert, das an Ihre E-Mail-Adresse <b>%{email}</b> gesendet wurde.
|
||||
please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: Bitte wenden Sie sich an den Absender, um Ihre E-Mail-Adresse für die Zwei-Faktor-Authentifizierung anzugeben.
|
||||
rate_limit_exceeded: Limit überschritten
|
||||
a_confirmation_email_has_been_sent_to_the_new_email_address: Eine Bestätigungs-E-Mail wurde an die neue E-Mail-Adresse gesendet.
|
||||
email_address_is_awaiting_confirmation_follow_the_link_in_the_email_to_confirm: "%{email} wartet auf Bestätigung. Folgen Sie dem Link in der E-Mail, um sie zu bestätigen."
|
||||
please_confirm_your_email_address_using_the_link_below_: 'Bitte bestätigen Sie Ihre E-Mail-Adresse über den folgenden Link:'
|
||||
confirm_email: E-Mail bestätigen
|
||||
unconfirmed: Unbestätigt
|
||||
you_requested_to_reset_your_password_use_the_link_below_to_continue: Sie haben angefordert, Ihr Passwort zurückzusetzen. Verwenden Sie den untenstehenden Link, um fortzufahren.
|
||||
if_you_didnt_request_this_you_can_ignore_this_email: "Wenn Sie dies nicht angefordert haben, können Sie diese E-Mail ignorieren."
|
||||
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Ihr Passwort wird erst geändert, wenn Sie den obigen Link öffnen und ein neues festlegen."
|
||||
too_many_requests_try_again_later: Zu viele Anfragen. Versuchen Sie es später erneut.
|
||||
devise:
|
||||
confirmations:
|
||||
confirmed: Ihre E-Mail-Adresse wurde erfolgreich bestätigt.
|
||||
@@ -5685,6 +5756,7 @@ de: &de
|
||||
send_reminder_email_to_html: '<b>Erinnerungs-E-Mail gesendet</b> an %{submitter_name}'
|
||||
send_sms_to_html: '<b>SMS gesendet</b> an %{submitter_name}'
|
||||
send_2fa_sms_to_html: '<b>Verifizierungs-SMS gesendet</b> an %{submitter_name}'
|
||||
send_2fa_email_to_html: '<b>Verifizierungs-E-Mail gesendet</b> an %{submitter_name}'
|
||||
open_email_by_html: '<b>E-Mail geöffnet</b> von %{submitter_name}'
|
||||
click_email_by_html: '<b>E-Mail-Link angeklickt</b> von %{submitter_name}'
|
||||
click_sms_by_html: '<b>SMS-Link angeklickt</b> von %{submitter_name}'
|
||||
@@ -5817,6 +5889,7 @@ pl:
|
||||
completed_on_time: 'Zakończono %{time}'
|
||||
document_has_been_signed_already: 'Dokument został już podpisany'
|
||||
form_has_been_submitted_already: Formularz został już przesłany
|
||||
re_send_email: Wyślij wiadomość e-mail ponownie
|
||||
send_copy_to_email: Wyślij kopię na Email
|
||||
sending: Wysyłanie
|
||||
resubmit: Prześlij ponownie
|
||||
@@ -5867,6 +5940,11 @@ pl:
|
||||
please_reply_to_this_email_if_you_didnt_request_this: Odpowiedz na ten e-mail, jeśli nie prosiłeś o to.
|
||||
your_user_account_has_been_archived_contact_your_administrator_to_restore_access_to_your_account: Twoje konto użytkownika zostało zarchiwizowane. Skontaktuj się z administratorem, aby przywrócić dostęp do konta.
|
||||
your_email_could_not_be_reached_this_may_happen_if_there_was_a_typo_in_your_address_or_if_your_mailbox_is_not_available_please_contact_support_email_to_log_in: Nie udało się uzyskać dostępu do Twojego adresu e-mail. Może to być spowodowane literówką w adresie lub niedostępnością skrzynki. Skontaktuj się z support@docuseal.com, aby się zalogować.
|
||||
verification_required_refresh_the_page_and_pass_2fa: Weryfikacja wymagana, odśwież stronę i przejdź uwierzytelnienie dwuskładnikowe.
|
||||
the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: Nadawca zażądał uwierzytelniania dwuskładnikowego za pośrednictwem hasła jednorazowego wysłanego na Twój adres e-mail <b>%{email}</b>.
|
||||
please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: Skontaktuj się z nadawcą, aby podać swój adres e-mail do uwierzytelniania dwuskładnikowego.
|
||||
rate_limit_exceeded: Przekroczono limit
|
||||
too_many_requests_try_again_later: Zbyt wiele żądań. Spróbuj ponownie później.
|
||||
|
||||
uk:
|
||||
require_phone_2fa_to_open: Вимагати двофакторну автентифікацію через телефон для відкриття
|
||||
@@ -5908,6 +5986,7 @@ uk:
|
||||
completed_on_time: 'Завершено %{time}'
|
||||
document_has_been_signed_already: 'Документ уже був підписаний'
|
||||
form_has_been_submitted_already: Форма вже була подана
|
||||
re_send_email: Надіслати e-mail знову
|
||||
send_copy_to_email: Надіслати копію на Email
|
||||
sending: Надсилання
|
||||
resubmit: Подати знову
|
||||
@@ -5958,6 +6037,11 @@ uk:
|
||||
please_reply_to_this_email_if_you_didnt_request_this: Відповідайте на цей лист, якщо ви цього не запитували.
|
||||
your_user_account_has_been_archived_contact_your_administrator_to_restore_access_to_your_account: Ваш обліковий запис було архівовано. Зверніться до адміністратора, щоб відновити доступ.
|
||||
your_email_could_not_be_reached_this_may_happen_if_there_was_a_typo_in_your_address_or_if_your_mailbox_is_not_available_please_contact_support_email_to_log_in: Не вдалося отримати доступ до вашої електронної пошти. Це може статися, якщо була допущена помилка в адресі або ваша скринька недоступна. Зверніться до support@docuseal.com, щоб увійти.
|
||||
verification_required_refresh_the_page_and_pass_2fa: Необхідна верифікація, оновіть сторінку та пройдіть двофакторну автентифікацію.
|
||||
the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: Відправник запросив двофакторну автентифікацію за допомогою одноразового пароля, відправленого на вашу електронну пошту <b>%{email}</b>.
|
||||
please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: Будь ласка, зв'яжіться з відправником, щоб вказати вашу електронну пошту для двофакторної автентифікації.
|
||||
rate_limit_exceeded: Перевищено ліміт
|
||||
too_many_requests_try_again_later: Забагато запитів. Спробуйте пізніше.
|
||||
|
||||
cs:
|
||||
require_phone_2fa_to_open: Vyžadovat otevření pomocí telefonního 2FA
|
||||
@@ -5999,6 +6083,7 @@ cs:
|
||||
completed_on_time: 'Dokončeno %{time}'
|
||||
document_has_been_signed_already: 'Dokument již byl podepsán'
|
||||
form_has_been_submitted_already: Formulář již byl odeslán
|
||||
re_send_email: Znovu odeslat e-mail
|
||||
send_copy_to_email: Odeslat kopii na Email
|
||||
sending: Odesílání
|
||||
resubmit: Odeslat znovu
|
||||
@@ -6049,6 +6134,11 @@ cs:
|
||||
please_reply_to_this_email_if_you_didnt_request_this: Odpovězte na tento e-mail, pokud jste o to nežádali.
|
||||
your_user_account_has_been_archived_contact_your_administrator_to_restore_access_to_your_account: Váš uživatelský účet byl archivován. Kontaktujte svého administrátora pro obnovení přístupu.
|
||||
your_email_could_not_be_reached_this_may_happen_if_there_was_a_typo_in_your_address_or_if_your_mailbox_is_not_available_please_contact_support_email_to_log_in: Nepodařilo se dosáhnout na váš e-mail. To se může stát, pokud je v adrese překlep nebo vaše schránka není dostupná. Kontaktujte support@docuseal.com pro přihlášení.
|
||||
verification_required_refresh_the_page_and_pass_2fa: Ověření vyžadováno. Aktualizujte stránku a dokončete dvoufaktorové ověření.
|
||||
the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: Odesílatel požádal o dvoufaktorové ověření pomocí jednorázového hesla odeslaného na vaši e-mailovou adresu <b>%{email}</b>.
|
||||
please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: Prosím kontaktujte odesílatele a uveďte svůj e-mail pro dvoufaktorové ověření.
|
||||
rate_limit_exceeded: Překročena hranice
|
||||
too_many_requests_try_again_later: Příliš mnoho požadavků. Zkuste to později.
|
||||
|
||||
he:
|
||||
require_phone_2fa_to_open: דרוש אימות דו-שלבי באמצעות טלפון לפתיחה
|
||||
@@ -6090,6 +6180,7 @@ he:
|
||||
completed_on_time: 'הושלם ב-%{time}'
|
||||
document_has_been_signed_already: 'המסמך כבר נחתם'
|
||||
form_has_been_submitted_already: הטופס כבר נשלח
|
||||
re_send_email: שלח דוא"ל שוב
|
||||
send_copy_to_email: שלח עותק לדוא"ל
|
||||
sending: שולח
|
||||
resubmit: שלח מחדש
|
||||
@@ -6140,8 +6231,15 @@ he:
|
||||
please_reply_to_this_email_if_you_didnt_request_this: 'השב למייל זה אם לא ביקשת זאת.'
|
||||
your_user_account_has_been_archived_contact_your_administrator_to_restore_access_to_your_account: החשבון שלך הועבר לארכיון. פנה למנהל המערכת כדי לשחזר את הגישה.
|
||||
your_email_could_not_be_reached_this_may_happen_if_there_was_a_typo_in_your_address_or_if_your_mailbox_is_not_available_please_contact_support_email_to_log_in: לא ניתן היה לגשת לדוא"ל שלך. ייתכן שזה קרה עקב שגיאת כתיב בכתובת או אם תיבת הדואר אינה זמינה. אנא פנה ל־support@docuseal.com כדי להתחבר.
|
||||
verification_required_refresh_the_page_and_pass_2fa: נדרשת אימות. רענן את הדף והשלם אימות דו-שלבי.
|
||||
the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: השולח ביקש אימות דו-שלבי באמצעות סיסמה חד-פעמית שנשלחה לכתובת הדוא"ל שלך <b>%{email}</b>.
|
||||
please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: אנא פנה לשולח וציין את כתובת הדוא"ל שלך לאימות דו-שלבי.
|
||||
rate_limit_exceeded: חריגה ממגבלת
|
||||
too_many_requests_try_again_later: יותר מדי בקשות. נסה שוב מאוחר יותר.
|
||||
|
||||
nl: &nl
|
||||
templates_that_require_email_or_phone_2fa_cannot_be_used_via_a_shared_link: Sjablonen waarvoor e-mail- of telefoon-2FA vereist is, kunnen niet via een gedeelde link worden gebruikt.
|
||||
make_owner: Eigenaar maken
|
||||
billing: Facturatie
|
||||
add_from_google_drive: Toevoegen vanuit Google Drive
|
||||
or_add_from: Of toevoegen vanuit
|
||||
@@ -6980,11 +7078,20 @@ nl: &nl
|
||||
reports: Rapporten
|
||||
completed_submissions: Voltooide inzendingen
|
||||
sms: SMS
|
||||
require_email_2fa_to_open: E-mail 2FA vereisen om te openen
|
||||
verification_required_refresh_the_page_and_pass_2fa: Verificatie vereist. Vernieuw de pagina en voer twee-factor-authenticatie uit.
|
||||
the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: De afzender heeft twee-factor-authenticatie aangevraagd via een eenmalig wachtwoord dat naar uw e-mailadres <b>%{email}</b> is verzonden.
|
||||
please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: Neem alstublieft contact op met de afzender om uw e-mailadres op te geven voor twee-factor-authenticatie.
|
||||
rate_limit_exceeded: Snelheidslimiet overschreden
|
||||
a_confirmation_email_has_been_sent_to_the_new_email_address: Er is een bevestigingsmail verzonden naar het nieuwe e-mailadres.
|
||||
email_address_is_awaiting_confirmation_follow_the_link_in_the_email_to_confirm: "%{email} wacht op bevestiging. Volg de link in de e-mail om te bevestigen."
|
||||
please_confirm_your_email_address_using_the_link_below_: 'Bevestig je e-mailadres via de onderstaande link:'
|
||||
confirm_email: E-mailadres bevestigen
|
||||
unconfirmed: Onbevestigd
|
||||
you_requested_to_reset_your_password_use_the_link_below_to_continue: Je hebt gevraagd je wachtwoord te resetten. Gebruik de onderstaande link om verder te gaan.
|
||||
if_you_didnt_request_this_you_can_ignore_this_email: "Als je dit niet hebt aangevraagd, kun je deze e-mail negeren."
|
||||
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Je wachtwoord wordt niet gewijzigd totdat je de bovenstaande link opent en een nieuw wachtwoord instelt."
|
||||
too_many_requests_try_again_later: Te veel verzoeken. Probeer het later opnieuw.
|
||||
devise:
|
||||
confirmations:
|
||||
confirmed: Je e-mailadres is succesvol bevestigd.
|
||||
@@ -7006,6 +7113,7 @@ nl: &nl
|
||||
send_reminder_email_to_html: "<b>Herinneringsmail verzonden</b> naar %{submitter_name}"
|
||||
send_sms_to_html: "<b>SMS verzonden</b> naar %{submitter_name}"
|
||||
send_2fa_sms_to_html: "<b>Verificatie-SMS verzonden</b> naar %{submitter_name}"
|
||||
send_2fa_email_to_html: "<b>Verificatie-e-mail verzonden</b> naar %{submitter_name}"
|
||||
open_email_by_html: "<b>E-mail geopend</b> door %{submitter_name}"
|
||||
click_email_by_html: "<b>E-maillink aangeklikt</b> door %{submitter_name}"
|
||||
click_sms_by_html: "<b>SMS-link aangeklikt</b> door %{submitter_name}"
|
||||
@@ -7137,6 +7245,7 @@ ar:
|
||||
completed_on_time: 'تم إكماله في %{time}'
|
||||
document_has_been_signed_already: 'تم توقيع الوثيقة بالفعل'
|
||||
form_has_been_submitted_already: تم تقديم الاستمارة بالفعل
|
||||
re_send_email: إعادة إرسال البريد الإلكتروني
|
||||
send_copy_to_email: إرسال نسخة إلى البريد الإلكتروني
|
||||
sending: جارٍ الإرسال
|
||||
resubmit: إعادة التقديم
|
||||
@@ -7188,6 +7297,11 @@ ar:
|
||||
please_reply_to_this_email_if_you_didnt_request_this: 'يرجى الرد على هذا البريد إذا لم تطلب ذلك.'
|
||||
your_user_account_has_been_archived_contact_your_administrator_to_restore_access_to_your_account: تم أرشفة حسابك. يرجى التواصل مع المسؤول لاستعادة الوصول إلى حسابك.
|
||||
your_email_could_not_be_reached_this_may_happen_if_there_was_a_typo_in_your_address_or_if_your_mailbox_is_not_available_please_contact_support_email_to_log_in: تعذّر الوصول إلى بريدك الإلكتروني. قد يحدث هذا في حال وجود خطأ في العنوان أو إذا كانت صندوق البريد غير متاح. يرجى التواصل مع support@docuseal.com لتسجيل الدخول.
|
||||
verification_required_refresh_the_page_and_pass_2fa: مطلوب التحقق. قم بتحديث الصفحة وأكمل المصادقة الثنائية.
|
||||
the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: طلب المرسل المصادقة الثنائية عبر كلمة مرور لمرة واحدة مرسلة إلى عنوان بريدك الإلكتروني <b>%{email}</b>.
|
||||
please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: يرجى الاتصال بالمرسل لتحديد عنوان بريدك الإلكتروني للمصادقة الثنائية.
|
||||
rate_limit_exceeded: تم تجاوز الحد المسموح به
|
||||
too_many_requests_try_again_later: طلبات كثيرة جدًا. حاول مرة أخرى لاحقًا.
|
||||
|
||||
ko:
|
||||
require_phone_2fa_to_open: 휴대폰 2FA를 열 때 요구함
|
||||
@@ -7228,6 +7342,7 @@ ko:
|
||||
completed_on_time: '%{time}에 완료됨'
|
||||
document_has_been_signed_already: '문서가 이미 서명되었습니다'
|
||||
form_has_been_submitted_already: 양식이 이미 제출되었습니다.
|
||||
re_send_email: 이메일 다시 보내기
|
||||
send_copy_to_email: 이메일로 사본 보내기
|
||||
sending: 전송 중
|
||||
resubmit: 다시 제출
|
||||
@@ -7279,6 +7394,11 @@ ko:
|
||||
please_reply_to_this_email_if_you_didnt_request_this: 요청하지 않았다면 이 이메일에 회신하세요.
|
||||
your_user_account_has_been_archived_contact_your_administrator_to_restore_access_to_your_account: 사용자 계정이 보관되었습니다. 계정 접근을 복원하려면 관리자에게 문의하세요.
|
||||
your_email_could_not_be_reached_this_may_happen_if_there_was_a_typo_in_your_address_or_if_your_mailbox_is_not_available_please_contact_support_email_to_log_in: 이메일에 접근할 수 없습니다. 주소에 오타가 있거나 메일박스가 사용 불가능한 경우 발생할 수 있습니다. 로그인하려면 support@docuseal.com에 문의하세요.
|
||||
verification_required_refresh_the_page_and_pass_2fa: 인증이 필요합니다. 페이지를 새로 고치고 2단계 인증을 완료하세요.
|
||||
the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: 발신자가 <b>%{email}</b> 이메일 주소로 전송된 일회용 비밀번호를 통해 2단계 인증을 요청했습니다.
|
||||
please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: 2단계 인증을 위해 이메일 주소를 지정하려면 발신자에게 문의하세요.
|
||||
rate_limit_exceeded: 속도 제한 초과
|
||||
too_many_requests_try_again_later: 요청이 너무 많습니다. 나중에 다시 시도하세요.
|
||||
|
||||
ja:
|
||||
require_phone_2fa_to_open: 電話による2段階認証が必要です
|
||||
@@ -7319,6 +7439,7 @@ ja:
|
||||
completed_on_time: '%{time} に完了'
|
||||
document_has_been_signed_already: ドキュメントはすでに署名されています
|
||||
form_has_been_submitted_already: フォームはすでに送信されています
|
||||
re_send_email: メールを再度送信
|
||||
send_copy_to_email: メールにコピーを送信
|
||||
sending: 送信中
|
||||
resubmit: 再送信
|
||||
@@ -7370,6 +7491,11 @@ ja:
|
||||
please_reply_to_this_email_if_you_didnt_request_this: このリクエストを行っていない場合は、このメールに返信してください。
|
||||
your_user_account_has_been_archived_contact_your_administrator_to_restore_access_to_your_account: あなたのユーザーアカウントはアーカイブされました。アクセスを復元するには管理者に連絡してください。
|
||||
your_email_could_not_be_reached_this_may_happen_if_there_was_a_typo_in_your_address_or_if_your_mailbox_is_not_available_please_contact_support_email_to_log_in: メールにアクセスできませんでした。アドレスの入力ミスやメールボックスが利用できない場合に発生することがあります。ログインするには support@docuseal.com に連絡してください。
|
||||
verification_required_refresh_the_page_and_pass_2fa: 認証が必要です。ページを更新して2段階認証を完了してください。
|
||||
the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: 送信者は、<b>%{email}</b> メールアドレスに送信されたワンタイムパスワードによる2段階認証を要求しました。
|
||||
please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: 2段階認証用にメールアドレスを指定するために、送信者にお問い合わせください。
|
||||
rate_limit_exceeded: レート制限を超えました
|
||||
too_many_requests_try_again_later: リクエストが多すぎます。後でもう一度お試しください。
|
||||
|
||||
en-US:
|
||||
<<: *en
|
||||
|
||||
@@ -132,6 +132,7 @@ Rails.application.routes.draw do
|
||||
end
|
||||
|
||||
resource :resubmit_form, controller: 'start_form', only: :update
|
||||
resource :submit_form_email_2fa, only: %i[create update]
|
||||
resources :start_form_email_2fa_send, only: :create
|
||||
|
||||
resources :submit_form, only: %i[], path: '' do
|
||||
|
||||
@@ -9,6 +9,8 @@ class AddIsFirstToCompletedSubmitters < ActiveRecord::Migration[8.0]
|
||||
add_index :completed_submitters, %i[account_id completed_at],
|
||||
where: 'is_first = TRUE',
|
||||
name: 'index_completed_submitters_account_id_completed_at_is_first'
|
||||
add_index :completed_submitters, :submission_id, unique: true, where: 'is_first = TRUE'
|
||||
|
||||
add_index :completed_submitters, :submission_id, unique: adapter_name != 'Mysql2',
|
||||
where: 'is_first = TRUE'
|
||||
end
|
||||
end
|
||||
|
||||
@@ -151,7 +151,8 @@ const token = jwt.sign({
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"drawFieldType": {
|
||||
@@ -194,7 +195,8 @@ const token = jwt.sign({
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"role": {
|
||||
@@ -321,7 +323,8 @@ const token = jwt.sign({
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"role": {
|
||||
@@ -444,6 +447,12 @@ const token = jwt.sign({
|
||||
"default": true,
|
||||
"description": "Set `false` to now show the fields list on the right. Fields list is displayed by default."
|
||||
},
|
||||
"withFieldsDetection": {
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": false,
|
||||
"description": "Display a button to automatically detect and add fields to the document with AI."
|
||||
},
|
||||
"withFieldPlaceholder": {
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
@@ -483,7 +492,7 @@ const token = jwt.sign({
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "en",
|
||||
"description": "UI language, 'en', 'es', 'de', 'fr', 'pt', 'he', 'ar' languages are available."
|
||||
"description": "UI language, 'en', 'es', 'de', 'fr', 'pt', 'nl', 'he', 'ar' languages are available."
|
||||
},
|
||||
"i18n": {
|
||||
"type": "object",
|
||||
|
||||
@@ -118,7 +118,8 @@
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"role": {
|
||||
@@ -249,7 +250,8 @@
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"role": {
|
||||
@@ -336,7 +338,8 @@
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"data-draw-field-type": {
|
||||
@@ -408,6 +411,12 @@
|
||||
"default": true,
|
||||
"description": "Set `false` to now show the fields list on the right. Fields list is displayed by default."
|
||||
},
|
||||
"data-with-fields-detection": {
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": false,
|
||||
"description": "Display a button to automatically detect and add fields to the document with AI."
|
||||
},
|
||||
"data-with-field-placeholder": {
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
@@ -453,7 +462,7 @@
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "en",
|
||||
"description": "UI language, 'en', 'es', 'de', 'fr', 'pt', 'he', 'ar' languages are available."
|
||||
"description": "UI language, 'en', 'es', 'de', 'fr', 'pt', 'nl', 'he', 'ar' languages are available."
|
||||
},
|
||||
"data-background-color": {
|
||||
"type": "string",
|
||||
|
||||
@@ -142,7 +142,8 @@ const token = jwt.sign({
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"drawFieldType": {
|
||||
@@ -185,7 +186,8 @@ const token = jwt.sign({
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"role": {
|
||||
@@ -312,7 +314,8 @@ const token = jwt.sign({
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"role": {
|
||||
@@ -435,6 +438,12 @@ const token = jwt.sign({
|
||||
"default": true,
|
||||
"description": "Set `false` to now show the fields list on the right. Fields list is displayed by default."
|
||||
},
|
||||
"withFieldsDetection": {
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": false,
|
||||
"description": "Display a button to automatically detect and add fields to the document with AI."
|
||||
},
|
||||
"withFieldPlaceholder": {
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
@@ -474,7 +483,7 @@ const token = jwt.sign({
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "en",
|
||||
"description": "UI language, 'en', 'es', 'de', 'fr', 'pt', 'he', 'ar' languages are available."
|
||||
"description": "UI language, 'en', 'es', 'de', 'fr', 'pt', 'nl', 'he', 'ar' languages are available."
|
||||
},
|
||||
"i18n": {
|
||||
"type": "object",
|
||||
|
||||
@@ -163,7 +163,8 @@ const token = jwt.sign({
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"draw-field-type": {
|
||||
@@ -206,7 +207,8 @@ const token = jwt.sign({
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"role": {
|
||||
@@ -333,7 +335,8 @@ const token = jwt.sign({
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"role": {
|
||||
@@ -450,6 +453,12 @@ const token = jwt.sign({
|
||||
"default": true,
|
||||
"description": "Set `false` to now show the fields list on the right. Fields list is displayed by default."
|
||||
},
|
||||
"with-fields-detection": {
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"default": false,
|
||||
"description": "Display a button to automatically detect and add fields to the document with AI."
|
||||
},
|
||||
"with-field-placeholder": {
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
@@ -483,7 +492,7 @@ const token = jwt.sign({
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"default": "en",
|
||||
"description": "UI language, 'en', 'es', 'de', 'fr', 'pt', 'he', 'ar' languages are available."
|
||||
"description": "UI language, 'en', 'es', 'de', 'fr', 'pt', 'nl', 'he', 'ar' languages are available."
|
||||
},
|
||||
"i18n": {
|
||||
"type": "object",
|
||||
|
||||
@@ -30,7 +30,7 @@ export class AppComponent {}
|
||||
"src": {
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"description": "Public URL of the document signing form. There are two types of URLs: <li><code>/d/{slug}</code> - template form signing URL can be copied from the template page in the admin dashboard. Also template \"slug\" key can be obtained via the <code>/templates</code> API.</li><li><code>/s/{slug}</code> - individual signer URL. Signer \"slug\" key can be obtained via the <code>/submissions</code> API which is used to initiate signature requests for a template form with recipients.</li>"
|
||||
"description": "Public URL of the document signing form. There are two types of URLs: <ul class=\"list-inside list-disc\"><li><code>/d/{slug}</code> - template form signing URL can be copied from the template page in the admin dashboard. Also template \"slug\" key can be obtained via the <code>/templates</code> API.</li><li><code>/s/{slug}</code> - individual signer URL. Signer \"slug\" key can be obtained via the <code>/submissions</code> API which is used to initiate signature requests for a template form with recipients.</li></ul>"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"data-src": {
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"description": "Public URL of the document signing form. There are two types of URLs: <li><code>/d/{slug}</code> - template form signing URL can be copied from the template page in the admin dashboard. Also template \"slug\" key can be obtained via the <code>/templates</code> API.</li><li><code>/s/{slug}</code> - individual signer URL. Signer \"slug\" key can be obtained via the <code>/submissions</code> API which is used to initiate signature requests for a template form with recipients.</li>"
|
||||
"description": "Public URL of the document signing form. There are two types of URLs: <ul class=\"list-inside list-disc\"><li><code>/d/{slug}</code> - template form signing URL can be copied from the template page in the admin dashboard. Also template \"slug\" key can be obtained via the <code>/templates</code> API.</li><li><code>/s/{slug}</code> - individual signer URL. Signer \"slug\" key can be obtained via the <code>/submissions</code> API which is used to initiate signature requests for a template form with recipients.</li></ul>"
|
||||
},
|
||||
"data-email": {
|
||||
"type": "string",
|
||||
|
||||
@@ -27,7 +27,7 @@ export function App() {
|
||||
"src": {
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"description": "Public URL of the document signing form. There are two types of URLs: <li><code>/d/{slug}</code> - template form signing URL can be copied from the template page in the admin dashboard. Also template \"slug\" key can be obtained via the <code>/templates</code> API.</li><li><code>/s/{slug}</code> - individual signer URL. Signer \"slug\" key can be obtained via the <code>/submissions</code> API which is used to initiate signature requests for a template form with recipients.</li>"
|
||||
"description": "Public URL of the document signing form. There are two types of URLs: <ul class=\"list-inside list-disc\"><li><code>/d/{slug}</code> - template form signing URL can be copied from the template page in the admin dashboard. Also template \"slug\" key can be obtained via the <code>/templates</code> API.</li><li><code>/s/{slug}</code> - individual signer URL. Signer \"slug\" key can be obtained via the <code>/submissions</code> API which is used to initiate signature requests for a template form with recipients.</li></ul>"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
|
||||
@@ -36,7 +36,7 @@ export default {
|
||||
"src": {
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"description": "Public URL of the document signing form. There are two types of URLs: <li><code>/d/{slug}</code> - template form signing URL can be copied from the template page in the admin dashboard. Also template \"slug\" key can be obtained via the <code>/templates</code> API.</li><li><code>/s/{slug}</code> - individual signer URL. Signer \"slug\" key can be obtained via the <code>/submissions</code> API which is used to initiate signature requests for a template form with recipients.</li>"
|
||||
"description": "Public URL of the document signing form. There are two types of URLs: <ul class=\"list-inside list-disc\"><li><code>/d/{slug}</code> - template form signing URL can be copied from the template page in the admin dashboard. Also template \"slug\" key can be obtained via the <code>/templates</code> API.</li><li><code>/s/{slug}</code> - individual signer URL. Signer \"slug\" key can be obtained via the <code>/submissions</code> API which is used to initiate signature requests for a template form with recipients.</li></ul>"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
|
||||
@@ -251,7 +251,8 @@
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"required": {
|
||||
@@ -277,6 +278,10 @@
|
||||
"type": "string",
|
||||
"description": "Font color of the field value."
|
||||
},
|
||||
"background": {
|
||||
"type": "string",
|
||||
"description": "Field box background color."
|
||||
},
|
||||
"align": {
|
||||
"type": "string",
|
||||
"description": "Horizontal alignment of the field text value."
|
||||
@@ -300,6 +305,13 @@
|
||||
"mask": {
|
||||
"type": "boolean",
|
||||
"description": "Indicates if the field is masked on the document."
|
||||
},
|
||||
"reasons": {
|
||||
"description": "An array of signature reasons to choose from.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -714,7 +726,8 @@
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"required": {
|
||||
@@ -740,6 +753,10 @@
|
||||
"type": "string",
|
||||
"description": "Font color of the field value."
|
||||
},
|
||||
"background": {
|
||||
"type": "string",
|
||||
"description": "Field box background color."
|
||||
},
|
||||
"align": {
|
||||
"type": "string",
|
||||
"description": "Horizontal alignment of the field text value."
|
||||
@@ -763,6 +780,13 @@
|
||||
"mask": {
|
||||
"type": "boolean",
|
||||
"description": "Indicates if the field is masked on the document."
|
||||
},
|
||||
"reasons": {
|
||||
"description": "An array of signature reasons to choose from.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1782,6 +1806,11 @@
|
||||
"description": "Set to `true` to require phone 2FA verification via a one-time code sent to the phone number in order to access the documents.",
|
||||
"default": false
|
||||
},
|
||||
"require_email_2fa": {
|
||||
"type": "boolean",
|
||||
"description": "Set to `true` to require email 2FA verification via a one-time code sent to the email address in order to access the documents.",
|
||||
"default": false
|
||||
},
|
||||
"message": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -1933,6 +1962,15 @@
|
||||
],
|
||||
"default": "black"
|
||||
},
|
||||
"background": {
|
||||
"type": "string",
|
||||
"description": "Field box background color.",
|
||||
"enum": [
|
||||
"black",
|
||||
"white",
|
||||
"blue"
|
||||
]
|
||||
},
|
||||
"align": {
|
||||
"type": "string",
|
||||
"description": "Horizontal alignment of the field text value.",
|
||||
@@ -1986,6 +2024,13 @@
|
||||
}
|
||||
],
|
||||
"default": false
|
||||
},
|
||||
"reasons": {
|
||||
"description": "An array of signature reasons to choose from.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2622,6 +2667,10 @@
|
||||
"event_timestamp": {
|
||||
"type": "string",
|
||||
"description": "Date and time when the event was triggered."
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"description": "Additional event details object."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2733,7 +2782,8 @@
|
||||
"id": 1,
|
||||
"submitter_id": 2,
|
||||
"event_type": "view_form",
|
||||
"event_timestamp": "2023-12-14T15:47:24.566Z"
|
||||
"event_timestamp": "2023-12-14T15:47:24.566Z",
|
||||
"data": {}
|
||||
}
|
||||
],
|
||||
"documents": [
|
||||
@@ -3318,7 +3368,8 @@
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"role": {
|
||||
@@ -3471,6 +3522,15 @@
|
||||
"description": "Set to `true` to require phone 2FA verification via a one-time code sent to the phone number in order to access the documents.",
|
||||
"default": false
|
||||
},
|
||||
"require_email_2fa": {
|
||||
"type": "boolean",
|
||||
"description": "Set to `true` to require email 2FA verification via a one-time code sent to the email address in order to access the documents.",
|
||||
"default": false
|
||||
},
|
||||
"invite_by": {
|
||||
"type": "string",
|
||||
"description": "Set the role name of the previous party that should invite this party via email."
|
||||
},
|
||||
"fields": {
|
||||
"type": "array",
|
||||
"description": "A list of configurations for document form fields.",
|
||||
@@ -3609,6 +3669,15 @@
|
||||
],
|
||||
"default": "black"
|
||||
},
|
||||
"background": {
|
||||
"type": "string",
|
||||
"description": "Field box background color.",
|
||||
"enum": [
|
||||
"black",
|
||||
"white",
|
||||
"blue"
|
||||
]
|
||||
},
|
||||
"align": {
|
||||
"type": "string",
|
||||
"description": "Horizontal alignment of the field text value.",
|
||||
@@ -3662,6 +3731,13 @@
|
||||
}
|
||||
],
|
||||
"default": false
|
||||
},
|
||||
"reasons": {
|
||||
"description": "An array of signature reasons to choose from.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3744,7 +3820,6 @@
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"submission_id",
|
||||
"uuid",
|
||||
"email",
|
||||
"slug",
|
||||
@@ -3833,6 +3908,53 @@
|
||||
"awaiting"
|
||||
]
|
||||
},
|
||||
"values": {
|
||||
"type": "array",
|
||||
"description": "An array of pre-filled values for the submitter.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"field",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"field": {
|
||||
"type": "string",
|
||||
"description": "Document template field name."
|
||||
},
|
||||
"value": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "boolean"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "Pre-filled value of the field."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"description": "The role of the submitter."
|
||||
@@ -3944,7 +4066,8 @@
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"required": {
|
||||
@@ -3970,6 +4093,10 @@
|
||||
"type": "string",
|
||||
"description": "Font color of the field value."
|
||||
},
|
||||
"background": {
|
||||
"type": "string",
|
||||
"description": "Field box background color."
|
||||
},
|
||||
"align": {
|
||||
"type": "string",
|
||||
"description": "Horizontal alignment of the field text value."
|
||||
@@ -3993,6 +4120,13 @@
|
||||
"mask": {
|
||||
"type": "boolean",
|
||||
"description": "Indicates if the field is masked on the document."
|
||||
},
|
||||
"reasons": {
|
||||
"description": "An array of signature reasons to choose from.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -4040,27 +4174,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"documents": {
|
||||
"type": "array",
|
||||
"description": "List of documents attached to the one-off submission.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"attachment_uuid",
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"attachment_uuid": {
|
||||
"type": "string",
|
||||
"description": "Unique indentifier of attached document to the one-off submission."
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name of the attached document to the one-off submission."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"expire_at": {
|
||||
"type": "string",
|
||||
"description": "Specify the expiration date and time after which the submission becomes unavailable for signature.",
|
||||
@@ -4158,7 +4271,7 @@
|
||||
"Submissions"
|
||||
],
|
||||
"summary": "Create a submission from DOCX",
|
||||
"description": "The API endpoint provides functionality to create a one-off submission request from a DOCX file with dynamic content variables. Use <code>[[variable_name]]</code> text tags to define dynamic content variables in the document. See <a href=\"https://www.docuseal.com/examples/demo_template.docx\" target=\"_blank\" class=\"link font-bold\">https://www.docuseal.com/examples/demo_template.docx</a> for the specific text variable syntax, including dynamic content tables and list. You can also use the <code>{{signature}}</code> fillable field syntax to define fillable fields, as in a PDF.<br><b>Related Guides</b><br><a href=\"https://www.docuseal.com/guides/use-embedded-text-field-tags-in-the-pdf-to-create-a-fillable-form\" class=\"link\">Use embedded text field tags to create a fillable form</a>",
|
||||
"description": "The API endpoint provides functionality to create a one-off submission request from a DOCX file with dynamic content variables. Use <code>[[variable_name]]</code> text tags to define dynamic content variables in the document. See <a href=\"https://www.docuseal.com/examples/demo_template.docx\" target=\"_blank\" class=\"link font-bold\">https://www.docuseal.com/examples/demo_template.docx</a> for the specific text variable syntax, including dynamic content tables and list. You can also use the <code>{{signature}}</code> field syntax to define fillable fields, as in a PDF.<br><b>Related Guides</b><br><a href=\"https://www.docuseal.com/guides/use-dynamic-content-variables-in-docx-to-create-personalized-documents\" class=\"link\">Use dynamic content variables in DOCX to create personalized documents</a>",
|
||||
"operationId": "createSubmissionFromDocx",
|
||||
"parameters": [],
|
||||
"requestBody": {
|
||||
@@ -4189,7 +4302,7 @@
|
||||
},
|
||||
"variables": {
|
||||
"type": "object",
|
||||
"description": "Dynamic content variables object",
|
||||
"description": "Dynamic content variables object. Variable values can be strings, numbers, arrays, objects, or HTML content used to generate styled text, paragraphs, and tables in DOCX.",
|
||||
"example": {
|
||||
"variable_name": "value"
|
||||
}
|
||||
@@ -4327,6 +4440,15 @@
|
||||
"description": "Set to `true` to require phone 2FA verification via a one-time code sent to the phone number in order to access the documents.",
|
||||
"default": false
|
||||
},
|
||||
"require_email_2fa": {
|
||||
"type": "boolean",
|
||||
"description": "Set to `true` to require email 2FA verification via a one-time code sent to the email address in order to access the documents.",
|
||||
"default": false
|
||||
},
|
||||
"invite_by": {
|
||||
"type": "string",
|
||||
"description": "Set the role name of the previous party that should invite this party via email."
|
||||
},
|
||||
"fields": {
|
||||
"type": "array",
|
||||
"description": "A list of configurations for document form fields.",
|
||||
@@ -4465,6 +4587,15 @@
|
||||
],
|
||||
"default": "black"
|
||||
},
|
||||
"background": {
|
||||
"type": "string",
|
||||
"description": "Field box background color.",
|
||||
"enum": [
|
||||
"black",
|
||||
"white",
|
||||
"blue"
|
||||
]
|
||||
},
|
||||
"align": {
|
||||
"type": "string",
|
||||
"description": "Horizontal alignment of the field text value.",
|
||||
@@ -4518,6 +4649,13 @@
|
||||
}
|
||||
],
|
||||
"default": false
|
||||
},
|
||||
"reasons": {
|
||||
"description": "An array of signature reasons to choose from.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4595,7 +4733,6 @@
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"submission_id",
|
||||
"uuid",
|
||||
"email",
|
||||
"slug",
|
||||
@@ -4684,6 +4821,53 @@
|
||||
"awaiting"
|
||||
]
|
||||
},
|
||||
"values": {
|
||||
"type": "array",
|
||||
"description": "An array of pre-filled values for the submitter.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"field",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"field": {
|
||||
"type": "string",
|
||||
"description": "Document template field name."
|
||||
},
|
||||
"value": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "boolean"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "Pre-filled value of the field."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"description": "The role of the submitter."
|
||||
@@ -4795,7 +4979,8 @@
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"required": {
|
||||
@@ -4821,6 +5006,10 @@
|
||||
"type": "string",
|
||||
"description": "Font color of the field value."
|
||||
},
|
||||
"background": {
|
||||
"type": "string",
|
||||
"description": "Field box background color."
|
||||
},
|
||||
"align": {
|
||||
"type": "string",
|
||||
"description": "Horizontal alignment of the field text value."
|
||||
@@ -4844,6 +5033,13 @@
|
||||
"mask": {
|
||||
"type": "boolean",
|
||||
"description": "Indicates if the field is masked on the document."
|
||||
},
|
||||
"reasons": {
|
||||
"description": "An array of signature reasons to choose from.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -4891,27 +5087,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"documents": {
|
||||
"type": "array",
|
||||
"description": "List of documents attached to the one-off submission.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"attachment_uuid",
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"attachment_uuid": {
|
||||
"type": "string",
|
||||
"description": "Unique indentifier of attached document to the one-off submission."
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name of the attached document to the one-off submission."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"expire_at": {
|
||||
"type": "string",
|
||||
"description": "Specify the expiration date and time after which the submission becomes unavailable for signature.",
|
||||
@@ -5198,6 +5373,15 @@
|
||||
"description": "Set to `true` to require phone 2FA verification via a one-time code sent to the phone number in order to access the documents.",
|
||||
"default": false
|
||||
},
|
||||
"require_email_2fa": {
|
||||
"type": "boolean",
|
||||
"description": "Set to `true` to require email 2FA verification via a one-time code sent to the email address in order to access the documents.",
|
||||
"default": false
|
||||
},
|
||||
"invite_by": {
|
||||
"type": "string",
|
||||
"description": "Set the role name of the previous party that should invite this party via email."
|
||||
},
|
||||
"fields": {
|
||||
"type": "array",
|
||||
"description": "A list of configurations for document form fields.",
|
||||
@@ -5336,6 +5520,15 @@
|
||||
],
|
||||
"default": "black"
|
||||
},
|
||||
"background": {
|
||||
"type": "string",
|
||||
"description": "Field box background color.",
|
||||
"enum": [
|
||||
"black",
|
||||
"white",
|
||||
"blue"
|
||||
]
|
||||
},
|
||||
"align": {
|
||||
"type": "string",
|
||||
"description": "Horizontal alignment of the field text value.",
|
||||
@@ -5389,6 +5582,13 @@
|
||||
}
|
||||
],
|
||||
"default": false
|
||||
},
|
||||
"reasons": {
|
||||
"description": "An array of signature reasons to choose from.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5461,7 +5661,6 @@
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"submission_id",
|
||||
"uuid",
|
||||
"email",
|
||||
"slug",
|
||||
@@ -5550,6 +5749,53 @@
|
||||
"awaiting"
|
||||
]
|
||||
},
|
||||
"values": {
|
||||
"type": "array",
|
||||
"description": "An array of pre-filled values for the submitter.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"field",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"field": {
|
||||
"type": "string",
|
||||
"description": "Document template field name."
|
||||
},
|
||||
"value": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "boolean"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "Pre-filled value of the field."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"description": "The role of the submitter."
|
||||
@@ -5661,7 +5907,8 @@
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"required": {
|
||||
@@ -5687,6 +5934,10 @@
|
||||
"type": "string",
|
||||
"description": "Font color of the field value."
|
||||
},
|
||||
"background": {
|
||||
"type": "string",
|
||||
"description": "Field box background color."
|
||||
},
|
||||
"align": {
|
||||
"type": "string",
|
||||
"description": "Horizontal alignment of the field text value."
|
||||
@@ -5710,6 +5961,13 @@
|
||||
"mask": {
|
||||
"type": "boolean",
|
||||
"description": "Indicates if the field is masked on the document."
|
||||
},
|
||||
"reasons": {
|
||||
"description": "An array of signature reasons to choose from.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -5757,27 +6015,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"documents": {
|
||||
"type": "array",
|
||||
"description": "List of documents attached to the one-off submission.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"attachment_uuid",
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"attachment_uuid": {
|
||||
"type": "string",
|
||||
"description": "Unique indentifier of attached document to the one-off submission."
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name of the attached document to the one-off submission."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"expire_at": {
|
||||
"type": "string",
|
||||
"description": "Specify the expiration date and time after which the submission becomes unavailable for signature.",
|
||||
@@ -6078,6 +6315,10 @@
|
||||
"event_timestamp": {
|
||||
"type": "string",
|
||||
"description": "Date and time when the event was triggered."
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"description": "Additional event details object."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6185,7 +6426,8 @@
|
||||
"id": 12,
|
||||
"submitter_id": 7,
|
||||
"event_type": "view_form",
|
||||
"event_timestamp": "2023-12-14T15:47:17.351Z"
|
||||
"event_timestamp": "2023-12-14T15:47:17.351Z",
|
||||
"data": {}
|
||||
}
|
||||
],
|
||||
"values": [
|
||||
@@ -6435,6 +6677,15 @@
|
||||
],
|
||||
"default": "black"
|
||||
},
|
||||
"background": {
|
||||
"type": "string",
|
||||
"description": "Field box background color.",
|
||||
"enum": [
|
||||
"black",
|
||||
"white",
|
||||
"blue"
|
||||
]
|
||||
},
|
||||
"align": {
|
||||
"type": "string",
|
||||
"description": "Horizontal alignment of the field text value.",
|
||||
@@ -6488,6 +6739,13 @@
|
||||
}
|
||||
],
|
||||
"default": false
|
||||
},
|
||||
"reasons": {
|
||||
"description": "An array of signature reasons to choose from.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6990,6 +7248,10 @@
|
||||
"event_timestamp": {
|
||||
"type": "string",
|
||||
"description": "Date and time when the event was triggered."
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"description": "Additional event details object."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7126,7 +7388,8 @@
|
||||
"id": 12,
|
||||
"submitter_id": 7,
|
||||
"event_type": "view_form",
|
||||
"event_timestamp": "2023-12-14T15:48:17.351Z"
|
||||
"event_timestamp": "2023-12-14T15:48:17.351Z",
|
||||
"data": {}
|
||||
}
|
||||
],
|
||||
"values": [
|
||||
@@ -7346,7 +7609,8 @@
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"required": {
|
||||
@@ -7372,6 +7636,10 @@
|
||||
"type": "string",
|
||||
"description": "Font color of the field value."
|
||||
},
|
||||
"background": {
|
||||
"type": "string",
|
||||
"description": "Field box background color."
|
||||
},
|
||||
"align": {
|
||||
"type": "string",
|
||||
"description": "Horizontal alignment of the field text value."
|
||||
@@ -7395,6 +7663,13 @@
|
||||
"mask": {
|
||||
"type": "boolean",
|
||||
"description": "Indicates if the field is masked on the document."
|
||||
},
|
||||
"reasons": {
|
||||
"description": "An array of signature reasons to choose from.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -7793,7 +8068,8 @@
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"required": {
|
||||
@@ -7819,6 +8095,10 @@
|
||||
"type": "string",
|
||||
"description": "Font color of the field value."
|
||||
},
|
||||
"background": {
|
||||
"type": "string",
|
||||
"description": "Field box background color."
|
||||
},
|
||||
"align": {
|
||||
"type": "string",
|
||||
"description": "Horizontal alignment of the field text value."
|
||||
@@ -7842,6 +8122,13 @@
|
||||
"mask": {
|
||||
"type": "boolean",
|
||||
"description": "Indicates if the field is masked on the document."
|
||||
},
|
||||
"reasons": {
|
||||
"description": "An array of signature reasons to choose from.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -8294,7 +8581,8 @@
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"required": {
|
||||
@@ -8320,6 +8608,10 @@
|
||||
"type": "string",
|
||||
"description": "Font color of the field value."
|
||||
},
|
||||
"background": {
|
||||
"type": "string",
|
||||
"description": "Field box background color."
|
||||
},
|
||||
"align": {
|
||||
"type": "string",
|
||||
"description": "Horizontal alignment of the field text value."
|
||||
@@ -8343,6 +8635,13 @@
|
||||
"mask": {
|
||||
"type": "boolean",
|
||||
"description": "Indicates if the field is masked on the document."
|
||||
},
|
||||
"reasons": {
|
||||
"description": "An array of signature reasons to choose from.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -8674,7 +8973,8 @@
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"role": {
|
||||
@@ -8812,6 +9112,15 @@
|
||||
],
|
||||
"default": "black"
|
||||
},
|
||||
"background": {
|
||||
"type": "string",
|
||||
"description": "Field box background color.",
|
||||
"enum": [
|
||||
"black",
|
||||
"white",
|
||||
"blue"
|
||||
]
|
||||
},
|
||||
"align": {
|
||||
"type": "string",
|
||||
"description": "Horizontal alignment of the field text value.",
|
||||
@@ -8865,6 +9174,13 @@
|
||||
}
|
||||
],
|
||||
"default": false
|
||||
},
|
||||
"reasons": {
|
||||
"description": "An array of signature reasons to choose from.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8989,7 +9305,8 @@
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"required": {
|
||||
@@ -9015,6 +9332,10 @@
|
||||
"type": "string",
|
||||
"description": "Font color of the field value."
|
||||
},
|
||||
"background": {
|
||||
"type": "string",
|
||||
"description": "Field box background color."
|
||||
},
|
||||
"align": {
|
||||
"type": "string",
|
||||
"description": "Horizontal alignment of the field text value."
|
||||
@@ -9038,6 +9359,13 @@
|
||||
"mask": {
|
||||
"type": "boolean",
|
||||
"description": "Indicates if the field is masked on the document."
|
||||
},
|
||||
"reasons": {
|
||||
"description": "An array of signature reasons to choose from.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -9369,7 +9697,8 @@
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"role": {
|
||||
@@ -9515,6 +9844,15 @@
|
||||
],
|
||||
"default": "black"
|
||||
},
|
||||
"background": {
|
||||
"type": "string",
|
||||
"description": "Field box background color.",
|
||||
"enum": [
|
||||
"black",
|
||||
"white",
|
||||
"blue"
|
||||
]
|
||||
},
|
||||
"align": {
|
||||
"type": "string",
|
||||
"description": "Horizontal alignment of the field text value.",
|
||||
@@ -9568,6 +9906,13 @@
|
||||
}
|
||||
],
|
||||
"default": false
|
||||
},
|
||||
"reasons": {
|
||||
"description": "An array of signature reasons to choose from.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9702,7 +10047,8 @@
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"required": {
|
||||
@@ -9728,6 +10074,10 @@
|
||||
"type": "string",
|
||||
"description": "Font color of the field value."
|
||||
},
|
||||
"background": {
|
||||
"type": "string",
|
||||
"description": "Field box background color."
|
||||
},
|
||||
"align": {
|
||||
"type": "string",
|
||||
"description": "Horizontal alignment of the field text value."
|
||||
@@ -9751,6 +10101,13 @@
|
||||
"mask": {
|
||||
"type": "boolean",
|
||||
"description": "Indicates if the field is masked on the document."
|
||||
},
|
||||
"reasons": {
|
||||
"description": "An array of signature reasons to choose from.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -10169,7 +10526,8 @@
|
||||
"stamp",
|
||||
"payment",
|
||||
"phone",
|
||||
"verification"
|
||||
"verification",
|
||||
"strikethrough"
|
||||
]
|
||||
},
|
||||
"required": {
|
||||
@@ -10195,6 +10553,10 @@
|
||||
"type": "string",
|
||||
"description": "Font color of the field value."
|
||||
},
|
||||
"background": {
|
||||
"type": "string",
|
||||
"description": "Field box background color."
|
||||
},
|
||||
"align": {
|
||||
"type": "string",
|
||||
"description": "Horizontal alignment of the field text value."
|
||||
@@ -10218,6 +10580,13 @@
|
||||
"mask": {
|
||||
"type": "boolean",
|
||||
"description": "Indicates if the field is masked on the document."
|
||||
},
|
||||
"reasons": {
|
||||
"description": "An array of signature reasons to choose from.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -281,6 +281,10 @@ Get submission creation, completion, expiration, and archiving notifications usi
|
||||
"event_timestamp": {
|
||||
"type": "string",
|
||||
"description": "Date and time when the event was triggered."
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"description": "Additional event details object."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,35 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module DownloadUtils
|
||||
LOCALHOSTS = %w[0.0.0.0 127.0.0.1 localhost].freeze
|
||||
LOCALHOSTS = Set[
|
||||
'0.0.0.0',
|
||||
'127.0.0.1',
|
||||
'127.0.1.1',
|
||||
'localhost',
|
||||
'localhost.localdomain',
|
||||
'::1',
|
||||
'[::1]',
|
||||
'ip6-localhost',
|
||||
'ip6-loopback',
|
||||
'127.0.0.0',
|
||||
'127.255.255.255',
|
||||
'::',
|
||||
'0:0:0:0:0:0:0:1',
|
||||
'[0:0:0:0:0:0:0:1]',
|
||||
'0000:0000:0000:0000:0000:0000:0000:0001',
|
||||
'[0000:0000:0000:0000:0000:0000:0000:0001]',
|
||||
'::0',
|
||||
'0::0',
|
||||
'::ffff:127.0.0.1',
|
||||
'[::ffff:127.0.0.1]',
|
||||
'::ffff:7f00:1',
|
||||
'[::ffff:7f00:1]',
|
||||
'local',
|
||||
'localhost.local',
|
||||
'ip6-localnet',
|
||||
'ip6-allnodes',
|
||||
'ip6-allrouters'
|
||||
].freeze
|
||||
|
||||
UnableToDownload = Class.new(StandardError)
|
||||
|
||||
@@ -14,10 +42,7 @@ module DownloadUtils
|
||||
Addressable::URI.parse(url).normalize
|
||||
end
|
||||
|
||||
if Docuseal.multitenant?
|
||||
raise UnableToDownload, "Error loading: #{uri}. Only HTTPS is allowed." if uri.scheme != 'https'
|
||||
raise UnableToDownload, "Error loading: #{uri}. Can't download from localhost." if uri.host.in?(LOCALHOSTS)
|
||||
end
|
||||
validate_uri!(uri) if Docuseal.multitenant?
|
||||
|
||||
resp = conn.get(uri)
|
||||
|
||||
@@ -26,9 +51,16 @@ module DownloadUtils
|
||||
resp
|
||||
end
|
||||
|
||||
def validate_uri!(uri)
|
||||
raise UnableToDownload, "Error loading: #{uri}. Only HTTPS is allowed." if uri.scheme != 'https'
|
||||
raise UnableToDownload, "Error loading: #{uri}. Can't download from localhost." if uri.host.in?(LOCALHOSTS)
|
||||
end
|
||||
|
||||
def conn
|
||||
Faraday.new do |faraday|
|
||||
faraday.response :follow_redirects
|
||||
faraday.response :follow_redirects, callback: lambda { |_, new_env|
|
||||
validate_uri!(new_env[:url]) if Docuseal.multitenant?
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -71,7 +71,11 @@ module Params
|
||||
end
|
||||
|
||||
def validate_submitter(submitter_params)
|
||||
required(submitter_params, %i[email phone name])
|
||||
if submitter_params['invite_by'].present?
|
||||
required(submitter_params, :role)
|
||||
else
|
||||
required(submitter_params, %i[email phone name])
|
||||
end
|
||||
|
||||
type(submitter_params, :name, String)
|
||||
type(submitter_params, :reply_to, String)
|
||||
|
||||
@@ -81,7 +81,7 @@ module Submissions
|
||||
|
||||
next if submission.submitters.blank?
|
||||
|
||||
maybe_add_invite_submitters(submission, template)
|
||||
maybe_add_invite_submitters(submission, template, attrs[:submitters])
|
||||
|
||||
submission.template = nil unless with_template
|
||||
|
||||
@@ -102,8 +102,16 @@ module Submissions
|
||||
end
|
||||
end
|
||||
|
||||
def maybe_add_invite_submitters(submission, template)
|
||||
def maybe_add_invite_submitters(submission, template, submitter_attrs)
|
||||
template.submitters.each_with_index do |item, index|
|
||||
submitter_attr = submitter_attrs.find { |e| e['role'].to_s.casecmp?(item['name'].to_s) }
|
||||
|
||||
if submitter_attr && submitter_attr['invite_by'].present?
|
||||
invite_by_uuid = template.submitters.find { |s| s['name'] == submitter_attr['invite_by'] }&.dig('uuid')
|
||||
|
||||
item = item.merge('invite_by_uuid' => invite_by_uuid) if invite_by_uuid
|
||||
end
|
||||
|
||||
next if item['invite_by_uuid'].blank? && item['optional_invite_by_uuid'].blank?
|
||||
next if submission.template_submitters.any? { |e| e['uuid'] == item['uuid'] }
|
||||
|
||||
|
||||
@@ -250,7 +250,7 @@ module Submissions
|
||||
submission.submission_events.find { |e| e.submitter_id == submitter.id && e.click_email? }
|
||||
|
||||
verify_email_event =
|
||||
submission.submission_events.find { |e| e.submitter_id == submitter.id && e.phone_verified? }
|
||||
submission.submission_events.find { |e| e.submitter_id == submitter.id && e.email_verified? }
|
||||
|
||||
is_phone_verified =
|
||||
submission.template_fields.any? do |e|
|
||||
|
||||
@@ -522,10 +522,17 @@ module Submissions
|
||||
if field['type'].in?(%w[multiple radio])
|
||||
option = field['options']&.find { |o| o['uuid'] == area['option_uuid'] }
|
||||
|
||||
option_name = option['value'].presence
|
||||
option_name ||= "#{I18n.t('option', locale: locale)} #{field['options'].index(option) + 1}"
|
||||
value =
|
||||
if option
|
||||
option_name = option['value'].presence
|
||||
option_name ||= "#{I18n.t('option', locale: locale)} #{field['options'].index(option) + 1}"
|
||||
|
||||
value = Array.wrap(value).include?(option_name)
|
||||
Array.wrap(value).include?(option_name)
|
||||
else
|
||||
Rollbar.error("Invalid option: #{field['uuid']}") if defined?(Rollbar)
|
||||
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
next unless value == true
|
||||
|
||||
@@ -106,7 +106,8 @@ module Submitters
|
||||
if AccountConfig.exists?(account_id: submitter.submission.account_id,
|
||||
key: AccountConfig::COMBINE_PDF_RESULT_KEY,
|
||||
value: true) &&
|
||||
submitter.submission.submitters.all?(&:completed_at?)
|
||||
submitter.submission.submitters.all?(&:completed_at?) &&
|
||||
submitter.submission.template_fields.none? { |f| f['type'] == 'verification' }
|
||||
return [submitter.submission.combined_document_attachment || Submissions::EnsureCombinedGenerated.call(submitter)]
|
||||
end
|
||||
|
||||
@@ -157,6 +158,7 @@ module Submitters
|
||||
preferences['send_email'] = params['send_email'].in?(TRUE_VALUES) if params.key?('send_email')
|
||||
preferences['send_sms'] = params['send_sms'].in?(TRUE_VALUES) if params.key?('send_sms')
|
||||
preferences['require_phone_2fa'] = params['require_phone_2fa'].in?(TRUE_VALUES) if params.key?('require_phone_2fa')
|
||||
preferences['require_email_2fa'] = params['require_email_2fa'].in?(TRUE_VALUES) if params.key?('require_email_2fa')
|
||||
preferences['bcc_completed'] = params['bcc_completed'] if params.key?('bcc_completed')
|
||||
preferences['reply_to'] = params['reply_to'] if params.key?('reply_to')
|
||||
preferences['go_to_last'] = params['go_to_last'] if params.key?('go_to_last')
|
||||
|
||||
@@ -24,7 +24,7 @@ module TextUtils
|
||||
text.to_s.gsub(TRANSLITERATION_REGEXP) { |e| TRANSLITERATIONS[e] }
|
||||
end
|
||||
|
||||
def mask_value(text, unmask_size = 0)
|
||||
def mask_value(text, unmask_size = 0, mask_symbol = MASK_SYMBOL)
|
||||
if unmask_size.is_a?(Numeric) && !unmask_size.zero? && unmask_size.abs < text.length
|
||||
if unmask_size.negative?
|
||||
[
|
||||
@@ -34,14 +34,34 @@ module TextUtils
|
||||
elsif unmask_size.positive?
|
||||
[
|
||||
text.first(unmask_size),
|
||||
text.last(text.length - unmask_size).gsub(MASK_REGEXP, MASK_SYMBOL)
|
||||
text.last(text.length - unmask_size).gsub(MASK_REGEXP, mask_symbol)
|
||||
].join
|
||||
end
|
||||
else
|
||||
text.to_s.gsub(MASK_REGEXP, MASK_SYMBOL)
|
||||
text.to_s.gsub(MASK_REGEXP, mask_symbol)
|
||||
end
|
||||
end
|
||||
|
||||
def mask_email(email, unmask_size = 2)
|
||||
return email if email.exclude?('@')
|
||||
|
||||
local, domain = email.split('@', 2)
|
||||
|
||||
return email if local.blank? || domain.blank?
|
||||
|
||||
masked_local = mask_value(local, unmask_size, '*')
|
||||
domain_parts = domain.split('.')
|
||||
|
||||
if domain_parts.blank? || domain_parts[0].blank?
|
||||
masked_domain = mask_value(domain, 1, '*')
|
||||
else
|
||||
domain_parts[0] = mask_value(domain_parts[0], 1, '*')
|
||||
masked_domain = domain_parts.join('.')
|
||||
end
|
||||
|
||||
"#{masked_local}@#{masked_domain}"
|
||||
end
|
||||
|
||||
def maybe_rtl_reverse(text)
|
||||
if text.match?(RTL_REGEXP)
|
||||
TwitterCldr::Shared::Bidi
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class DeviseMailerPreview < ActionMailer::Preview
|
||||
def reset_password_instructions
|
||||
user = User.first
|
||||
token = user.send(:set_reset_password_token)
|
||||
Devise::Mailer.reset_password_instructions(user, token)
|
||||
end
|
||||
end
|
||||
@@ -22,4 +22,8 @@ class SubmitterMailerPreview < ActionMailer::Preview
|
||||
|
||||
SubmitterMailer.documents_copy_email(submitter)
|
||||
end
|
||||
|
||||
def otp_verification_email
|
||||
SubmitterMailer.otp_verification_email(Submitter.last)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1130,4 +1130,76 @@ RSpec.describe 'Signing Form' do
|
||||
end.to change(ProcessSubmitterCompletionJob.jobs, :size).by(1)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the 2FA email verification is enabled', sidekiq: :inline do
|
||||
let(:template) { create(:template, account:, author:, only_field_types: %w[text]) }
|
||||
let(:submission) { create(:submission, template:) }
|
||||
let(:submitter) do
|
||||
create(:submitter, submission:, uuid: template.submitters.first['uuid'], account:)
|
||||
end
|
||||
|
||||
before do
|
||||
template.update(preferences: { require_email_2fa: true })
|
||||
create(:encrypted_config, key: EncryptedConfig::ESIGN_CERTS_KEY,
|
||||
value: GenerateCertificate.call.transform_values(&:to_pem))
|
||||
end
|
||||
|
||||
it 'completes the form if the one-time password is filled correctly' do
|
||||
visit submit_form_path(slug: submitter.slug)
|
||||
|
||||
click_button 'Send verification code'
|
||||
|
||||
email = ActionMailer::Base.deliveries.last
|
||||
one_time_code = email.body.encoded[%r{<b>(\d{6})</b>}, 1]
|
||||
|
||||
fill_in 'one_time_code', with: one_time_code
|
||||
|
||||
click_button 'Submit'
|
||||
|
||||
fill_in 'First Name', with: 'Mary'
|
||||
click_button 'Complete'
|
||||
|
||||
expect(page).to have_content('Form has been completed!')
|
||||
|
||||
submitter.reload
|
||||
|
||||
expect(submitter.completed_at).to be_present
|
||||
expect(field_value(submitter, 'First Name')).to eq 'Mary'
|
||||
end
|
||||
|
||||
it "doesn't complete the form if the one-time code is invalid" do
|
||||
visit submit_form_path(slug: submitter.slug)
|
||||
|
||||
click_button 'Send verification code'
|
||||
fill_in 'one_time_code', with: '123456'
|
||||
click_button 'Submit'
|
||||
|
||||
expect(page).to have_content 'Invalid code'
|
||||
end
|
||||
|
||||
it 'completes the form after resending the one time code' do
|
||||
visit submit_form_path(slug: submitter.slug)
|
||||
|
||||
click_button 'Send verification code'
|
||||
|
||||
find('#resend_label').click
|
||||
|
||||
email = ActionMailer::Base.deliveries.last
|
||||
one_time_code = email.body.encoded[%r{<b>(\d{6})</b>}, 1]
|
||||
|
||||
fill_in 'one_time_code', with: one_time_code
|
||||
|
||||
click_button 'Submit'
|
||||
|
||||
fill_in 'First Name', with: 'Mary'
|
||||
click_button 'Complete'
|
||||
|
||||
expect(page).to have_content('Form has been completed!')
|
||||
|
||||
submitter.reload
|
||||
|
||||
expect(submitter.completed_at).to be_present
|
||||
expect(field_value(submitter, 'First Name')).to eq 'Mary'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||