active_record_api-rest 1.0.3 → 1.0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f46306ab7aa8dfd69c9d099776f1fc095c2e9188eee1ece50edc83b87543ac69
4
- data.tar.gz: 59fc5ee48bfa4341773b76b41e7f543f0aefe6973332751aaa931b49a6197fb8
3
+ metadata.gz: d6c7bfa36f4f4e1cf3a3013003dc091864a44e6a2f0df9c47886ce37b7c4a88f
4
+ data.tar.gz: 5929dfad290e2789a5acbfa574cde379c409d4de125679966c0ed5e98f230edf
5
5
  SHA512:
6
- metadata.gz: 421c5a6f00e821c52d51d1b940664e9f8498b049ab77fbec9adb955564b7053ccc804c2310d7322d3e3806f801b536c890c46baf4d23a6a07d63abefb0d8aee1
7
- data.tar.gz: 69b974c414193b3667f0e5327e0e60e12939b6024937452c2d3f7b6ed7f05582eb339828b6f3ac5d8d52eadb155ac68d6e3e573a7f70a2085b22c2790fb7d4d2
6
+ metadata.gz: a524c311c0cd8ecda10d96d82a9900b68853e108c96d59109e5493dce0052a6ee31348807a2f423a0234ce011bbf272eccf3d39ca2063e095ca585ef951033b1
7
+ data.tar.gz: b3c7af25eb3864129781d0cdc564c33a65ba14da22001601b5450a517267466fa865e1dd63b0b48d6d26b89137c61b9f227c8a06ddbfe7675ba50abe5ce9b719
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- active_record_api-rest (1.0.1)
4
+ active_record_api-rest (1.0.3)
5
5
  active_attr
6
6
  active_model_serializers
7
7
  rails (>= 5.1)
@@ -1,12 +1,13 @@
1
- # module ActiveRecordApi
2
- # module Rest
3
- # class AccessDeniedException < Exception
4
- # attr_reader :action
5
- # attr_reader :controller
6
- # def initialize(controller, action)
7
- # @action = action
8
- # @controller = controller
9
- # end
10
- # end
11
- # end
12
- # end
1
+ module ActiveRecordApi
2
+ module Rest
3
+ class AccessDeniedException < Exception
4
+ attr_reader :action
5
+ attr_reader :controller
6
+ def initialize(controller, action, message)
7
+ super(message)
8
+ @action = action
9
+ @controller = controller
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,32 +1,60 @@
1
1
  module ActiveRecordApi
2
2
  module Rest
3
3
  class ApplicationPolicy
4
+ class Scope
5
+ attr_reader :user, :scope
6
+
7
+ def initialize(user, scope)
8
+ @user = user
9
+ @scope = scope
10
+ end
11
+
12
+ def resolve
13
+ @scope.where(id: false)
14
+ end
15
+ end
16
+
4
17
  attr_reader :user
5
- attr_reader :entity
18
+ attr_reader :model_class
19
+
20
+ READ = 'read'.freeze
21
+ MANAGE = 'manage'.freeze
6
22
 
7
- def initialize(user, entity)
23
+ def initialize(user, model_class)
8
24
  @user = user
9
- @entity = entity
25
+ @model_class = model_class
10
26
  end
11
27
 
12
28
  def index?
13
- true
29
+ can?(READ)
14
30
  end
15
31
 
16
32
  def show?
17
- true
33
+ can?(READ)
18
34
  end
19
35
 
20
36
  def create?
21
- true
37
+ can?(MANAGE)
22
38
  end
23
39
 
24
40
  def update?
25
- true
41
+ can?(MANAGE)
26
42
  end
27
43
 
28
44
  def destroy?
29
- true
45
+ can?(MANAGE)
46
+ end
47
+
48
+ protected
49
+
50
+ def can?(action)
51
+ user.full_permissions.include?("#{service_name}__#{@model_class.name.downcase}:#{action}")
52
+ end
53
+
54
+ private
55
+
56
+ def service_name
57
+ File.basename(Rails.root.to_s)
30
58
  end
31
59
  end
32
60
  end
@@ -1,6 +1,12 @@
1
1
  module ActiveRecordApi
2
2
  module Rest
3
3
  class BadSessionException < Exception
4
+ attr_reader :action
5
+ attr_reader :controller
6
+ def initialize(controller, action)
7
+ @action = action
8
+ @controller = controller
9
+ end
4
10
  end
5
11
  end
6
12
  end
@@ -60,7 +60,7 @@ module ActiveRecordApi
60
60
  end
61
61
 
62
62
  def load_model
63
- @model ||= model_klass.find(params[:id])
63
+ @model ||= scope_filter(model_klass).find(params[:id])
64
64
  end
65
65
 
66
66
  def initialize_model
@@ -68,10 +68,16 @@ module ActiveRecordApi
68
68
  end
69
69
 
70
70
  def authorize
