diff --git a/app/controllers/api/active_storage_blobs_proxy_controller.rb b/app/controllers/api/active_storage_blobs_proxy_controller.rb index 6995fdb0..87eea303 100644 --- a/app/controllers/api/active_storage_blobs_proxy_controller.rb +++ b/app/controllers/api/active_storage_blobs_proxy_controller.rb @@ -10,9 +10,9 @@ module Api before_action :set_cors_headers def show - blob_uuid, purp = ApplicationRecord.signed_id_verifier.verified(params[:signed_uuid]) + blob_uuid, purp, exp = ApplicationRecord.signed_id_verifier.verified(params[:signed_uuid]) - if blob_uuid.blank? || purp != 'blob' + if blob_uuid.blank? || purp != 'blob' || (exp && exp < Time.current.to_i) Rollbar.error('Blob not found') if defined?(Rollbar) return head :not_found diff --git a/app/controllers/send_submission_email_controller.rb b/app/controllers/send_submission_email_controller.rb index 28e2a364..4a3fa1e0 100644 --- a/app/controllers/send_submission_email_controller.rb +++ b/app/controllers/send_submission_email_controller.rb @@ -12,13 +12,16 @@ class SendSubmissionEmailController < ApplicationController def create @submitter = if params[:template_slug] - Submitter.joins(submission: :template).find_by!(email: params[:email], + Submitter.joins(submission: :template).find_by!(email: params[:email].to_s.downcase, template: { slug: params[:template_slug] }) + elsif params[:submission_slug] + Submitter.joins(:submission).find_by!(email: params[:email].to_s.downcase, + submission: { slug: params[:submission_slug] }) else Submitter.find_by!(slug: params[:submitter_slug]) end - SubmitterMailer.documents_copy_email(@submitter).deliver_later! + SubmitterMailer.documents_copy_email(@submitter, sig: true).deliver_later! respond_to do |f| f.html { redirect_to success_send_submission_email_index_path } diff --git a/app/controllers/submissions_controller.rb b/app/controllers/submissions_controller.rb index fcc7b90b..69f3aa49 100644 --- a/app/controllers/submissions_controller.rb +++ b/app/controllers/submissions_controller.rb @@ -6,23 +6,8 @@ class SubmissionsController < ApplicationController load_and_authorize_resource :submission, only: %i[show destroy] - PRELOAD_ALL_PAGES_AMOUNT = 200 - def show - 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 + @submission = Submissions.preload_with_pages(@submission) render :show, layout: 'plain' end diff --git a/app/controllers/submissions_download_controller.rb b/app/controllers/submissions_download_controller.rb index e9ce7adc..334204f8 100644 --- a/app/controllers/submissions_download_controller.rb +++ b/app/controllers/submissions_download_controller.rb @@ -4,10 +4,20 @@ class SubmissionsDownloadController < ApplicationController skip_before_action :authenticate_user! skip_authorization_check - TTL = 20.minutes + TTL = 40.minutes + FILES_TTL = 5.minutes def index - submitter = Submitter.find_by!(slug: params[:submitter_slug]) + submitter = Submitter.find_signed(params[:sig], purpose: :download_completed) if params[:sig].present? + + signature_valid = + if submitter&.slug == params[:submitter_slug] + true + else + submitter = nil + end + + submitter ||= Submitter.find_by!(slug: params[:submitter_slug]) Submissions::EnsureResultGenerated.call(submitter) @@ -17,18 +27,24 @@ class SubmissionsDownloadController < ApplicationController return head :not_found unless last_submitter.completed_at? - if last_submitter.completed_at < TTL.ago && - (current_user.nil? || !current_user.account.submitters.exists?(id: last_submitter.id)) + if last_submitter.completed_at < TTL.ago && !signature_valid && !current_user_submitter?(last_submitter) Rollbar.info("TTL: #{last_submitter.id}") if defined?(Rollbar) return head :not_found end - urls = - Submitters.select_attachments_for_download(last_submitter).map do |attachment| - ActiveStorage::Blob.proxy_url(attachment.blob) - end + render json: build_urls(last_submitter) + end - render json: urls + private + + def current_user_submitter?(submitter) + current_user && current_user.account.submitters.exists?(id: submitter.id) + end + + def build_urls(submitter) + Submitters.select_attachments_for_download(submitter).map do |attachment| + ActiveStorage::Blob.proxy_url(attachment.blob, expires_at: FILES_TTL.minutes.from_now.to_i) + end end end diff --git a/app/controllers/submissions_preview_controller.rb b/app/controllers/submissions_preview_controller.rb index 12db79cf..dbf29294 100644 --- a/app/controllers/submissions_preview_controller.rb +++ b/app/controllers/submissions_preview_controller.rb @@ -4,37 +4,31 @@ class SubmissionsPreviewController < ApplicationController skip_before_action :authenticate_user! skip_authorization_check - PRELOAD_ALL_PAGES_AMOUNT = 200 - - TTL = 20.minutes + TTL = 40.minutes def show - @submission = Submission.find_by!(slug: params[:slug]) + submitter = Submitter.find_signed(params[:sig], purpose: :download_completed) if params[:sig].present? + + signature_valid = + if submitter && submitter.submission.slug == params[:slug] + @submission = submitter.submission + + true + end + + @submission ||= Submission.find_by!(slug: params[:slug]) if !@submission.submitters.all?(&:completed_at?) && current_user.blank? raise ActionController::RoutingError, 'Not Found' end - unless submission_valid_ttl?(@submission) + if !submission_valid_ttl?(@submission) && !signature_valid Rollbar.info("TTL: #{@submission.id}") if defined?(Rollbar) return redirect_to submissions_preview_completed_path(@submission.slug) end - 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 + @submission = Submissions.preload_with_pages(@submission) render 'submissions/show', layout: 'plain' end @@ -42,7 +36,7 @@ class SubmissionsPreviewController < ApplicationController def completed @submission = Submission.find_by!(slug: params[:submissions_preview_slug]) - render :completed, layout: 'plain' + render :completed, layout: 'form' end private diff --git a/app/mailers/submitter_mailer.rb b/app/mailers/submitter_mailer.rb index d7304070..c3fe43a4 100644 --- a/app/mailers/submitter_mailer.rb +++ b/app/mailers/submitter_mailer.rb @@ -2,6 +2,7 @@ class SubmitterMailer < ApplicationMailer MAX_ATTACHMENTS_SIZE = 10.megabytes + SIGN_TTL = 1.hour + 20.minutes DEFAULT_INVITATION_SUBJECT = 'You are invited to submit a form' @@ -61,9 +62,10 @@ class SubmitterMailer < ApplicationMailer subject:) end - def documents_copy_email(submitter, to: nil) + def documents_copy_email(submitter, to: nil, sig: false) @current_account = submitter.submission.template.account @submitter = submitter + @sig = submitter.signed_id(expires_in: SIGN_TTL, purpose: :download_completed) if sig Submissions::EnsureResultGenerated.call(@submitter) diff --git a/app/views/submissions/show.html.erb b/app/views/submissions/show.html.erb index af3d9a29..eae5be9e 100644 --- a/app/views/submissions/show.html.erb +++ b/app/views/submissions/show.html.erb @@ -6,7 +6,7 @@
Hi there,
Please check the copy of your "<%= @submitter.submission.template.name %>" submission in the email attachments.
Alternatively, you can review and download your copy using:
- <%= link_to @submitter.template.name, submissions_preview_url(@submitter.submission.slug) %> + <%= link_to @submitter.template.name, submissions_preview_url(@submitter.submission.slug, { sig: @sig }.compact) %>
Thanks,
<%= @current_account.name %>
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 4ca0ee80..c08aa1d1 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -129,7 +129,7 @@ Rails.application.configure do
config.lograge.custom_payload do |controller|
{
- fwd: controller.request.ip.to_s[/\A\d+\.(.*)/, 1],
+ fwd: controller.request.ip,
params: controller.request.params&.slice(:id),
host: controller.request.host,
uid: controller.instance_variable_get(:@current_user).try(:id)
diff --git a/config/initializers/active_storage.rb b/config/initializers/active_storage.rb
index ef04d0ac..8fb88efe 100644
--- a/config/initializers/active_storage.rb
+++ b/config/initializers/active_storage.rb
@@ -13,9 +13,9 @@ end
ActiveSupport.on_load(:active_storage_blob) do
attribute :uuid, :string, default: -> { SecureRandom.uuid }
- def self.proxy_url(blob, expires_in: nil)
+ def self.proxy_url(blob, expires_at: nil)
Rails.application.routes.url_helpers.blobs_proxy_url(
- signed_uuid: blob.signed_uuid(expires_in:), filename: blob.filename,
+ signed_uuid: blob.signed_uuid(expires_at:), filename: blob.filename,
**Docuseal.default_url_options
)
end
@@ -28,8 +28,10 @@ ActiveSupport.on_load(:active_storage_blob) do
end
end
- def signed_uuid(expires_in: nil)
- ApplicationRecord.signed_id_verifier.generate([uuid, 'blob'], expires_in:)
+ def signed_uuid(expires_at: nil)
+ expires_at = expires_at.to_i if expires_at
+
+ ApplicationRecord.signed_id_verifier.generate([uuid, 'blob', expires_at].compact)
end
def delete
diff --git a/lib/replace_email_variables.rb b/lib/replace_email_variables.rb
index 6b894eab..5fbe881f 100644
--- a/lib/replace_email_variables.rb
+++ b/lib/replace_email_variables.rb
@@ -18,7 +18,7 @@ module ReplaceEmailVariables
module_function
# rubocop:disable Metrics
- def call(text, submitter:, tracking_event_type: 'click_email')
+ def call(text, submitter:, tracking_event_type: 'click_email', sig: nil)
submitter_link = build_submitter_link(submitter, tracking_event_type)
submission_link = build_submission_link(submitter.submission) if submitter.submission
@@ -35,8 +35,8 @@ module ReplaceEmailVariables
if text.include?(SUBMISSION_SUBMITTERS)
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(DOCUMENTS_LINKS, build_documents_links_text(submitter, sig))
+ text = text.gsub(DOCUMENTS_LINK, build_documents_links_text(submitter, sig))
text = text.gsub(ACCOUNT_NAME, submitter.template.account.name) if submitter.template
@@ -44,9 +44,9 @@ module ReplaceEmailVariables
end
# rubocop:enable Metrics
- def build_documents_links_text(submitter)
+ def build_documents_links_text(submitter, sig = nil)
Rails.application.routes.url_helpers.submissions_preview_url(
- submitter.submission.slug, **Docuseal.default_url_options
+ submitter.submission.slug, { sig:, **Docuseal.default_url_options }.compact
)
end
diff --git a/lib/submissions.rb b/lib/submissions.rb
index 6bac4a0c..20f47932 100644
--- a/lib/submissions.rb
+++ b/lib/submissions.rb
@@ -3,6 +3,8 @@
module Submissions
DEFAULT_SUBMITTERS_ORDER = 'random'
+ PRELOAD_ALL_PAGES_AMOUNT = 200
+
module_function
def search(submissions, keyword)
@@ -27,6 +29,25 @@ module Submissions
submission.save!
end
+ def preload_with_pages(submission)
+ 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
+
+ submission
+ end
+
def create_from_emails(template:, user:, emails:, source:, mark_as_sent: false, params: {})
preferences = Submitters.normalize_preferences(user.account, user, params)