kant 0.0.3 → 0.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
  SHA1:
3
- metadata.gz: d0b65ae77365d3fb81725cb1dad2634d25b51640
4
- data.tar.gz: dac368c947e0ab658ce42dbc0570214d218dbec5
3
+ metadata.gz: 4405afa9ea78fb2fcee60f09c4f31521626ae1b1
4
+ data.tar.gz: b337033ed3ecc3119602b260a0c9aff1c14013ed
5
5
  SHA512:
6
- metadata.gz: 4a6684cc5fbbe9d9a90a8b14aa7c32b75dfc112eac379630c383646679f9cf0588e932057ad0eb585a2ea6ec7108287342cf73ca458aacad83cc8d82d3338628
7
- data.tar.gz: bd2b8391077f3f7ec7b13b03375bf6e4310fe9f57ff3dc957a9be82785cfc2f786a575f35f216eefc0c27a61a3372496d9d2dfa728b063ed911cff30e8362caa
6
+ metadata.gz: 6fed5522437eab76c2d21f814ebbeeaa472acdc11605ae95ab109e756a3d31d1f52330d63577d0baa6506ca3b08a8da853458a39d9e20d555c1fe6ef2e850b31
7
+ data.tar.gz: 1440cbd44f47d426e31832e65eaa21a7cbf439042ea17328808273b9a5bc97fed20a46b4a6e9425195541ec1e0c549a3173ed2c52c5293f2e2484ccf4b05a4b8
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Kant v0.0.3
1
+ # Kant v0.0.4
2
2
 
3
3
  Kant is a tiny authorization library for your Ruby (especially Rails and/or
4
4
  ActiveRecord) projects.
@@ -37,12 +37,12 @@ module Kant
37
37
  #
38
38
  # ability.accessible(:read, Content)
39
39
  # # => a Content scope
40
- def accessible(action, scope)
40
+ def accessible(action, scope, *rest)
41
41
  abilities = resolve_scope(scope)
42
42
  _scope_method = scope_method(abilities, action)
43
43
 
44
44
  if _scope_method
45
- abilities.send(_scope_method, scope, user)
45
+ abilities.send(_scope_method, scope, user, *rest)
46
46
  else
47
47
  scope.none
48
48
  end
data/lib/kant/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Kant
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -1,5 +1,6 @@
1
1
  require 'spec_helper'
2
2
  require 'kant/policy_access'
3
+ require 'kant/access_denied'
3
4
 
4
5
  describe Kant::PolicyAccess do
5
6
  setup_models
@@ -99,6 +100,7 @@ describe Kant::PolicyAccess do
99
100
 
100
101
  describe "#accessible" do
101
102
  let(:user) { User.create!(email: 'foo@bar.com') }
103
+ let(:another_user) { User.create!(email: 'foo@baz.com') }
102
104
  subject(:policy_access) { Kant::PolicyAccess.new(user) }
103
105
 
104
106
  it "delegates to a Policy module" do
@@ -130,6 +132,94 @@ describe Kant::PolicyAccess do
130
132
 
131
133
  expect(policy_access.accessible(:read, Todo)).to eq(Todo.none)
132
134
  end
135
+
136
+ # The motivation here is that, when performing authorization for "index"
137
+ # actions, this often involves some context. For example, the user might be
138
+ # listing all the todos under a particular project (GET /projects/1/todos).
139
+ # In a lot of cases it might be possible to define an ActiveRecord or SQL
140
+ # query that describes what records the user can access regardless of
141
+ # context, but in some cases this might result in a very complicated query.
142
+ # (Unfortunately, the example below really doesn't really do the motivation
143
+ # justice.)
144
+ #
145
+ # Imagine instead that a user can normally only access their own User
146
+ # record (the check being `user == me`). However, when the user is part of
147
+ # a project they can also see other users in the company that the project
148
+ # is a part of. (For example, so that they can send a DM to a user.)
149
+ #
150
+ # - Company
151
+ # - has many Projects
152
+ # - has many Users
153
+ #
154
+ # Imagine what the query would look like to return all the users I can
155
+ # message...
156
+ #
157
+ # def self.readable_for_messaging(users, me)
158
+ # my_companies = Company.joins(:projects).merge(me.projects)
159
+ # my_companies_projects = Project.joins(:company).merge(my_companies)
160
+ # my_companies_users = User.joins(:projects).merge(my_companies_projects)
161
+ # users.merge(my_companies_users)
162
+ # end
163
+ #
164
+ # Some notes here:
165
+ #
166
+ # 1. This honestly isn't such a gross example, in production this logic can
167
+ # get much, much worse.
168
+ # 2. Even so, you can see it gets pretty complicated.
169
+ # 3. In practice what we have to do after all this is query the resulting
170
+ # scope for users in a particular company... which means more gross queries.
171
+ #
172
+ # Instead, by having extra params in the *able function, we can specify a
173
+ # context (typically this will probably match the shape of the endpoint, so
174
+ # if your endpoint is /companies/1/users then your *able function will
175
+ # probably take an extra `companies:` param).
176
+ #
177
+ # def self.readable_for_messaging(users, me, company:)
178
+ # my_companies = Company.joins(:projects).merge(me.projects)
179
+ # if !my_companies.where(id: company.id).any?
180
+ # fail Kant::AccessDenied, "no access"
181
+ # end
182
+ #
183
+ # users.joins(:projects).where(projects: { company_id: company.id })
184
+ # end
185
+ it "passes along other params to the *able method" do
186
+ # module TodoPolicy
187
+ # def self.readable_as_owner(todos, user, project:)
188
+ # if project.owner_id == user.id
189
+ # todos.where(project_id: project_id, completed: true)
190
+ # else
191
+ # fail Kant::AccessDenied, "user does not have access to this project"
192
+ # end
193
+ # end
194
+ # end
195
+ todo_policy = Class.new do
196
+ define_singleton_method(:readable_as_owner) do |todos, user, project:|
197
+ if project.owner_id == user.id
198
+ todos.where(project_id: project.id, completed: true)
199
+ else
200
+ fail Kant::AccessDenied, "user does not have access to this project"
201
+ end
202
+ end
203
+ end
204
+
205
+ stub_const("TodoPolicy", todo_policy)
206
+
207
+ my_project = Project.create!(owner: user)
208
+ another_project = Project.create!(owner: another_user)
209
+ my_complete_todo = Todo.create!(project: my_project, completed: true)
210
+ my_incomplete_todo = Todo.create!(project: my_project, completed: false)
211
+ another_complete_todo = Todo.create!(project: another_project, completed: true)
212
+
213
+ expect{
214
+ policy_access.accessible(:read_as_owner, Todo)
215
+ }.to raise_error(ArgumentError)
216
+
217
+ expect(policy_access.accessible(:read_as_owner, Todo, project: my_project)).to eq([my_complete_todo])
218
+
219
+ expect{
220
+ policy_access.accessible(:read_as_owner, Todo, project: another_project)
221
+ }.to raise_error(Kant::AccessDenied)
222
+ end
133
223
  end
134
224
 
135
225
  describe "the policies_module option in initializer" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark Przepiora
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-07 00:00:00.000000000 Z
11
+ date: 2018-05-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler