pragma-operation 0.1.2 → 1.0.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 +4 -4
- data/doc/03-policies.md +26 -2
- data/doc/04-decorators.md +26 -0
- data/lib/pragma/operation/authorization.rb +29 -2
- data/lib/pragma/operation/base.rb +4 -3
- data/lib/pragma/operation/decoration.rb +70 -0
- data/lib/pragma/operation/validation.rb +9 -2
- data/lib/pragma/operation/version.rb +1 -1
- data/lib/pragma/operation.rb +2 -1
- data/pragma-operation.gemspec +1 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d1a35deac8b18a13c8f5e7cd9b4ee1372afb6321
|
4
|
+
data.tar.gz: 6f2abba3db47e143d06c407fe33a1416f44cffac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1af71177cbec88e40273ebc84fd5118d2bf2d894df7823791850e50d12dcd5ca0e2ba649b6c4509ff71708bfdafb3bd13ba78064cdc78709f9a3e59267c1626d
|
7
|
+
data.tar.gz: fd674718c93267c02e48e6ce035ff0595a1cb6db79ed047938a762ae4e555ed35e9be6348ec02d5b0aed038fe428f64c738fc10edd7c62498b9c24bec37976bb
|
data/doc/03-policies.md
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
# Policies
|
2
2
|
|
3
3
|
Operations integrate with [Pragma::Policy](https://github.com/pragmarb/pragma-policy). All you have
|
4
|
-
to do is specify the policy class with `#policy
|
5
|
-
`#authorize!`:
|
4
|
+
to do is specify the policy class with `#policy`:
|
6
5
|
|
7
6
|
```ruby
|
8
7
|
module API
|
@@ -92,3 +91,28 @@ module API
|
|
92
91
|
end
|
93
92
|
end
|
94
93
|
```
|
94
|
+
|
95
|
+
## Authorizing collections
|
96
|
+
|
97
|
+
To authorize a collection, use `#authorize_collection`. This will call `.accessible_by` on the
|
98
|
+
policy class with the current user and the provided collection and return an authorized collection
|
99
|
+
containing only records accessible by the user.
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
module API
|
103
|
+
module V1
|
104
|
+
module Post
|
105
|
+
module Operation
|
106
|
+
class Index < Pragma::Operation::Base
|
107
|
+
policy API::V1::Post::Policy
|
108
|
+
|
109
|
+
def call
|
110
|
+
posts = authorize_collection Post.all
|
111
|
+
respond_with status: :ok, resource: posts
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
```
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Decorators
|
2
|
+
|
3
|
+
Operations integrate with [Pragma::Decorator](https://github.com/pragmarb/pragma-decorator). All you
|
4
|
+
have to do is specify the policy class with `#decorator`. This will give you access to `#decorate`:
|
5
|
+
|
6
|
+
```ruby
|
7
|
+
module API
|
8
|
+
module V1
|
9
|
+
module Post
|
10
|
+
module Operation
|
11
|
+
class Show < Pragma::Operation::Base
|
12
|
+
policy API::V1::Post::Policy
|
13
|
+
|
14
|
+
def call
|
15
|
+
post = Post.find(params[:id])
|
16
|
+
respond_with status: :ok, resource: decorate(post)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
```
|
24
|
+
|
25
|
+
Note that `#decorate` works with both singular resources and collections, as it uses the decorator's
|
26
|
+
[`.represent`](http://trailblazer.to/gems/representable/3.0/api.html) method.
|
@@ -18,6 +18,13 @@ module Pragma
|
|
18
18
|
@policy = klass
|
19
19
|
end
|
20
20
|
|
21
|
+
# Returns the policy class.
|
22
|
+
#
|
23
|
+
# @return [Class]
|
24
|
+
def policy_klass
|
25
|
+
@policy
|
26
|
+
end
|
27
|
+
|
21
28
|
# Builds the policy for the given user and resource, using the previous defined policy
|
22
29
|
# class.
|
23
30
|
#
|
@@ -28,7 +35,7 @@ module Pragma
|
|
28
35
|
#
|
29
36
|
# @see #policy
|
30
37
|
def build_policy(user:, resource:)
|
31
|
-
|
38
|
+
policy_klass.new(user: user, resource: resource)
|
32
39
|
end
|
33
40
|
end
|
34
41
|
|
@@ -48,11 +55,15 @@ module Pragma
|
|
48
55
|
|
49
56
|
# Authorizes this operation on the provided resource or policy.
|
50
57
|
#
|
58
|
+
# If no policy was defined, simply returns true.
|
59
|
+
#
|
51
60
|
# @param authorizable [Pragma::Policy::Base|Object] resource or policy
|
52
61
|
#
|
53
62
|
# @return [Boolean] whether the operation is authorized
|
54
63
|
def authorize(authorizable)
|
55
|
-
|
64
|
+
return true unless self.class.policy_klass
|
65
|
+
|
66
|
+
policy = if authorizable.is_a?(self.class.policy_klass)
|
56
67
|
authorizable
|
57
68
|
else
|
58
69
|
build_policy(authorizable)
|
@@ -77,6 +88,22 @@ module Pragma
|
|
77
88
|
}
|
78
89
|
)
|
79
90
|
end
|
91
|
+
|
92
|
+
# Scopes the provided collection.
|
93
|
+
#
|
94
|
+
# If no policy class is defined, simply returns the collection.
|
95
|
+
#
|
96
|
+
# @param collection [Enumerable]
|
97
|
+
#
|
98
|
+
# @return [Pragma::Decorator::Base|Enumerable]
|
99
|
+
def authorize_collection(collection)
|
100
|
+
return collection unless self.class.policy_klass
|
101
|
+
|
102
|
+
self.class.policy_klass.accessible_by(
|
103
|
+
user: current_user,
|
104
|
+
scope: collection
|
105
|
+
)
|
106
|
+
end
|
80
107
|
end
|
81
108
|
end
|
82
109
|
end
|
@@ -9,6 +9,10 @@ module Pragma
|
|
9
9
|
class Base
|
10
10
|
include Interactor
|
11
11
|
|
12
|
+
include Authorization
|
13
|
+
include Validation
|
14
|
+
include Decoration
|
15
|
+
|
12
16
|
STATUSES = {
|
13
17
|
200 => :ok,
|
14
18
|
201 => :created,
|
@@ -70,9 +74,6 @@ module Pragma
|
|
70
74
|
class << self
|
71
75
|
def inherited(child)
|
72
76
|
child.class_eval do
|
73
|
-
include Authorization
|
74
|
-
include Validation
|
75
|
-
|
76
77
|
before :setup_context
|
77
78
|
around :handle_halt
|
78
79
|
after :mark_result, :consolidate_status, :validate_status, :set_default_status
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Pragma
|
2
|
+
module Operation
|
3
|
+
# Provides integration with {https://github.com/pragmarb/pragma-decorator Pragma::Decorator}.
|
4
|
+
#
|
5
|
+
# @author Alessandro Desantis
|
6
|
+
module Decoration
|
7
|
+
def self.included(base)
|
8
|
+
base.extend ClassMethods
|
9
|
+
base.include InstanceMethods
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods # :nodoc:
|
13
|
+
# Sets the decorator to use for validating this operation.
|
14
|
+
#
|
15
|
+
# @param klass [Class] a subclass of +Pragma::Decorator::Base+
|
16
|
+
def decorator(klass)
|
17
|
+
@decorator = klass
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns the decorator class.
|
21
|
+
#
|
22
|
+
# @return [Class]
|
23
|
+
def decorator_klass
|
24
|
+
@decorator
|
25
|
+
end
|
26
|
+
|
27
|
+
# Builds the decorator for the given resource, using the previously defined decorator class.
|
28
|
+
#
|
29
|
+
# Works with both singular resources and collections.
|
30
|
+
#
|
31
|
+
# @param resource [Object]
|
32
|
+
#
|
33
|
+
# @return [Pragma::Decorator::Base]
|
34
|
+
#
|
35
|
+
# @see #decorator
|
36
|
+
def build_decorator(resource)
|
37
|
+
decorator_klass.represent(resource)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module InstanceMethods # :nodoc:
|
42
|
+
# Builds the decorator for the given resource, using the previously defined decorator class.
|
43
|
+
#
|
44
|
+
# This is just an instance-level alias of {.build_decorator}. You should use this from
|
45
|
+
# inside the operation.
|
46
|
+
#
|
47
|
+
# @param resource [Object]
|
48
|
+
#
|
49
|
+
# @return [Pragma::Decorator::Base]
|
50
|
+
#
|
51
|
+
# @see #decorate
|
52
|
+
def build_decorator(resource)
|
53
|
+
self.class.build_decorator(resource)
|
54
|
+
end
|
55
|
+
|
56
|
+
# If a decorator is defined, acts as an alias for {#build_decorator}. If not, simply returns
|
57
|
+
# the provided resource.
|
58
|
+
# @param decoratable [Object]
|
59
|
+
#
|
60
|
+
# @return [Pragma::Decorator::Base|Object]
|
61
|
+
#
|
62
|
+
# @see #build_decorator
|
63
|
+
def decorate(decoratable)
|
64
|
+
return decoratable unless self.class.decorator_klass
|
65
|
+
build_decorator(decoratable)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -18,6 +18,13 @@ module Pragma
|
|
18
18
|
@contract = klass
|
19
19
|
end
|
20
20
|
|
21
|
+
# Returns the contract class.
|
22
|
+
#
|
23
|
+
# @return [Class]
|
24
|
+
def contract_klass
|
25
|
+
@contract
|
26
|
+
end
|
27
|
+
|
21
28
|
# Builds the contract for the given resource, using the previous defined contract class.
|
22
29
|
#
|
23
30
|
# @param resource [Object]
|
@@ -26,7 +33,7 @@ module Pragma
|
|
26
33
|
#
|
27
34
|
# @see #contract
|
28
35
|
def build_contract(resource)
|
29
|
-
|
36
|
+
contract_klass.new(resource)
|
30
37
|
end
|
31
38
|
end
|
32
39
|
|
@@ -53,7 +60,7 @@ module Pragma
|
|
53
60
|
# @return [Boolean] whether the operation is valid
|
54
61
|
def validate(validatable)
|
55
62
|
# rubocop:disable Metrics/LineLength
|
56
|
-
contract = if
|
63
|
+
contract = if validatable.is_a?(self.class.contract_klass)
|
57
64
|
validatable
|
58
65
|
else
|
59
66
|
build_contract(validatable)
|
data/lib/pragma/operation.rb
CHANGED
@@ -2,9 +2,10 @@
|
|
2
2
|
require 'interactor'
|
3
3
|
|
4
4
|
require 'pragma/operation/version'
|
5
|
-
require 'pragma/operation/base'
|
6
5
|
require 'pragma/operation/authorization'
|
7
6
|
require 'pragma/operation/validation'
|
7
|
+
require 'pragma/operation/decoration'
|
8
|
+
require 'pragma/operation/base'
|
8
9
|
|
9
10
|
module Pragma
|
10
11
|
# Operations provide business logic encapsulation for your JSON API.
|
data/pragma-operation.gemspec
CHANGED
@@ -24,6 +24,7 @@ Gem::Specification.new do |spec|
|
|
24
24
|
|
25
25
|
spec.add_development_dependency 'pragma-policy', '~> 0.1.0'
|
26
26
|
spec.add_development_dependency 'pragma-contract', '~> 0.1.0'
|
27
|
+
spec.add_development_dependency 'pragma-decorator', '~> 0.1.0'
|
27
28
|
|
28
29
|
spec.add_development_dependency "bundler"
|
29
30
|
spec.add_development_dependency "rake"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pragma-operation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alessandro Desantis
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-12-
|
11
|
+
date: 2016-12-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: interactor
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 0.1.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pragma-decorator
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.1.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.1.0
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: bundler
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -156,9 +170,11 @@ files:
|
|
156
170
|
- doc/01-basic-usage.md
|
157
171
|
- doc/02-contracts.md
|
158
172
|
- doc/03-policies.md
|
173
|
+
- doc/04-decorators.md
|
159
174
|
- lib/pragma/operation.rb
|
160
175
|
- lib/pragma/operation/authorization.rb
|
161
176
|
- lib/pragma/operation/base.rb
|
177
|
+
- lib/pragma/operation/decoration.rb
|
162
178
|
- lib/pragma/operation/validation.rb
|
163
179
|
- lib/pragma/operation/version.rb
|
164
180
|
- pragma-operation.gemspec
|