CP-10359 - Add ATS prefill field extraction for template and submission views

- Add PrefillFieldsHelper module to extract ATS field data from base64 encoded parameters
- Integrate ATS field extraction into TemplatesController and SubmissionsController
- Support employee, manager, account, and location field name patterns
- Add comprehensive test coverage for field validation and error handling
- Remove unused backgroundColor style from template builder
pull/544/head
Bernardo Anderson 4 months ago
parent 6228b8a037
commit be41cebcca

@ -1,6 +1,8 @@
# frozen_string_literal: true
class SubmissionsController < ApplicationController
include PrefillFieldsHelper
skip_before_action :verify_authenticity_token
before_action :load_template, only: %i[new create]
authorize_resource :template, only: %i[new create]
@ -15,6 +17,10 @@ class SubmissionsController < ApplicationController
def show
@submission = Submissions.preload_with_pages(@submission)
@available_ats_fields = extract_ats_prefill_fields
# Optional: store in session for persistence across requests
session[:ats_prefill_fields] = @available_ats_fields if @available_ats_fields.any?
unless @submission.submitters.all?(&:completed_at?)
ActiveRecord::Associations::Preloader.new(
@ -91,6 +97,7 @@ class SubmissionsController < ApplicationController
private
def save_template_message(template, params)
template.preferences['request_email_subject'] = params[:subject] if params[:subject].present?
template.preferences['request_email_body'] = params[:body] if params[:body].present?

@ -1,6 +1,8 @@
# frozen_string_literal: true
class TemplatesController < ApplicationController
include PrefillFieldsHelper
skip_before_action :maybe_redirect_to_setup
skip_before_action :verify_authenticity_token
@ -39,6 +41,9 @@ class TemplatesController < ApplicationController
associations: [schema_documents: [:blob, { preview_images_attachments: :blob }]]
).call
# Process ATS fields for template editing
@available_ats_fields = extract_ats_prefill_fields
@template_data =
@template.as_json.merge(
documents: @template.schema_documents.as_json(

@ -0,0 +1,33 @@
# frozen_string_literal: true
module PrefillFieldsHelper
def extract_ats_prefill_fields
return [] if params[:ats_fields].blank?
begin
decoded_json = Base64.urlsafe_decode64(params[:ats_fields])
field_names = JSON.parse(decoded_json)
# Validate that we got an array of strings
return [] unless field_names.is_a?(Array) && field_names.all?(String)
# Filter to only expected field name patterns
valid_fields = field_names.select { |name| valid_ats_field_name?(name) }
# Log successful field reception
Rails.logger.info "Received #{valid_fields.length} ATS prefill fields: #{valid_fields.join(', ')}"
valid_fields
rescue StandardError => e
Rails.logger.warn "Failed to parse ATS prefill fields: #{e.message}"
[]
end
end
private
def valid_ats_field_name?(name)
# Only allow expected field name patterns (security)
name.match?(/\A(employee|manager|account|location)_[a-z_]+\z/)
end
end

@ -55,7 +55,6 @@
id="title_container"
class="flex justify-between py-1.5 items-center pr-4 top-0 z-10 title-container"
:class="{ sticky: withStickySubmitters || isBreakpointLg }"
:style="{ backgroundColor }"
>
<div />
<div class="space-x-3 flex items-center flex-shrink-0">

@ -0,0 +1,153 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe PrefillFieldsHelper, type: :helper do
describe '#extract_ats_prefill_fields' do
it 'extracts valid field names from base64 encoded parameter' do
fields = %w[employee_first_name employee_email manager_firstname]
encoded = Base64.urlsafe_encode64(fields.to_json)
allow(helper).to receive(:params).and_return({ ats_fields: encoded })
result = helper.extract_ats_prefill_fields
expect(result).to eq(fields)
end
it 'returns empty array for invalid base64' do
allow(helper).to receive(:params).and_return({ ats_fields: 'invalid_base64' })
result = helper.extract_ats_prefill_fields
expect(result).to eq([])
end
it 'returns empty array for invalid JSON' do
invalid_json = Base64.urlsafe_encode64('invalid json')
allow(helper).to receive(:params).and_return({ ats_fields: invalid_json })
result = helper.extract_ats_prefill_fields
expect(result).to eq([])
end
it 'filters out invalid field names' do
fields = %w[employee_first_name malicious_field account_name invalid-field]
encoded = Base64.urlsafe_encode64(fields.to_json)
allow(helper).to receive(:params).and_return({ ats_fields: encoded })
result = helper.extract_ats_prefill_fields
expect(result).to eq(%w[employee_first_name account_name])
end
it 'returns empty array when no ats_fields parameter' do
allow(helper).to receive(:params).and_return({})
result = helper.extract_ats_prefill_fields
expect(result).to eq([])
end
it 'returns empty array when ats_fields parameter is empty' do
allow(helper).to receive(:params).and_return({ ats_fields: '' })
result = helper.extract_ats_prefill_fields
expect(result).to eq([])
end
it 'returns empty array when decoded JSON is not an array' do
not_array = Base64.urlsafe_encode64({ field: 'employee_name' }.to_json)
allow(helper).to receive(:params).and_return({ ats_fields: not_array })
result = helper.extract_ats_prefill_fields
expect(result).to eq([])
end
it 'returns empty array when array contains non-string values' do
mixed_array = ['employee_first_name', 123, 'manager_firstname']
encoded = Base64.urlsafe_encode64(mixed_array.to_json)
allow(helper).to receive(:params).and_return({ ats_fields: encoded })
result = helper.extract_ats_prefill_fields
expect(result).to eq([])
end
it 'accepts all valid field name patterns' do
fields = %w[
employee_first_name
employee_middle_name
employee_last_name
employee_email
manager_firstname
manager_lastname
account_name
location_name
location_street
]
encoded = Base64.urlsafe_encode64(fields.to_json)
allow(helper).to receive(:params).and_return({ ats_fields: encoded })
result = helper.extract_ats_prefill_fields
expect(result).to eq(fields)
end
it 'logs successful field reception' do
fields = %w[employee_first_name employee_email]
encoded = Base64.urlsafe_encode64(fields.to_json)
allow(helper).to receive(:params).and_return({ ats_fields: encoded })
allow(Rails.logger).to receive(:info)
helper.extract_ats_prefill_fields
expect(Rails.logger).to have_received(:info).with(
'Received 2 ATS prefill fields: employee_first_name, employee_email'
)
end
it 'logs parsing errors' do
allow(helper).to receive(:params).and_return({ ats_fields: 'invalid_base64' })
allow(Rails.logger).to receive(:warn)
helper.extract_ats_prefill_fields
expect(Rails.logger).to have_received(:warn).with(
a_string_matching(/Failed to parse ATS prefill fields:/)
)
end
end
describe '#valid_ats_field_name?' do
it 'returns true for valid employee field names' do
expect(helper.send(:valid_ats_field_name?, 'employee_first_name')).to be true
expect(helper.send(:valid_ats_field_name?, 'employee_email')).to be true
expect(helper.send(:valid_ats_field_name?, 'employee_phone_number')).to be true
end
it 'returns true for valid manager field names' do
expect(helper.send(:valid_ats_field_name?, 'manager_firstname')).to be true
expect(helper.send(:valid_ats_field_name?, 'manager_lastname')).to be true
expect(helper.send(:valid_ats_field_name?, 'manager_email')).to be true
end
it 'returns true for valid account field names' do
expect(helper.send(:valid_ats_field_name?, 'account_name')).to be true
expect(helper.send(:valid_ats_field_name?, 'account_id')).to be true
end
it 'returns true for valid location field names' do
expect(helper.send(:valid_ats_field_name?, 'location_name')).to be true
expect(helper.send(:valid_ats_field_name?, 'location_street')).to be true
expect(helper.send(:valid_ats_field_name?, 'location_city')).to be true
end
it 'returns false for invalid field names' do
expect(helper.send(:valid_ats_field_name?, 'malicious_field')).to be false
expect(helper.send(:valid_ats_field_name?, 'invalid-field')).to be false
expect(helper.send(:valid_ats_field_name?, 'EMPLOYEE_NAME')).to be false
expect(helper.send(:valid_ats_field_name?, 'employee')).to be false
expect(helper.send(:valid_ats_field_name?, 'employee_')).to be false
expect(helper.send(:valid_ats_field_name?, '_employee_name')).to be false
end
end
end
Loading…
Cancel
Save