71
- user = current_user
72
- raise BadSessionException if user.nil?
73
- policy = ("#{controller_name.classify}Policy".safe_constantize) ? "#{controller_name.classify}Policy".constantize.new(user, model) : ApplicationPolicy.new(user, model)
74
- raise AccessDeniedException.new(controller_name, action_name) unless policy.send("#{action_name}?")
71
+ raise BadSessionException.new(controller_name, action_name) if current_user.nil?
72
+ raise AccessDeniedException.new(controller_name, action_name, 'Insufficient permissions') unless policy.send("#{action_name}?")
73
+ end
74
+
75
+ def scope_filter(scope)
76
+ "#{policy.class.name}::Scope".constantize.new(current_user, scope).resolve
77
+ end
78
+
79
+ def policy
80
+ @policy ||= ("#{controller_name.classify}Policy".safe_constantize) ? "#{controller_name.classify}Policy".constantize.new(current_user, model_klass) : ApplicationPolicy.new(current_user, model_klass)
75
81
  end
76
82
  end
77
83
  end
@@ -8,9 +8,13 @@ module ActiveRecordApi
8
8
  render status: :not_found, json: { base: exception.message }
9
9
  end
10
10
 
11
- # rescue_from AccessDeniedException do |exception|
12
- # render status: :forbidden, json: { base: "Access denied on #{exception.action} #{exception.controller}" }
13
- # end
11
+ rescue_from BadSessionException do |exception|
12
+ render status: :unauthorized, json: { base: "No user for session on #{exception.action} #{exception.controller}" }
13
+ end
14
+
15
+ rescue_from AccessDeniedException do |exception|
16
+ render status: :forbidden, json: { base: "Access denied on #{exception.action} #{exception.controller}", message: exception.message }
17
+ end
14
18
  end
15
19
  end
16
20
  end
@@ -36,7 +36,7 @@ module ActiveRecordApi
36
36
  end
37
37
 
38
38
  def load_models
39
- @models = model_klass.where(filtered_params)
39
+ @models = scope_filter(model_klass).where(filtered_params)
40
40
  @total = models.count
41
41
  page_models
42
42
  end
@@ -1,15 +1,14 @@
1
1
  shared_examples 'all::rest::actions' do
2
- let(:authorize_read) { mock_valid_auth(permission_name(model_klass, 'r'), model.organization_id) }
3
- let(:unauthorize_read) { mock_valid_auth(permission_name(model_klass, ''), -1) }
4
- let(:authorize_create) { mock_valid_auth(permission_name(model_klass, 'c'), model.organization_id) }
5
- let(:unauthorize_create) { mock_valid_auth(permission_name(model_klass, ''), -1) }
6
- let(:authorize_update) { mock_valid_auth(permission_name(model_klass, 'u'), model.organization_id) }
7
- let(:unauthorize_update) { mock_valid_auth(permission_name(model_klass, ''), -1) }
8
- let(:authorize_delete) { mock_valid_auth(permission_name(model_klass, 'd'), model.organization_id) }
9
- let(:unauthorize_delete) { mock_valid_auth(permission_name(model_klass, ''), -1) }
2
+ let(:authorize_read) { mock_valid_auth([permission_name(model_klass, 'read')]) }
3
+ let(:unauthorize_read) { mock_valid_auth([permission_name(model_klass, '')]) }
4
+ let(:authorize_create) { mock_valid_auth([permission_name(model_klass, 'manage')]) }
5
+ let(:unauthorize_create) { mock_valid_auth([permission_name(model_klass, '')]) }
6
+ let(:authorize_update) { mock_valid_auth([permission_name(model_klass, 'manage')]) }
7
+ let(:unauthorize_update) { mock_valid_auth([permission_name(model_klass, '')]) }
8
+ let(:authorize_delete) { mock_valid_auth([permission_name(model_klass, 'manage')]) }
9
+ let(:unauthorize_delete) { mock_valid_auth([permission_name(model_klass, '')]) }
10
10
  let(:factory_symbol) { model_klass.to_s.underscore.to_sym }
11
- let(:index_non_accessible_data) { create factory_symbol, organization_id: (model.organization_id + 1) }
12
- let(:model_array) { [model] + create_list(factory_symbol, 4, organization_id: model.organization_id) }
11
+ let(:model_array) { [model] + create_list(factory_symbol, 4) }
13
12
  let(:base_model_klass) do
14
13
  if model_klass.superclass == ApplicationRecord
15
14
  model_klass
@@ -59,14 +58,21 @@ shared_examples 'get::show' do
59
58
  it { expect(JSON.parse(response.body)['base']).to include "Couldn't find #{base_model_klass} with 'id'=-1" }
60
59
  end
61
60
  end
62
- # context 'when not authorized' do
63
- # before(:each) do
64
- # unauthorize_read
65
- # get :show, params: { id: model.to_param }
66
- # end
67
- # it { expect(response.status).to eq 403 }
68
- # it { expect(JSON.parse(response.body)['base']).to include 'Access denied on show' }
69
- # end
61
+ context 'when not authorized' do
62
+ before(:each) do
63
+ unauthorize_read
64
+ get :show, params: { id: model.to_param }
65
+ end
66
+ it { expect(response.status).to eq 403 }
67
+ it { expect(JSON.parse(response.body)['base']).to include 'Access denied on show' }
68
+ end
69
+ context 'when bad session' do
70
+ before(:each) do
71
+ get :show, params: { id: model.to_param }
72
+ end
73
+ it { expect(response.status).to eq 401 }
74
+ it { expect(JSON.parse(response.body)['base']).to include 'No user for session on show' }
75
+ end
70
76
  end
