grabli 0.1.0
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 +7 -0
- data/.gitignore +9 -0
- data/.rspec +3 -0
- data/.travis.yml +5 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +50 -0
- data/LICENSE.txt +13 -0
- data/README.md +73 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/grabli.gemspec +23 -0
- data/lib/grabli.rb +71 -0
- data/lib/grabli/version.rb +3 -0
- metadata +112 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 22817abd7cf1fcd173e9c6d804fd9ce27df4c6b5ef3df83678e65c4d1a43c911
|
4
|
+
data.tar.gz: f59006fd5d79f420043a94bbf98fe9103802ac42f39bcc10543ac2310fff2af6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dc895810cd249c7646d188e73da2c2715356077bbe43eb5051a9bd12caef9b5b5a3fc458ee2f29d761dc5f82ba2d1854281d9e17582b3feb63cf208ed16af5db
|
7
|
+
data.tar.gz: ca971071066b83c562e2721c6eadc294f94fda1ae429842b6ce1e2fe4246753cae63fd9986023f32b80ec600e80e8118a245c3b0075a5d59eeb7afe6769d785c
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
grabli (0.1.0)
|
5
|
+
pundit (> 0)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
activesupport (5.1.5)
|
11
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
12
|
+
i18n (~> 0.7)
|
13
|
+
minitest (~> 5.1)
|
14
|
+
tzinfo (~> 1.1)
|
15
|
+
concurrent-ruby (1.0.5)
|
16
|
+
diff-lcs (1.3)
|
17
|
+
i18n (0.9.5)
|
18
|
+
concurrent-ruby (~> 1.0)
|
19
|
+
minitest (5.11.3)
|
20
|
+
pundit (1.1.0)
|
21
|
+
activesupport (>= 3.0.0)
|
22
|
+
rake (10.5.0)
|
23
|
+
rspec (3.7.0)
|
24
|
+
rspec-core (~> 3.7.0)
|
25
|
+
rspec-expectations (~> 3.7.0)
|
26
|
+
rspec-mocks (~> 3.7.0)
|
27
|
+
rspec-core (3.7.1)
|
28
|
+
rspec-support (~> 3.7.0)
|
29
|
+
rspec-expectations (3.7.0)
|
30
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
31
|
+
rspec-support (~> 3.7.0)
|
32
|
+
rspec-mocks (3.7.0)
|
33
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
34
|
+
rspec-support (~> 3.7.0)
|
35
|
+
rspec-support (3.7.1)
|
36
|
+
thread_safe (0.3.6)
|
37
|
+
tzinfo (1.2.5)
|
38
|
+
thread_safe (~> 0.1)
|
39
|
+
|
40
|
+
PLATFORMS
|
41
|
+
ruby
|
42
|
+
|
43
|
+
DEPENDENCIES
|
44
|
+
bundler (~> 1.16)
|
45
|
+
grabli!
|
46
|
+
rake (~> 10.0)
|
47
|
+
rspec (~> 3.0)
|
48
|
+
|
49
|
+
BUNDLED WITH
|
50
|
+
1.16.0
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
2
|
+
Version 2, December 2004
|
3
|
+
|
4
|
+
Copyright (C) 2018 dikond <di.kondratenko@gmail.com>
|
5
|
+
|
6
|
+
Everyone is permitted to copy and distribute verbatim or modified
|
7
|
+
copies of this license document, and changing it is allowed as long
|
8
|
+
as the name is changed.
|
9
|
+
|
10
|
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
11
|
+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
12
|
+
|
13
|
+
0. You just DO WHAT THE FUCK YOU WANT TO.
|
data/README.md
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# Grabli
|
2
|
+
|
3
|
+
Hola :v:
|
4
|
+
|
5
|
+
The very specific goal of this gem is to extract pundit policy permissions to something serializable... like a ruby array! Why do you need that? To tell the front-end application or API consumer what you think of the current user, hehe :smirk: As a bonus, I find it easier to write unit tests for policies. But to have a dependency on third-party gems for unit tests, even as awesome as this one, may be undesirable.
|
6
|
+
|
7
|
+
## Usage
|
8
|
+
|
9
|
+
With a given `UserPolicy` (e.g. the one defined in `/spec/spec_helper.rb`) you can do:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
require 'grabli'
|
13
|
+
|
14
|
+
Grabli.new.collect(@user, @company)
|
15
|
+
# => [:create?, :update?]
|
16
|
+
|
17
|
+
Grabli.new.collect(@user, :company)
|
18
|
+
# => [:create?]
|
19
|
+
```
|
20
|
+
|
21
|
+
Let's say your app have a public Rest API. It may look like:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
require 'grabli'
|
25
|
+
|
26
|
+
class Api::UsersController < ApplicationController
|
27
|
+
def show
|
28
|
+
@user = User.find(params[:id])
|
29
|
+
authorize @user
|
30
|
+
|
31
|
+
permissions = Grabli.new.collect(current_user, @user)
|
32
|
+
|
33
|
+
render json: { user: @user.to_json, permissions: permissions }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
38
|
+
You can then create a helper and use it across your app, for example:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
# /app/controllers/application_controller.rb
|
42
|
+
require 'grabli'
|
43
|
+
|
44
|
+
class ApplicationController
|
45
|
+
def collect_permissions_for(subject)
|
46
|
+
Grabli.new.collect(current_user, subject)
|
47
|
+
end
|
48
|
+
helper_method :collect_permissions_for
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
# /app/controllers/api/users_controller.rb
|
53
|
+
class Api::UsersController < ApplicationController
|
54
|
+
def show
|
55
|
+
@user = User.find(params[:id])
|
56
|
+
authorize @user
|
57
|
+
|
58
|
+
render json: { user: @user.to_json, permissions: collect_permissions_for(@user) }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
## Further plans
|
64
|
+
|
65
|
+
1) Improve cases when subject is a `Symbol`
|
66
|
+
|
67
|
+
Since pundit policy doesn't limit the subject types it can be anything, even a `Symbol`.
|
68
|
+
|
69
|
+
Make `Intruder` a bit more clever proxy object which delegates to the subject and intercepts `NoMethodError` for cases when `Symbol` subject mean "no subject".
|
70
|
+
|
71
|
+
## Contributing
|
72
|
+
|
73
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/grabli.
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "grabli"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/grabli.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative "lib/grabli/version"
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "grabli"
|
5
|
+
spec.version = Grabli::VERSION
|
6
|
+
spec.authors = ["dikond"]
|
7
|
+
spec.email = ["di.kondratenko@gmail.com"]
|
8
|
+
spec.license = "wtfpl"
|
9
|
+
|
10
|
+
spec.summary = "Grab permissions from your Pundit policies"
|
11
|
+
spec.homepage = "https://github.com/dikond/grabli"
|
12
|
+
|
13
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
14
|
+
f.match(%r{^(test|spec|features)/})
|
15
|
+
end
|
16
|
+
|
17
|
+
spec.require_paths = ["lib"]
|
18
|
+
|
19
|
+
spec.add_runtime_dependency "pundit", "> 0"
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.16"
|
21
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
22
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
23
|
+
end
|
data/lib/grabli.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require "grabli/version"
|
2
|
+
require "pundit"
|
3
|
+
|
4
|
+
class Grabli
|
5
|
+
#
|
6
|
+
# Collect allowed policy permissions for the given user.
|
7
|
+
#
|
8
|
+
# @param user [Object] user object your policy work with
|
9
|
+
# @param subject [Symbol, Object] subject object your policy work with
|
10
|
+
# @return [Array<Symbol>] array of allowed policy permission
|
11
|
+
# @example
|
12
|
+
#
|
13
|
+
# Grabli.new.collect(@user, @company)
|
14
|
+
# #=> [:create?, :update?, :manage_occupied?]
|
15
|
+
#
|
16
|
+
# Grabli.new.collect(@user, :company)
|
17
|
+
# #=> [:create?]
|
18
|
+
#
|
19
|
+
def collect(user, subject)
|
20
|
+
policy_class(subject)
|
21
|
+
.public_instance_methods(false)
|
22
|
+
.reject! { |n| n =~ /permitted_attributes/ }
|
23
|
+
.each_with_object([]) do |permission, collection|
|
24
|
+
# allows to collect permissions without subject, for more @see Intruder
|
25
|
+
isubject = subject.is_a?(Symbol) ? Intruder.new(false) : subject
|
26
|
+
policy = policy_class(subject).new(user, isubject)
|
27
|
+
|
28
|
+
collection << permission if allowed? policy, permission
|
29
|
+
end
|
30
|
+
.sort
|
31
|
+
end
|
32
|
+
|
33
|
+
# Check whether certain permission is allowed.
|
34
|
+
#
|
35
|
+
# @param policy [ApplicationPolicy] instantiated policy
|
36
|
+
# @param permission [Symbol] permission name
|
37
|
+
# @return [Boolen, Object] true or false in case subject intruded
|
38
|
+
# or whatever you policy permission returns
|
39
|
+
# @example
|
40
|
+
#
|
41
|
+
# policy = Pundit.policy(@user, @company)
|
42
|
+
# Grabli.new.allowed?(policy, :create?)
|
43
|
+
# #=> true
|
44
|
+
#
|
45
|
+
def allowed?(policy, permission)
|
46
|
+
result = policy.public_send(permission)
|
47
|
+
return !policy.record.intruded if policy.record.is_a?(Intruder)
|
48
|
+
result
|
49
|
+
end
|
50
|
+
|
51
|
+
private def policy_class(record)
|
52
|
+
Pundit::PolicyFinder.new(record).policy
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# When no subject specified by the user or the subject is a Symbol,
|
57
|
+
# we pass that object as a subject.
|
58
|
+
#
|
59
|
+
# If the subject isn't used it means we can add this permission as allowed.
|
60
|
+
# If it's used, CURRENTLY, we assume that the given permission isn't allowed.
|
61
|
+
#
|
62
|
+
# TODO: delegate to the original subject if it was given
|
63
|
+
# and intercept NoMethodError
|
64
|
+
#
|
65
|
+
Intruder = Struct.new(:intruded) do
|
66
|
+
def method_missing(*)
|
67
|
+
self[:intruded] = true
|
68
|
+
self
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
metadata
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: grabli
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- dikond
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-03-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: pundit
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.16'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.16'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.0'
|
69
|
+
description:
|
70
|
+
email:
|
71
|
+
- di.kondratenko@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".gitignore"
|
77
|
+
- ".rspec"
|
78
|
+
- ".travis.yml"
|
79
|
+
- Gemfile
|
80
|
+
- Gemfile.lock
|
81
|
+
- LICENSE.txt
|
82
|
+
- README.md
|
83
|
+
- Rakefile
|
84
|
+
- bin/console
|
85
|
+
- grabli.gemspec
|
86
|
+
- lib/grabli.rb
|
87
|
+
- lib/grabli/version.rb
|
88
|
+
homepage: https://github.com/dikond/grabli
|
89
|
+
licenses:
|
90
|
+
- wtfpl
|
91
|
+
metadata: {}
|
92
|
+
post_install_message:
|
93
|
+
rdoc_options: []
|
94
|
+
require_paths:
|
95
|
+
- lib
|
96
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
requirements: []
|
107
|
+
rubyforge_project:
|
108
|
+
rubygems_version: 2.7.6
|
109
|
+
signing_key:
|
110
|
+
specification_version: 4
|
111
|
+
summary: Grab permissions from your Pundit policies
|
112
|
+
test_files: []
|