Skip to content

Commit 6ab68cc

Browse files
authored
Merge from docusealco/wip
2 parents aa38773 + ee2400a commit 6ab68cc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+2168
-760
lines changed

Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ ENV OPENSSL_CONF=/etc/openssl_legacy.cnf
5151

5252
WORKDIR /app
5353

54-
RUN apk add --no-cache sqlite-dev libpq-dev mariadb-dev vips-dev yaml-dev redis libheif vips-heif gcompat ttf-freefont onnxruntime && mkdir /fonts && rm /usr/share/fonts/freefont/FreeSans.otf
54+
RUN apk add --no-cache sqlite-dev libpq-dev vips-dev yaml-dev redis libheif vips-heif gcompat ttf-freefont onnxruntime && mkdir /fonts && rm /usr/share/fonts/freefont/FreeSans.otf
5555

5656
RUN addgroup -g 2000 docuseal && adduser -u 2000 -G docuseal -s /bin/sh -D -h /home/docuseal docuseal
5757

@@ -69,7 +69,7 @@ activate = 1' >> /etc/openssl_legacy.cnf
6969

7070
COPY --chown=docuseal:docuseal ./Gemfile ./Gemfile.lock ./
7171

72-
RUN apk add --no-cache build-base && bundle install && apk del --no-cache build-base && rm -rf ~/.bundle /usr/local/bundle/cache && ruby -e "puts Dir['/usr/local/bundle/**/{spec,rdoc,resources/shared,resources/collation,resources/locales}']" | xargs rm -rf && ln -sf /usr/lib/libonnxruntime.so.1 $(ruby -e "print Dir[Gem::Specification.find_by_name('onnxruntime').gem_dir + '/vendor/*.so'].first")
72+
RUN apk add --no-cache build-base git && bundle install && apk del --no-cache build-base git && rm -rf ~/.bundle /usr/local/bundle/cache && ruby -e "puts Dir['/usr/local/bundle/**/{spec,rdoc,resources/shared,resources/collation,resources/locales}']" | xargs rm -rf && ln -sf /usr/lib/libonnxruntime.so.1 $(ruby -e "print Dir[Gem::Specification.find_by_name('onnxruntime').gem_dir + '/vendor/*.so'].first")
7373

7474
COPY --chown=docuseal:docuseal ./bin ./bin
7575
COPY --chown=docuseal:docuseal ./app ./app

Gemfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ gem 'hexapdf'
2323
gem 'image_processing'
2424
gem 'jwt', require: false
2525
gem 'lograge'
26-
gem 'mysql2', require: false
2726
gem 'numo-narray-alt', require: false
2827
gem 'oj'
2928
gem 'onnxruntime', require: false
@@ -45,6 +44,7 @@ gem 'shakapacker'
4544
gem 'sidekiq'
4645
gem 'sqlite3', require: false
4746
gem 'strip_attributes'
47+
gem 'trilogy', github: 'trilogy-libraries/trilogy', glob: 'contrib/ruby/*.gemspec', require: false
4848
gem 'turbo-rails'
4949
gem 'twitter_cldr', require: false
5050
gem 'tzinfo-data'