71
77
  end
72
78
 
@@ -98,27 +104,17 @@ shared_examples 'get::index' do
98
104
  it { expect(response.headers['x-link-next']).to eq "#{host}#{request.path}?limit=1&previous_id=#{next_previous_id}" }
99
105
  it { expect(response.body).to be_json_eql model_klass.where('id > ?', previous_id).limit(1).map { |o| serializer.new(o) }.to_json }
100
106
  end
101
-
102
- # context 'when only access some of the data' do
103
- # before(:each) do
104
- # index_non_accessible_data
105
- # get :index
106
- # end
107
- # it { expect(response.status).to eq 200 }
108
- # it { expect(response.headers['x-total']).to eq 1 }
109
- # it { expect(response.body).to be_json_eql [serializer.new(model)].to_json }
110
- # end
111
107
  end
112
- # context 'when not authorized' do
113
- # before(:each) do
114
- # unauthorize_read
115
- # end
116
- # before(:each) do
117
- # get :index
118
- # end
119
- # it { expect(response.status).to eq 403 }
120
- # it { expect(JSON.parse(response.body)['base']).to include 'Access denied on index' }
121
- # end
108
+ context 'when not authorized' do
109
+ before(:each) do
110
+ unauthorize_read
111
+ end
112
+ before(:each) do
113
+ get :index
114
+ end
115
+ it { expect(response.status).to eq 403 }
116
+ it { expect(JSON.parse(response.body)['base']).to include 'Access denied on index' }
117
+ end
122
118
  end
123
119
  end
124
120
 
@@ -154,14 +150,14 @@ shared_examples 'put::update' do
154
150
  it { expect(response.body).to be_json_eql({ base: 'Extra parameters are not allow: foobars' }.to_json) }
155
151
  end
156
152
  end
157
- # context 'when not authorized' do
158
- # before(:each) do
159
- # unauthorize_update
160
- # get :show, params: new_attributes
161
- # end
162
- # it { expect(response.status).to eq 403 }
163
- # it { expect(JSON.parse(response.body)['base']).to include 'Access denied on show' }
164
- # end
153
+ context 'when not authorized' do
154
+ before(:each) do
155
+ unauthorize_update
156
+ get :show, params: new_attributes
157
+ end
158
+ it { expect(response.status).to eq 403 }
159
+ it { expect(JSON.parse(response.body)['base']).to include 'Access denied on show' }
160
+ end
165
161
  end
166
162
  end
167
163
 
@@ -192,14 +188,14 @@ shared_examples 'post::create' do
192
188
  end
193
189
  end
194
190
  end
195
- # context 'when not authorized' do
196
- # before(:each) do
197
- # unauthorize_create
198
- # post :create, params: new_attributes
199
- # end
200
- # it { expect(response.status).to eq 403 }
201
- # it { expect(JSON.parse(response.body)['base']).to include 'Access denied on create' }
202
- # end
191
+ context 'when not authorized' do
192
+ before(:each) do
193
+ unauthorize_create
194
+ post :create, params: new_attributes
195
+ end
196
+ it { expect(response.status).to eq 403 }
197
+ it { expect(JSON.parse(response.body)['base']).to include 'Access denied on create' }
198
+ end
203
199
  end
204
200
  end
205
201
 
@@ -210,19 +206,19 @@ shared_examples 'delete::delete' do
210
206
  authorize_delete
211
207
  end
212
208
  it 'remove record' do
213
- expect {
214
- expect_any_instance_of(model_klass).to receive(:destroyed_bus_cleanup_message_publish) if model.respond_to? :destroyed_bus_cleanup_message_publish
215
- delete :destroy, params: { id: model.id }
216
- }.to change(model_klass, :count).by(-1)
209
+ model
210
+ before_count = model_klass.count
211
+ delete :destroy, params: { id: model.id }
212
+ expect(model_klass.count).to eq(before_count - 1)
213
+ end
214
+ end
215
+ context 'when not authorized' do
216
+ before(:each) do
217
+ unauthorize_delete
218
+ delete :destroy, params: { id: model.id }
217
219
  end
220
+ it { expect(response.status).to eq 403 }
221
+ it { expect(JSON.parse(response.body)['base']).to include 'Access denied on destroy' }
218
222
  end
219
- # context 'when not authorized' do
220
- # before(:each) do
221
- # unauthorize_delete
222
- # delete :destroy, params: { id: model.id }
223
- # end
224
- # it { expect(response.status).to eq 403 }
225
- # it { expect(JSON.parse(response.body)['base']).to include 'Access denied on destroy' }
226
- # end
227
223
  end
228
224
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ActiveRecordApi
4
4
  module Rest
5
- VERSION = '1.0.3'.freeze
5
+ VERSION = '1.0.4'.freeze
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_record_api-rest
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Full Measure Education
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-03-15 00:00:00.000000000 Z
11
+ date: 2019-03-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler