add I18n Audit log

pull/381/head
Alex Turchyn 1 year ago committed by Oleksandr Turchyn
parent 95e9b34033
commit 1ff23d7c40

@ -577,6 +577,35 @@ en: &en
opened: Opened
sent: Sent
awaiting: Awaiting
document_id: Document ID
envelope_id: Envelope ID
event_log: Event Log
verify: Verify
testing_log_not_for_production_use: Testing Log - Not for Production Use
original_sha256: Original SHA256
result_sha256: Result SHA256
generated_at: Generated at
email_verification: Email verification
phone_verification: Phone verification
session_id: Session ID
type_field: '%{type} Field'
paid_price: 'Paid %{price}'
verified: Verified
unverified: Unverified
submission_event_names:
send_email_to_html: '<b>Email sent</b> to %{submitter_name}'
send_reminder_email_to_html: '<b>Reminder email sent</b> to %{submitter_name}'
send_sms_to_html: '<b>SMS sent</b> to %{submitter_name}'
send_2fa_sms_to_html: '<b>Verification SMS 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}'
phone_verified_by_html: '<b>Phone verified</b> by %{submitter_name}'
start_form_by_html: '<b>Submission started</b> by %{submitter_name}'
view_form_by_html: '<b>Form viewed</b> by %{submitter_name}'
invite_party_by_html: '<b>Invited</b> %{invited_submitter_name} by %{submitter_name}'
complete_form_by_html: '<b>Submission completed</b> by %{submitter_name}'
api_complete_form_by_html: '<b>Submission completed via API</b> by %{submitter_name}'
import_list:
select_worksheet: Select Worksheet
open: Open
@ -1158,6 +1187,35 @@ es: &es
opened: Abierto
sent: Enviado
awaiting: Pendiente
document_id: ID del Documento
envelope_id: ID del Sobre
event_log: Registro de Eventos
verify: Verificar
testing_log_not_for_production_use: Registro de Pruebas - No para Uso en Producción
original_sha256: SHA256 Original
result_sha256: SHA256 del Resultado
generated_at: Generado el
email_verification: Verificación de correo electrónico
phone_verification: Verificación telefónica
session_id: ID de la Sesión
type_field: 'Campo %{type}'
paid_price: 'Pagado %{price}'
verified: Verificado
unverified: No verificado
submission_event_names:
send_email_to_html: '<b>Correo electrónico enviado</b> a %{submitter_name}'
send_reminder_email_to_html: '<b>Correo de recordatorio enviado</b> a %{submitter_name}'
send_sms_to_html: '<b>SMS enviado</b> a %{submitter_name}'
send_2fa_sms_to_html: '<b>SMS 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}'
phone_verified_by_html: '<b>Teléfono verificado</b> por %{submitter_name}'
start_form_by_html: '<b>Envío iniciado</b> por %{submitter_name}'
view_form_by_html: '<b>Formulario visto</b> por %{submitter_name}'
invite_party_by_html: '<b>Invitado</b> %{invited_submitter_name} por %{submitter_name}'
complete_form_by_html: '<b>Envío completado</b> por %{submitter_name}'
api_complete_form_by_html: '<b>Envío completado vía API</b> por %{submitter_name}'
import_list:
select_worksheet: Seleccionar hoja de cálculo
open: Abrir
@ -1739,6 +1797,35 @@ it: &it
opened: Aperto
sent: Inviato
awaiting: In attesa
document_id: ID del Documento
envelope_id: ID della Busta
event_log: Registro degli Eventi
verify: Verifica
testing_log_not_for_production_use: Registro di Test - Non per Uso in Produzione
original_sha256: SHA256 Originale
result_sha256: SHA256 del Risultato
generated_at: Generato il
email_verification: Verifica e-mail
phone_verification: Verifica telefono
session_id: ID della Sessione
type_field: 'Campo %{type}'
paid_price: 'Pagato %{price}'
verified: Verificato
unverified: Non verificato
submission_event_names:
send_email_to_html: '<b>E-mail inviato</b> a %{submitter_name}'
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}'
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}"
phone_verified_by_html: '<b>Telefono verificato</b> da %{submitter_name}'
start_form_by_html: '<b>Invio iniziato</b> da %{submitter_name}'
view_form_by_html: '<b>Modulo visualizzato</b> da %{submitter_name}'
invite_party_by_html: '<b>Invitato</b> %{invited_submitter_name} da %{submitter_name}'
complete_form_by_html: '<b>Invio completato</b> da %{submitter_name}'
api_complete_form_by_html: '<b>Invio completato tramite API</b> da %{submitter_name}'
import_list:
select_worksheet: Seleziona il foglio di lavoro
open: Apri
@ -2321,6 +2408,35 @@ fr: &fr
opened: Ouvert
sent: Envoyé
awaiting: En attente
document_id: ID du document
envelope_id: ID de l'enveloppe
event_log: Journal d'événements
verify: Vérifier
testing_log_not_for_production_use: Journal de test - Ne pas utiliser en production
original_sha256: SHA256 original
result_sha256: SHA256 du résultat
generated_at: Généré le
email_verification: Vérification de l'e-mail
phone_verification: Vérification du téléphone
session_id: ID de session
type_field: 'Champ %{type}'
paid_price: 'Payé %{price}'
verified: Vérifié
unverified: Non vérifié
submission_event_names:
send_email_to_html: '<b>E-mail envoyé</b> à %{submitter_name}'
send_reminder_email_to_html: '<b>E-mail de rappel envoyé</b> à %{submitter_name}'
send_sms_to_html: '<b>SMS envoyé</b> à %{submitter_name}'
send_2fa_sms_to_html: '<b>SMS 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 de l'e-mail cliqué</b> par %{submitter_name}"
click_sms_by_html: '<b>Lien du SMS cliqué</b> par %{submitter_name}'
phone_verified_by_html: '<b>Téléphone vérifié</b> par %{submitter_name}'
start_form_by_html: '<b>Soumission commencée</b> par %{submitter_name}'
view_form_by_html: '<b>Formulaire consulté</b> par %{submitter_name}'
invite_party_by_html: '<b>Invité</b> %{invited_submitter_name} par %{submitter_name}'
complete_form_by_html: '<b>Soumission terminée</b> par %{submitter_name}'
api_complete_form_by_html: "<b>Soumission terminée via l'API</b> par %{submitter_name}"
import_list:
select_worksheet: Sélectionner la feuille de calcul
open: Ouvrir
@ -2902,6 +3018,35 @@ pt: &pt
opened: Aberto
sent: Enviado
awaiting: Aguardando
document_id: ID do Documento
envelope_id: ID do Envelope
event_log: Log de Eventos
verify: Verificar
testing_log_not_for_production_use: Log de Teste - Não para Uso em Produção
original_sha256: SHA256 Original
result_sha256: SHA256 do Resultado
generated_at: Gerado em
email_verification: Verificação de E-mail
phone_verification: Verificação de Telefone
session_id: ID da Sessão
type_field: 'Campo %{type}'
paid_price: 'Pago %{price}'
verified: Verificado
unverified: Não verificado
submission_event_names:
send_email_to_html: '<b>E-mail enviado</b> para %{submitter_name}'
send_reminder_email_to_html: '<b>E-mail 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}'
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}'
phone_verified_by_html: '<b>Telefone verificado</b> por %{submitter_name}'
start_form_by_html: '<b>Submissão iniciada</b> por %{submitter_name}'
view_form_by_html: '<b>Formulário visualizado</b> por %{submitter_name}'
invite_party_by_html: '<b>Convidado</b> %{invited_submitter_name} por %{submitter_name}'
complete_form_by_html: '<b>Submissão concluída</b> por %{submitter_name}'
api_complete_form_by_html: '<b>Submissão concluída via API</b> por %{submitter_name}'
import_list:
select_worksheet: Selecionar planilha
open: Abrir
@ -3483,6 +3628,35 @@ de: &de
opened: Geöffnet
sent: Gesendet
awaiting: Ausstehend
document_id: Dokumenten-ID
envelope_id: Umschlag-ID
event_log: Ereignisprotokoll
verify: Überprüfen
testing_log_not_for_production_use: Testprotokoll - Nicht für den Produktionseinsatz
original_sha256: Original SHA256
result_sha256: Ergebnis SHA256
generated_at: Generiert am
email_verification: E-Mail-Verifizierung
phone_verification: Telefonverifizierung
session_id: Sitzungs-ID
type_field: '%{type} Feld'
paid_price: 'Bezahlt %{price}'
verified: Verifiziert
unverified: Nicht verifiziert
submission_event_names:
send_email_to_html: '<b>E-Mail gesendet</b> an %{submitter_name}'
send_reminder_email_to_html: '<b>Erinnerungs-E-Mail gesendet</b> an %{submitter_name}'
send_sms_to_html: '<b>SMS gesendet</b> an %{submitter_name}'
send_2fa_sms_to_html: '<b>Verifizierungs-SMS 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}'
phone_verified_by_html: '<b>Telefon verifiziert</b> von %{submitter_name}'
start_form_by_html: '<b>Einreichung gestartet</b> von %{submitter_name}'
view_form_by_html: '<b>Formular angesehen</b> von %{submitter_name}'
invite_party_by_html: '<b>Eingeladen</b> %{invited_submitter_name} von %{submitter_name}'
complete_form_by_html: '<b>Einreichung abgeschlossen</b> von %{submitter_name}'
api_complete_form_by_html: '<b>Einreichung über API abgeschlossen</b> von %{submitter_name}'
import_list:
select_worksheet: Arbeitsblatt auswählen
open: Öffnen

