diff --git a/app/controllers/api/submissions_controller.rb b/app/controllers/api/submissions_controller.rb index c71d697d..f30afc84 100644 --- a/app/controllers/api/submissions_controller.rb +++ b/app/controllers/api/submissions_controller.rb @@ -93,7 +93,7 @@ module Api end render json: submissions.flat_map(&:submitters) - rescue Submitters::NormalizeValues::UnknownFieldName, Submitters::NormalizeValues::UnknownSubmitterName => e + rescue Submitters::NormalizeValues::BaseError => e Rollbar.warning(e) if defined?(Rollbar) render json: { error: e.message }, status: :unprocessable_entity diff --git a/app/views/submissions/show.html.erb b/app/views/submissions/show.html.erb index 93f02f68..a96c8f10 100644 --- a/app/views/submissions/show.html.erb +++ b/app/views/submissions/show.html.erb @@ -144,10 +144,10 @@
<% if field['type'].in?(%w[signature initials]) %>
- +
<% elsif field['type'].in?(['image', 'stamp']) %> - + <% elsif field['type'] == 'file' || field['type'] == 'payment' %>
<% Array.wrap(value).each do |val| %> diff --git a/lib/submitters/generate_font_image.rb b/lib/submitters/generate_font_image.rb new file mode 100644 index 00000000..b64580fc --- /dev/null +++ b/lib/submitters/generate_font_image.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Submitters + module GenerateFontImage + WIDTH = 3000 + HEIGHT = 160 + + FONTS = { + 'Dancing Script Regular' => '/fonts/DancingScript-Regular.otf', + 'Go Noto Kurrent-Bold Bold' => '/fonts/GoNotoKurrent-Bold.ttf' + }.freeze + + FONT_ALIASES = { + 'initials' => 'Go Noto Kurrent-Bold Bold', + 'signature' => 'Dancing Script Regular' + }.freeze + + module_function + + def call(text, font: nil) + font = FONT_ALIASES[font] || font + + text_image = Vips::Image.text(text, font:, fontfile: FONTS[font], + width: WIDTH, height: HEIGHT, wrap: :none) + + text_mask = Vips::Image.black(text_image.width, text_image.height) + + text_mask.bandjoin(text_image).copy(interpretation: :b_w).write_to_buffer('.png') + end + end +end diff --git a/lib/submitters/normalize_values.rb b/lib/submitters/normalize_values.rb index df02d957..75deeb70 100644 --- a/lib/submitters/normalize_values.rb +++ b/lib/submitters/normalize_values.rb @@ -4,8 +4,11 @@ module Submitters module NormalizeValues CHECKSUM_CACHE_STORE = ActiveSupport::Cache::MemoryStore.new - UnknownFieldName = Class.new(StandardError) - UnknownSubmitterName = Class.new(StandardError) + BaseError = Class.new(StandardError) + + UnknownFieldName = Class.new(BaseError) + InvalidDefaultValue = Class.new(BaseError) + UnknownSubmitterName = Class.new(BaseError) module_function @@ -32,7 +35,7 @@ module Submitters if field['type'].in?(%w[initials signature image file]) && value.present? new_value, new_attachments = - normalize_attachment_value(value, template.account, attachments, for_submitter) + normalize_attachment_value(value, field['type'], template.account, attachments, for_submitter) attachments.push(*new_attachments) @@ -88,26 +91,37 @@ module Submitters .merge(fields.index_by { |e| e['name'].to_s.downcase }) end - def normalize_attachment_value(value, account, attachments, for_submitter = nil) + def normalize_attachment_value(value, type, account, attachments, for_submitter = nil) if value.is_a?(Array) new_attachments = value.map do |v| - new_attachment = find_or_build_attachment(v, account, for_submitter) + new_attachment = find_or_build_attachment(v, type, account, for_submitter) attachments.find { |a| a.blob_id == new_attachment.blob_id } || new_attachment end [new_attachments.map(&:uuid), new_attachments] else - new_attachment = find_or_build_attachment(value, account, for_submitter) + new_attachment = find_or_build_attachment(value, type, account, for_submitter) existing_attachment = attachments.find { |a| a.blob_id == new_attachment.blob_id } - [new_attachment.uuid, existing_attachment || new_attachment] + attachment = existing_attachment || new_attachment + + [attachment.uuid, attachment] end end - def find_or_build_attachment(value, account, for_submitter = nil) - blob = find_or_create_blobs(account, value) + def find_or_build_attachment(value, type, account, for_submitter = nil) + blob = + if value.match?(%r{\Ahttps?://}) + find_or_create_blob_from_url(account, value) + elsif type.in?(%w[signature initials]) + raise InvalidDefaultValue, "Text value can't be more than 50 characters: #{value}" unless value.length < 50 + + find_or_create_blob_from_text(account, value, type) + else + raise InvalidDefaultValue, "Invalid default value, url is expected: #{value}" + end attachment = for_submitter.attachments.find_by(blob_id: blob.id) if for_submitter @@ -119,7 +133,20 @@ module Submitters attachment end - def find_or_create_blobs(account, url) + def find_or_create_blob_from_text(account, text, type) + data = Submitters::GenerateFontImage.call(text, font: type) + + checksum = Digest::MD5.base64digest(data) + + blob = find_blob_by_checksum(checksum, account) + + blob || ActiveStorage::Blob.create_and_upload!( + io: StringIO.new(data), + filename: "#{type}.png" + ) + end + + def find_or_create_blob_from_url(account, url) cache_key = [account.id, url].join(':') checksum = CHECKSUM_CACHE_STORE.fetch(cache_key) @@ -142,11 +169,15 @@ module Submitters end def find_blob_by_checksum(checksum, account) - ActiveStorage::Blob - .joins('JOIN active_storage_attachments ON active_storage_attachments.blob_id = active_storage_blobs.id') - .where(active_storage_attachments: { record_id: account.submitters.select(:id), - record_type: 'Submitter' }) - .find_by(checksum:) + blob = ActiveStorage::Blob.find_by(checksum:) + + return unless blob + + return blob unless blob.attachments.exists? + + return blob if account.submitters.exists?(id: blob.attachments.where(record_type: 'Submitter').select(:record_id)) + + nil end def conn