diff --git a/app/models/lettings_log.rb b/app/models/lettings_log.rb index 7bf963212..d70f9cbff 100644 --- a/app/models/lettings_log.rb +++ b/app/models/lettings_log.rb @@ -59,17 +59,25 @@ class LettingsLog < Log query.all } scope :search_by, lambda { |param| - by_id = Arel.sql("CASE WHEN lettings_logs.id = #{param.to_i} THEN 0 ELSE 1 END") - by_tenant_code = Arel.sql("CASE WHEN tenancycode = '#{param}' THEN 0 WHEN tenancycode ILIKE '%#{param}%' THEN 1 ELSE 2 END") - by_propcode = Arel.sql("CASE WHEN propcode = '#{param}' THEN 0 WHEN propcode ILIKE '%#{param}%' THEN 1 ELSE 2 END") - by_postcode = Arel.sql("CASE WHEN REPLACE(postcode_full, ' ', '') = '#{param.delete(' ')}' THEN 0 when REPLACE(postcode_full, ' ', '') ILIKE '%#{param.delete(' ')}%' then 1 ELSE 2 END") + sanitized_param = ActiveRecord::Base.sanitize_sql(param) + param_without_spaces = sanitized_param.delete(" ") + + by_id = Arel.sql("CASE WHEN lettings_logs.id = ? THEN 0 ELSE 1 END") + by_tenant_code = Arel.sql("CASE WHEN tenancycode = ? THEN 0 WHEN tenancycode ILIKE ? THEN 1 ELSE 2 END") + by_propcode = Arel.sql("CASE WHEN propcode = ? THEN 0 WHEN propcode ILIKE ? THEN 1 ELSE 2 END") + by_postcode = Arel.sql("CASE WHEN REPLACE(postcode_full, ' ', '') = ? THEN 0 WHEN REPLACE(postcode_full, ' ', '') ILIKE ? THEN 1 ELSE 2 END") filter_by_location_postcode(param) .or(filter_by_tenant_code(param)) .or(filter_by_propcode(param)) .or(filter_by_postcode(param)) .or(filter_by_id(param.gsub(/log/i, ""))) - .order(by_id, by_tenant_code, by_propcode, by_postcode) + .order( + [by_id, sanitized_param.to_i], + [by_tenant_code, sanitized_param, sanitized_param], + [by_propcode, sanitized_param, sanitized_param], + [by_postcode, param_without_spaces, param_without_spaces], + ) } scope :after_date, ->(date) { where("lettings_logs.startdate >= ?", date) } scope :before_date, ->(date) { where("lettings_logs.startdate < ?", date) } diff --git a/app/models/sales_log.rb b/app/models/sales_log.rb index 8312b8bff..aca80ef94 100644 --- a/app/models/sales_log.rb +++ b/app/models/sales_log.rb @@ -46,14 +46,19 @@ class SalesLog < Log } scope :filter_by_purchaser_code, ->(purchid) { where("purchid ILIKE ?", "%#{purchid}%") } scope :search_by, lambda { |param| - by_id = Arel.sql("CASE WHEN id = #{param.to_i} THEN 0 ELSE 1 END") - by_purchaser_code = Arel.sql("CASE WHEN purchid = '#{param}' THEN 0 WHEN purchid ILIKE '%#{param}%' THEN 1 ELSE 2 END") - by_postcode = Arel.sql("CASE WHEN REPLACE(postcode_full, ' ', '') = '#{param.delete(' ')}' THEN 0 WHEN REPLACE(postcode_full, ' ', '') ILIKE '%#{param.delete(' ')}%' THEN 1 ELSE 2 END") + sanitized_param = ActiveRecord::Base.sanitize_sql(param) + param_without_spaces = sanitized_param.delete(" ") + + by_id = Arel.sql("CASE WHEN id = ? THEN 0 ELSE 1 END") + by_purchaser_code = Arel.sql("CASE WHEN purchid = ? THEN 0 WHEN purchid ILIKE ? THEN 1 ELSE 2 END") + by_postcode = Arel.sql("CASE WHEN REPLACE(postcode_full, ' ', '') = ? THEN 0 WHEN REPLACE(postcode_full, ' ', '') ILIKE ? THEN 1 ELSE 2 END") filter_by_purchaser_code(param) .or(filter_by_postcode(param)) .or(filter_by_id(param.gsub(/log/i, ""))) - .order(by_id, by_purchaser_code, by_postcode) + .order([by_id, sanitized_param.to_i], + [by_purchaser_code, sanitized_param, sanitized_param], + [by_postcode, param_without_spaces, param_without_spaces]) } scope :age1_answered, -> { where.not(age1: nil).or(where(age1_known: [1, 2])) } scope :duplicate_logs, lambda { |log| diff --git a/app/models/user.rb b/app/models/user.rb index c8dfd53de..d3ce339e6 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -207,6 +207,10 @@ class User < ApplicationRecord end def assignable_roles + if Rails.env.staging? && Rails.application.credentials[:staging_role_update_email_allowlist].include?(email.split("@").last.downcase) + return ROLES + end + return {} unless data_coordinator? || support? return ROLES if support? diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc index c9d564782..9cd4bba71 100644 --- a/config/credentials.yml.enc +++ b/config/credentials.yml.enc @@ -1 +1 @@ -EZNV2LiNWzf52erbQ41Dz3Bh+2f3Uih8liEyhXp5XzHCLzAbmN6/IJqr7b9cTZiCiroFo4n/dFoG3yYrospp3frKsDXxF1K2/MTCJWjpgnn7wc+HiPQWG0W3HRtQCNkyyrHes0YKcYyDWIP6kztYv1I/Me3p0pGEx6t3CpSTg1v46eRnOlDWiUz3rVxPauwq9IYZ75gmnThqvg/Z8wcYsWLx0arago0SXtRPASCNj4uO/lbqTcAfyIXOTSiOlcAIjoPFRSQY7UqY0o2p8jRR/1L16SmGDsk8ijm+UygNmMexa3Khy5WcKctpQICakHs4NRjHNflqgXpXKL9dVBmNc9d7h+gbhbGJQ53Y0d+a35UbhPRMiv4SRH98FwB+WEsLCDdGSHvdmM6ArfOLljTrqrsmSRf0JfUrvzyVYmMCxjv4xgJwUS/TD5lQD1yPwkp2ss00kQJqzNmB7qwFhA8a3e2iNzV8qtAV/Nj+tMlr99Hb7vZZs98/38G2p5RAsE/5Xl9taKhc/ACnVc/bwJND4JWaBB7duCa08xVB8nkjlt5cCwMurzAcy1ZT+e8JepR+g6s8fpScMEWVJXE0hd8=--rZ41rY9TMXmiBUJw--QiLRVNVXZzTW446s7cec1g== \ No newline at end of file +QGn9IiI91BaO4IGAtfy92FrNP46X9T2jJErRv+o/PRG9LrimEGeuOE+FwhArKZQ5cTipaDqo8u9Ajv45Kitv3c0GynOOvz0r3OjPRHO/p4hW8BFWQDv581cWWPsyZT2JO51zZ5LnwNFvWrjEB2q49YESgtfADPkJWmtx/By5Cg2/PVIRxvhGKOnheme5cih050wqg/43BdiF0PD9FDTZXJDLJg/QQ8nQYkvQe2jN4nM4mTVpkQkmzDKgGknmUWFfW3qWFzlsdMkdkPdeP9wLnJVbFTeyaaJT3wv6l19d2rKqo8iVvacdaQjRev+LVXqOsNAjVHwcPNQVq9s8pxG24HLk3aQ14Eyjf6tHAuZAV4jLnNqQtBQ0AIldWeOl6SKmlTom1P1tcLp9KpajEADplmWSwUktIGmaakFjk/ApYaUBiYTku2iLHMrT/xSc3jPj5W/ZggeJ0Ij6nuGYE1cmBxWGxda9PzOrDP8coEK9vPHiNeDDM1RoukVmf8gwDmshILi5EwIAsO2gJXM1wtPYMu41+H4/y3c0GIwgfv9QP11q+nqhG1MMcOrAUKGhypAS+M+uLwfGQudfQDKP9Zv3VCnOk3mkKlpIzMMD4UdJxQeE/8sfwIsEhWggEo3oa93ptbRdvJ7YYcVvmMmkVBxk0KWFprl4i/BkFHLWrKNl5LBOGA==--ziMOTnYBB5TDyXYU--3FJMs8e6R8lheqcqB8p8uQ== \ No newline at end of file diff --git a/spec/models/lettings_log_spec.rb b/spec/models/lettings_log_spec.rb index 92452f197..e28f0f2c5 100644 --- a/spec/models/lettings_log_spec.rb +++ b/spec/models/lettings_log_spec.rb @@ -1345,6 +1345,13 @@ RSpec.describe LettingsLog do expect(result.third.id).to eq lettings_log_with_postcode.id end end + + it "sanitises input for order" do + lettings_log_to_search.update!(tenancycode: "' 1234") + result = described_class.search_by(lettings_log_to_search.tenancycode) + expect(result.count).to eq(1) + expect(result.first.id).to eq lettings_log_to_search.id + end end end diff --git a/spec/models/sales_log_spec.rb b/spec/models/sales_log_spec.rb index a568ca330..ae9b00d4c 100644 --- a/spec/models/sales_log_spec.rb +++ b/spec/models/sales_log_spec.rb @@ -214,6 +214,13 @@ RSpec.describe SalesLog, type: :model do expect(result).to include(have_attributes(id: sales_log_to_search.id)) end end + + it "sanitises input for order" do + sales_log_to_search.update!(purchid: "' 123456") + result = described_class.search_by(sales_log_to_search.purchid) + expect(result.count).to be >= 1 + expect(result).to include(have_attributes(id: sales_log_to_search.id)) + end end context "when filtering by year or nil" do diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index f34b0ee38..2c035c9fd 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -243,6 +243,128 @@ RSpec.describe User, type: :model do expect(user.need_two_factor_authentication?(nil)).to be false end end + + context "when the user is in non staging environment" do + before do + allow(Rails.env).to receive(:staging?).and_return(false) + end + + context "and the user is in the staging role update email allowlist" do + before do + allow(Rails.application.credentials).to receive(:[]).with(:staging_role_update_email_allowlist).and_return(["example.com"]) + end + + context "when the user is a data provider" do + it "cannot assign roles" do + expect(user.assignable_roles).to eq({}) + end + end + + context "when the user is a data coordinator" do + let(:user) { create(:user, :data_coordinator) } + + it "can assign all roles except support" do + expect(user.assignable_roles).to eq({ + data_provider: 1, + data_coordinator: 2, + }) + end + end + + context "when the user is a Support user" do + let(:user) { create(:user, :support) } + + it "can assign all roles" do + expect(user.assignable_roles).to eq({ + data_provider: 1, + data_coordinator: 2, + support: 99, + }) + end + end + end + end + + context "when the user is in staging environment" do + before do + allow(Rails.env).to receive(:staging?).and_return(true) + end + + context "and the user is not in the staging role update email allowlist" do + context "when the user is a data provider" do + let(:user) { create(:user, :data_provider) } + + it "cannot assign roles" do + expect(user.assignable_roles).to eq({}) + end + end + + context "when the user is a data coordinator" do + let(:user) { create(:user, :data_coordinator) } + + it "can assign all roles except support" do + expect(user.assignable_roles).to eq({ + data_provider: 1, + data_coordinator: 2, + }) + end + end + + context "when the user is a Support user" do + let(:user) { create(:user, :support) } + + it "can assign all roles" do + expect(user.assignable_roles).to eq({ + data_provider: 1, + data_coordinator: 2, + support: 99, + }) + end + end + end + + context "and the user is in the staging role update email allowlist" do + before do + allow(Rails.application.credentials).to receive(:[]).with(:staging_role_update_email_allowlist).and_return(["example.com"]) + end + + context "when the user is a data provider" do + let(:user) { create(:user, :data_provider) } + + it "can assign all roles" do + expect(user.assignable_roles).to eq({ + data_provider: 1, + data_coordinator: 2, + support: 99, + }) + end + end + + context "when the user is a data coordinator" do + let(:user) { create(:user, :data_coordinator) } + + it "can assign all roles" do + expect(user.assignable_roles).to eq({ + data_provider: 1, + data_coordinator: 2, + support: 99, + }) + end + end + + context "when the user is a Support user" do + let(:user) { create(:user, :support) } + + it "can assign all roles" do + expect(user.assignable_roles).to eq({ + data_provider: 1, + data_coordinator: 2, + support: 99, + }) + end + end + end + end end describe "paper trail" do