Skip to content

Commit

Permalink
Rewrite query with active record
Browse files Browse the repository at this point in the history
Adds a new scope to claim  `with_award_amount` allowing for querying
claims in the db by their award amount.
  • Loading branch information
rjlynch committed Nov 8, 2024
1 parent 5d465f9 commit 24dcf92
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 34 deletions.
22 changes: 22 additions & 0 deletions app/models/claim.rb
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,28 @@ class Claim < ApplicationRecord
where.not(id: Claim.awaiting_further_education_provider_verification)
end

scope :with_award_amounts, -> do
joins(
<<~SQL
JOIN (
#{
Policies::POLICIES.map do |policy|
"
SELECT
id,
#{policy.award_amount_column} AS award_amount,
'#{policy::Eligibility}' AS eligibility_type
FROM #{policy::Eligibility.table_name}
"
end.join(" UNION ALL ")
}
) AS eligibilities
ON claims.eligibility_id = eligibilities.id
AND claims.eligibility_type = eligibilities.eligibility_type
SQL
)
end

def onelogin_idv_full_name
"#{onelogin_idv_first_name} #{onelogin_idv_last_name}"
end
Expand Down
54 changes: 20 additions & 34 deletions app/models/payroll_run.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,48 +72,34 @@ def payments_count
@payments_count ||= payments.count
end

class LineItem < Struct.new(:id, :award_amount, keyword_init: true); end

def line_items(policy, filter: :all)
eligibilities_cte = "WITH eligibilities AS("
eligibilities_cte += Policies::POLICIES.map do |policy|
<<~SQL
SELECT
id,
#{policy.award_amount_column} AS award_amount,
'#{policy::Eligibility}' AS eligibility_type
FROM #{policy::Eligibility.table_name}
SQL
end.join(" UNION ALL ")
eligibilities_cte += ")"

sql = <<~SQL
#{eligibilities_cte}
SELECT
/* A topup is always paid in different payment/payroll_run than the main claim was */
scope = Claim
.select(
"
DISTINCT(claims.id),
COALESCE(topups.award_amount, eligibilities.award_amount) AS award_amount
FROM payments
JOIN claim_payments ON claim_payments.payment_id = payments.id
JOIN claims ON claims.id = claim_payments.claim_id
JOIN eligibilities
ON claims.eligibility_id = eligibilities.id
AND claims.eligibility_type = eligibilities.eligibility_type
LEFT JOIN topups ON topups.claim_id = claims.id
WHERE payments.payroll_run_id = '#{id}'
SQL

unless policy == :all
sql += "\nAND claims.eligibility_type = 'Policies::#{policy}::Eligibility'"
end
"
)
.with_award_amounts
.left_joins(payments: :topups)
.joins(payments: :payroll_run)
.where(payroll_runs: {id: id})

scope = scope.by_policy(policy) unless policy == :all

case filter
when :all
sql
when :claims
sql += "\nAND topups.id IS NULL"
scope = scope.where(topups: {id: nil})
when :topups
sql += "\nAND topups.id IS NOT NULL"
scope = scope.where.not(topups: {id: nil})
end

ActiveRecord::Base.connection.execute(sql).map(&OpenStruct.method(:new))
# Claim delegates it's award amount to eligibility, so we want to return
# a non claim object ensuring the award amount is from the topup if there
# is one
ActiveRecord::Base.connection.execute(scope.to_sql).map(&LineItem.method(:new))
end

def ensure_no_payroll_run_this_month
Expand Down
46 changes: 46 additions & 0 deletions config/brakeman.ignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,29 @@
],
"note": ""
},
{
"warning_type": "SQL Injection",
"warning_code": 0,
"fingerprint": "0ac253105d2af7d0dd324537b4be4a392ded73c0f3df8ca4d32db09cac7b586d",
"check_name": "SQL",
"message": "Possible SQL injection",
"file": "app/models/claim/search.rb",
"line": 35,
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
"code": "Claim.submitted.where(\"LOWER(#{attribute}) = LOWER(?)\", search_term)",
"render_path": null,
"location": {
"type": "method",
"class": "Search",
"method": "search_by"
},
"user_input": "attribute",
"confidence": "Medium",
"cwe_id": [
89
],
"note": ""
},
{
"warning_type": "Dynamic Render Path",
"warning_code": 15,
Expand Down Expand Up @@ -115,6 +138,29 @@
],
"note": ""
},
{
"warning_type": "SQL Injection",
"warning_code": 0,
"fingerprint": "cddc34b96e07d19510d574438a1ce61b69d9c1f28c0d4e5eee631d17a9b38ba6",
"check_name": "SQL",
"message": "Possible SQL injection",
"file": "app/models/claim.rb",
"line": 222,
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
"code": "joins(\"JOIN (\\n #{Policies::POLICIES.map do\n \"\\n SELECT\\n id,\\n #{policy.award_amount_column} AS award_amount,\\n '#{policy::Eligibility}' AS eligibility_type\\n FROM #{policy::Eligibility.table_name}\\n \"\n end.join(\" UNION ALL \")}\\n) AS eligibilities\\nON claims.eligibility_id = eligibilities.id\\nAND claims.eligibility_type = eligibilities.eligibility_type\\n\")",
"render_path": null,
"location": {
"type": "method",
"class": "Claim",
"method": "with_award_amounts"
},
"user_input": "Policies::POLICIES.map do\n \"\\n SELECT\\n id,\\n #{policy.award_amount_column} AS award_amount,\\n '#{policy::Eligibility}' AS eligibility_type\\n FROM #{policy::Eligibility.table_name}\\n \"\n end.join(\" UNION ALL \")",
"confidence": "Medium",
"cwe_id": [
89
],
"note": "Non of the columns used in generating the join are user provided"
},
{
"warning_type": "SQL Injection",
"warning_code": 0,
Expand Down

0 comments on commit 24dcf92

Please sign in to comment.