eaco 0.6.1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -3
- data/features/authorization_parse_error.feature +157 -0
- data/features/enterprise_authorization.feature +159 -0
- data/features/rails_integration.feature +1 -1
- data/features/role_based_authorization.feature +30 -7
- data/features/step_definitions/actor_steps.rb +29 -25
- data/features/step_definitions/enterprise_steps.rb +81 -0
- data/features/step_definitions/error_steps.rb +49 -0
- data/features/step_definitions/fixture_steps.rb +14 -0
- data/features/step_definitions/resource_steps.rb +16 -24
- data/features/support/env.rb +4 -2
- data/lib/eaco.rb +2 -0
- data/lib/eaco/actor.rb +4 -3
- data/lib/eaco/adapters/active_record.rb +1 -1
- data/lib/eaco/adapters/active_record/compatibility.rb +19 -14
- data/lib/eaco/adapters/active_record/compatibility/scoped.rb +25 -0
- data/lib/eaco/adapters/active_record/compatibility/v40.rb +11 -3
- data/lib/eaco/adapters/active_record/compatibility/v41.rb +14 -3
- data/lib/eaco/adapters/active_record/compatibility/v42.rb +10 -2
- data/lib/eaco/controller.rb +16 -3
- data/lib/eaco/coverage.rb +83 -0
- data/lib/eaco/cucumber/active_record.rb +13 -18
- data/lib/eaco/cucumber/active_record/department.rb +4 -0
- data/lib/eaco/cucumber/active_record/position.rb +2 -0
- data/lib/eaco/cucumber/active_record/schema.rb +20 -2
- data/lib/eaco/cucumber/active_record/user.rb +9 -0
- data/lib/eaco/cucumber/active_record/user/designators.rb +4 -1
- data/lib/eaco/cucumber/active_record/user/designators/authenticated.rb +54 -0
- data/lib/eaco/cucumber/active_record/user/designators/department.rb +58 -0
- data/lib/eaco/cucumber/active_record/user/designators/position.rb +53 -0
- data/lib/eaco/cucumber/active_record/user/designators/user.rb +4 -0
- data/lib/eaco/cucumber/world.rb +115 -5
- data/lib/eaco/designator.rb +7 -2
- data/lib/eaco/dsl.rb +9 -1
- data/lib/eaco/dsl/acl.rb +2 -2
- data/lib/eaco/dsl/actor.rb +6 -3
- data/lib/eaco/dsl/base.rb +5 -0
- data/lib/eaco/error.rb +10 -1
- data/lib/eaco/rake.rb +1 -0
- data/lib/eaco/rake/default_task.rb +29 -9
- data/lib/eaco/rake/utils.rb +38 -0
- data/lib/eaco/version.rb +1 -1
- data/spec/eaco/acl_spec.rb +34 -0
- data/spec/spec_helper.rb +3 -3
- metadata +18 -2
data/lib/eaco/controller.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
begin
|
2
2
|
require 'active_support/concern'
|
3
3
|
rescue LoadError
|
4
|
-
# This is falsely true during specs ran by Guard. FIXME.
|
4
|
+
# :nocov: This is falsely true during specs ran by Guard. FIXME.
|
5
5
|
abort 'Eaco::Controller requires activesupport. Please add it to Gemfile.'
|
6
|
+
# :nocov:
|
6
7
|
end
|
7
8
|
|
8
9
|
module Eaco
|
@@ -59,7 +60,14 @@ module Eaco
|
|
59
60
|
end
|
60
61
|
|
61
62
|
##
|
62
|
-
#
|
63
|
+
# Gets the permission required to access the given +action+, falling
|
64
|
+
# back on the default +:all+ action, or +nil+ if no permission is
|
65
|
+
# defined.
|
66
|
+
#
|
67
|
+
# @return [Symbol] the required permission or nil
|
68
|
+
#
|
69
|
+
# @see {Eaco::Resource}
|
70
|
+
# @see {Eaco::DSL::Resource}
|
63
71
|
#
|
64
72
|
def permission_for(action)
|
65
73
|
authorization_permissions[action] || authorization_permissions[:all]
|
@@ -67,7 +75,12 @@ module Eaco
|
|
67
75
|
|
68
76
|
protected
|
69
77
|
##
|
70
|
-
# Permission requirements configured on this controller
|
78
|
+
# Permission requirements configured on this controller, keyed by
|
79
|
+
# permission symbol and with role symbols as values.
|
80
|
+
#
|
81
|
+
# @return [Hash]
|
82
|
+
#
|
83
|
+
# @see {Eaco::DSL::Resource}
|
71
84
|
#
|
72
85
|
def authorization_permissions
|
73
86
|
@_authorization_permissions ||= {}
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'coveralls'
|
2
|
+
require 'simplecov'
|
3
|
+
require 'eaco/rake'
|
4
|
+
|
5
|
+
module Eaco
|
6
|
+
|
7
|
+
##
|
8
|
+
# Integration with code coverage tools.
|
9
|
+
#
|
10
|
+
# Loading this module will start collecting coverage data.
|
11
|
+
#
|
12
|
+
module Coverage
|
13
|
+
extend self
|
14
|
+
|
15
|
+
##
|
16
|
+
# Starts collecting coverage data.
|
17
|
+
#
|
18
|
+
# @return [nil]
|
19
|
+
#
|
20
|
+
def start!
|
21
|
+
Coveralls.wear_merged!(&simplecov_configuration)
|
22
|
+
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# Reports coverage data to the remote service
|
28
|
+
#
|
29
|
+
# @return [nil]
|
30
|
+
#
|
31
|
+
def report!
|
32
|
+
simplecov
|
33
|
+
Coveralls.push!
|
34
|
+
|
35
|
+
nil
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# Formats coverage results using the default formatter.
|
40
|
+
#
|
41
|
+
# @return [String] Coverage summary
|
42
|
+
#
|
43
|
+
def format!
|
44
|
+
Rake::Utils.capture_stdout do
|
45
|
+
result && result.format!
|
46
|
+
end.strip
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
##
|
52
|
+
# The coverage result
|
53
|
+
#
|
54
|
+
# @return [SimpleCov::Result]
|
55
|
+
#
|
56
|
+
def result
|
57
|
+
simplecov.result
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# Configures simplecov using {.simplecov_configuration}
|
62
|
+
#
|
63
|
+
# @return [Class] +SimpleCov+
|
64
|
+
#
|
65
|
+
def simplecov
|
66
|
+
SimpleCov.configure(&simplecov_configuration)
|
67
|
+
end
|
68
|
+
|
69
|
+
##
|
70
|
+
# Configures +SimpleCov+ to use a different directory
|
71
|
+
# for each different appraisal +Gemfile+.
|
72
|
+
#
|
73
|
+
# @return [Proc] a +SimpleCov+ configuration block.
|
74
|
+
#
|
75
|
+
def simplecov_configuration
|
76
|
+
proc do
|
77
|
+
gemfile = Eaco::Rake::Utils.gemfile
|
78
|
+
coverage_dir "coverage/#{gemfile}"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
@@ -1,7 +1,9 @@
|
|
1
1
|
begin
|
2
2
|
require 'active_record'
|
3
3
|
rescue LoadError
|
4
|
+
# :nocov:
|
4
5
|
abort "ActiveRecord requires the rails appraisal. Try `appraisal cucumber`"
|
6
|
+
# :nocov:
|
5
7
|
end
|
6
8
|
|
7
9
|
require 'yaml'
|
@@ -58,15 +60,6 @@ module Eaco
|
|
58
60
|
active_record.logger
|
59
61
|
end
|
60
62
|
|
61
|
-
##
|
62
|
-
# @return [ActiveRecord::Connection] the current +ActiveRecord+ connection
|
63
|
-
# object.
|
64
|
-
#
|
65
|
-
def connection
|
66
|
-
active_record.connection
|
67
|
-
end
|
68
|
-
alias adapter connection
|
69
|
-
|
70
63
|
##
|
71
64
|
# Returns an Hash wit the database configuration.
|
72
65
|
#
|
@@ -80,9 +73,11 @@ module Eaco
|
|
80
73
|
def configuration
|
81
74
|
@_config ||= YAML.load(config_file.read).tap do |conf|
|
82
75
|
def conf.to_s
|
76
|
+
# :nocov:
|
83
77
|
'pgsql://%s:%s@%s/%s' % values_at(
|
84
78
|
:username, :password, :hostname, :database
|
85
79
|
)
|
80
|
+
# :nocov:
|
86
81
|
end
|
87
82
|
end
|
88
83
|
end
|
@@ -104,6 +99,7 @@ module Eaco
|
|
104
99
|
Pathname.new('features/active_record.yml').realpath
|
105
100
|
|
106
101
|
rescue Errno::ENOENT => error
|
102
|
+
# :nocov:
|
107
103
|
raise error.class.new, <<-EOF.squeeze(' ')
|
108
104
|
|
109
105
|
#{error.message}.
|
@@ -112,6 +108,7 @@ module Eaco
|
|
112
108
|
default location, or specify your configuration file location by
|
113
109
|
passing the `EACO_AR_CONFIG' environment variable.
|
114
110
|
EOF
|
111
|
+
# :nocov:
|
115
112
|
end
|
116
113
|
|
117
114
|
##
|
@@ -143,23 +140,21 @@ module Eaco
|
|
143
140
|
protected
|
144
141
|
|
145
142
|
##
|
146
|
-
# Captures stdout and logs it
|
143
|
+
# Captures stdout emitted by the given +block+ and logs it
|
144
|
+
# as +info+ messages.
|
147
145
|
#
|
146
|
+
# @param block [Proc]
|
148
147
|
# @return [nil]
|
148
|
+
# @see {Rake::Utils.capture_stdout}
|
149
149
|
#
|
150
|
-
def log_stdout
|
151
|
-
stdout
|
152
|
-
$stdout = string
|
153
|
-
|
154
|
-
yield
|
150
|
+
def log_stdout(&block)
|
151
|
+
stdout = Rake::Utils.capture_stdout(&block)
|
155
152
|
|
156
|
-
|
153
|
+
stdout.split("\n").each do |line|
|
157
154
|
logger.info line
|
158
155
|
end
|
159
156
|
|
160
157
|
nil
|
161
|
-
ensure
|
162
|
-
$stdout = stdout
|
163
158
|
end
|
164
159
|
end
|
165
160
|
|
@@ -2,6 +2,18 @@ module Eaco
|
|
2
2
|
module Cucumber
|
3
3
|
module ActiveRecord
|
4
4
|
|
5
|
+
# @!method clean
|
6
|
+
#
|
7
|
+
# Drops all tables currently instantiated in the database.
|
8
|
+
#
|
9
|
+
# @see Eaco::Cucumber::World
|
10
|
+
#
|
11
|
+
::ActiveRecord::Base.connection.tap do |connection|
|
12
|
+
connection.tables.each do |table_name|
|
13
|
+
connection.drop_table table_name
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
5
17
|
# @!method schema
|
6
18
|
#
|
7
19
|
# Defines the database schema for the {Eaco::Cucumber::World} scenario.
|
@@ -9,21 +21,27 @@ module Eaco
|
|
9
21
|
# @see Eaco::Cucumber::World
|
10
22
|
#
|
11
23
|
::ActiveRecord::Schema.define(version: '2015022301') do
|
24
|
+
# Resource
|
12
25
|
create_table 'documents', force: true do |t|
|
13
26
|
t.string :name
|
14
27
|
t.column :acl, :jsonb
|
15
28
|
end
|
16
29
|
|
30
|
+
# Actor
|
17
31
|
create_table 'users', force: true do |t|
|
18
32
|
t.string :name
|
33
|
+
t.boolean :admin, default: false
|
19
34
|
end
|
20
35
|
|
36
|
+
# Designator source
|
21
37
|
create_table 'departments', force: true do |t|
|
22
|
-
t.string :
|
38
|
+
t.string :name
|
23
39
|
end
|
40
|
+
add_index :departments, :name, unique: true
|
24
41
|
|
42
|
+
# Designator source
|
25
43
|
create_table 'positions', force: true do |t|
|
26
|
-
t.string :
|
44
|
+
t.string :name
|
27
45
|
|
28
46
|
t.references :user
|
29
47
|
t.references :department
|
@@ -17,6 +17,15 @@ module Eaco
|
|
17
17
|
|
18
18
|
has_many :positions
|
19
19
|
has_many :departments, through: :positions
|
20
|
+
|
21
|
+
##
|
22
|
+
# The {Department} names this User has a {Position} in.
|
23
|
+
#
|
24
|
+
# @return [Array] the {Department} names as +String+s.
|
25
|
+
#
|
26
|
+
def department_names
|
27
|
+
departments.to_set(&:name)
|
28
|
+
end
|
20
29
|
end
|
21
30
|
|
22
31
|
end
|
@@ -9,7 +9,10 @@ module Eaco
|
|
9
9
|
# @see World
|
10
10
|
#
|
11
11
|
module Designators
|
12
|
-
autoload :
|
12
|
+
autoload :Authenticated, 'eaco/cucumber/active_record/user/designators/authenticated.rb'
|
13
|
+
autoload :Department, 'eaco/cucumber/active_record/user/designators/department.rb'
|
14
|
+
autoload :Position, 'eaco/cucumber/active_record/user/designators/position.rb'
|
15
|
+
autoload :User, 'eaco/cucumber/active_record/user/designators/user.rb'
|
13
16
|
end
|
14
17
|
|
15
18
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Eaco
|
2
|
+
module Cucumber
|
3
|
+
module ActiveRecord
|
4
|
+
class User
|
5
|
+
module Designators
|
6
|
+
|
7
|
+
##
|
8
|
+
# A {Designator} based on a the {User} class.
|
9
|
+
#
|
10
|
+
# This is an example on how to grant rights to all instances
|
11
|
+
# of a given model.
|
12
|
+
#
|
13
|
+
# The class name is available as the {Designator#value}.
|
14
|
+
#
|
15
|
+
# The String representation for an example User is
|
16
|
+
# +"authenticated:User"+.
|
17
|
+
#
|
18
|
+
class Authenticated < Eaco::Designator
|
19
|
+
label "Any user"
|
20
|
+
|
21
|
+
##
|
22
|
+
# This {Designator} description.
|
23
|
+
#
|
24
|
+
# @return [String] an hardcoded description
|
25
|
+
#
|
26
|
+
def describe(*)
|
27
|
+
"Any authenticated user"
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# {User}s matching this designator.
|
32
|
+
#
|
33
|
+
# @return [Array] All {User}s.
|
34
|
+
#
|
35
|
+
def resolve
|
36
|
+
klass.all
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
##
|
41
|
+
# Looks up this class by constantizing it.
|
42
|
+
#
|
43
|
+
# @return [Class]
|
44
|
+
#
|
45
|
+
def klass
|
46
|
+
@_klass ||= self.value.constantize
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Eaco
|
2
|
+
module Cucumber
|
3
|
+
module ActiveRecord
|
4
|
+
class User
|
5
|
+
module Designators
|
6
|
+
|
7
|
+
##
|
8
|
+
# A {Designator} based on a the {Department} an {User} occupies
|
9
|
+
# a {Position} in. It resolves {Actor}s by id looking them up
|
10
|
+
# through the {Position} model.
|
11
|
+
#
|
12
|
+
# As {Department}s have unique names, their name instead of
|
13
|
+
# their ID is used in this example.
|
14
|
+
#
|
15
|
+
# The Department name is available as the {Designator#value}.
|
16
|
+
#
|
17
|
+
# The String representation for an example ICT Department is
|
18
|
+
# +"department:ICT"+.
|
19
|
+
#
|
20
|
+
class Department < Eaco::Designator
|
21
|
+
##
|
22
|
+
# This {Designator} description.
|
23
|
+
#
|
24
|
+
# @return [String] the {Department} name, such as ICT or COM
|
25
|
+
# or EXE or BAT.
|
26
|
+
#
|
27
|
+
def describe(*)
|
28
|
+
department.name
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# {User}s matching this designator.
|
33
|
+
#
|
34
|
+
# @return [Array] all users currently occupying a position in
|
35
|
+
# this Department
|
36
|
+
#
|
37
|
+
def resolve
|
38
|
+
department.users
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
##
|
43
|
+
# Looks up this Department by name, and memoizes it in an
|
44
|
+
# instance variable.
|
45
|
+
#
|
46
|
+
# @return [ActiveRecord::Department] the referenced department
|
47
|
+
#
|
48
|
+
def department
|
49
|
+
@_department ||= ActiveRecord::Department.
|
50
|
+
where(name: self.value).first!
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Eaco
|
2
|
+
module Cucumber
|
3
|
+
module ActiveRecord
|
4
|
+
class User
|
5
|
+
module Designators
|
6
|
+
|
7
|
+
##
|
8
|
+
# A {Designator} based on a position an {User} occupies in an
|
9
|
+
# organigram. It resolves {Actor}s by id looking them up from
|
10
|
+
# the +user_id+ field.
|
11
|
+
#
|
12
|
+
# The Position ID is available as the {Designator#value}.
|
13
|
+
#
|
14
|
+
# The String representation for an example Position 42 is
|
15
|
+
# +"position:42"+.
|
16
|
+
#
|
17
|
+
class Position < Eaco::Designator
|
18
|
+
##
|
19
|
+
# This {Designator} description.
|
20
|
+
#
|
21
|
+
# @return [String] the {Position} name, such as "Manager" or
|
22
|
+
# or "Systems Analyst" or "Consultant".
|
23
|
+
#
|
24
|
+
def describe(*)
|
25
|
+
"#{position.name} in #{position.department.name}"
|
26
|
+
end
|
27
|
+
|
28
|
+
##
|
29
|
+
# {User}s matching this designator.
|
30
|
+
#
|
31
|
+
# @return [Array] the user currently occupying this Position.
|
32
|
+
#
|
33
|
+
def resolve
|
34
|
+
[position.user]
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
##
|
39
|
+
# Looks up this position by ID, and memoizes it in an instance
|
40
|
+
# variable.
|
41
|
+
#
|
42
|
+
# @return [ActiveRecord::Position] the referenced Position.
|
43
|
+
#
|
44
|
+
def position
|
45
|
+
@_position ||= ActiveRecord::Position.find(self.value)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|