@ -3,22 +3,6 @@
module SubmissionEvents
TRACKING_PARAM_LENGTH = 6
EVENT_NAMES = {
send_email: 'Email sent',
send_reminder_email: 'Reminder email sent',
send_sms: 'SMS sent',
send_2fa_sms: 'Verification SMS sent',
open_email: 'Email opened',
click_email: 'Email link clicked',
click_sms: 'SMS link clicked',
phone_verified: 'Phone verified',
start_form: 'Submission started',
view_form: 'Form viewed',
invite_party: 'Invited',
complete_form: 'Submission completed',
api_complete_form: 'Submission completed via API'
}.freeze
module_function
def build_tracking_param(submitter, event_type = 'click_email')

@ -12,9 +12,6 @@ module Submissions
'Helvetica'
end
VERIFIED_TEXT = 'Verified'
UNVERIFIED_TEXT = 'Unverified'
CURRENCY_SYMBOLS = {
'USD' => '$',
'EUR' => '€',
@ -32,35 +29,37 @@ module Submissions
# rubocop:disable Metrics
def call(submission)
document = build_audit_trail(submission)
account = submission.account
pkcs = Accounts.load_signing_pkcs(account)
tsa_url = Accounts.load_timeserver_url(account)
I18n.with_locale(account.locale) do
document = build_audit_trail(submission)
io = StringIO.new
pkcs = Accounts.load_signing_pkcs(account)
tsa_url = Accounts.load_timeserver_url(account)
document.trailer.info[:Creator] = "#{Docuseal.product_name} (#{Docuseal::PRODUCT_URL})"
io = StringIO.new
last_submitter = submission.submitters.select(&:completed_at).max_by(&:completed_at)
document.trailer.info[:Creator] = "#{Docuseal.product_name} (#{Docuseal::PRODUCT_URL})"
sign_params = {
reason: sign_reason,
**Submissions::GenerateResultAttachments.build_signing_params(last_submitter, pkcs, tsa_url)
}
last_submitter = submission.submitters.select(&:completed_at).max_by(&:completed_at)
document.sign(io, **sign_params)
sign_params = {
reason: sign_reason,
**Submissions::GenerateResultAttachments.build_signing_params(last_submitter, pkcs, tsa_url)
}
Submissions::GenerateResultAttachments.maybe_enable_ltv(io, sign_params)
document.sign(io, **sign_params)
ActiveStorage::Attachment.create!(
blob: ActiveStorage::Blob.create_and_upload!(
io: io.tap(&:rewind), filename: "Audit Log - #{submission.template.name}.pdf"
),
name: 'audit_trail',
record: submission
)
Submissions::GenerateResultAttachments.maybe_enable_ltv(io, sign_params)
ActiveStorage::Attachment.create!(
blob: ActiveStorage::Blob.create_and_upload!(
io: io.tap(&:rewind), filename: "#{I18n.t('audit_log')} - #{submission.template.name}.pdf"
),
name: 'audit_trail',
record: submission
)
end
end
def build_audit_trail(submission)
@ -130,7 +129,7 @@ module Submissions
TESTING_FOOTER
end
else
"Document ID: #{document_id}"
"#{I18n.t('document_id')}: #{document_id}"
end
text = HexaPDF::Layout::TextFragment.create(
@ -158,17 +157,19 @@ module Submissions
composer.column(columns: 1) do |column|
add_logo(column, submission)
column.text(account.testing? ? 'Testing Log - Not for Production Use' : 'Audit Log',
column.text(account.testing? ? I18n.t('testing_log_not_for_production_use') : I18n.t('audit_log'),
font_size: 16,
padding: [10, 0, 0, 0],
position: :float, text_align: :right)
end
composer.column(columns: 1) do |column|
column.text("Envelope ID: #{submission.id}", font_size: 12, padding: [15, 0, 8, 0], position: :float)
column.text("#{I18n.t('envelope_id')}: #{submission.id}", font_size: 12,
padding: [15, 0, 8, 0],
position: :float)
unless submission.source.in?(%w[embed api])
column.formatted_text([{ link: verify_url, text: 'Verify', style: :link }],
column.formatted_text([{ link: verify_url, text: I18n.t('verify'), style: :link }],
font_size: 9, padding: [15, 0, 10, 0], position: :float, text_align: :right)
end
end
@ -197,13 +198,13 @@ module Submissions
),
composer.document.layout.formatted_text_box(
[
{ text: "Original SHA256:\n", font: [FONT_NAME, { variant: :bold }] },
{ text: "#{I18n.t('original_sha256')}:\n", font: [FONT_NAME, { variant: :bold }] },
original_documents.map { |d| d.metadata['sha256'] || d.checksum }.join("\n"),
"\n",
{ text: "Result SHA256:\n", font: [FONT_NAME, { variant: :bold }] },
{ text: "#{I18n.t('result_sha256')}:\n", font: [FONT_NAME, { variant: :bold }] },
document.metadata['sha256'] || document.checksum,
"\n",
{ text: 'Generated at: ', font: [FONT_NAME, { variant: :bold }] },
{ text: "#{I18n.t('generated_at')}: ", font: [FONT_NAME, { variant: :bold }] },
"#{I18n.l(document.created_at.in_time_zone(account.timezone), format: :long, locale: account.locale)} " \
"#{TimeUtils.timezone_abbr(account.timezone, document.created_at)}"
], line_spacing: 1.3
@ -250,13 +251,13 @@ module Submissions
composer.document.layout.formatted_text_box(
[
submitter.email && click_email_event && {
text: "Email verification: #{VERIFIED_TEXT}\n"
text: "#{I18n.t('email_verification')}: #{I18n.t('verified')}\n"
},
submitter.phone && is_phone_verified && {
text: "Phone verification: #{VERIFIED_TEXT}\n"
text: "#{I18n.t('phone_verification')}: #{I18n.t('verified')}\n"
},
completed_event.data['ip'] && { text: "IP: #{completed_event.data['ip']}\n" },
completed_event.data['sid'] && { text: "Session ID: #{completed_event.data['sid']}\n" },
completed_event.data['sid'] && { text: "#{I18n.t('session_id')}: #{completed_event.data['sid']}\n" },
completed_event.data['ua'] && { text: "User agent: #{completed_event.data['ua']}\n" },
"\n"
].compact_blank, line_spacing: 1.3, padding: [10, 20, 20, 0]
@ -284,7 +285,8 @@ module Submissions
[
{
text: TextUtils.maybe_rtl_reverse(field_name).upcase.presence ||
"#{field['type']} Field #{submitter_field_counters[field['type']]}\n".upcase,
"#{I18n.t('type_field',
type: field['type'])} #{submitter_field_counters[field['type']]}\n".upcase,
font_size: 6
}
].compact_blank,
@ -316,7 +318,8 @@ module Submissions
price = ApplicationController.helpers.number_to_currency(field['preferences']['price'], unit:)
composer.formatted_text_box([{ text: "Paid #{price}\n" }], padding: [0, 0, 10, 0])
composer.formatted_text_box([{ text: "#{I18n.t('paid_price', price:)}\n" }],
padding: [0, 0, 10, 0])
end
composer.formatted_text_box(
@ -354,31 +357,38 @@ module Submissions
composer.draw_box(divider)
end
composer.text('Event Log', font_size: 12, padding: [10, 0, 20, 0])
composer.text(I18n.t('event_log'), font_size: 12, padding: [10, 0, 20, 0])
events_data = submission.submission_events.sort_by(&:event_timestamp).map do |event|
submitter = submission.submitters.find { |e| e.id == event.submitter_id }
submitter_name =
if event.event_type.include?('sms') || event.event_type.include?('phone')
event.data['phone'] || submitter.phone
else
submitter.name || submitter.email || submitter.phone
end
text = SubmissionEvents::EVENT_NAMES[event.event_type.to_sym]
if event.event_type == 'invite_party' &&
(invited_submitter = submission.submitters.find { |e| e.uuid == event.data['uuid'] }) &&
(name = submission.template_submitters.find { |e| e['uuid'] == event.data['uuid'] }&.dig('name'))
text += ['', invited_submitter.name || invited_submitter.email || invited_submitter.phone, name].join(' ')
end
text =
if event.event_type == 'invite_party' &&
(invited_submitter = submission.submitters.find { |e| e.uuid == event.data['uuid'] }) &&
(name = submission.template_submitters.find { |e| e['uuid'] == event.data['uuid'] }&.dig('name'))
invited_submitter_name = [invited_submitter.name || invited_submitter.email || invited_submitter.phone,
name].join(' ')
I18n.t('submission_event_names.invite_party_by_html', invited_submitter_name:,
submitter_name:)
elsif event.event_type.include?('send_')
I18n.t("submission_event_names.#{event.event_type}_to_html", submitter_name:)
else
I18n.t("submission_event_names.#{event.event_type}_by_html", submitter_name:)
end
[
"#{I18n.l(event.event_timestamp.in_time_zone(account.timezone), format: :long, locale: account.locale)} " \
"#{TimeUtils.timezone_abbr(account.timezone, event.event_timestamp)}",
composer.document.layout.formatted_text_box(
[
{ text:, font: [FONT_NAME, { variant: :bold }] },
event.event_type.include?('send_') ? ' to ' : ' by ',
if event.event_type.include?('sms') || event.event_type.include?('phone')
event.data['phone'] || submitter.phone
else
submitter.name || submitter.email || submitter.phone
end
{ text: text[%r{<b>(.*?)</b>}, 1], font: [FONT_NAME, { variant: :bold }] },
text[%r{<b>(.*?)</b>(.*)}, 2]
]
)
]

@ -38,7 +38,9 @@ module Submissions
def build_combined_pdf(submitter)
pdfs_index = Submissions::GenerateResultAttachments.generate_pdfs(submitter)
audit_trail = Submissions::GenerateAuditTrail.build_audit_trail(submitter.submission)
audit_trail = I18n.with_locale(submitter.account.locale) do
Submissions::GenerateAuditTrail.build_audit_trail(submitter.submission)
end
audit_trail.dispatch_message(:complete_objects)

Loading…
Cancel
Save