From 66d1ae2f64fff76f4d6df0110b7c8f80fb66e2d3 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Mon, 20 Nov 2023 00:52:05 +0200 Subject: [PATCH] link to submission preview page in completed emails --- .../submissions_preview_controller.rb | 29 +++++++++++++++++++ app/models/account_config.rb | 2 +- app/models/submission.rb | 4 +++ app/views/submissions/show.html.erb | 12 ++++---- .../documents_copy_email.html.erb | 12 +++----- config/routes.rb | 2 ++ .../20231119222105_add_slug_to_submissions.rb | 23 +++++++++++++++ db/schema.rb | 4 ++- lib/replace_email_variables.rb | 13 ++++----- lib/submissions/generate_audit_trail.rb | 12 ++------ lib/time_utils.rb | 13 +++++++++ spec/system/submission_preview_spec.rb | 22 ++++++++++++++ 12 files changed, 114 insertions(+), 34 deletions(-) create mode 100644 app/controllers/submissions_preview_controller.rb create mode 100644 db/migrate/20231119222105_add_slug_to_submissions.rb create mode 100644 lib/time_utils.rb create mode 100644 spec/system/submission_preview_spec.rb diff --git a/app/controllers/submissions_preview_controller.rb b/app/controllers/submissions_preview_controller.rb new file mode 100644 index 000000000..878dfe266 --- /dev/null +++ b/app/controllers/submissions_preview_controller.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +class SubmissionsPreviewController < ApplicationController + skip_before_action :authenticate_user! + skip_authorization_check + + PRELOAD_ALL_PAGES_AMOUNT = 200 + + def show + @submission = Submission.find_by!(slug: params[:slug]) + + ActiveRecord::Associations::Preloader.new( + records: [@submission], + associations: [:template, { template_schema_documents: :blob }] + ).call + + total_pages = + @submission.template_schema_documents.sum { |e| e.metadata.dig('pdf', 'number_of_pages').to_i } + + if total_pages < PRELOAD_ALL_PAGES_AMOUNT + ActiveRecord::Associations::Preloader.new( + records: @submission.template_schema_documents, + associations: [:blob, { preview_images_attachments: :blob }] + ).call + end + + render 'submissions/show', layout: 'plain' + end +end diff --git a/app/models/account_config.rb b/app/models/account_config.rb index 9d7c6b218..b592cbca3 100644 --- a/app/models/account_config.rb +++ b/app/models/account_config.rb @@ -49,7 +49,7 @@ class AccountConfig < ApplicationRecord 'body' => "Hi there,\n\n" \ "Please check the copy of your \"{{template.name}}\" submission in the email attachments.\n" \ "Alternatively, you can download your copy using:\n\n" \ - "{{documents.links}}\n\n" \ + "{{documents.link}}\n\n" \ "Thanks,\n" \ '{{account.name}}' } diff --git a/app/models/submission.rb b/app/models/submission.rb index 5ce023673..e240c774f 100644 --- a/app/models/submission.rb +++ b/app/models/submission.rb @@ -6,6 +6,7 @@ # # id :bigint not null, primary key # deleted_at :datetime +# slug :string not null # source :text not null # submitters_order :string not null # template_fields :text @@ -19,6 +20,7 @@ # Indexes # # index_submissions_on_created_by_user_id (created_by_user_id) +# index_submissions_on_slug (slug) UNIQUE # index_submissions_on_template_id (template_id) # # Foreign Keys @@ -41,6 +43,8 @@ class Submission < ApplicationRecord attribute :source, :string, default: 'link' attribute :submitters_order, :string, default: 'random' + attribute :slug, :string, default: -> { SecureRandom.base58(14) } + has_one_attached :audit_trail has_many :template_schema_documents, diff --git a/app/views/submissions/show.html.erb b/app/views/submissions/show.html.erb index ad198a432..ccb757da9 100644 --- a/app/views/submissions/show.html.erb +++ b/app/views/submissions/show.html.erb @@ -61,7 +61,7 @@ <% fields_index.dig(document.uuid, index)&.each do |(area, field)| %> <% value = values[field['uuid']] %> <% next if value.blank? %> - <%= render 'submissions/value', area:, field:, attachments_index:, value:, locale: current_account.locale %> + <%= render 'submissions/value', area:, field:, attachments_index:, value:, locale: @submission.template.account.locale %> <% end %> @@ -109,18 +109,18 @@
<%= svg_icon('writing', class: 'w-5 h-5') %> - <%= submitter&.completed_at? ? l(submitter.completed_at.in_time_zone(current_account.timezone), format: :long, locale: current_account.locale) : 'Not completed yet' %> + <%= submitter&.completed_at? ? l(submitter.completed_at.in_time_zone(@submission.template.account.timezone), format: :long, locale: @submission.template.account.locale) : 'Not completed yet' %>
- <% if submitter && submitter.email && !submitter.completed_at && can?(:update, submitter) %> + <% if signed_in? && submitter && submitter.email && !submitter.completed_at && can?(:update, submitter) %>
<%= button_to button_title(title: submitter.sent_at? ? 'Re-send Email' : 'Send Email', disabled_with: 'Sending'), submitter_send_email_index_path(submitter_slug: submitter.slug), class: 'btn btn-sm btn-primary w-full' %>
<% end %> - <% if submitter && submitter.phone && !submitter.completed_at && can?(:update, submitter) %> + <% if signed_in? && submitter && submitter.phone && !submitter.completed_at && can?(:update, submitter) %> <%= render 'send_sms_button', submitter: %> <% end %> - <% if submitter && !submitter.completed_at? && can?(:create, submitter) %> + <% if signed_in? && submitter && !submitter.completed_at? && can?(:create, submitter) %>
Submit Form @@ -160,7 +160,7 @@ <% elsif field['type'] == 'checkbox' %> <%= svg_icon('check', class: 'w-6 h-6') %> <% elsif field['type'] == 'date' %> - <%= l(Date.parse(value), locale: current_account.locale, format: :long) %> + <%= l(Date.parse(value), locale: @submission.template.account.locale, format: :long) %> <% else %> <%= Array.wrap(value).join(', ') %> <% end %> diff --git a/app/views/submitter_mailer/documents_copy_email.html.erb b/app/views/submitter_mailer/documents_copy_email.html.erb index 931d2aba4..ac438e76f 100644 --- a/app/views/submitter_mailer/documents_copy_email.html.erb +++ b/app/views/submitter_mailer/documents_copy_email.html.erb @@ -3,14 +3,10 @@ <% else %>

Hi there,

Please check the copy of your "<%= @submitter.submission.template.name %>" submission in the email attachments.

-

Alternatively, you can download your copy using:

- <% @documents.each do |document| %> -
    -
  • - <%= link_to document.filename.to_s, rails_blob_url(document) %> -
  • -
- <% end %> +

Alternatively, you can review and download your copy using:

+

+ <%= link_to @submitter.template.name, submissions_preview_url(@submitter.submission.slug) %> +

Thanks,
<%= @current_account.name %>

diff --git a/config/routes.rb b/config/routes.rb index d4fb5a91f..cc6fb5c05 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -80,6 +80,8 @@ get :completed end + resources :submissions_preview, only: %i[show], path: 'e', param: 'slug' + resources :send_submission_email, only: %i[create] do get :success, on: :collection end diff --git a/db/migrate/20231119222105_add_slug_to_submissions.rb b/db/migrate/20231119222105_add_slug_to_submissions.rb new file mode 100644 index 000000000..53651defd --- /dev/null +++ b/db/migrate/20231119222105_add_slug_to_submissions.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +class AddSlugToSubmissions < ActiveRecord::Migration[7.0] + class MigrationSubmission < ApplicationRecord + self.table_name = 'submissions' + end + + def up + add_column :submissions, :slug, :string + + MigrationSubmission.where(slug: nil).find_each do |submission| + submission.update_columns(slug: SecureRandom.base58(14)) + end + + change_column_null :submissions, :slug, false + + add_index :submissions, :slug, unique: true + end + + def down + remove_column :submissions, :slug + end +end diff --git a/db/schema.rb b/db/schema.rb index ce043569b..b01abe1f6 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_11_12_224432) do +ActiveRecord::Schema[7.0].define(version: 2023_11_19_222105) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -124,7 +124,9 @@ t.text "template_submitters" t.text "source", null: false t.string "submitters_order", null: false + t.string "slug", null: false t.index ["created_by_user_id"], name: "index_submissions_on_created_by_user_id" + t.index ["slug"], name: "index_submissions_on_slug", unique: true t.index ["template_id"], name: "index_submissions_on_template_id" end diff --git a/lib/replace_email_variables.rb b/lib/replace_email_variables.rb index 5c721cf8a..a6035a5a4 100644 --- a/lib/replace_email_variables.rb +++ b/lib/replace_email_variables.rb @@ -9,6 +9,7 @@ module ReplaceEmailVariables SUBMISSION_LINK = '{{submission.link}}' SUBMISSION_SUBMITTERS = '{{submission.submitters}}' DOCUMENTS_LINKS = '{{documents.links}}' + DOCUMENTS_LINK = '{{documents.link}}' module_function @@ -26,6 +27,7 @@ def call(text, submitter:, tracking_event_type: 'click_email') text = text.gsub(SUBMISSION_SUBMITTERS, build_submission_submitters(submitter.submission)) end text = text.gsub(DOCUMENTS_LINKS, build_documents_links_text(submitter)) + text = text.gsub(DOCUMENTS_LINK, build_documents_links_text(submitter)) text = text.gsub(ACCOUNT_NAME, submitter.template.account.name) if submitter.template @@ -33,14 +35,9 @@ def call(text, submitter:, tracking_event_type: 'click_email') end def build_documents_links_text(submitter) - Submitters.select_attachments_for_download(submitter).map do |document| - link = - Rails.application.routes.url_helpers.rails_blob_url( - document, **Docuseal.default_url_options - ) - - "#{link}\n" - end.join + Rails.application.routes.url_helpers.submissions_preview_url( + submitter.submission.slug, **Docuseal.default_url_options + ) end def build_submitter_link(submitter, tracking_event_type) diff --git a/lib/submissions/generate_audit_trail.rb b/lib/submissions/generate_audit_trail.rb index dd84dbebe..1cdd8499c 100644 --- a/lib/submissions/generate_audit_trail.rb +++ b/lib/submissions/generate_audit_trail.rb @@ -107,7 +107,7 @@ def call(submission) "\n", { text: 'Generated at: ', font: [FONT_BOLD_NAME, { variant: :bold }] }, "#{I18n.l(document.created_at.in_time_zone(account.timezone), format: :long, locale: account.locale)} " \ - "#{timezone_abbr(account.timezone, document.created_at)}" + "#{TimeUtils.timezone_abbr(account.timezone, document.created_at)}" ], line_spacing: 1.8 ) ] @@ -232,7 +232,7 @@ def call(submission) submitter = submission.submitters.find { |e| e.id == event.submitter_id } [ "#{I18n.l(event.event_timestamp.in_time_zone(account.timezone), format: :long, locale: account.locale)} " \ - "#{timezone_abbr(account.timezone, event.event_timestamp)}", + "#{TimeUtils.timezone_abbr(account.timezone, event.event_timestamp)}", composer.document.layout.formatted_text_box( [ { text: SubmissionEvents::EVENT_NAMES[event.event_type.to_sym], @@ -268,14 +268,6 @@ def call(submission) ) end - def timezone_abbr(timezone, time = Time.current) - tz_info = TZInfo::Timezone.get( - ActiveSupport::TimeZone::MAPPING[timezone] || timezone || 'UTC' - ) - - tz_info.abbreviation(time) - end - def add_logo(column) column.image(PdfIcons.logo_io, width: 40, height: 40, position: :float) diff --git a/lib/time_utils.rb b/lib/time_utils.rb new file mode 100644 index 000000000..c708ead5a --- /dev/null +++ b/lib/time_utils.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module TimeUtils + module_function + + def timezone_abbr(timezone, time = Time.current) + tz_info = TZInfo::Timezone.get( + ActiveSupport::TimeZone::MAPPING[timezone] || timezone || 'UTC' + ) + + tz_info.abbreviation(time) + end +end diff --git a/spec/system/submission_preview_spec.rb b/spec/system/submission_preview_spec.rb new file mode 100644 index 000000000..aea89e3b6 --- /dev/null +++ b/spec/system/submission_preview_spec.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Submission Preview' do + let(:account) { create(:account) } + let(:user) { create(:user, account:) } + let(:template) { create(:template, account:, author: user) } + + context 'when not submitted' do + let(:submission) { create(:submission, template:, created_by_user: user) } + let(:submitters) { template.submitters.map { |s| create(:submitter, submission:, uuid: s['uuid']) } } + + before do + visit submissions_preview_path(slug: submission.slug) + end + + it 'completes the form' do + expect(page).to have_content('Not completed') + end + end +end