kojac 0.13.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e697fc52a995658f75cf2064bfdb2fe1b1d4d280
4
- data.tar.gz: 15edfaca5fd47b4d860ae74382d12ea761f84a4a
3
+ metadata.gz: c4c2362fb512574c8a5ef15983cca66fd6bd2aab
4
+ data.tar.gz: 1f23df6b7d057f077b5563523cd7cf86d6e4862f
5
5
  SHA512:
6
- metadata.gz: 6e0fd6b7d3a30b9ddce381f2c8c4ea477bc7bceeb9df2d6e1f57f8974eda3f33e76c71fb9ce5292788ad28044b8359f10fd1bda2689e0253a89f81568e9c6bc4
7
- data.tar.gz: b69cab1d039380b960f25ee761df2b1cdb389090e7e51053c84cbe9896ac45d5721e20a4504fb6079368c1f45503dde681a9c684c93a043d2c9923d3f017f117
6
+ metadata.gz: a6ca900452043b77c3cdb3433dc3ab4763d9be78483f514f6c09e87c31fed58ef3c67c43ee81f074a45569a70ae1a0f4ff47c4d0b28b711f77b1df7e037f6ae3
7
+ data.tar.gz: 177f53ce53cdd7f5d3f4afa9128332b78cbd392cfce2b4228cbea2dad4e2666ebb275088eb33e8669bcc14eb931bc399dec2a406d6a6e20206f0b16259a9f603
@@ -280,7 +280,7 @@ Ember.computed.collectIds = function(aCollectionProperty,aPrefix,aModelCachePath
280
280
  }
281
281
  return objects;
282
282
  });
283
- return result.property.apply(result, _.compact([aModelCachePath,aCollectionProperty]));
283
+ return result.property.apply(result, _.compact([aModelCachePath,aCollectionProperty+'.@each']));
284
284
  };
285
285
 
286
286
  Ember.computed.has_many = function(aResource,aForeignKey,aLocalPropertyPath,aModelCachePath,aFilterFn){
@@ -1,8 +1,10 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/kojac_front_methods.rb')
2
2
 
3
- class KojacBaseController < ActionController::Base
3
+ class KojacFrontController < ActionController::Base
4
4
 
5
5
  include KojacFrontMethods
6
+ include Kojac::ControllerOpMethods
7
+
6
8
  respond_to :json
7
9
 
8
10
  public
@@ -6,40 +6,49 @@ module KojacFrontMethods
6
6
  raise aMessage || "You are not authorized to perform this action"
7
7
  end
8
8
 
9
- def kojac_current_user
10
- current_user
9
+ def do_op(op)
10
+ output = nil
11
+ method = "#{op[:verb].to_s.downcase}_op".to_sym
12
+ resource = op[:key].split('__').first
13
+
14
+ if controller_class = (resource.camelize+'Controller::KojacController').safe_constantize
15
+ ctrlr = controller_class.new
16
+ raise "Unsupported verb #{op[:verb]} on #{class_name}" unless ctrlr.respond_to? method
17
+ ctrlr.kojac_setup(current_user,op) if ctrlr.respond_to? :kojac_setup
18
+ output = ctrlr.send method
19
+ elsif (controller_class = (resource.camelize+'Controller').safe_constantize) and ctrlr = controller_class.new and ctrlr.respond_to?(method) # use rails controller
20
+ # result = controller_class.new
21
+ # raise "Unsupported verb #{op[:verb]} on #{class_name}" unless ctrlr.respond_to? method
22
+ ctrlr.current_user = self.current_user
23
+ ctrlr.params = {op: op}
24
+ output = ctrlr.send method
25
+ # else
26
+ # raise "Controller class #{class_name} not defined" unless
27
+ else
28
+ raise "Controller not found for #{resource} resource. Please define #{resource.camelize+'Controller::KojacController'}"
29
+ end
30
+ output
11
31
  end
12
-
32
+
13
33
  def process_ops(aInput)
14
34
  result = {}
15
35
  if ops = aInput[:ops]
16
36
  result[:ops] = []
17
- ops.each do |op|
18
- method = "#{op[:verb].to_s.downcase}_op".to_sym
19
- ctrlr = self.controller_for_key(op[:key])
20
- if ctrlr.respond_to? method
21
- ctrlr.params = {op: op}
22
- output = ctrlr.send method
23
- result[:ops] << output
37
+ ops.each_with_index do |op,i|
38
+ output = do_op(op)
39
+ if output[:error]
40
+ result[:error] = output[:error]
41
+ result[:error_index] = i
42
+ result.delete :ops
43
+ break
24
44
  else
25
- raise "Unsupported verb #{op[:verb]}"
45
+ result[:ops] << output
26
46
  end
27
47
  end
28
48
  end
29
49
  result
30
50
  end
31
51
 
32
- def controller_for_key(aKey)
33
- resource = aKey.split('__').first
34
- controller_name = resource.camelize+'Controller'
35
- if controller = controller_name.constantize
36
- result = controller.new
37
- result.current_user = self.kojac_current_user
38
- result
39
- else
40
- nil
41
- end
42
- end
43
52
 
44
53
  def process_input(aInputJson)
45
54
  output = nil
@@ -67,7 +76,7 @@ module KojacFrontMethods
67
76
  end
68
77
  send(:after_process, [aInputJson, output]) if respond_to? :after_process
69
78
  status = output[:error] ? :unprocessable_entity : :ok
70
- jsono = KojacUtils.to_jsono(output, scope: kojac_current_user)
79
+ jsono = KojacUtils.to_jsono(output, scope: current_user)
71
80
  [jsono,status]
72
81
  end
73
82
 
@@ -0,0 +1,131 @@
1
+ class ConcentricPolicy
2
+
3
+ class_attribute :filters
4
+
5
+ attr_reader :user, :record, :ability
6
+
7
+ def initialize(user, record)
8
+ raise Pundit::NotAuthorizedError, "must be logged in" unless user
9
+ @user = user
10
+ @record = record
11
+ end
12
+
13
+ def unauthorized!(aMessage=nil)
14
+ raise Pundit::NotAuthorizedError, aMessage||"You are not authorized to perform this action"
15
+ end
16
+
17
+ def self.allow_filter(aOptions=nil,&block)
18
+ aOptions = {all: true} if !aOptions
19
+ if rings = aOptions[:ring]
20
+ rings = [rings] unless rings.is_a? Array
21
+ aOptions[:ring] = rings.map {|r| Concentric.lookup_ring(r) }
22
+ end
23
+ if abilities = aOptions[:ability]
24
+ aOptions[:ability] = [abilities] unless abilities.is_a? Array
25
+ end
26
+ if block
27
+ self.filters ||= []
28
+ self.filters += [[aOptions,block]] # double brackets necessary to add an array into the array
29
+ end
30
+ end
31
+
32
+ # this could use an alternative field or method in future
33
+ def user_ring
34
+ user.ring
35
+ end
36
+
37
+ def apply_filters(aResult)
38
+ if self.class.filters
39
+ self.class.filters.each do |f|
40
+ options, handler = f
41
+ unless options[:all]
42
+ if rings = options[:ring]
43
+ next unless rings.include? user_ring
44
+ end
45
+ if abilities = options[:ability]
46
+ next unless abilities.include? @ability
47
+ end
48
+ end
49
+ aResult = handler.call(self, aResult.clone) # ring not necessary, use aPolicy.user.ring instead. aAbility not necessary, use aPolicy.ability
50
+ end
51
+ aResult.uniq!
52
+ aResult.sort!
53
+ end
54
+ aResult
55
+ end
56
+
57
+ def inner_query_fields(aAbility=nil)
58
+ aAbility = @ability = (aAbility || @ability)
59
+ raise "Ability must be set or given" unless aAbility
60
+ cls = record.is_a?(Class) ? record : record.class
61
+ result = cls.permitted(user_ring,aAbility)
62
+ result = apply_filters(result)
63
+ result
64
+ end
65
+
66
+ def permitted_attributes(aAbility=nil)
67
+ inner_query_fields(aAbility)
68
+ end
69
+
70
+ def permitted_fields(aAbility=nil)
71
+ result = inner_query_fields(aAbility)
72
+ cls = record.is_a?(Class) ? record : record.class
73
+ result.delete_if { |f| cls.reflections.has_key? f }
74
+ result
75
+ end
76
+
77
+ def permitted_associations(aAbility=nil)
78
+ result = inner_query_fields(aAbility)
79
+ cls = record.is_a?(Class) ? record : record.class
80
+ result.delete_if { |f| !cls.reflections.has_key? f }
81
+ result
82
+ end
83
+
84
+ def inner_query_ability(aAbility)
85
+ @ability = aAbility
86
+ inner_query_fields.length > 0
87
+ end
88
+
89
+ # kojac methods
90
+ def create?
91
+ inner_query_ability(:create)
92
+ end
93
+
94
+ def read?
95
+ inner_query_ability(:read)
96
+ end
97
+
98
+ def write?
99
+ inner_query_ability(:write)
100
+ end
101
+
102
+ def destroy?
103
+ inner_query_ability(:destroy)
104
+ end
105
+
106
+ # rails methods
107
+ def index?
108
+ inner_query_ability(:read)
109
+ end
110
+
111
+ def show?
112
+ inner_query_ability(:read)
113
+ end
114
+
115
+ def new?
116
+ inner_query_ability(:create)
117
+ end
118
+
119
+ def update?
120
+ inner_query_ability(:write)
121
+ end
122
+
123
+ def edit?
124
+ inner_query_ability(:write)
125
+ end
126
+
127
+ def scope
128
+ Pundit.policy_scope!(user, record.class)
129
+ end
130
+
131
+ end
@@ -1,154 +1,2 @@
1
- class KojacBasePolicy
2
-
3
- class_attribute :filters
4
-
5
- attr_reader :user, :record, :op
6
-
7
- def initialize(user, record, op=nil)
8
- raise Pundit::NotAuthorizedError, "must be logged in" unless user
9
- @user = user
10
- @record = record
11
- @op = op
12
- end
13
-
14
- def unauthorized!(aMessage=nil)
15
- raise Pundit::NotAuthorizedError, aMessage||"You are not authorized to perform this action"
16
- end
17
-
18
- def self.ability_from_op(aOp)
19
- return nil unless aOp
20
- case aOp[:verb]
21
- when 'CREATE'
22
- when 'UPDATE'
23
- :write
24
- when 'READ'
25
- :read
26
- when 'ADD'
27
- :add
28
- when 'REMOVE'
29
- :remove
30
- when 'CREATE_ON'
31
- :create_on
32
- end
33
- end
34
-
35
- def self.allow_filter(aOptions=nil,&block)
36
- aOptions = {all: true} if !aOptions
37
- if rings = aOptions[:ring]
38
- rings = [rings] unless rings.is_a? Array
39
- aOptions[:ring] = rings.map {|r| Concentric.lookup_ring(r) }
40
- end
41
- if abilities = aOptions[:ability]
42
- aOptions[:ability] = [abilities] unless abilities.is_a? Array
43
- end
44
- if block
45
- self.filters ||= []
46
- self.filters += [[aOptions,block]] # double brackets necessary to add an array into the array
47
- end
48
- end
49
-
50
- def query_ring
51
- user.ring
52
- end
53
-
54
- def apply_filters(aResult, aAbility)
55
- if self.class.filters
56
- self.class.filters.each do |f|
57
- options, handler = f
58
- unless options[:all]
59
- if rings = options[:ring]
60
- next unless rings.include? query_ring
61
- end
62
- if abilities = options[:ability]
63
- next unless abilities.include? aAbility
64
- end
65
- end
66
- aResult = handler.call(self, aResult.clone, query_ring, aAbility)
67
- end
68
- aResult.uniq!
69
- aResult.sort!
70
- end
71
- aResult
72
- end
73
-
74
- def inner_query_fields(aAbility)
75
- cls = record.is_a?(Class) ? record : record.class
76
- result = cls.permitted(query_ring,aAbility)
77
- result = apply_filters(result, aAbility)
78
- result
79
- end
80
-
81
- def inner_query_record(aAbility)
82
- inner_query_fields(aAbility).length > 0
83
- end
84
-
85
- def permitted_attributes(aAbility=nil)
86
- #raise "Ability from op no longer supported" if !aAbility && @op && @op[:verb]
87
- aAbility ||= self.class.ability_from_op(@op)
88
- raise "ability not given" unless aAbility
89
- fields = inner_query_fields(aAbility)
90
-
91
- #cls = record.is_a?(Class) ? record : record.class
92
- #fields = cls.permitted(query_ring,aAbility)
93
- #result = apply_filters(fields,aAbility)
94
- fields
95
- end
96
-
97
- def permitted_fields(aAbility=nil)
98
- result = permitted_attributes(aAbility)
99
- cls = record.is_a?(Class) ? record : record.class
100
- result.delete_if { |f| cls.reflections.has_key? f }
101
- result
102
- end
103
-
104
- def permitted_associations(aAbility=nil)
105
- result = permitted_attributes(aAbility)
106
- cls = record.is_a?(Class) ? record : record.class
107
- result.delete_if { |f| !cls.reflections.has_key? f }
108
- result
109
- end
110
-
111
- # kojac methods
112
- def create?
113
- inner_query_record(:create)
114
- end
115
-
116
- def read?
117
- inner_query_record(:read)
118
- end
119
-
120
- def write?
121
- inner_query_record(:write)
122
- end
123
-
124
- def destroy?
125
- inner_query_record(:destroy)
126
- end
127
-
128
- # rails methods
129
- def index?
130
- inner_query_record(:read)
131
- end
132
-
133
- def show?
134
- inner_query_record(:read)
135
- end
136
-
137
- def new?
138
- inner_query_record(:create)
139
- end
140
-
141
- def update?
142
- inner_query_record(:write)
143
- end
144
-
145
- def edit?
146
- inner_query_record(:write)
147
- end
148
-
149
- def scope
150
- Pundit.policy_scope!(user, record.class)
151
- end
152
-
1
+ class KojacBasePolicy < ConcentricPolicy
153
2
  end
154
-
@@ -1,3 +1,5 @@
1
+ require 'active_model/serializer'
2
+
1
3
  class KojacBaseSerializer < ActiveModel::Serializer
2
4
 
3
5
  self.root = false
@@ -10,7 +12,7 @@ class KojacBaseSerializer < ActiveModel::Serializer
10
12
 
11
13
  def attributes
12
14
  attrs = nil
13
- source = if policy = Kojac::policy(scope,object)
15
+ source = if policy = Pundit::policy(scope,object)
14
16
  attrs = policy.permitted_attributes(:read).map(&:to_s)
15
17
  object.attributes
16
18
  elsif object.respond_to? :attributes
data/kojac.gemspec CHANGED
@@ -28,7 +28,8 @@ Gem::Specification.new do |s|
28
28
 
29
29
  #s.add_runtime_dependency "jquery-rails"
30
30
  #s.add_runtime_dependency "rails", ">= 3.1"
31
- # s.add_development_dependency "rspec-rails"
31
+ s.add_development_dependency "rake"
32
+ s.add_development_dependency "rspec"
32
33
  # s.add_development_dependency "canjs-rails"
33
34
  # s.add_development_dependency "ember-rails"
34
35
  # s.add_development_dependency "jquery-rails"
@@ -33,7 +33,20 @@
33
33
  #
34
34
  #end
35
35
 
36
-
36
+ # Update: 2015-03-26
37
+ #
38
+ # * Extracted ConcentricPolicy from Kojac
39
+ # * Concentric is now a way of creating Pundit policies based on ConcentricPolicy. It allows shorthand ring security for
40
+ # simple scenarios, then allow_filter for refinement and arbitrary complex logic to be implemented
41
+ # * Concentric works on the simple idea that there are 4 basic abilities: read, write, create and delete.
42
+ # * Read and write apply primarily to fields; create and delete apply to records.
43
+ # * Creating a record requires the ability to create the record, then normally you require the ability to write some fields.
44
+ # * In order to read a record, you need the ability to read at least one field
45
+ # * In order to write to a record, you need the ability to write at least one field
46
+ # * In order to delete a record, you need the ability to delete the record
47
+ # * With Concentric you first use the ring and
48
+ #
49
+ # implement Pundit Policy classes and methods (eg. update? show?) by querying these 4 abilities
37
50
 
38
51
  class Concentric
39
52
 
@@ -67,29 +80,29 @@ module Concentric::Model
67
80
 
68
81
  def self.included(aClass)
69
82
  aClass.cattr_accessor :rings_abilities
70
- aClass.rings_abilities = [] # [1] => {read: [:name,:address], delete: true}
83
+ aClass.rings_abilities = {} # [1] => {read: [:name,:address], delete: true}
71
84
  aClass.send :extend, ClassMethods
72
85
  end
73
86
 
74
87
  module ClassMethods
75
88
 
76
89
  # supports different formats :
77
- # ring :sales, :write => [:name,:address] ie. sales can write the name and address fields
78
- # ring :sales, :read ie. sales can read this model
79
- # ring :sales, [:read, :create, :destroy] ie. sales can read, create and destroy this model
80
- def ring(aRing,aAbilities)
90
+ # allow :sales, :write => [:name,:address] ie. sales can write the name and address fields
91
+ # allow :sales, :read ie. sales can read this model
92
+ # allow :sales, [:read, :create, :destroy] ie. sales can read, create and destroy this model
93
+ def allow(aRing,aAbilities)
81
94
  #aRing.each {|r| ring(r,aAbilities)} and return if aRing.is_a? Array shouldn't need this because of ring system
82
95
  aRing = Concentric.lookup_ring(aRing)
83
96
  raise "aRing must be a number or a symbol defined in Concentric.config.ring_names" if !aRing.is_a?(Fixnum)
84
97
  raise "aAbilities must be a Hash" unless aAbilities.is_a? Hash # eg. :write => [:name,:address]
85
98
 
86
99
  ring_rec = self.rings_abilities[aRing]
87
- aAbilities.each do |abilities,fields|
88
- abilities = [abilities] unless abilities.is_a?(Array)
89
- fields = [fields] unless fields.is_a?(Array)
100
+ aAbilities.each do |abilities, fields|
101
+ abilities = [abilities] unless abilities.is_a?(Array)
102
+ fields = [fields] unless fields.is_a?(Array)
90
103
  next if fields.empty?
91
- abilities.each do |a|
92
- a = a.to_sym
104
+ abilities.each do |a|
105
+ a = a.to_sym
93
106
  ring_rec ||= {}
94
107
  if fields==[:this]
95
108
  ring_rec[a] = true unless ring_rec[a].to_nil
@@ -106,6 +119,11 @@ module Concentric::Model
106
119
  end
107
120
  end
108
121
 
122
+ # deprecated
123
+ def ring(aRing,aAbilities)
124
+ allow(aRing,aAbilities)
125
+ end
126
+
109
127
  # returns properties that this ring can use this ability on
110
128
  def permitted(aRing,aAbility)
111
129
  aRing = Concentric.lookup_ring(aRing)
@@ -113,7 +131,9 @@ module Concentric::Model
113
131
  return [] unless aRing and rings_abilities = self.respond_to?(:rings_abilities) && self.rings_abilities.to_nil
114
132
 
115
133
  fields = []
116
- aRing.upto(rings_abilities.length-1) do |i|
134
+ ring_keys = rings_abilities.keys.sort
135
+ ring_keys.each do |i|
136
+ next unless i >= aRing
117
137
  next unless ring_rec = rings_abilities[i]
118
138
  if af = ring_rec[aAbility.to_sym]
119
139
  next if af==true
@@ -128,7 +148,7 @@ module Concentric::Model
128
148
  # Query
129
149
  # aFields specifies fields you require to act on
130
150
  # This is no longer used by KojacBasePolicy because it does not observe its filters that operate on fields. It may still provide a faster check when there are no filters applied
131
- def ring_can?(aRing,aAbility,aFields=nil)
151
+ def allowed?(aRing,aAbility,aFields=nil)
132
152
  if aFields
133
153
  pf = permitted(aRing,aAbility)
134
154
  if aFields.is_a? Array
@@ -141,13 +161,20 @@ module Concentric::Model
141
161
  aRing = Concentric.lookup_ring(aRing)
142
162
  return [] unless aRing and rings_abilities = self.respond_to?(:rings_abilities).to_nil && self.rings_abilities
143
163
 
144
- aRing.upto(rings_abilities.length-1) do |i|
164
+ ring_keys = rings_abilities.keys.sort
165
+ ring_keys.each do |i|
166
+ next unless i >= aRing
145
167
  next unless ring_rec = rings_abilities[i]
146
168
  return true if ring_rec[aAbility.to_sym].to_nil
147
169
  end
148
170
  return false
149
171
  end
150
172
 
173
+ # deprecated
174
+ def ring_can?(aRing,aAbility,aFields=nil)
175
+ allowed?(aRing,aAbility,aFields)
176
+ end
177
+
151
178
  end
152
179
 
153
180
  end
@@ -0,0 +1,7 @@
1
+ module Kojac
2
+ class KojacController
3
+ include ::Kojac::ControllerOpMethods
4
+
5
+ attr_accessor :op, :options, :verb, :key, :value, :error, :params, :current_user
6
+ end
7
+ end