Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

08/07/24 form filler #214

Merged
merged 15 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/assets/builds/tailwind.css

Large diffs are not rendered by default.

48 changes: 48 additions & 0 deletions app/services/applier/devit_form_filler.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# frozen_string_literal: true

module Applier
class DevitFormFiller < FormFiller
def initialize(payload = sample_payload)
super
end

def submit_button
first(:button, text: /\bsend\b/i) || first(:link, text: /\bsend\b/i)
end

def sample_payload
{
user_fullname: 'John Smith',
apply_url: 'https://devitjobs.uk/jobs/Critical-Software-Software-Engineer',
form_locator: 'form',
fields: [
{
locator: 'name',
interaction: :input,
value: 'John Smith'
},
{
locator: 'email',
interaction: :input,
value: 'j.smith@example.com'
},
{
locator: 'isFromEurope',
interaction: :radiogroup,
value: 'Yes'
},
{
locator: '#cvFileId',
interaction: :upload,
value: File.open('public/Obretetskiy_cv.pdf')
},
{
locator: 'motivationLetter',
interaction: :input,
value: 'Thank you for considering my application. It really is an honor to apply to your company. Please hire me. I would like to work here very much. I promise to work very very hard and always get along well with my coworkers.'
}
]
}
end
end
end
131 changes: 90 additions & 41 deletions app/services/applier/form_filler.rb
Original file line number Diff line number Diff line change
@@ -1,69 +1,118 @@
# frozen_string_literal: true

require 'json'
# require 'open-uri'
# require 'htmltoword'

# TODO: Handle job posting becoming closed (redirect or notification on page)
module Applier
# Core class for filling out forms using Capybara
class FormFiller < ApplicationTask
include Capybara::DSL

def initialize(job_application, payload)
@job_application = job_application
@url = @job_application.job.posting_url
@ats = @job_application.job.applicant_tracking_system
@fields = JSON.parse(payload)
# @user = @job_application.application_process.user
@errors = nil

# include the relevant ATS form_filler module
include_ats_module
def initialize(payload)
@application_form = payload[:form_locator]
@fields = payload[:fields]
@session = Capybara::Session.new(:selenium)
@url = payload[:apply_url]
@user_fullname = payload[:user_fullname]
end

def call
return unless processable
return false unless processable

process
rescue StandardError => e
Rails.logger.error "Error running FormFiller: #{e.message}"
nil
Capybara.using_session(@session) do
process
end
end

private

def processable
@url && @fields && @job_application && @ats
@url && @fields && @session
end

def process
p "Hello from FormFiller!"
submit_application
visit_url
click_apply_button
fill_in_all_fields
sleep 2
click_submit_button
confirm_submission_was_successful
ensure
@session.quit
end
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about something like this instead ?

def process
  visit_url
  fill_application_form
  click_submit_button
  # sleep 2 add this to click_submit_button
  verify_submission # instead of confirm_submission_was_successful
ensure
  @session.quit
end

private

def fill_application_form
  click_apply_button
  fill_in_all_fields
end

def verify_submission
  # Add logic to check for successful submission message or other indicators
end

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! :)


def apply_button
first(:button, text: /apply/i) || first(:link, text: /apply/i)
end

def attach_file_to_application(filepath, locator)
find(locator).attach_file(filepath)
end

def include_ats_module
ats_name = @ats.name.gsub(/\W/, '').capitalize
module_name = "Ats::#{ats_name}::SubmitApplication"
extend Object.const_get(module_name) if Object.const_defined?(module_name)
def click_apply_button
apply_button.click
end

def submit_application
return super if defined?(super)
def click_submit_button
submit_button.click
end

def confirm_submission_was_successful
sleep 4
end

puts "Write a submit method for #{@ats.name}!"
return
def doc_tmp_file(file_text)
docx = Htmltoword::Document.create(file_text)
filepath = Rails.root.join("tmp", "Cover Letter_#{unique_string}.docx")
File.binwrite(filepath, docx)
filepath
end

# def take_screenshot_and_store(session, job_application)
# screenshot_path = Rails.root.join('tmp', "screenshot-#{job_application.id}.png")
# session.save_screenshot(screenshot_path)
def fill_in_all_fields
within(@application_form) do
@fields.each do |field|
fill_in_field(field)
end
end
end

# file = File.open(screenshot_path)
# job_app = job_application
# job_app.screenshot.attach(io: file, filename: "screenshot-#{job_application.id}.png", content_type: 'image/png')
def fill_in_field(field)
fill_in_method = :"handle_#{field[:interaction]}"
send(fill_in_method, field)
rescue Capybara::ElementNotFound => e
p e.message
end

def handle_input(field)
fill_in(field[:locator], with: field[:value])
end

# File.delete(screenshot_path)
# end
def handle_radiogroup(field)
choose(option: field[:value], name: field[:locator])
end

def handle_upload(field)
file = field[:value]
filepath = file.instance_of?(String) ? doc_tmp_file(file) : pdf_tmp_file(file)
attach_file_to_application(filepath, field[:locator])
end

def pdf_tmp_file(file)
filepath = Rails.root.join("tmp", "Resume - #{unique_string}.pdf")
File.binwrite(filepath, file)
filepath
end

def submit_button
first(:button, text: /submit/i) || first(:link, text: /submit/i)
end

def timestamp
Time.now.to_s.truncate(19).gsub(/\D/, '')
end

def unique_string
"#{@user_fullname}_#{timestamp}"
end

def visit_url
visit(@url)
p "Successfully reached #{@url}"
end
end
end
1 change: 1 addition & 0 deletions storage/csv/unparseable_urls.csv
Original file line number Diff line number Diff line change
Expand Up @@ -24201,3 +24201,4 @@ https://uk.indeed.com/tmn/ccs/64491030ef20905b/6298a5756c1c7089366ef2e8c1b704cea
https://uk.indeed.com/tmn/ccs/9a0b2c4f69b9e643/52f25543d1f0ce4be8323b03411752a86d36f8daac73db1eb88b75581610316c/7985898892702321?sf=PYM00,
https://uk.indeed.com/tmn/ccs/87c1590d56e224f7/939f9e062f0e84a2ff50cc3cdcb6a5b9882ca8afd73f19e9673b69fc7bf44f41/7985898892702321?sf=PYM00,
https://uk.indeed.com/tmn/ccs/681c16faa8f6659b/6c832c14f86c96d6a982e35c5736ca3a7abb232a59f66c34a4987d0d3be344e2/7985898892702321?sf=PYM00,
https://www.tesla.com/careers/search/job/223235,
Loading