forest_liana 9.22.15 → 9.22.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/forest_liana/stripe_controller.rb +27 -1
- data/app/services/forest_liana/ability/exceptions/unsupported_conditionals.rb +17 -0
- data/app/services/forest_liana/ability/permission/smart_action_checker.rb +3 -1
- data/app/services/forest_liana/ability/permission.rb +19 -0
- data/lib/forest_liana/version.rb +1 -1
- data/spec/requests/stripe_refund_spec.rb +292 -0
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fc453faf72f6b0f7030087482ead90361fe6e3e16c4d2e7b25e2a53cbc1b5fe4
|
|
4
|
+
data.tar.gz: 6b13ab236bf05d9c5099cc8a987bd1616ecc7ba7097f077ffe3938674a428a75
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 48fac66a8b958fdf847c8861992d38f1a61efd8ff9df7da04d1254c5470246b684f0f584fd3881c80aff673f69284b115f0d44852f5eb97c62ba438c3f43dad2
|
|
7
|
+
data.tar.gz: fae68b2cf78f032cfef3a5609f9309631b69e0784b579cfc3dbe772b298c3202d5bd29a74d92796ee5610fa9b57443f80eb9bce2f8c910433a15ec67bdce2106
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
module ForestLiana
|
|
2
2
|
class StripeController < ForestLiana::ApplicationController
|
|
3
|
+
include ForestLiana::Ability
|
|
4
|
+
|
|
5
|
+
rescue_from ForestLiana::Ability::Exceptions::TriggerForbidden, with: :render_error
|
|
6
|
+
rescue_from ForestLiana::Ability::Exceptions::RequireApproval, with: :render_error
|
|
7
|
+
rescue_from ForestLiana::Ability::Exceptions::UnsupportedConditionals, with: :render_error
|
|
8
|
+
|
|
9
|
+
before_action :authorize_refund, only: :refund
|
|
3
10
|
|
|
4
11
|
def payments
|
|
5
12
|
getter = StripePaymentsGetter.new(params, request.headers['Stripe-Secret-Key'],
|
|
@@ -27,7 +34,7 @@ module ForestLiana
|
|
|
27
34
|
|
|
28
35
|
def refund
|
|
29
36
|
begin
|
|
30
|
-
refunder = StripePaymentRefunder.new(
|
|
37
|
+
refunder = StripePaymentRefunder.new(@refund_parameters)
|
|
31
38
|
refunder.perform
|
|
32
39
|
|
|
33
40
|
render serializer: nil, json: {}
|
|
@@ -137,5 +144,24 @@ module ForestLiana
|
|
|
137
144
|
def get_serializer_type(suffix)
|
|
138
145
|
"#{params[:collection]}_#{suffix}"
|
|
139
146
|
end
|
|
147
|
+
|
|
148
|
+
private
|
|
149
|
+
|
|
150
|
+
def authorize_refund
|
|
151
|
+
raise ForestLiana::Errors::HTTP422Error.new if params.dig(:data, :attributes, :requester_id).present?
|
|
152
|
+
|
|
153
|
+
parameters = refund_request_parameters
|
|
154
|
+
collection_name = parameters.dig(:data, :attributes, :collection_name).to_s
|
|
155
|
+
is_integration_action_authorized?(forest_user, collection_name, 'Refund', params)
|
|
156
|
+
@refund_parameters = parameters
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def refund_request_parameters
|
|
160
|
+
return params.permit! unless params.dig(:data, :attributes, :signed_approval_request)
|
|
161
|
+
|
|
162
|
+
ForestLiana::Ability::Permission::RequestPermission.decodeSignedApprovalRequest(params.permit!)
|
|
163
|
+
rescue JWT::DecodeError
|
|
164
|
+
raise ForestLiana::Errors::HTTP400Error.new('Invalid signed action parameters')
|
|
165
|
+
end
|
|
140
166
|
end
|
|
141
167
|
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module ForestLiana
|
|
2
|
+
module Ability
|
|
3
|
+
module Exceptions
|
|
4
|
+
class UnsupportedConditionals < ForestLiana::Errors::ExpectedError
|
|
5
|
+
def initialize(backtrace = nil)
|
|
6
|
+
super(
|
|
7
|
+
422,
|
|
8
|
+
:unprocessable_entity,
|
|
9
|
+
'The roles conditions (conditional smart actions) are not supported with Smart Collection. Please contact an administrator.',
|
|
10
|
+
'UnsupportedConditionalsFeatureError',
|
|
11
|
+
backtrace
|
|
12
|
+
)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -43,7 +43,7 @@ module ForestLiana
|
|
|
43
43
|
elsif @smart_action['approvalRequired'].include?(@user['roleId'])
|
|
44
44
|
if condition_by_role_id(@smart_action['approvalRequiredConditions']).blank? || match_conditions('approvalRequiredConditions')
|
|
45
45
|
# Global actions target no specific records — never resolve.
|
|
46
|
-
if @parameters[:data][:attributes][:all_records] && @action_type != 'global'
|
|
46
|
+
if @parameters[:data][:attributes][:all_records] && @action_type != 'global' && @collection
|
|
47
47
|
record_ids = select_all_record_ids
|
|
48
48
|
end
|
|
49
49
|
|
|
@@ -83,6 +83,8 @@ module ForestLiana
|
|
|
83
83
|
end
|
|
84
84
|
|
|
85
85
|
def match_conditions(condition_name)
|
|
86
|
+
raise ForestLiana::Ability::Exceptions::UnsupportedConditionals.new unless @collection
|
|
87
|
+
|
|
86
88
|
begin
|
|
87
89
|
attributes = @parameters[:data][:attributes]
|
|
88
90
|
condition = condition_by_role_id(@smart_action[condition_name])
|
|
@@ -53,6 +53,19 @@ module ForestLiana
|
|
|
53
53
|
end
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
+
# An integration collection (`<Model>_stripe_payments`, …) has no model: a select-all is not
|
|
57
|
+
# resolved for its approval, and a role condition on its action is refused as unsupported.
|
|
58
|
+
def is_integration_action_authorized?(user, collection_name, action_name, parameters)
|
|
59
|
+
return true unless has_permission_system?
|
|
60
|
+
|
|
61
|
+
schema_action = find_integration_action(collection_name, action_name)
|
|
62
|
+
user_data = get_user_data(user['id'])
|
|
63
|
+
smart_action = schema_action && get_collections_permissions_data.dig(collection_name, :actions, action_name)
|
|
64
|
+
raise ForestLiana::Ability::Exceptions::TriggerForbidden.new unless user_data && smart_action
|
|
65
|
+
|
|
66
|
+
SmartActionChecker.new(parameters, nil, smart_action, user_data, schema_action.type, user).can_execute?
|
|
67
|
+
end
|
|
68
|
+
|
|
56
69
|
# +refetch+ drops the cached permissions first. Only a caller about to refuse on a denial asks
|
|
57
70
|
# for it (a stale, up to TTL-old cache may sit behind a permission granted moments ago): the
|
|
58
71
|
# refetch rewrites the cluster-wide `forest.collections` entry and this request's copy, so a
|
|
@@ -367,6 +380,12 @@ module ForestLiana
|
|
|
367
380
|
nil
|
|
368
381
|
end
|
|
369
382
|
|
|
383
|
+
def find_integration_action(collection_name, action_name)
|
|
384
|
+
collection = ForestLiana.apimap.find { |candidate| candidate.name.to_s == collection_name && candidate.integration.present? }
|
|
385
|
+
|
|
386
|
+
collection&.actions&.find { |action| action.name == action_name }
|
|
387
|
+
end
|
|
388
|
+
|
|
370
389
|
def find_action_from_endpoint(collection_name, endpoint, http_method)
|
|
371
390
|
collection = ForestLiana.apimap.find { |collection| collection.name.to_s == collection_name }
|
|
372
391
|
|
data/lib/forest_liana/version.rb
CHANGED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
require 'rails_helper'
|
|
2
|
+
|
|
3
|
+
describe 'Stripe payments refund', type: :request do
|
|
4
|
+
let(:rendering_id) { 13 }
|
|
5
|
+
let(:user_id) { 38 }
|
|
6
|
+
let(:role_id) { 1 }
|
|
7
|
+
let(:approver_role_id) { 3 }
|
|
8
|
+
let(:trigger_roles) { [role_id] }
|
|
9
|
+
let(:approval_roles) { [] }
|
|
10
|
+
let(:user_approval_roles) { [] }
|
|
11
|
+
let(:trigger_conditions) { [] }
|
|
12
|
+
let(:permissions_users) { [{ 'id' => user_id, 'roleId' => role_id }] }
|
|
13
|
+
let(:has_permission_system) { true }
|
|
14
|
+
let(:cache) { ActiveSupport::Cache::MemoryStore.new }
|
|
15
|
+
let(:refunder) { instance_double(ForestLiana::StripePaymentRefunder, perform: nil) }
|
|
16
|
+
let(:refund_requests) { [] }
|
|
17
|
+
let(:payments_collection) do
|
|
18
|
+
ForestLiana::Model::Collection.new(
|
|
19
|
+
name: 'Island_stripe_payments',
|
|
20
|
+
integration: 'stripe',
|
|
21
|
+
is_virtual: true,
|
|
22
|
+
actions: [ForestLiana::Model::Action.new(name: 'Refund', endpoint: '/forest/stripe_payments/refunds')]
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
let(:token) do
|
|
27
|
+
JWT.encode({
|
|
28
|
+
id: user_id,
|
|
29
|
+
email: 'michael.kelso@that70.show',
|
|
30
|
+
first_name: 'Michael',
|
|
31
|
+
last_name: 'Kelso',
|
|
32
|
+
team: 'Operations',
|
|
33
|
+
rendering_id: rendering_id,
|
|
34
|
+
exp: Time.now.to_i + 2.weeks.to_i,
|
|
35
|
+
permission_level: 'user'
|
|
36
|
+
}, ForestLiana.auth_secret, 'HS256')
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
let(:headers) do
|
|
40
|
+
{
|
|
41
|
+
'Accept' => 'application/json',
|
|
42
|
+
'Content-Type' => 'application/json',
|
|
43
|
+
'Authorization' => "Bearer #{token}"
|
|
44
|
+
}
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
let(:attributes) do
|
|
48
|
+
{
|
|
49
|
+
collection_name: 'Island_stripe_payments',
|
|
50
|
+
ids: ['ch_1', 'ch_2'],
|
|
51
|
+
values: {},
|
|
52
|
+
all_records: false,
|
|
53
|
+
smart_action_id: 'Island_stripe_payments-Refund'
|
|
54
|
+
}
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
let(:params) { { data: { attributes: attributes, type: 'custom-action-requests' }, timezone: 'Europe/Paris' } }
|
|
58
|
+
|
|
59
|
+
def environment_permissions
|
|
60
|
+
enabled = { 'roles' => [role_id, approver_role_id] }
|
|
61
|
+
crud = %w[browseEnabled readEnabled editEnabled addEnabled deleteEnabled exportEnabled].to_h { |key| [key, enabled] }
|
|
62
|
+
refund = {
|
|
63
|
+
'triggerEnabled' => { 'roles' => trigger_roles },
|
|
64
|
+
'triggerConditions' => trigger_conditions,
|
|
65
|
+
'approvalRequired' => { 'roles' => approval_roles },
|
|
66
|
+
'approvalRequiredConditions' => [],
|
|
67
|
+
'userApprovalEnabled' => { 'roles' => user_approval_roles },
|
|
68
|
+
'userApprovalConditions' => [],
|
|
69
|
+
'selfApprovalEnabled' => { 'roles' => [] }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
{ 'collections' => { 'Island_stripe_payments' => { 'collection' => crud, 'actions' => { 'Refund' => refund } } } }
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def signed_approval_request(ids:, requester_id:)
|
|
76
|
+
JWT.encode({
|
|
77
|
+
data: {
|
|
78
|
+
attributes: attributes.merge(ids: ids, requester_id: requester_id),
|
|
79
|
+
type: 'custom-action-requests'
|
|
80
|
+
}
|
|
81
|
+
}, ForestLiana.env_secret, 'HS256')
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def refund(request_headers = headers)
|
|
85
|
+
post '/forest/stripe_payments/refunds', params: JSON.dump(params), headers: request_headers
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def refunded_ids
|
|
89
|
+
refund_requests.map { |refund_params| refund_params[:data][:attributes][:ids] }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
before do
|
|
93
|
+
ForestLiana.apimap << payments_collection
|
|
94
|
+
|
|
95
|
+
allow(Rails).to receive(:cache).and_return(cache)
|
|
96
|
+
allow_any_instance_of(ForestLiana::Ability::Fetch).to receive(:get_permissions) do |_, path|
|
|
97
|
+
case path
|
|
98
|
+
when '/liana/v4/permissions/environment' then has_permission_system ? environment_permissions : true
|
|
99
|
+
when '/liana/v4/permissions/users' then permissions_users
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
allow(ForestLiana::StripePaymentRefunder).to receive(:new) do |refund_params|
|
|
104
|
+
refund_requests << refund_params
|
|
105
|
+
refunder
|
|
106
|
+
end
|
|
107
|
+
allow(ForestLiana::IpWhitelist).to receive(:is_ip_whitelist_retrieved) { true }
|
|
108
|
+
allow(ForestLiana::IpWhitelist).to receive(:is_ip_valid) { true }
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
after { ForestLiana.apimap.delete(payments_collection) }
|
|
112
|
+
|
|
113
|
+
context 'when the role is allowed to trigger the Refund action' do
|
|
114
|
+
it 'responds 200 and refunds each requested charge' do
|
|
115
|
+
refund
|
|
116
|
+
|
|
117
|
+
expect(response.status).to eq(200)
|
|
118
|
+
expect(refunded_ids).to eq([['ch_1', 'ch_2']])
|
|
119
|
+
expect(refunder).to have_received(:perform).with(no_args)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
context 'when the project has no permission system' do
|
|
124
|
+
let(:has_permission_system) { false }
|
|
125
|
+
let(:trigger_roles) { [] }
|
|
126
|
+
|
|
127
|
+
it 'responds 200 and refunds each requested charge' do
|
|
128
|
+
refund
|
|
129
|
+
|
|
130
|
+
expect(response.status).to eq(200)
|
|
131
|
+
expect(refunded_ids).to eq([['ch_1', 'ch_2']])
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
context 'when the role is not allowed to trigger the Refund action' do
|
|
136
|
+
let(:trigger_roles) { [approver_role_id] }
|
|
137
|
+
|
|
138
|
+
it 'responds 403 and refunds nothing' do
|
|
139
|
+
refund
|
|
140
|
+
|
|
141
|
+
expect(response.status).to eq(403)
|
|
142
|
+
expect(JSON.parse(response.body)['errors'].first['name']).to eq('CustomActionTriggerForbiddenError')
|
|
143
|
+
expect(ForestLiana::StripePaymentRefunder).not_to have_received(:new)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
context 'when the user is no longer in the permissions system' do
|
|
148
|
+
let(:permissions_users) { [] }
|
|
149
|
+
|
|
150
|
+
it 'responds 403 and refunds nothing' do
|
|
151
|
+
refund
|
|
152
|
+
|
|
153
|
+
expect(response.status).to eq(403)
|
|
154
|
+
expect(ForestLiana::StripePaymentRefunder).not_to have_received(:new)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
context 'when the Refund action requires approval for the role' do
|
|
159
|
+
let(:approval_roles) { [role_id] }
|
|
160
|
+
let(:user_approval_roles) { [approver_role_id] }
|
|
161
|
+
|
|
162
|
+
it 'responds 403 with the roles allowed to approve and refunds nothing' do
|
|
163
|
+
refund
|
|
164
|
+
|
|
165
|
+
expect(response.status).to eq(403)
|
|
166
|
+
error = JSON.parse(response.body)['errors'].first
|
|
167
|
+
expect(error['name']).to eq('CustomActionRequiresApprovalError')
|
|
168
|
+
expect(error['data']).to eq('roleIdsAllowedToApprove' => [approver_role_id])
|
|
169
|
+
expect(ForestLiana::StripePaymentRefunder).not_to have_received(:new)
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
context 'when an approver sends a signed approval request' do
|
|
174
|
+
let(:role_id) { approver_role_id }
|
|
175
|
+
let(:trigger_roles) { [] }
|
|
176
|
+
let(:user_approval_roles) { [approver_role_id] }
|
|
177
|
+
let(:attributes) do
|
|
178
|
+
super().merge(ids: ['ch_99'], signed_approval_request: signed_approval_request(ids: ['ch_1'], requester_id: 12))
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
it 'responds 200 and refunds the charges of the approved request' do
|
|
182
|
+
refund
|
|
183
|
+
|
|
184
|
+
expect(response.status).to eq(200)
|
|
185
|
+
expect(refunded_ids).to eq([['ch_1']])
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
context 'when the approval request is not signed with the environment secret' do
|
|
190
|
+
let(:role_id) { approver_role_id }
|
|
191
|
+
let(:trigger_roles) { [] }
|
|
192
|
+
let(:user_approval_roles) { [approver_role_id] }
|
|
193
|
+
let(:attributes) do
|
|
194
|
+
forged = JWT.encode({ data: { attributes: { collection_name: 'Island_stripe_payments', ids: ['ch_1'], requester_id: 12 } } }, 'another-secret', 'HS256')
|
|
195
|
+
super().merge(signed_approval_request: forged)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
it 'responds 400 and refunds nothing' do
|
|
199
|
+
refund
|
|
200
|
+
|
|
201
|
+
expect(response.status).to eq(400)
|
|
202
|
+
expect(JSON.parse(response.body)['errors'].first['detail']).to eq('Invalid signed action parameters')
|
|
203
|
+
expect(ForestLiana::StripePaymentRefunder).not_to have_received(:new)
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
context 'when the body carries a requester id outside a signed approval request' do
|
|
208
|
+
let(:attributes) { super().merge(requester_id: 12) }
|
|
209
|
+
|
|
210
|
+
it 'responds 422 and refunds nothing, even for a role allowed to trigger the Refund action' do
|
|
211
|
+
refund
|
|
212
|
+
|
|
213
|
+
expect(response.status).to eq(422)
|
|
214
|
+
expect(ForestLiana::StripePaymentRefunder).not_to have_received(:new)
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
context 'when the role can trigger the Refund action only under a condition' do
|
|
219
|
+
let(:trigger_conditions) do
|
|
220
|
+
[{ 'roleId' => role_id, 'filter' => { 'field' => 'amount', 'operator' => 'greater_than', 'value' => 0, 'source' => 'data' } }]
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
it 'responds 422 and refunds nothing, since role conditions are not supported on Stripe payments' do
|
|
224
|
+
refund
|
|
225
|
+
|
|
226
|
+
expect(response.status).to eq(422)
|
|
227
|
+
expect(JSON.parse(response.body)['errors'].first['name']).to eq('UnsupportedConditionalsFeatureError')
|
|
228
|
+
expect(ForestLiana::StripePaymentRefunder).not_to have_received(:new)
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
context 'when a role needing approval selects every payment' do
|
|
233
|
+
let(:approval_roles) { [role_id] }
|
|
234
|
+
let(:user_approval_roles) { [approver_role_id] }
|
|
235
|
+
let(:attributes) { super().merge(all_records: true, all_records_ids_excluded: []) }
|
|
236
|
+
|
|
237
|
+
it 'responds 403 with the roles allowed to approve and refunds nothing' do
|
|
238
|
+
refund
|
|
239
|
+
|
|
240
|
+
expect(response.status).to eq(403)
|
|
241
|
+
error = JSON.parse(response.body)['errors'].first
|
|
242
|
+
expect(error['name']).to eq('CustomActionRequiresApprovalError')
|
|
243
|
+
expect(error['data']).to eq('roleIdsAllowedToApprove' => [approver_role_id])
|
|
244
|
+
expect(ForestLiana::StripePaymentRefunder).not_to have_received(:new)
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
context 'when the request names a collection without the Stripe Refund action' do
|
|
249
|
+
let(:attributes) { super().merge(collection_name: 'Island') }
|
|
250
|
+
|
|
251
|
+
it 'responds 403 and refunds nothing' do
|
|
252
|
+
refund
|
|
253
|
+
|
|
254
|
+
expect(response.status).to eq(403)
|
|
255
|
+
expect(JSON.parse(response.body)['errors'].first['name']).to eq('CustomActionTriggerForbiddenError')
|
|
256
|
+
expect(ForestLiana::StripePaymentRefunder).not_to have_received(:new)
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
context 'when the request names no collection' do
|
|
261
|
+
let(:attributes) { super().except(:collection_name) }
|
|
262
|
+
|
|
263
|
+
it 'responds 403 and refunds nothing' do
|
|
264
|
+
refund
|
|
265
|
+
|
|
266
|
+
expect(response.status).to eq(403)
|
|
267
|
+
expect(JSON.parse(response.body)['errors'].first['name']).to eq('CustomActionTriggerForbiddenError')
|
|
268
|
+
expect(ForestLiana::StripePaymentRefunder).not_to have_received(:new)
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
context 'when the project has no permission system and the request names no collection' do
|
|
273
|
+
let(:has_permission_system) { false }
|
|
274
|
+
let(:attributes) { super().except(:collection_name) }
|
|
275
|
+
|
|
276
|
+
it 'responds 200 and refunds each requested charge' do
|
|
277
|
+
refund
|
|
278
|
+
|
|
279
|
+
expect(response.status).to eq(200)
|
|
280
|
+
expect(refunded_ids).to eq([['ch_1', 'ch_2']])
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
context 'when the request is not authenticated' do
|
|
285
|
+
it 'responds 401 and refunds nothing' do
|
|
286
|
+
refund(headers.except('Authorization'))
|
|
287
|
+
|
|
288
|
+
expect(response.status).to eq(401)
|
|
289
|
+
expect(ForestLiana::StripePaymentRefunder).not_to have_received(:new)
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: forest_liana
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 9.22.
|
|
4
|
+
version: 9.22.16
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sandro Munda
|
|
@@ -286,6 +286,7 @@ files:
|
|
|
286
286
|
- app/services/forest_liana/ability/exceptions/unauthorized_query_field_error.rb
|
|
287
287
|
- app/services/forest_liana/ability/exceptions/unexposed_query_collection_error.rb
|
|
288
288
|
- app/services/forest_liana/ability/exceptions/unknown_collection.rb
|
|
289
|
+
- app/services/forest_liana/ability/exceptions/unsupported_conditionals.rb
|
|
289
290
|
- app/services/forest_liana/ability/fetch.rb
|
|
290
291
|
- app/services/forest_liana/ability/permission.rb
|
|
291
292
|
- app/services/forest_liana/ability/permission/request_permission.rb
|
|
@@ -498,6 +499,7 @@ files:
|
|
|
498
499
|
- spec/requests/smart_field_named_like_unexposed_relation_spec.rb
|
|
499
500
|
- spec/requests/stats_spec.rb
|
|
500
501
|
- spec/requests/sti_record_conversion_spec.rb
|
|
502
|
+
- spec/requests/stripe_refund_spec.rb
|
|
501
503
|
- spec/requests/test.ru
|
|
502
504
|
- spec/requests/unresolved_polymorphic_relation_spec.rb
|
|
503
505
|
- spec/requests/workflow_executions_spec.rb
|
|
@@ -863,6 +865,7 @@ test_files:
|
|
|
863
865
|
- spec/requests/smart_field_named_like_unexposed_relation_spec.rb
|
|
864
866
|
- spec/requests/stats_spec.rb
|
|
865
867
|
- spec/requests/sti_record_conversion_spec.rb
|
|
868
|
+
- spec/requests/stripe_refund_spec.rb
|
|
866
869
|
- spec/requests/test.ru
|
|
867
870
|
- spec/requests/unresolved_polymorphic_relation_spec.rb
|
|
868
871
|
- spec/requests/workflow_executions_spec.rb
|