Skip to content

Commit 22afd01

Browse files
authored
Merge from docusealco/wip
2 parents f87ef67 + fd9eb09 commit 22afd01

27 files changed

+627
-359
lines changed

.rubocop.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ Metrics/PerceivedComplexity:
4545
Style/MultipleComparison:
4646
Enabled: false
4747

48+
Style/NumericPredicate:
49+
Enabled: false
50+
4851
Naming/PredicateMethod:
4952
Enabled: false
5053

app/controllers/personalization_settings_controller.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ class PersonalizationSettingsController < ApplicationController
44
ALLOWED_KEYS = [
55
AccountConfig::FORM_COMPLETED_BUTTON_KEY,
66
AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY,
7+
AccountConfig::SUBMITTER_INVITATION_REMINDER_EMAIL_KEY,
78
AccountConfig::SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY,
89
AccountConfig::SUBMITTER_COMPLETED_EMAIL_KEY,
910
AccountConfig::FORM_COMPLETED_MESSAGE_KEY,

app/controllers/templates_preferences_controller.rb

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,15 @@
33
class TemplatesPreferencesController < ApplicationController
44
load_and_authorize_resource :template
55

6+
RESETTABLE_PREFERENCE_KEYS = {
7+
AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY => %w[request_email_subject request_email_body submitters],
8+
AccountConfig::SUBMITTER_INVITATION_REMINDER_EMAIL_KEY => %w[invitation_reminder_email_subject
9+
invitation_reminder_email_body],
10+
AccountConfig::SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY => %w[documents_copy_email_subject documents_copy_email_body],
11+
AccountConfig::SUBMITTER_COMPLETED_EMAIL_KEY => %w[completed_notification_email_subject
12+
completed_notification_email_body]
13+
}.freeze
14+
615
def show; end
716

817
def create
@@ -15,19 +24,38 @@ def create
1524
head :ok
1625
end
1726

27+
def destroy
28+
authorize!(:update, @template)
29+
30+
config_key = params[:config_key]
31+
preferences_to_delete = RESETTABLE_PREFERENCE_KEYS[config_key]
32+
33+
return head :ok if preferences_to_delete.blank?
34+
35+
preferences_to_delete.each do |key|
36+
@template.preferences.delete(key)
37+
end
38+
39+
@template.save!
40+
41+
render turbo_stream: turbo_stream.replace("#{config_key}_form",
42+
partial: "templates_preferences/#{config_key}_form"),
43+
status: :ok
44+
end
45+
1846
private
1947

2048
def template_params
2149
params.require(:template).permit(
2250
preferences: %i[bcc_completed request_email_subject request_email_body
51+
invitation_reminder_email_subject invitation_reminder_email_body
2352
documents_copy_email_subject documents_copy_email_body
2453
documents_copy_email_enabled documents_copy_email_attach_audit
2554
documents_copy_email_attach_documents documents_copy_email_reply_to
2655
completed_notification_email_attach_documents
2756
completed_redirect_url validate_unique_submitters
2857
require_all_submitters submitters_order require_phone_2fa
29-
default_expire_at_duration shared_link_2fa
30-
default_expire_at request_email_enabled
58+
default_expire_at_duration shared_link_2fa default_expire_at request_email_enabled
3159
completed_notification_email_subject completed_notification_email_body
3260
completed_notification_email_enabled completed_notification_email_attach_audit] +
3361
[completed_message: %i[title body],

app/controllers/users_controller.rb

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,19 @@ def new; end
2424
def edit; end
2525

2626
def create
27-
if User.accessible_by(current_ability).exists?(email: @user.email)
28-
@user.errors.add(:email, I18n.t('already_exists'))
27+
existing_user = User.accessible_by(current_ability).find_by(email: @user.email)
28+
29+
if existing_user
30+
if existing_user.archived_at? &&
31+
current_ability.can?(:manage, existing_user) && current_ability.can?(:manage, @user.account)
32+
existing_user.assign_attributes(@user.slice(:first_name, :last_name, :role, :account_id))
33+
existing_user.archived_at = nil
34+
@user = existing_user
35+
else
36+
@user.errors.add(:email, I18n.t('already_exists'))
2937

30-
return render turbo_stream: turbo_stream.replace(:modal, template: 'users/new'), status: :unprocessable_content
38+
return render turbo_stream: turbo_stream.replace(:modal, template: 'users/new'), status: :unprocessable_content
39+
end
3140
end
3241

3342
@user.password = SecureRandom.hex if @user.password.blank?

app/javascript/submission_form/signature_step.vue

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@
211211
@input="updateWrittenSignature"
212212
>
213213
<select
214-
v-if="requireSigningReason && !isOtherReason"
214+
v-if="withSigningReason && !isOtherReason"
215215
class="select base-input !text-2xl w-full mt-6 text-center"
216216
:class="{ 'text-gray-300': !reason }"
217217
required
@@ -226,24 +226,37 @@
226226
>
227227
{{ t('select_a_reason') }}
228228
</option>
229-
<option
230-
v-for="(label, option) in defaultReasons"
231-
:key="option"
232-
:value="option"
233-
:selected="reason === option"
234-
class="text-base-content"
235-
>
236-
{{ label }}
237-
</option>
238-
<option
239-
value="other"
240-
class="text-base-content"
241-
>
242-
{{ t('other') }}
243-
</option>
229+
<template v-if="field.preferences?.reasons">
230+
<option
231+
v-for="option in field.preferences.reasons"
232+
:key="option"
233+
:value="option"
234+
:selected="reason === option"
235+
class="text-base-content"
236+
>
237+
{{ option }}
238+
</option>
239+
</template>
240+
<template v-else>
241+
<option
242+
v-for="(label, option) in defaultReasons"
243+
:key="option"
244+
:value="option"
245+
:selected="reason === option"
246+
class="text-base-content"
247+
>
248+
{{ label }}
249+
</option>
250+
<option
251+
value="other"
252+
class="text-base-content"
253+
>
254+
{{ t('other') }}
255+
</option>
256+
</template>
244257
</select>
245258
<input
246-
v-if="requireSigningReason && isOtherReason"
259+
v-if="withSigningReason && isOtherReason"
247260
class="base-input !text-2xl w-full mt-6"
248261
required
249262
:name="`values[${field.preferences.reason_field_uuid}]`"
@@ -253,7 +266,7 @@
253266
@input="$emit('update:reason', $event.target.value)"
254267
>
255268
<input
256-
v-if="requireSigningReason"
269+
v-if="withSigningReason"
257270
hidden
258271
name="with_reason"
259272
:value="field.preferences.reason_field_uuid"
@@ -406,6 +419,9 @@ export default {
406419
format () {
407420
return this.field.preferences?.format
408421
},
422+
withSigningReason () {
423+
return this.requireSigningReason || this.field.preferences?.reasons?.length
424+
},
409425
defaultReasons () {
410426
return {
411427
[this.t('approved_by')]: this.t('approved'),
@@ -424,10 +440,11 @@ export default {
424440
created () {
425441
this.isSignatureStarted = !!this.computedPreviousValue
426442
427-
if (this.requireSigningReason) {
443+
if (this.withSigningReason) {
428444
this.field.preferences ||= {}
429445
this.field.preferences.reason_field_uuid ||= v4()
430-
this.isOtherReason = this.reason && !this.defaultReasons[this.reason]
446+
this.isOtherReason = this.reason && !this.defaultReasons[this.reason] &&
447+
(!this.field.preferences?.reasons?.length || !this.field.preferences.reasons.includes(this.reason))
431448
}
432449
},
433450
async mounted () {

app/javascript/template_builder/fields.vue

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@
236236
</span>
237237
</template>
238238
<template v-else>
239-
<IconListSearch width="22" />
239+
<IconSparkles width="22" />
240240
<span
241241
class="hidden md:inline"
242242
>
@@ -268,7 +268,7 @@
268268
import Field from './field'
269269
import FieldType from './field_type'
270270
import FieldSubmitter from './field_submitter'
271-
import { IconLock, IconCirclePlus, IconInnerShadowTop, IconListSearch } from '@tabler/icons-vue'
271+
import { IconLock, IconCirclePlus, IconInnerShadowTop, IconSparkles } from '@tabler/icons-vue'
272272
import IconDrag from './icon_drag'
273273
274274
export default {
@@ -277,7 +277,7 @@ export default {
277277
Field,
278278
FieldType,
279279
IconCirclePlus,
280-
IconListSearch,
280+
IconSparkles,
281281
IconInnerShadowTop,
282282
FieldSubmitter,
283283
IconDrag,
@@ -470,9 +470,13 @@ export default {
470470
const data = JSON.parse(jsonStr)
471471
472472
if (data.error) {
473-
alert(data.error)
473+
if ((data.fields || fields).length) {
474+
this.template.fields = data.fields || fields
474475
475-
this.template.fields = data.fields || fields
476+
this.save()
477+
} else {
478+
alert(data.error)
479+
}
476480
477481
break
478482
} else if (data.analyzing) {

app/javascript/template_builder/i18n.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ const en = {
188188
}
189189

190190
const es = {
191+
autodetect_fields: 'Autodetectar campos',
191192
analyzing_: 'Analizando...',
192193
download: 'Descargar',
193194
downloading_: 'Descargando...',
@@ -376,6 +377,7 @@ const es = {
376377
}
377378

378379
const it = {
380+
autodetect_fields: 'Rileva campi',
379381
analyzing_: 'Analisi...',
380382
download: 'Scarica',
381383
downloading_: 'Download in corso...',
@@ -564,6 +566,7 @@ const it = {
564566
}
565567

566568
const pt = {
569+
autodetect_fields: 'Detectar campos',
567570
analyzing_: 'Analisando...',
568571
download: 'Baixar',
569572
downloading_: 'Baixando...',
@@ -752,6 +755,7 @@ const pt = {
752755
}
753756

754757
const fr = {
758+
autodetect_fields: 'Détecter les champs',
755759
analyzing_: 'Analyse...',
756760
download: 'Télécharger',
757761
downloading_: 'Téléchargement...',
@@ -940,6 +944,7 @@ const fr = {
940944
}
941945

942946
const de = {
947+
autodetect_fields: 'Felder erkennen',
943948
analyzing_: 'Analysiere...',
944949
download: 'Download',
945950
downloading_: 'Download...',
@@ -1128,6 +1133,7 @@ const de = {
11281133
}
11291134

11301135
const nl = {
1136+
autodetect_fields: 'Velden detecteren',
11311137
analyzing_: 'Analyseren...',
11321138
download: 'Downloaden',
11331139
downloading_: 'Downloaden...',

app/jobs/send_submitter_invitation_email_job.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ def perform(params = {})
77
submitter = Submitter.find(params['submitter_id'])
88

99
return if submitter.completed_at?
10+
return if submitter.submission.archived_at?
11+
return if submitter.template&.archived_at?
1012
return if submitter.submission.source == 'invite' && !Accounts.can_send_emails?(submitter.account, on_events: true)
1113

1214
unless Accounts.can_send_invitation_emails?(submitter.account)

app/models/account_config.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#
2323
class AccountConfig < ApplicationRecord
2424
SUBMITTER_INVITATION_EMAIL_KEY = 'submitter_invitation_email'
25+
SUBMITTER_INVITATION_REMINDER_EMAIL_KEY = 'submitter_invitation_reminder_email'
2526
SUBMITTER_COMPLETED_EMAIL_KEY = 'submitter_completed_email'
2627
SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY = 'submitter_documents_copy_email'
2728
BCC_EMAILS = 'bcc_emails'
@@ -59,6 +60,12 @@ class AccountConfig < ApplicationRecord
5960
'body' => I18n.t(:submitter_invitation_email_sign_body)
6061
}
6162
},
63+
SUBMITTER_INVITATION_REMINDER_EMAIL_KEY => lambda {
64+
{
65+
'subject' => I18n.t(:you_are_invited_to_sign_a_document),
66+
'body' => I18n.t(:submitter_invitation_email_sign_body)
67+
}
68+
},
6269
SUBMITTER_COMPLETED_EMAIL_KEY => lambda {
6370
{
6471
'subject' => I18n.t(:template_name_has_been_completed_by_submitters),
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<svg class="<%= local_assigns[:class] %>" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2+
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
3+
<path d="M3 5a1 1 0 0 1 1 -1h16a1 1 0 0 1 1 1v10a1 1 0 0 1 -1 1h-16a1 1 0 0 1 -1 -1v-10z" />
4+
<path d="M7 20h10" /><path d="M9 16v4" />
5+
<path d="M15 16v4" /></svg>
6+
<path d="M9 16v4" />
7+
<path d="M15 16v4" />
8+
</svg>

0 commit comments

Comments
 (0)