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

admin api fix audit whodunnit #1629

Merged
merged 1 commit into from
Nov 25, 2024
Merged
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
6 changes: 6 additions & 0 deletions app/controllers/api/rest/admin/base_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ class Api::Rest::Admin::BaseController < Api::RestController
include JSONAPI::ActsAsResourceController
include AdminApiAuthorizable

before_action :set_paper_trail_whodunnit # must be after `include AdminApiAuthorizable`

def user_for_paper_trail
current_admin_user&.id || 'Unknown user'
end

def handle_exceptions(e)
capture_error(e) unless e.is_a?(JSONAPI::Exceptions::Error)
super
Expand Down
50 changes: 34 additions & 16 deletions spec/controllers/api/rest/admin/accounts_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,31 @@
end

describe 'POST create' do
before do
subject do
post :create, params: request_payload
end

shared_examples :creates_account do
it 'creates account' do
expect { subject }.to change { Account.count }.by(1)
.and change { AccountBalanceNotificationSetting.count }.by(1)
end

include_examples :creates_audit_log, qty: 1, ordered: true do
let(:audit_log_attrs) do
item = Account.last
{ event: 'create', item_id: item.id, item_type: item.class.name, whodunnit: admin_user.id.to_s }
end
end
end

shared_examples :does_not_create_account do
it 'creates account' do
expect { subject }.not_to change { [Account.count, AccountBalanceNotificationSetting.count] }
end
end

let!(:contractor) { create(:contractor, vendor: true) }
let(:request_payload) do
{
data: {
Expand Down Expand Up @@ -115,23 +136,21 @@
let(:relationships) do
{
timezone: wrap_relationship(:timezones, 1),
contractor: wrap_relationship(:contractors, create(:contractor, vendor: true).id)
contractor: wrap_relationship(:contractors, contractor.id)
}
end

context 'when attributes and relationships are valid' do
it { expect(response.status).to eq(201) }
it { expect(Account.count).to eq(1) }
it { expect(AccountBalanceNotificationSetting.count).to eq(1) }
include_examples :responds_with_status, 201
include_examples :creates_account
end

context 'when attributes and relationships are invalid' do
let(:attributes) { { name: 'name', 'max-balance': -1 } }
let(:relationships) { {} }

it { expect(response.status).to eq(422) }
it { expect(Account.count).to eq(0) }
it { expect(AccountBalanceNotificationSetting.count).to eq(0) }
include_examples :responds_with_status, 422
include_examples :does_not_create_account
end

context 'when only required attributes and relationships' do
Expand All @@ -142,13 +161,12 @@
end
let(:relationships) do
{
contractor: wrap_relationship(:contractors, create(:contractor, vendor: true).id)
contractor: wrap_relationship(:contractors, contractor.id)
}
end

it { expect(response.status).to eq(201) }
it { expect(Account.count).to eq(1) }
it { expect(AccountBalanceNotificationSetting.count).to eq(1) }
include_examples :responds_with_status, 201
include_examples :creates_account
end

context 'with attributes balance-low-threshold = balance-high-threshold' do
Expand All @@ -157,8 +175,8 @@
'balance-high-threshold': 90
end

it { expect(response.status).to eq(422) }
it { expect(Account.count).to eq(0) }
include_examples :responds_with_status, 422
include_examples :does_not_create_account
end

context 'with attributes balance-low-threshold > balance-high-threshold' do
Expand All @@ -167,8 +185,8 @@
'balance-high-threshold': 90
end

it { expect(response.status).to eq(422) }
it { expect(Account.count).to eq(0) }
include_examples :responds_with_status, 422
include_examples :does_not_create_account
end
end

Expand Down
5 changes: 2 additions & 3 deletions spec/controllers/api/rest/admin/balance_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,8 @@
it 'should change balance' do
expect { subject }.to change { account.reload.balance }.from(balance).to(attributes[:balance])
end
it 'should skip audit log' do
expect { subject }.not_to change { AuditLogItem.count }
end

include_examples :does_not_create_audit_log

context 'response' do
before { subject }
Expand Down
36 changes: 36 additions & 0 deletions spec/support/examples/audit_logs/creates_audit_log.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# frozen_string_literal: true

# @example usage:
# include_examples :creates_audit_log do
# let(:audit_log_attrs) do
# item = Account.last
# { event: 'create', item_id: item.id, item_type: item.class.name, whodunnit: admin_user.id.to_s }
# end
# end
# # when several items are created at once
# include_examples :creates_audit_log, qty: 2 do
# let(:audit_log_attrs) do
# [Account.last, CustomersAuth.last].map do |item|
# { event: 'create', item_id: item.id, item_type: item.class.name, whodunnit: admin_user.id.to_s }
# end
# end
# end
RSpec.shared_examples :creates_audit_log do |qty: 1, ordered: false|
# Note: we didn't calculate qty by audit_log_attrs, because we want it to be called only after subject,
# so we could use subject result in audit_log_attrs.

it 'creates audit log', :aggregate_failures do
expect { subject }.to change { AuditLogItem.count }.by(qty)
logs = AuditLogItem.last(qty)
actual_attrs_list = logs.map { |log| log.attributes.symbolize_keys }
expected_attrs_list = Array.wrap(audit_log_attrs).map { |attrs| hash_including(attrs) }

if ordered
expected_attrs_list.each_with_index do |expected_attrs, index|
expect(actual_attrs_list[index]).to match(expected_attrs)
end
else
expect(actual_attrs_list).to match_array(expected_attrs_list)
end
end
end
9 changes: 9 additions & 0 deletions spec/support/examples/audit_logs/does_not_create_audit_log.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

# @example usage:
# include_examples :does_not_create_audit_log
RSpec.shared_examples :does_not_create_audit_log do
it 'dos not create audit log' do
expect { subject }.not_to change { AuditLogItem.count }
end
end
Loading