kojac 0.13.0 → 0.15.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 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