Gemfile.lock

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
GIT
2+
remote: https://github.com/trilogy-libraries/trilogy.git
3+
revision: 3963d490459df7a2b5bedb42424c3285f25eab22
4+
glob: contrib/ruby/*.gemspec
5+
specs:
6+
trilogy (2.10.0)
7+
bigdecimal
8+
19
GEM
210
remote: https://rubygems.org/
311
specs:
@@ -318,8 +326,6 @@ GEM
318326
prism (~> 1.5)
319327
msgpack (1.8.0)
320328
multi_json (1.19.1)
321-
mysql2 (0.5.7)
322-
bigdecimal
323329
net-http (0.9.1)
324330
uri (>= 0.11.1)
325331
net-imap (0.6.2)
@@ -644,7 +650,6 @@ DEPENDENCIES
644650
jwt
645651
letter_opener_web
646652
lograge
647-
mysql2
648653
numo-narray-alt
649654
oj
650655
onnxruntime
@@ -673,6 +678,7 @@ DEPENDENCIES
673678
simplecov
674679
sqlite3
675680
strip_attributes
681+
trilogy!
676682
turbo-rails
677683
twitter_cldr
678684
tzinfo-data

app/controllers/api/submissions_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ def submissions_params
188188
message: %i[subject body],
189189
submitters: [[:send_email, :send_sms, :completed_redirect_url, :uuid, :name, :email, :role,
190190
:completed, :phone, :application_key, :external_id, :reply_to, :go_to_last,
191-
:require_phone_2fa, :require_email_2fa, :order, :invite_by,
191+
:require_phone_2fa, :require_email_2fa, :order, :index, :invite_by,
192192
{ metadata: {}, values: {}, roles: [], readonly_fields: [], message: %i[subject body],
193193
fields: [:name, :uuid, :default_value, :value, :title, :description,
194194
:readonly, :required, :validation_pattern, :invalid_message,

app/javascript/draw.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ window.customElements.define('draw-signature', class extends HTMLElement {
8989
}
9090

9191
redrawCanvas (oldWidth, oldHeight) {
92-
if (this.pad && !this.pad.isEmpty()) {
92+
if (this.pad && !this.pad.isEmpty() && oldWidth > 0 && oldHeight > 0) {
9393
const sx = this.canvas.width / oldWidth
9494
const sy = this.canvas.height / oldHeight
9595

app/javascript/elements/field_condition.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,22 @@ export default class extends HTMLElement {
6464
if (action === 'empty' || action === 'unchecked') return this.isEmpty(actual)
6565
if (action === 'not_empty' || action === 'checked') return !this.isEmpty(actual)
6666

67+
if (['equal', 'not_equal', 'greater_than', 'less_than'].includes(action) && this.sourceEl?.getAttribute('type') === 'number') {
68+
if (this.isEmpty(actual) || this.isEmpty(expected)) return false
69+
70+
const actualNumber = parseFloat(actual)
71+
const expectedNumber = parseFloat(expected)
72+
73+
if (Number.isNaN(actualNumber) || Number.isNaN(expectedNumber)) return false
74+
75+
if (action === 'equal') return Math.abs(actualNumber - expectedNumber) < Number.EPSILON
76+
if (action === 'not_equal') return Math.abs(actualNumber - expectedNumber) > Number.EPSILON
77+
if (action === 'greater_than') return actualNumber > expectedNumber
78+
if (action === 'less_than') return actualNumber < expectedNumber
79+
80+
return false
81+
}
82+
6783
if (action === 'equal') {
6884
const list = Array.isArray(actual) ? actual : [actual]
6985
return list.filter((v) => v !== null && v !== undefined).map(String).includes(String(expected))

app/javascript/elements/signature_form.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export default targetable(class extends HTMLElement {
8080
}
8181

8282
redrawCanvas (oldWidth, oldHeight) {
83-
if (this.pad && !this.pad.isEmpty()) {
83+
if (this.pad && !this.pad.isEmpty() && oldWidth > 0 && oldHeight > 0) {
8484
const sx = this.canvas.width / oldWidth
8585
const sy = this.canvas.height / oldHeight
8686

app/javascript/submission_form/area.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,8 @@
182182
</div>
183183
<div
184184
v-else-if="field.type === 'cells'"
185-
class="w-full flex items-center"
186-
:class="{ 'justify-end': field.preferences?.align === 'right', ...fontClasses }"
185+
class="w-full flex"
186+
:class="{ 'justify-end': field.preferences?.align === 'right', ...alignClasses, ...fontClasses }"
187187
>
188188
<div
189189
v-for="(char, index) in modelValue"

app/javascript/submission_form/form.vue

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,9 @@
395395
v-model="values[currentField.uuid]"
396396
:reason="values[currentField.preferences?.reason_field_uuid]"
397397
:field="currentField"
398+
:values="values"
398399
:previous-value="previousSignatureValueFor(currentField) || previousSignatureValue"
400+
:touch-attachment-uuid="previousSignatureValue"
399401
:with-typed-signature="withTypedSignature"
400402
:remember-signature="rememberSignature"
401403
:attachments-index="attachmentsIndex"
@@ -407,6 +409,7 @@
407409
:submitter="submitter"
408410
:show-field-names="showFieldNames"
409411
@update:reason="values[currentField.preferences?.reason_field_uuid] = $event"
412+
@touch-attachment="attachmentsIndex[previousSignatureValue] ? attachmentsIndex[previousSignatureValue].created_at = new Date() : null"
410413
@attached="attachments.push($event)"
411414
@start="scrollIntoField(currentField)"
412415
@minimize="minimizeForm"
@@ -926,10 +929,12 @@ export default {
926929
}, {})
927930
},
928931
attachmentConditionsIndex () {
932+
const cache = {}
933+
929934
return this.schema.reduce((acc, item) => {
930935
if (item.conditions?.length) {
931936
if (item.conditions.every((c) => this.fieldsUuidIndex[c.field_uuid])) {
932-
acc[item.attachment_uuid] = this.checkFieldConditions(item)
937+
acc[item.attachment_uuid] = this.checkFieldConditions(item, cache)
933938
} else {
934939
acc[item.attachment_uuid] = true
935940
}
@@ -996,7 +1001,9 @@ export default {
9961001
},
9971002
previousInitialsValue () {
9981003
if (this.reuseSignature !== false) {
999-
const initialsField = [...this.fields].reverse().find((field) => field.type === 'initials' && !!this.values[field.uuid])
1004+
const initialsField = this.fields.findLast
1005+
? this.fields.findLast((field) => field.type === 'initials' && !!this.values[field.uuid])
1006+
: [...this.fields].reverse().find((field) => field.type === 'initials' && !!this.values[field.uuid])
10001007
10011008
return this.values[initialsField?.uuid]
10021009
} else {
@@ -1023,7 +1030,9 @@ export default {
10231030
return this.readonlyFields.filter((f) => f.conditions?.length)
10241031
},
10251032
readonlyFields () {
1026-
return this.fields.filter((f) => f.readonly && this.checkFieldConditions(f) && this.checkFieldDocumentsConditions(f))
1033+
const cache = {}
1034+
1035+
return this.fields.filter((f) => f.readonly && this.checkFieldConditions(f, cache) && this.checkFieldDocumentsConditions(f))
10271036
},
10281037
stepFields () {
10291038
const verificationFields = []
@@ -1078,10 +1087,12 @@ export default {
10781087
sortedFields.push(verificationFields.pop())
10791088
}
10801089
1090+
const cache = {}
1091+
10811092
return sortedFields.reduce((acc, f) => {
10821093
const prevStep = acc[acc.length - 1]
10831094
1084-
if (this.checkFieldConditions(f) && this.checkFieldDocumentsConditions(f)) {
1095+
if (this.checkFieldConditions(f, cache) && this.checkFieldDocumentsConditions(f)) {
10851096
if (f.type === 'checkbox' && Array.isArray(prevStep) && prevStep[0].type === 'checkbox' && !f.description) {
10861097
prevStep.push(f)
10871098
} else {
@@ -1093,7 +1104,9 @@ export default {
10931104
}, [])
10941105
},
10951106
formulaFields () {
1096-
return this.fields.filter((f) => f.preferences?.formula && f.type !== 'payment' && this.checkFieldConditions(f) && this.checkFieldDocumentsConditions(f))
1107+
const cache = {}
1108+
1109+
return this.fields.filter((f) => f.preferences?.formula && f.type !== 'payment' && this.checkFieldConditions(f, cache) && this.checkFieldDocumentsConditions(f))
10971110
},
10981111
attachmentsIndex () {
10991112
return this.attachments.reduce((acc, a) => {
@@ -1155,7 +1168,9 @@ export default {
11551168
this.currentStep = Math.max(stepIndex, 0)
11561169
} else if (this.goToLast) {
11571170
const requiredEmptyStepIndex = this.stepFields.indexOf(this.stepFields.find((fields) => fields.some((f) => f.required && !this.submittedValues[f.uuid])))
1158-
const lastFilledStepIndex = this.stepFields.indexOf([...this.stepFields].reverse().find((fields) => fields.some((f) => !!this.submittedValues[f.uuid]))) + 1
1171+
const lastFilledStepIndex = this.stepFields.indexOf(this.stepFields.findLast
1172+
? this.stepFields.findLast((fields) => fields.some((f) => !!this.submittedValues[f.uuid]))
1173+
: [...this.stepFields].reverse().find((fields) => fields.some((f) => !!this.submittedValues[f.uuid]))) + 1
11591174
11601175
const indexesList = [this.stepFields.length - 1]
11611176
@@ -1223,27 +1238,33 @@ export default {
12231238
return true
12241239
}
12251240
},
1226-
checkFieldConditions (field) {
1241+
checkFieldConditions (field, cache = {}) {
1242+
if (cache[field.uuid] !== undefined) {
1243+
return cache[field.uuid]
1244+
}
1245+
1246+
cache[field.uuid] = true
1247+
12271248
if (field.conditions?.length) {
12281249
const result = field.conditions.reduce((acc, cond) => {
12291250
if (cond.operation === 'or') {
1230-
acc.push(acc.pop() || this.checkFieldCondition(cond))
1251+
acc.push(acc.pop() || this.checkFieldCondition(cond, cache))
12311252
} else {
1232-
acc.push(this.checkFieldCondition(cond))
1253+
acc.push(this.checkFieldCondition(cond, cache))
12331254
}
12341255
12351256
return acc
12361257
}, [])
12371258
1238-
return !result.includes(false)
1239-
} else {
1240-
return true
1259+
cache[field.uuid] = !result.includes(false)
12411260
}
1261+
1262+
return cache[field.uuid]
12421263
},
1243-
checkFieldCondition (condition) {
1264+
checkFieldCondition (condition, cache = {}) {
12441265
const field = this.fieldsUuidIndex[condition.field_uuid]
12451266
1246-
if (['not_empty', 'checked', 'equal', 'contains'].includes(condition.action) && field && !this.checkFieldConditions(field)) {
1267+
if (['not_empty', 'checked', 'equal', 'contains', 'greater_than', 'less_than'].includes(condition.action) && field && !this.checkFieldConditions(field, cache)) {
12471268
return false
12481269
}
12491270
@@ -1253,6 +1274,22 @@ export default {
12531274
return isEmpty(this.values[condition.field_uuid] ?? defaultValue)
12541275
} else if (['not_empty', 'checked'].includes(condition.action)) {
12551276
return !isEmpty(this.values[condition.field_uuid] ?? defaultValue)
1277+
} else if (field?.type === 'number' && ['equal', 'not_equal', 'greater_than', 'less_than'].includes(condition.action)) {
1278+
const value = this.values[condition.field_uuid] ?? defaultValue
1279+
1280+
if (isEmpty(value) || isEmpty(condition.value)) return false
1281+
1282+
const actual = parseFloat(value)
1283+
const expected = parseFloat(condition.value)
1284+
1285+
if (Number.isNaN(actual) || Number.isNaN(expected)) return false
1286+
1287+
if (condition.action === 'equal') return Math.abs(actual - expected) < Number.EPSILON
1288+
if (condition.action === 'not_equal') return Math.abs(actual - expected) > Number.EPSILON
1289+
if (condition.action === 'greater_than') return actual > expected
1290+
if (condition.action === 'less_than') return actual < expected
1291+
1292+
return false
12561293
} else if (['equal', 'contains'].includes(condition.action) && field) {
12571294
if (field.options) {
12581295
const option = field.options.find((o) => o.uuid === condition.value)
@@ -1353,9 +1390,9 @@ export default {
13531390
},
13541391
previousSignatureValueFor (field) {
13551392
if (this.reuseSignature !== false) {
1356-
const signatureField = [...this.fields].reverse().find((f) =>
1357-
f.type === 'signature' && field.preferences?.format === f.preferences?.format && !!this.values[f.uuid]
1358-
)
1393+
const signatureField = this.fields.findLast
1394+
? this.fields.findLast((f) => f.type === 'signature' && field.preferences?.format === f.preferences?.format && !!this.values[f.uuid])
1395+
: [...this.fields].reverse().find((f) => f.type === 'signature' && field.preferences?.format === f.preferences?.format && !!this.values[f.uuid])
13591396
13601397
return this.values[signatureField?.uuid]
13611398
} else {

app/javascript/submission_form/kba_step.vue

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -497,10 +497,10 @@ export default {
497497
body: JSON.stringify(payload)
498498
})
499499
500-
if (!resp.ok) throw new Error('Failed to start KBA')
501-
502500
const data = await resp.json()
503501
502+
if (!resp.ok) throw new Error(data.error || 'Failed to start KBA')
503+
504504
if (data.result && data.result.action === 'FAIL') {
505505
if (data.result.detail === 'NO MATCH') {
506506
throw new Error('Unfortunately, we were unable to start Knowledge Based Authentication with the details provided. Please review and confirm that all your personal details are correct.')
@@ -555,7 +555,11 @@ export default {
555555
const data = await resp.json()
556556
557557
if (data.result?.action !== 'PASS') {
558-
this.error = 'Knowledge Based Authentication Failed - make sure you provide correct answers for the Knowledge Based authentication.'
558+
if (data.result?.issues?.length) {
559+
this.error = `Knowledge Based Authentication Failed - make sure you provide correct details for the Knowledge Based authentication: ${data.result.issues.join(', ')}`
560+
} else {
561+
this.error = 'Knowledge Based Authentication Failed - make sure you provide correct answers for the Knowledge Based authentication.'
562+
}
559563
560564
throw new Error('Knowledge Based Authentication Failed')
561565
}

0 commit comments

Comments
 (0)