protector 0.0.1 → 0.0.2
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/lib/protector/adapters/active_record.rb +55 -3
- data/lib/protector/dsl.rb +9 -2
- data/lib/protector/version.rb +1 -1
- data/spec/lib/adapters/active_record_spec.rb +30 -8
- data/spec/spec_helpers/model.rb +50 -24
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 098c77da509ed0a347c0a22df9dd6c6a8d34289a
|
4
|
+
data.tar.gz: b9ae1d35809445399fda713c3f0276ac91114659
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d0cc601d414b036f8eb6db9381c9f30a93bc1bdb5bd92a946165f32ea97f9229be9fa76210a7b98ec878da9b0476f6dacffb6bf7e24200c496bf8e6106a6b4bf
|
7
|
+
data.tar.gz: 9994bc1d0e0a3a93f81f4ee07fabf7cf1faf7c02c958952ec8cd80a6452349c20cd8fc7a79bf51665da2cbccdef179ce85963cc4ab0528b039b6b21a735b85bc
|
@@ -4,6 +4,8 @@ module Protector
|
|
4
4
|
def self.activate!
|
5
5
|
::ActiveRecord::Base.send :include, Protector::Adapters::ActiveRecord::Base
|
6
6
|
::ActiveRecord::Relation.send :include, Protector::Adapters::ActiveRecord::Relation
|
7
|
+
::ActiveRecord::Associations::SingularAssociation.send :include, Protector::Adapters::ActiveRecord::Association
|
8
|
+
::ActiveRecord::Associations::CollectionAssociation.send :include, Protector::Adapters::ActiveRecord::Association
|
7
9
|
end
|
8
10
|
|
9
11
|
module Base
|
@@ -33,6 +35,28 @@ module Protector
|
|
33
35
|
def restrict(subject)
|
34
36
|
all.restrict(subject)
|
35
37
|
end
|
38
|
+
|
39
|
+
def define_method_attribute(name)
|
40
|
+
safe_name = name.unpack('h*').first
|
41
|
+
|
42
|
+
if primary_key == name || (primary_key.is_a?(Array) && primary_key.include?(name))
|
43
|
+
condition = "true"
|
44
|
+
else
|
45
|
+
condition = "!@protector_subject || protector_meta.readable?(#{name.inspect})"
|
46
|
+
end
|
47
|
+
|
48
|
+
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
|
49
|
+
def __temp__#{safe_name}
|
50
|
+
if #{condition}
|
51
|
+
read_attribute(AttrNames::ATTR_#{safe_name}) { |n| missing_attribute(n, caller) }
|
52
|
+
else
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
alias_method #{name.inspect}, :__temp__#{safe_name}
|
57
|
+
undef_method :__temp__#{safe_name}
|
58
|
+
STR
|
59
|
+
end
|
36
60
|
end
|
37
61
|
|
38
62
|
def protector_meta
|
@@ -50,23 +74,37 @@ module Protector
|
|
50
74
|
|
51
75
|
def visible?
|
52
76
|
protector_meta.relation.where(
|
53
|
-
self.class.primary_key =>
|
77
|
+
self.class.primary_key => id
|
54
78
|
).any?
|
55
79
|
end
|
56
80
|
|
57
81
|
def creatable?
|
58
|
-
fields = HashWithIndifferentAccess[changed.map{|x| [x,
|
82
|
+
fields = HashWithIndifferentAccess[changed.map{|x| [x, read_attribute(x)]}]
|
59
83
|
protector_meta.creatable?(fields)
|
60
84
|
end
|
61
85
|
|
62
86
|
def updatable?
|
63
|
-
fields = HashWithIndifferentAccess[changed.map{|x| [x,
|
87
|
+
fields = HashWithIndifferentAccess[changed.map{|x| [x, read_attribute(x)]}]
|
64
88
|
protector_meta.updatable?(fields)
|
65
89
|
end
|
66
90
|
|
67
91
|
def destroyable?
|
68
92
|
protector_meta.destroyable?
|
69
93
|
end
|
94
|
+
|
95
|
+
def [](name)
|
96
|
+
if !@protector_subject || protector_meta.readable?(name)
|
97
|
+
super
|
98
|
+
else
|
99
|
+
nil
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def association(*args)
|
104
|
+
association = super
|
105
|
+
association.restrict @protector_subject
|
106
|
+
association
|
107
|
+
end
|
70
108
|
end
|
71
109
|
|
72
110
|
module Relation
|
@@ -100,6 +138,20 @@ module Protector
|
|
100
138
|
@records = merge(protector_meta.relation).unrestrict.send :exec_queries
|
101
139
|
end
|
102
140
|
end
|
141
|
+
|
142
|
+
module Association
|
143
|
+
extend ActiveSupport::Concern
|
144
|
+
|
145
|
+
included do
|
146
|
+
include Protector::DSL::Base
|
147
|
+
|
148
|
+
alias_method_chain :reader, :protector
|
149
|
+
end
|
150
|
+
|
151
|
+
def reader_with_protector
|
152
|
+
reader_without_protector.restrict(@protector_subject)
|
153
|
+
end
|
154
|
+
end
|
103
155
|
end
|
104
156
|
end
|
105
157
|
end
|
data/lib/protector/dsl.rb
CHANGED
@@ -9,6 +9,7 @@ module Protector
|
|
9
9
|
@model = model
|
10
10
|
@fields = fields
|
11
11
|
@access = {update: {}, view: {}, create: {}}.with_indifferent_access
|
12
|
+
@access_keys = {}.with_indifferent_access
|
12
13
|
@relation = false
|
13
14
|
@destroyable = false
|
14
15
|
|
@@ -21,6 +22,8 @@ module Protector
|
|
21
22
|
instance_exec &b
|
22
23
|
end
|
23
24
|
end
|
25
|
+
|
26
|
+
@access.each{|k,v| @access_keys[k] = v.keys}
|
24
27
|
end
|
25
28
|
|
26
29
|
def scope(&block)
|
@@ -63,6 +66,10 @@ module Protector
|
|
63
66
|
end
|
64
67
|
end
|
65
68
|
|
69
|
+
def readable?(field)
|
70
|
+
@access_keys[:view].include?(field.to_s)
|
71
|
+
end
|
72
|
+
|
66
73
|
def creatable?(fields=false)
|
67
74
|
modifiable? :create, fields
|
68
75
|
end
|
@@ -78,10 +85,10 @@ module Protector
|
|
78
85
|
private
|
79
86
|
|
80
87
|
def modifiable?(part, fields)
|
81
|
-
return false unless @
|
88
|
+
return false unless @access_keys[part].length > 0
|
82
89
|
|
83
90
|
if fields
|
84
|
-
return false if (fields.keys - @
|
91
|
+
return false if (fields.keys - @access_keys[part]).length > 0
|
85
92
|
|
86
93
|
fields.each do |k,v|
|
87
94
|
case x = @access[part][k]
|
data/lib/protector/version.rb
CHANGED
@@ -4,18 +4,36 @@ describe Protector::Adapters::ActiveRecord do
|
|
4
4
|
before(:all) do
|
5
5
|
ActiveRecord::Schema.verbose = false
|
6
6
|
ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
|
7
|
+
|
7
8
|
ActiveRecord::Migration.create_table :dummies do |t|
|
8
|
-
t.string
|
9
|
-
t.integer
|
10
|
-
t.text
|
9
|
+
t.string :string
|
10
|
+
t.integer :number
|
11
|
+
t.text :text
|
12
|
+
t.timestamps
|
13
|
+
end
|
14
|
+
|
15
|
+
ActiveRecord::Migration.create_table :fluffies do |t|
|
16
|
+
t.string :string
|
17
|
+
t.belongs_to :dummy
|
11
18
|
t.timestamps
|
12
19
|
end
|
13
20
|
|
14
|
-
|
21
|
+
Protector::Adapters::ActiveRecord.activate!
|
22
|
+
|
23
|
+
class Dummy < ActiveRecord::Base
|
24
|
+
protect do; end
|
25
|
+
has_many :fluffies
|
26
|
+
end
|
15
27
|
Dummy.create! string: 'zomgstring', number: 999, text: 'zomgtext'
|
16
28
|
Dummy.create! string: 'zomgstring', number: 777, text: 'zomgtext'
|
17
29
|
|
18
|
-
|
30
|
+
class Fluffy < ActiveRecord::Base
|
31
|
+
protect do
|
32
|
+
can :view, :dummy_id
|
33
|
+
end
|
34
|
+
belongs_to :dummy
|
35
|
+
end
|
36
|
+
Fluffy.create! string: 'zomgstring', dummy_id: 1
|
19
37
|
end
|
20
38
|
|
21
39
|
describe Protector::Adapters::ActiveRecord::Base do
|
@@ -30,8 +48,12 @@ describe Protector::Adapters::ActiveRecord do
|
|
30
48
|
end
|
31
49
|
|
32
50
|
it "scopes" do
|
51
|
+
@dummy.instance_eval do
|
52
|
+
protect do; scope{ all }; end
|
53
|
+
end
|
54
|
+
|
33
55
|
scope = @dummy.restrict('!')
|
34
|
-
scope.should
|
56
|
+
scope.should be_a_kind_of ActiveRecord::Relation
|
35
57
|
scope.protector_subject.should == '!'
|
36
58
|
end
|
37
59
|
|
@@ -56,7 +78,7 @@ describe Protector::Adapters::ActiveRecord do
|
|
56
78
|
context "with null relation" do
|
57
79
|
before(:each) do
|
58
80
|
@dummy.instance_eval do
|
59
|
-
protect
|
81
|
+
protect do; scope{ none }; end
|
60
82
|
end
|
61
83
|
end
|
62
84
|
|
@@ -76,7 +98,7 @@ describe Protector::Adapters::ActiveRecord do
|
|
76
98
|
context "with active relation" do
|
77
99
|
before(:each) do
|
78
100
|
@dummy.instance_eval do
|
79
|
-
protect
|
101
|
+
protect do; scope{ where(number: 999) }; end
|
80
102
|
end
|
81
103
|
end
|
82
104
|
|
data/spec/spec_helpers/model.rb
CHANGED
@@ -39,25 +39,51 @@ shared_examples_for "a model" do
|
|
39
39
|
meta.access[:update].should == fields
|
40
40
|
end
|
41
41
|
|
42
|
+
describe "association" do
|
43
|
+
context "(has_many)" do
|
44
|
+
it "passes subject" do
|
45
|
+
Dummy.first.restrict('!').fluffies.protector_subject.should == '!'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "(belongs_to)" do
|
50
|
+
it "passes subject" do
|
51
|
+
Fluffy.first.restrict('!').dummy.protector_subject.should == '!'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
42
56
|
describe "visibility" do
|
43
57
|
it "marks blocked" do
|
44
58
|
@dummy.instance_eval do
|
45
|
-
protect do
|
46
|
-
scope { none }
|
47
|
-
end
|
59
|
+
protect do; scope { none }; end
|
48
60
|
end
|
49
61
|
|
50
62
|
@dummy.first.restrict('!').visible?.should == false
|
51
63
|
end
|
52
64
|
|
53
65
|
it "marks allowed" do
|
66
|
+
@dummy.instance_eval do
|
67
|
+
protect do; scope { limit(5) }; end
|
68
|
+
end
|
69
|
+
|
70
|
+
@dummy.first.restrict('!').visible?.should == true
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "readability" do
|
75
|
+
it "hides fields" do
|
54
76
|
@dummy.instance_eval do
|
55
77
|
protect do
|
56
|
-
|
78
|
+
can :view, :string
|
57
79
|
end
|
58
80
|
end
|
59
81
|
|
60
|
-
@dummy.first.restrict('!')
|
82
|
+
dummy = @dummy.first.restrict('!')
|
83
|
+
dummy.number.should == nil
|
84
|
+
dummy[:number].should == nil
|
85
|
+
dummy.read_attribute(:number).should_not == nil
|
86
|
+
dummy.string.should == 'zomgstring'
|
61
87
|
end
|
62
88
|
end
|
63
89
|
|
@@ -74,10 +100,10 @@ shared_examples_for "a model" do
|
|
74
100
|
dummy.restrict('!').creatable?.should == false
|
75
101
|
end
|
76
102
|
|
77
|
-
it "invalidates" do
|
78
|
-
|
79
|
-
|
80
|
-
end
|
103
|
+
# it "invalidates" do
|
104
|
+
# dummy = @dummy.new(string: 'bam', number: 1).restrict('!')
|
105
|
+
# dummy.should invalidate
|
106
|
+
# end
|
81
107
|
end
|
82
108
|
|
83
109
|
context "by list of fields" do
|
@@ -99,10 +125,10 @@ shared_examples_for "a model" do
|
|
99
125
|
dummy.restrict('!').creatable?.should == true
|
100
126
|
end
|
101
127
|
|
102
|
-
it "invalidates" do
|
103
|
-
|
104
|
-
|
105
|
-
end
|
128
|
+
# it "invalidates" do
|
129
|
+
# dummy = @dummy.new(string: 'bam', number: 1).restrict('!')
|
130
|
+
# dummy.should invalidate
|
131
|
+
# end
|
106
132
|
|
107
133
|
it "validates" do
|
108
134
|
dummy = @dummy.new(string: 'bam').restrict('!')
|
@@ -114,7 +140,7 @@ shared_examples_for "a model" do
|
|
114
140
|
before(:each) do
|
115
141
|
@dummy.instance_eval do
|
116
142
|
protect do
|
117
|
-
can :create, string: -> (x) { x.length == 5 }
|
143
|
+
can :create, string: -> (x) { x.try(:length) == 5 }
|
118
144
|
end
|
119
145
|
end
|
120
146
|
end
|
@@ -129,10 +155,10 @@ shared_examples_for "a model" do
|
|
129
155
|
dummy.restrict('!').creatable?.should == true
|
130
156
|
end
|
131
157
|
|
132
|
-
it "invalidates" do
|
133
|
-
|
134
|
-
|
135
|
-
end
|
158
|
+
# it "invalidates" do
|
159
|
+
# dummy = @dummy.new(string: 'bam').restrict('!')
|
160
|
+
# dummy.should invalidate
|
161
|
+
# end
|
136
162
|
|
137
163
|
it "validates" do
|
138
164
|
dummy = @dummy.new(string: '12345').restrict('!')
|
@@ -159,10 +185,10 @@ shared_examples_for "a model" do
|
|
159
185
|
dummy.restrict('!').creatable?.should == true
|
160
186
|
end
|
161
187
|
|
162
|
-
it "invalidates" do
|
163
|
-
|
164
|
-
|
165
|
-
end
|
188
|
+
# it "invalidates" do
|
189
|
+
# dummy = @dummy.new(number: 500).restrict('!')
|
190
|
+
# dummy.should invalidate
|
191
|
+
# end
|
166
192
|
|
167
193
|
it "validates" do
|
168
194
|
dummy = @dummy.new(number: 2).restrict('!')
|
@@ -230,7 +256,7 @@ shared_examples_for "a model" do
|
|
230
256
|
before(:each) do
|
231
257
|
@dummy.instance_eval do
|
232
258
|
protect do
|
233
|
-
can :update, string: -> (x) { x.length == 5 }
|
259
|
+
can :update, string: -> (x) { x.try(:length) == 5 }
|
234
260
|
end
|
235
261
|
end
|
236
262
|
end
|
@@ -326,7 +352,7 @@ shared_examples_for "a model" do
|
|
326
352
|
end
|
327
353
|
|
328
354
|
dummy = @dummy.create!.restrict('!')
|
329
|
-
dummy.destroy
|
355
|
+
dummy.destroy!.should == dummy
|
330
356
|
dummy.destroyed?.should == true
|
331
357
|
end
|
332
358
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: protector
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Boris Staal
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-05-
|
11
|
+
date: 2013-05-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|