Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
8 changes: 8 additions & 0 deletions app/controllers/vacancies_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ def show
end
# rubocop:enable Metrics/AbcSize

def apply
vacancy = PublishedVacancy.live.friendly.find(params[:id])
raise ActiveRecord::RecordNotFound if vacancy.application_link.blank?

vacancy.increment!(:external_application_clicks)
redirect_to vacancy.application_link, allow_other_host: true
end

def campaign_landing_page
@campaign_page = CampaignPage[params[:utm_content]]
campaign_params = CampaignSearchParamsMerger.new(campaign_search_params, @campaign_page).merged_params
Expand Down
2 changes: 1 addition & 1 deletion app/helpers/links_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def external_advert_link(vacancy, **)
def apply_link(vacancy, **)
tracked_open_in_new_tab_button_link_to(
t("jobs.view_advert.#{school_or_college_type(vacancy.organisation)}"),
vacancy.application_link,
apply_job_path(vacancy),
"aria-label": t("jobs.aria_labels.apply_link"),
link_type: :get_more_information,
link_subject: vacancy.id,
Expand Down
1 change: 1 addition & 0 deletions app/models/vacancy_template.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class VacancyTemplate < ApplicationRecord
external_source
external_reference
external_advert_url
external_application_clicks
start_date_type
earliest_start_date
latest_start_date
Expand Down
1 change: 1 addition & 0 deletions config/analytics.yml
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,7 @@ shared:
- job_address_county
- job_address_postcode
- fe_role_qts_required
- external_application_clicks
failed_imported_vacancies:
- id
- import_errors
Expand Down
23 changes: 23 additions & 0 deletions config/brakeman.ignore
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,29 @@
],
"note": ""
},
{
"warning_type": "Redirect",
"warning_code": 18,
"fingerprint": "42ada4273ecac39e5a82c397387ce17fba49366e31977c50aba4d8114ecc4da9",
"check_name": "Redirect",
"message": "Possible unprotected redirect",
"file": "app/controllers/vacancies_controller.rb",
"line": 46,
"link": "https://brakemanscanner.org/docs/warning_types/redirect/",
"code": "redirect_to(PublishedVacancy.live.friendly.find(params[:id]).application_link, :allow_other_host => true)",
"render_path": null,
"location": {
"type": "method",
"class": "VacanciesController",
"method": "apply"
},
"user_input": "PublishedVacancy.live.friendly.find(params[:id]).application_link",
"confidence": "Weak",
"cwe_id": [
601
],
"note": "The destination is a stored application URL and redirecting to the external recruitment site is the intended behaviour."
},
{
"warning_type": "Unscoped Find",
"warning_code": 82,
Expand Down
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@
post "/cookies-preferences", to: "cookies_preferences#create", as: "create_cookies_preferences"

resources :jobs, only: %i[index show], controller: "vacancies" do
get :apply, on: :member
resources :documents, only: %i[show]
member do
get :trn_interstitial
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddExternalApplicationClicksToVacancies < ActiveRecord::Migration[8.1]
def change
add_column :vacancies, :external_application_clicks, :integer, default: 0, null: false
end
end
3 changes: 2 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[8.1].define(version: 2026_08_18_075048) do
ActiveRecord::Schema[8.1].define(version: 2026_08_24_135752) do
# These are extensions that must be enabled in order to support this database
enable_extension "btree_gist"
enable_extension "citext"
Expand Down Expand Up @@ -983,6 +983,7 @@
t.datetime "expires_at", precision: nil
t.integer "extension_reason"
t.string "external_advert_url"
t.integer "external_application_clicks", default: 0, null: false
t.string "external_reference"
t.string "external_source"
t.boolean "fe_role_qts_required"
Expand Down
1 change: 1 addition & 0 deletions spec/jobs/import_from_vacancy_source_job_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ def each(...)
"expired_vacancy_feedback_email_sent_at" => nil,
"expires_at" => "2023-06-06T09:00:00.000+01:00",
"external_advert_url" => "https://example.com/jobs/123",
"external_application_clicks" => 0,
"external_reference" => "invalid_vac_ref",
"external_source" => "may_the_feed_be_with_you",
"fixed_term_contract_duration" => "",
Expand Down
1 change: 1 addition & 0 deletions spec/models/vacancy_template_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
publisher_organisation_id
readable_job_location
external_advert_url
external_application_clicks
external_reference
external_source
geolocation
Expand Down
29 changes: 29 additions & 0 deletions spec/requests/vacancies_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,33 @@
end
end
end

describe "GET #apply" do
let(:vacancy) { create(:vacancy, :apply_via_website, external_application_clicks: 2) }

it "increments the application click count and redirects to the application website" do
expect { get apply_job_path(vacancy) }
.to change { vacancy.reload.external_application_clicks }.from(2).to(3)

expect(response).to redirect_to(vacancy.application_link)
end

it "does not count clicks for an expired vacancy" do
vacancy.update!(expires_at: 1.day.ago)

expect { get apply_job_path(vacancy) }
.to(not_change { vacancy.reload.external_application_clicks })

expect(response).to have_http_status(:not_found)
end

it "does not count clicks when there is no application link" do
vacancy.update!(application_link: nil)

expect { get apply_job_path(vacancy) }
.to(not_change { vacancy.reload.external_application_clicks })

expect(response).to have_http_status(:not_found)
end
end
end
2 changes: 1 addition & 1 deletion spec/views/vacancies/show.html.slim_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
end

it "has an application link" do
expect(rendered).to have_link I18n.t("jobs.view_advert.school"), href: vacancy.application_link
expect(rendered).to have_link I18n.t("jobs.view_advert.school"), href: apply_job_path(vacancy)
end
end
end
Expand Down
Loading