lib/kojac/kojac_rails.rb in kojac-0.13.0 vs lib/kojac/kojac_rails.rb in kojac-0.15.0
- old
+ new
@@ -211,33 +211,21 @@
public
def results
@results ||= {}
end
-
- def deduce_model_class
- KojacUtils.model_class_for_key(self.kojac_resource)
- end
-
- def kojac_resource
- self.class.to_s.chomp('Controller').snake_case
- end
-
- def kojac_current_user
- self.current_user
- end
-
+
def current_ring
- kojac_current_user.try(:ring).to_i
+ current_user.try(:ring).to_i
end
def create_on_association(aItem,aAssoc,aValues,aRing)
raise "User does not have permission for create on #{aAssoc}" unless aItem.class.ring_can?(aRing,:create_on,aAssoc.to_sym)
return nil unless ma = aItem.class.reflect_on_association(aAssoc.to_sym)
a_model_class = ma.klass
- policy = Kojac.policy!(kojac_current_user,a_model_class)
+ policy = Pundit.policy!(current_user,a_model_class)
aValues = KojacUtils.upgrade_hashes_to_params(aValues || {})
case ma.macro
when :belongs_to
@@ -275,75 +263,112 @@
#else
# next
#end
end
+ # Unknown resource :
+ # CREATE: already there with given id => error
+ # READ: isn't there, or we don't have access => nil
+ # UPDATE: isn't there, or we don't have access => nil
+ # DESTROY: isn't there, or we don't have access => nil
+
def create_op
ring = current_ring
- op = params[:op]
+ op = (self.respond_to?(:op) && self.op || params[:op])
+ #op = params[:op] unless self.respond_to? :op
options = op[:options] || {}
- model_class = deduce_model_class
resource,id,assoc = op['key'].split_kojac_key
- if assoc # create operation on an association eg. {verb: "CREATE", key: "order.items"}
- raise "User does not have permission for #{op[:verb]} operation on #{model_class.to_s}.#{assoc}" unless model_class.ring_can?(ring,:create_on,assoc.to_sym)
- item = KojacUtils.model_for_key(key_join(resource,id))
- ma = model_class.reflect_on_association(assoc.to_sym)
- a_value = op[:value] # get data for this association, assume {}
- raise "create multiple not yet implemented for associations" unless a_value.is_a?(Hash)
+ if model_class = KojacUtils.model_class_for_key(resource)
+ if assoc # create operation on an association eg. {verb: "CREATE", key: "order.items"}
+ if model_class.ring_can?(ring,:create_on,assoc.to_sym)
+ item = KojacUtils.model_for_key(key_join(resource,id))
+ ma = model_class.reflect_on_association(assoc.to_sym)
+ a_value = op[:value] # get data for this association, assume {}
+ raise "create multiple not yet implemented for associations" unless a_value.is_a?(Hash)
- a_model_class = ma.klass
- policy = Kojac.policy!(kojac_current_user,a_model_class)
- p_fields = policy.permitted_fields(:write)
- fields = a_value.permit( *p_fields )
- new_sub_item = nil
- case ma.macro
- when :has_many
- a_model_class.write_op_filter(current_user,fields,a_value) if a_model_class.respond_to? :write_op_filter
- new_sub_item = item.send(assoc.to_sym).create(fields)
+ a_model_class = ma.klass
+ policy = Pundit.policy!(current_user,a_model_class)
+ p_fields = policy.permitted_fields(:write)
+ fields = a_value.permit( *p_fields )
+ new_sub_item = nil
+ case ma.macro
+ when :has_many
+ a_model_class.write_op_filter(current_user,fields,a_value) if a_model_class.respond_to? :write_op_filter
+ new_sub_item = item.send(assoc.to_sym).create(fields)
+ else
+ raise "#{ma.macro} association unsupported in CREATE"
+ end
+ result_key = op[:result_key] || new_sub_item.kojac_key
+ merge_model_into_results(new_sub_item)
else
- raise "#{ma.macro} association unsupported in CREATE"
- end
- result_key = op[:result_key] || new_sub_item.kojac_key
- merge_model_into_results(new_sub_item)
- else # create operation on a resource eg. {verb: "CREATE", key: "order_items"} but may have embedded association values
- raise "User does not have permission for #{op[:verb]} operation on #{model_class.to_s}" unless model_class.ring_can?(:create,ring)
- policy = Kojac.policy!(kojac_current_user,model_class)
- p_fields = policy.permitted_fields(:write)
+ error = {
+ code: 403,
+ status: "Forbidden",
+ message: "User does not have permission for #{op[:verb]} operation on #{model_class.to_s}.#{assoc}"
+ }
+ end
+ else # create operation on a resource eg. {verb: "CREATE", key: "order_items"} but may have embedded association values
+ if model_class.ring_can?(:create,ring)
+ policy = Pundit.policy!(current_user,model_class)
+ p_fields = policy.permitted_fields(:write)
- p_fields = op[:value].permit( *p_fields )
- model_class.write_op_filter(current_user,p_fields,op[:value]) if model_class.respond_to? :write_op_filter
- item = model_class.create!(p_fields)
+ p_fields = op[:value].permit( *p_fields )
+ model_class.write_op_filter(current_user,p_fields,op[:value]) if model_class.respond_to? :write_op_filter
+ item = model_class.create!(p_fields)
- options_include = options['include'] || []
- included_assocs = []
- p_assocs = policy.permitted_associations(:write)
- if p_assocs
- p_assocs.each do |a|
- next unless (a_value = op[:value][a]) || options_include.include?(a.to_s)
- create_on_association(item,a,a_value,ring)
- included_assocs << a.to_sym
+ options_include = options['include'] || []
+ included_assocs = []
+ p_assocs = policy.permitted_associations(:write)
+ if p_assocs
+ p_assocs.each do |a|
+ next unless (a_value = op[:value][a]) || options_include.include?(a.to_s)
+ create_on_association(item,a,a_value,ring)
+ included_assocs << a.to_sym
+ end
+ end
+ item.save!
+ result_key = op[:result_key] || item.kojac_key
+ merge_model_into_results(item,result_key,:include => included_assocs)
+ else
+ error = {
+ code: 403,
+ status: "Forbidden",
+ message: "User does not have permission for #{op[:verb]} operation on #{model_class.to_s}"
+ }
end
end
- item.save!
- result_key = op[:result_key] || item.kojac_key
- merge_model_into_results(item,result_key,:include => included_assocs)
+ else
+ error = {
+ code: 501,
+ status: "Not Implemented",
+ message: "model class not found"
+ }
end
- {
+ response = {
key: op[:key],
verb: op[:verb],
- result_key: result_key,
- results: results
}
+ if error
+ response[:error] = error
+ else
+ response[:results] = results
+ response[:result_key] = result_key
+ end
+ response
end
protected
+ def rails_controller?
+ self.is_a? ActionController::Base
+ end
+
def merge_model_into_results(aItem,aResultKey=nil,aOptions=nil)
ring = current_ring
- aResultKey ||= aItem.g? :kojac_key
- results[aResultKey] = (aItem && KojacUtils.to_jsono(aItem,scope: kojac_current_user))
- if policy = Kojac.policy!(kojac_current_user,aItem)
+ aResultKey ||= aItem.g?(:kojac_key)
+ results[aResultKey] = (aItem && KojacUtils.to_jsono(aItem,scope: current_user))
+ if policy = Pundit.policy!(current_user,aItem)
aOptions ||= {}
if included_assocs = aOptions[:include]
included_assocs = included_assocs.split(',') if included_assocs.is_a?(String)
included_assocs = [included_assocs] unless included_assocs.is_a?(Array)
included_assocs.map!(&:to_sym) if included_assocs.is_a?(Array)
@@ -358,113 +383,140 @@
use_assocs.each do |a|
next unless a_contents = aItem.send(a)
if a_contents.is_a? Array
contents_h = []
a_contents.each do |sub_item|
- results[sub_item.kojac_key] = KojacUtils.to_jsono(sub_item,scope: kojac_current_user)
+ results[sub_item.kojac_key] = KojacUtils.to_jsono(sub_item,scope: current_user)
end
else
- results[a_contents.kojac_key] = KojacUtils.to_jsono(a_contents,scope: kojac_current_user)
+ results[a_contents.kojac_key] = KojacUtils.to_jsono(a_contents,scope: current_user)
end
end
end
end
results_insert_filter(results,aItem,aResultKey,aOptions) if respond_to?(:results_insert_filter)
results
end
+
public
+ def kojac_setup(aCurrentUser,aOp)
+ self.current_user = aCurrentUser if self.respond_to? :current_user
+ self.op = aOp if self.respond_to? :op
+ self.verb = aOp['verb'] if self.respond_to? :verb
+ self.key = aOp['key'] if self.respond_to? :key
+ self.value = aOp['value'] if self.respond_to? :value
+ self.params = aOp['params'] || {} if self.respond_to? :params
+ self.options = aOp['options'] || {} if self.respond_to? :options
+ self.error = aOp['error'] if self.respond_to? :error
+ self
+ end
+
def read_op
- op = params[:op]
+ op = (self.respond_to?(:op) && self.op || params[:op])
key = op[:key]
result_key = nil
+ error = nil
resource,id = key.split '__'
- model = deduce_model_class
- scope = Kojac.policy_scope(current_user, model, op) || model
- if id # item
- if scope
- item = scope.load_by_key(key,op)
- #item = item.first
- #item.prepare(key,op) if item.respond_to? :prepare
- result_key = op[:result_key] || (item && item.kojac_key) || op[:key]
- merge_model_into_results(item,result_key,op[:options])
- else
- result_key = op[:result_key] || op[:key]
- results[result_key] = null
- end
- else # collection
- result_key = op[:result_key] || op[:key]
- results[result_key] = []
- if scope
- items = scope
- items = send(:after_scope,items,op) if respond_to? :after_scope
- items = items.load_by_key(key,op)
- #items = scope.by_key(key,op)
- #items = items.all
- items.each do |item|
- item.prepare(key,op) if item.respond_to? :prepare
+ model = KojacUtils.model_class_for_key(key)
+ #raise "model class not found" unless
+ if scope = Pundit.policy_scope(current_user, model) || model
+ if id # item
+ scope = scope.where(id: id)
+ scope = after_scope(scope) if respond_to?(:after_scope)
+ if item = scope.first
+ #item.prepare(key,op) if item.respond_to? :prepare
+ result_key = op[:result_key] || (item && item.kojac_key) || op[:key]
+ merge_model_into_results(item,result_key,op[:options])
+ else
+ result_key = op[:result_key] || op[:key]
+ results[result_key] = nil
end
+ else # collection
+ if rails_controller? # deprecated
+ items = scope.respond_to?(:all) ? scope.all : scope.to_a
+ result_key = op[:result_key] || op[:key]
+ results[result_key] = []
+ items = after_scope(items) if respond_to?(:after_scope)
+ else
+ scope = after_scope(scope) if respond_to?(:after_scope)
+ items = scope.respond_to?(:all) ? scope.all : scope.to_a
+ result_key = op[:result_key] || op[:key]
+ results[result_key] = []
+ end
if op[:options] and op[:options][:atomise]==false
items_json = []
- items_json = items.map {|i| KojacUtils.to_jsono(i,scope: kojac_current_user) }
+ items_json = items.map {|i| KojacUtils.to_jsono(i,scope: current_user) }
results[result_key] = items_json
else
items.each do |m|
item_key = m.kojac_key
results[result_key] << item_key.split_kojac_key[1]
merge_model_into_results(m,item_key,op[:options])
end
end
end
+ else
+ error = {
+ code: 501,
+ status: "Not Implemented",
+ message: "model class not found"
+ }
end
- {
+ response = {
key: op[:key],
verb: op[:verb],
- results: results,
- result_key: result_key
}
+ if error
+ response[:error] = error
+ else
+ response[:results] = results
+ response[:result_key] = result_key
+ end
+ response
end
def update_op
result = nil
ring = current_ring
- op = params[:op]
+ op = (self.respond_to?(:op) && self.op || params[:op])
result_key = nil
- model = deduce_model_class
- scope = Kojac.policy_scope(current_user, model, op) || model
-
- if item = scope.load_by_key(op[:key],op)
-
+ model = KojacUtils.model_class_for_key(op[:key].base_key)
+ scope = Pundit.policy_scope(current_user, model) || model
+ scope = after_scope(scope) if scope && respond_to?(:after_scope)
+ if scope and item = scope.load_by_key(op[:key],op)
#run_callbacks :update_op do
- policy = Kojac.policy!(kojac_current_user,item,op)
+ policy = Pundit.policy!(current_user,item)
item.update_permitted_attributes!(op[:value], policy)
associations = policy.permitted_associations(:write)
associations.each do |k|
next unless assoc = model.reflect_on_association(k)
next unless op[:value][k]
case assoc.macro
when :belongs_to
if leaf = (item.send(k) || item.send("build_#{k}".to_sym))
- policy = Kojac.policy!(kojac_current_user,leaf)
+ policy = Pundit.policy!(current_user,leaf)
leaf.update_permitted_attributes!(op[:value][k], policy)
end
end
end
- result_key = item.kojac_key
- #results[result_key] = item
+ result_key = op[:result_key] || (item && item.kojac_key) || op[:key]
merge_model_into_results(item,result_key,op[:options])
associations.each do |a|
next unless assoc_item = item.send(a)
next unless key = assoc_item.respond_to?(:kojac_key) && assoc_item.kojac_key
#results[key] = assoc_item
merge_model_into_results(assoc_item,key)
end
#end
+ else
+ result_key = op[:result_key] || op[:key]
+ results[result_key] = nil
end
{
key: op[:key],
verb: op[:verb],
result_key: result_key,
@@ -472,14 +524,23 @@
}
end
def destroy_op
ring = current_ring
- op = params[:op]
+ op = (self.respond_to?(:op) && self.op || params[:op])
result_key = op[:result_key] || op[:key]
- item = KojacUtils.model_for_key(op[:key])
- item.destroy if item
+ # item = KojacUtils.model_for_key(op[:key])
+ # item.destroy if item
+ r,id,a = op[:key].split_kojac_key
+
+ if id
+ model = KojacUtils.model_class_for_key(op[:key].base_key)
+ scope = Pundit.policy_scope(current_user, model) || model
+ scope = after_scope(scope) if scope && respond_to?(:after_scope)
+ item = scope.where(id: id).first
+ item.destroy if item
+ end
results[result_key] = nil
{
key: op[:key],
verb: op[:verb],
result_key: result_key,
@@ -491,12 +552,12 @@
# puts 'execute_op'
#end
def add_op
ring = current_ring
- op = params[:op]
- model = deduce_model_class
+ op = (self.respond_to?(:op) && self.op || params[:op])
+ model = KojacUtils.model_class_for_key(op[:key].base_key)
raise "ADD only supports associated collections at present eg order.items" unless op[:key].index('.')
item = KojacUtils.model_for_key(op[:key].base_key)
assoc = (assoc=op[:key].key_assoc) && assoc.to_sym
id = op[:value]['id']
@@ -524,12 +585,12 @@
}
end
def remove_op
ring = current_ring
- op = params[:op]
- model = deduce_model_class
+ op = (self.respond_to?(:op) && self.op || params[:op])
+ model = KojacUtils.model_class_for_key(op[:key].base_key)
raise "REMOVE only supports associated collections at present eg order.items" unless op[:key].key_assoc
item = KojacUtils.model_for_key(op[:key].base_key)
assoc = (assoc=op[:key].key_assoc) && assoc.to_sym
id = op[:value]['id']
@@ -557,25 +618,26 @@
results: results
}
end
def execute_op
- op = params[:op]
+ op = (self.respond_to?(:op) && self.op || params[:op])
resource,action = op[:key].split_kojac_key
raise "action not given" unless action.is_a? String
- action = "execute_#{action}"
+ action = rails_controller? ? "execute_#{action}" : "execute__#{action}"
raise "action #{action} not implemented on #{resource}" unless respond_to? action.to_sym
- result = send(action.to_sym,op)
- if op[:error]
+ result = rails_controller? ? send(action.to_sym,op) : send(action)
+ error = rails_controller? ? op[:error] : (respond_to?(:error).to_nil && send(:error))
+ if error
{
key: op[:key],
verb: op[:verb],
- error: op[:error]
+ error: error
}
else
result_key = op[:result_key] || op[:key]
results = op[:results] || {} # look at op[:results][result_key]. If empty, fill with returned value from action
- results[result_key] = KojacUtils.to_jsono(result,scope: kojac_current_user) unless results.has_key? result_key
+ results[result_key] = KojacUtils.to_jsono(result,scope: current_user) unless results.has_key? result_key
{
key: op[:key],
verb: op[:verb],
result_key: result_key,
results: results
\ No newline at end of file