eaco 0.6.1 → 0.7.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 +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
|