Skip to content

Commit

Permalink
Merge 0a14289 into d90499d
Browse files Browse the repository at this point in the history
  • Loading branch information
vjt committed Jul 26, 2017
2 parents d90499d + 0a14289 commit afe29a6
Show file tree
Hide file tree
Showing 25 changed files with 344 additions and 125 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ gemfiles/*.gemfile.lock
_yardoc
coverage
doc/
features/active_record.yml
features/active_record.mysql.yml
features/active_record.pgsql.yml
features/active_record.log
lib/bundler/man
pkg
Expand Down
11 changes: 6 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ rvm:
- 2.3.1

gemfile:
- gemfiles/rails_3.2.gemfile
- gemfiles/rails_4.0.gemfile
- gemfiles/rails_4.1.gemfile
- gemfiles/rails_4.2.gemfile
- gemfiles/rails_5.0.gemfile
- gemfiles/rails_3.2_pg.gemfile
- gemfiles/rails_4.0_pg.gemfile
- gemfiles/rails_4.1_pg.gemfile
- gemfiles/rails_4.2_pg.gemfile
- gemfiles/rails_5.0_pg.gemfile
- gemfiles/rails_4.2_mysql.gemfile

matrix:
exclude:
Expand Down
18 changes: 14 additions & 4 deletions Appraisals
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
# Test against 3.2 -> 4.2
#
appraise 'rails-3.2' do
appraise 'rails-3.2-pg' do
gem 'rails', '~> 3.2.0'
gem 'pg'
gem 'activerecord-postgres-json'
end

appraise 'rails-4.0' do
appraise 'rails-4.0-pg' do
gem 'rails', '~> 4.0.0'
gem 'pg'
end

appraise 'rails-4.1' do
appraise 'rails-4.1-pg' do
gem 'rails', '~> 4.1.0'
gem 'pg'
end

appraise 'rails-4.2' do
appraise 'rails-4.2-pg' do
gem 'rails', '~> 4.2.0'
gem 'pg'
end

appraise 'rails-5.0-pg' do
gem 'rails', '~> 5.0.0'
gem 'pg'
end

appraise 'rails-4.2-mysql' do
gem 'rails', '~> 4.2.0'
gem 'mysql'
end
2 changes: 0 additions & 2 deletions eaco.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,4 @@ Gem::Specification.new do |spec|
spec.add_development_dependency "yard-cucumber"
spec.add_development_dependency "coveralls"
spec.add_development_dependency "guard-shell"
spec.add_development_dependency "rails"
spec.add_development_dependency "pg"
end
6 changes: 3 additions & 3 deletions features/authorization_parse_error.feature
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ Feature: Authorization rules error handling
Scenario: Authorizing a Resource with a known ORM but without the acl field
When I have a wrong authorization definition on model Department such as
"""
authorize $MODEL
authorize $MODEL, using: :pg_jsonb
"""
Then I should receive a DSL error Eaco::Error saying
"""
Expand All @@ -126,7 +126,7 @@ Feature: Authorization rules error handling
"""
Then I should receive a DSL error Eaco::Error saying
"""
.+Document.+ORM.+ActiveRecord::Base.+ use one of the available strategies: pg_jsonb
.+Document.+ORM.+ActiveRecord::Base.+ use one of the available strategies: pg_jsonb, mysql_json
"""

Scenario: Authorizing a Resource with the wrong ACL column type
Expand All @@ -138,7 +138,7 @@ Feature: Authorization rules error handling
end
end
authorize ::Grabach
authorize ::Grabach, using: :pg_jsonb
"""
Then I should receive a DSL error Eaco::Error saying
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ source "https://rubygems.org"

gem "rails", "~> 3.2.0"
gem "pg"
gem "activerecord-postgres-json", :require => false
gem "activerecord-postgres-json"

gemspec :path => "../"
File renamed without changes.
File renamed without changes.
8 changes: 8 additions & 0 deletions gemfiles/rails_4.2_mysql.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# This file was generated by Appraisal

source "https://rubygems.org"

gem "rails", "~> 4.2.0"
gem "mysql"

gemspec :path => "../"
File renamed without changes.
File renamed without changes.
21 changes: 6 additions & 15 deletions lib/eaco/adapters/active_record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ module Adapters
#
module ActiveRecord
autoload :PostgresJSONb, 'eaco/adapters/active_record/postgres_jsonb'
autoload :MySQLJSON, 'eaco/adapters/active_record/mysql_json'

autoload :Compatibility, 'eaco/adapters/active_record/compatibility'

##
Expand All @@ -17,31 +19,20 @@ module ActiveRecord
# @return Hash
#
def self.strategies
{:pg_jsonb => PostgresJSONb}
{
:pg_jsonb => PostgresJSONb,
:mysql_json => MySQLJSON,
}
end

##
# Checks whether the model's data structure fits the ACL persistance
# requirements.
#
# @param base [Class] your application's model
#
# @return void
#
def self.included(base)
Compatibility.new(base).check!

return unless base.table_exists?

column = base.columns_hash.fetch('acl', nil)

unless column
raise Malformed, "Please define a jsonb column named `acl` on #{base}."
end

unless column.type == :json || column.type == :jsonb
raise Malformed, "The `acl` column on #{base} must be of the jsonb type."
end
end

##
Expand Down
16 changes: 1 addition & 15 deletions lib/eaco/adapters/active_record/compatibility/v32.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,8 @@ module Adapters
module ActiveRecord
class Compatibility

##
# Rails 3.2 JSONB support module.
#
# Uses https://github.com/romanbsd/activerecord-postgres-json to do
# the dirty compatibility stuff. This module only uses +.serialize+
# to set the +JSON+ coder.
#
module V32
require 'activerecord-postgres-json'

##
# Sets the JSON coder on the acl column
#
def self.included(base)
base.serialize :acl, ::ActiveRecord::Coders::JSON
end
# Is supported. Nothing to add.
end

end
Expand Down
54 changes: 0 additions & 54 deletions lib/eaco/adapters/active_record/compatibility/v40.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,64 +3,10 @@ module Adapters
module ActiveRecord
class Compatibility

##
# Rails v4.0.X compatibility layer for jsonb
#
module V40
##
#
# Sets up the OID Type Map, reloads it, hacks native database types,
# and makes jsonb mimick itself as a json - for the rest of the AR
# machinery to work intact.
#
# @param base [Class] the +ActiveRecord+ model to mangle
# @return [void]
#
def self.included(base)
adapter = base.connection

adapter.class::OID.register_type 'jsonb', adapter.class::OID::Json.new
adapter.send :reload_type_map

adapter.native_database_types.update(jsonb: {name: 'jsonb'})

adapter.class.parent::PostgreSQLColumn.instance_eval do
include Column
end

base.extend Scoped
end

##
# Patches to ActiveRecord::ConnectionAdapters::PostgreSQLColumn
#
module Column
##
# Makes +sql_type+ return +json+ for +jsonb+ columns. This is
# an hack to let the casting machinery in AR 4.0 keep working
# with the unsupported +jsonb+ type.
#
# @return [String] the SQL type.
#
def sql_type
orig_type = super
orig_type == 'jsonb' ? 'json' : orig_type
end

##
# Makes +simplified_type+ return +json+ for +jsonb+ columns
#
# @param field_type [String] the database field type
# @return [Symbol] the simplified type
#
def simplified_type(field_type)
if field_type == 'jsonb'
:json
else
super
end
end
end
end

end
Expand Down
7 changes: 1 addition & 6 deletions lib/eaco/adapters/active_record/compatibility/v41.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,15 @@ module ActiveRecord
class Compatibility

##
# Rails 4.1 support module.
#
# Magically, the 4.0 hacks work on 4.1. But on 4.1 we need the
# +.scoped+ API so we revive it through the {Scoped} module.
# Rails 4.1 support module - same as 4.0.
#
# @see V40
# @see Scoped
#
module V41
extend ActiveSupport::Concern

included do
include V40
extend Scoped
end
end

Expand Down
60 changes: 60 additions & 0 deletions lib/eaco/adapters/active_record/mysql_json.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
module Eaco
module Adapters
module ActiveRecord

##
# Authorized collection extractor on MySQL >= 5.7 and a +json+
# column named +acl+.
#
# TODO negative authorizations (using a separate column?)
#
# @see ACL
# @see Actor
# @see Resource
#
module MySQLJSON

##
# Uses +JSON_CONTAINS_PATH()+ to check whether one of the +Actor+'s
# +Designator+ instances exist as keys in the +ACL+ object.
#
# @param actor [Actor]
#
# @return [ActiveRecord::Relation] the authorized collection scope.
#
def accessible_by(actor)
return scoped if actor.is_admin?

designators = actor.designators.map {|d| sanitize("$.#{d}") }

column = "#{connection.quote_table_name(table_name)}.acl"

where("JSON_CONTAINS_PATH(#{column}, 'one', #{designators.join(',')})")
end

##
# Checks whether the model's data structure fulfills
# the ACL persistance requirements.
#
def self.validate!(model)
return unless model.table_exists?

column = model.columns_hash.fetch('acl', nil)

unless column
raise Malformed, "Please define a json column named `acl` on #{model}."
end

unless column.type == required_column_type
raise Malformed, "The `acl` column on #{model} must be of the JSON type - found: #{column.type}."
end
end

def self.required_column_type
:json
end
end

end
end
end
25 changes: 25 additions & 0 deletions lib/eaco/adapters/active_record/postgres_jsonb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ module ActiveRecord
# @see Resource
#
module PostgresJSONb
autoload :Compatibility, 'eaco/adapters/active_record/postgres_jsonb/compatibility'

##
# Uses the json key existance operator +?|+ to check whether one of the
Expand All @@ -31,6 +32,30 @@ def accessible_by(actor)

where("#{column} ?| array[#{designators.join(',')}]::varchar[]")
end

##
# Checks whether the model's AR version is supported and the ACL
# data structure fulfills the ACL persistance requirements.
#
def self.validate!(model)
Compatibility.new(model).check!

return unless model.table_exists?

column = model.columns_hash.fetch('acl', nil)

unless column
raise Malformed, "Please define a jsonb column named `acl` on #{model}."
end

unless column.type == required_column_type
raise Malformed, "The `acl` column on #{model} must be of the jsonb type - found: #{column.type}."
end
end

def self.required_column_type
:jsonb
end
end

end
Expand Down
15 changes: 15 additions & 0 deletions lib/eaco/adapters/active_record/postgres_jsonb/compatibility.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module Eaco
module Adapters
module ActiveRecord
module PostgresJSONb
class Compatibility < Eaco::Adapters::ActiveRecord::Compatibility
autoload :V32, 'eaco/adapters/active_record/postgres_jsonb/compatibility/v32.rb'
autoload :V40, 'eaco/adapters/active_record/postgres_jsonb/compatibility/v40.rb'
autoload :V41, 'eaco/adapters/active_record/postgres_jsonb/compatibility/v41.rb'
autoload :V42, 'eaco/adapters/active_record/postgres_jsonb/compatibility/v42.rb'
autoload :V50, 'eaco/adapters/active_record/postgres_jsonb/compatibility/v50.rb'
end
end
end
end
end

0 comments on commit afe29a6

Please sign in to comment.