hydra-access-controls 6.3.4 → 6.4.0.pre1

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: a66021a35f6755132cb22674e59e880d6980b571
4
- data.tar.gz: 4d82907106c6f1c80e63d13cf02aef92b8ab6faa
3
+ metadata.gz: d58a98abb5fa51ab9dcc8d38a80475d6bc9310cb
4
+ data.tar.gz: 23bc49074fa0715dc9515c1e9c7638484ba8040e
5
5
  SHA512:
6
- metadata.gz: dc5a599c3da37b374063f605ecc405db4ec68ea8b7b099a1c65507ff308459d58aea801589e05d98d6c52a33e33b31b2fc628de153071be8a451aba214659819
7
- data.tar.gz: d135be6d700d4aba21be4736d3e867c3327929a39f95b7eb63adaad205eb0a1792641511342e13aa96d4fb5ef26306c581387eb7670d5187dcaeb2389481a7e5
6
+ metadata.gz: 4b7e22c6d6e32dbdd5b39032af3d3caad5b3f6a885fbcf40b7852cc714ec1109aca94906b88f9044652375ca3ca81cb247fce852e58960ca728ab0678c06343c
7
+ data.tar.gz: dd23a59d0a72cd311011244ccba077cd8964cf0a295f5dace58e6487081411b35bfac55e767767ee3c5380b3be0fdf8b8bff0721f32e59af36ccce98e2266f56
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/README.textile CHANGED
@@ -87,18 +87,14 @@ Object-level permissions and Policy-level permissions are combined to produce th
87
87
 
88
88
  To turn on Policy-based enforcement,
89
89
 
90
- * include the Hydra::PolicyAwareAbility module in your Ability class (Make sure to include it _after_ Hydra::Ability because it overrides some of the methods provided by that module.)
90
+ * include the Hydra::PolicyAwareAbility module in your Ability class (Make sure to remove `include Hydra::Ability`)
91
91
  * include the Hydra::PolicyAwareAccessControlsEnforcement module into any appropriate Controllers (or into ApplicationController)
92
92
 
93
93
 
94
94
  Example app/models/ability.rb
95
95
 
96
96
  <pre>
97
- # Allows you to use CanCan to control access to Models
98
- require 'cancan'
99
97
  class Ability
100
- include CanCan::Ability
101
- include Hydra::Ability
102
98
  include Hydra::PolicyAwareAbility
103
99
  end
104
100
  </pre>
@@ -0,0 +1,9 @@
1
+ module Hydra
2
+ module AccessControls
3
+ extend ActiveSupport::Autoload
4
+ autoload :AccessRight
5
+ autoload :WithAccessRight
6
+ autoload :Visibility
7
+ autoload :Permissions
8
+ end
9
+ end
@@ -0,0 +1,82 @@
1
+ module Hydra
2
+ module AccessControls
3
+ class AccessRight
4
+ # What these groups are called in the Hydra rightsMetadata XML:
5
+ PERMISSION_TEXT_VALUE_PUBLIC = 'public'.freeze
6
+ PERMISSION_TEXT_VALUE_AUTHENTICATED = 'registered'.freeze
7
+
8
+ # The values that get drawn to the page
9
+ VISIBILITY_TEXT_VALUE_PUBLIC = 'open'.freeze
10
+ VISIBILITY_TEXT_VALUE_EMBARGO = 'open_with_embargo_release_date'.freeze
11
+ VISIBILITY_TEXT_VALUE_AUTHENTICATED = 'authenticated'.freeze
12
+ VISIBILITY_TEXT_VALUE_PRIVATE = 'restricted'.freeze
13
+
14
+ # @param permissionable [#visibility, #permissions]
15
+ # @example
16
+ # file = GenericFile.find('sufia:1234')
17
+ # access = Sufia::AccessRight.new(file)
18
+ def initialize(permissionable)
19
+ @permissionable = permissionable
20
+ end
21
+
22
+ attr_reader :permissionable
23
+ delegate :persisted?, :permissions, :visibility, to: :permissionable
24
+ protected :persisted?, :permissions, :visibility
25
+
26
+
27
+ def open_access?
28
+ return true if has_visibility_text_for?(VISIBILITY_TEXT_VALUE_PUBLIC)
29
+ # We don't want to know if its under embargo, simply does it have a date.
30
+ # In this way, we can properly inform the label input
31
+ persisted_open_access_permission? && !permissionable.embargo_release_date.present?
32
+ end
33
+
34
+ def open_access_with_embargo_release_date?
35
+ return false unless permissionable_is_embargoable?
36
+ return true if has_visibility_text_for?(VISIBILITY_TEXT_VALUE_EMBARGO)
37
+ # We don't want to know if its under embargo, simply does it have a date.
38
+ # In this way, we can properly inform the label input
39
+ persisted_open_access_permission? && permissionable.embargo_release_date.present?
40
+ end
41
+
42
+ def authenticated_only?
43
+ return false if open_access?
44
+ has_permission_text_for?(PERMISSION_TEXT_VALUE_AUTHENTICATED) ||
45
+ has_visibility_text_for?(VISIBILITY_TEXT_VALUE_AUTHENTICATED)
46
+ end
47
+
48
+ def private?
49
+ return false if open_access?
50
+ return false if authenticated_only?
51
+ return false if open_access_with_embargo_release_date?
52
+ true
53
+ end
54
+
55
+ private
56
+
57
+ def persisted_open_access_permission?
58
+ if persisted?
59
+ has_permission_text_for?(PERMISSION_TEXT_VALUE_PUBLIC)
60
+ else
61
+ visibility.to_s == ''
62
+ end
63
+ end
64
+
65
+ def on_or_after_any_embargo_release_date?
66
+ return true unless permissionable.embargo_release_date
67
+ permissionable.embargo_release_date.to_date < Date.today
68
+ end
69
+
70
+ def permissionable_is_embargoable?
71
+ permissionable.respond_to?(:embargo_release_date)
72
+ end
73
+
74
+ def has_visibility_text_for?(text)
75
+ visibility == text
76
+ end
77
+ def has_permission_text_for?(text)
78
+ !!permissions.detect { |perm| perm[:name] == text }
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,13 @@
1
+ module Hydra
2
+ module AccessControls
3
+ module Permissions
4
+ extend ActiveSupport::Concern
5
+ include Hydra::ModelMixins::RightsMetadata
6
+ include Hydra::AccessControls::Visibility
7
+
8
+ included do
9
+ has_metadata "rightsMetadata", type: Hydra::Datastream::RightsMetadata
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,59 @@
1
+ module Hydra
2
+ module AccessControls
3
+ module Visibility
4
+ extend ActiveSupport::Concern
5
+
6
+ def visibility=(value)
7
+ return if value.nil?
8
+ # only set explicit permissions
9
+ case value
10
+ when Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PUBLIC
11
+ public_visibility!
12
+ when Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_AUTHENTICATED
13
+ registered_visibility!
14
+ when Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PRIVATE
15
+ private_visibility!
16
+ else
17
+ raise ArgumentError, "Invalid visibility: #{value.inspect}"
18
+ end
19
+ end
20
+
21
+ def visibility
22
+ if read_groups.include? Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_PUBLIC
23
+ Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PUBLIC
24
+ elsif read_groups.include? Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_AUTHENTICATED
25
+ Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_AUTHENTICATED
26
+ else
27
+ Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PRIVATE
28
+ end
29
+ end
30
+
31
+ def visibility_changed?
32
+ @visibility_will_change
33
+ end
34
+
35
+ private
36
+ def visibility_will_change!
37
+ @visibility_will_change = true
38
+ end
39
+
40
+ def public_visibility!
41
+ visibility_will_change! unless visibility == Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PUBLIC
42
+ self.datastreams["rightsMetadata"].permissions({:group=>Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_PUBLIC}, "read")
43
+ end
44
+
45
+ def registered_visibility!
46
+ visibility_will_change! unless visibility == Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_AUTHENTICATED
47
+ self.datastreams["rightsMetadata"].permissions({:group=>Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_AUTHENTICATED}, "read")
48
+ self.datastreams["rightsMetadata"].permissions({:group=>Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_PUBLIC}, "none")
49
+ end
50
+
51
+ def private_visibility!
52
+ visibility_will_change! unless visibility == Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PRIVATE
53
+ self.datastreams["rightsMetadata"].permissions({:group=>Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_AUTHENTICATED}, "none")
54
+ self.datastreams["rightsMetadata"].permissions({:group=>Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_PUBLIC}, "none")
55
+ end
56
+
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,20 @@
1
+ module Hydra
2
+ module AccessControls
3
+ module WithAccessRight
4
+ extend ActiveSupport::Concern
5
+
6
+ def under_embargo?
7
+ @under_embargo ||= rightsMetadata.under_embargo?
8
+ end
9
+
10
+ delegate :open_access?, :open_access_with_embargo_release_date?,
11
+ :authenticated_only_access?, :private_access?, to: :access_rights
12
+
13
+ protected
14
+ def access_rights
15
+ @access_rights ||= AccessRight.new(self)
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -6,6 +6,7 @@ require 'rails'
6
6
 
7
7
  module Hydra
8
8
  extend ActiveSupport::Autoload
9
+ autoload :AccessControls
9
10
  autoload :User
10
11
  autoload :AccessControlsEnforcement
11
12
  autoload :PolicyAwareAccessControlsEnforcement
@@ -19,6 +20,9 @@ module Hydra
19
20
  autoload :PermissionsCache
20
21
  autoload :PermissionsSolrDocument
21
22
  class Engine < Rails::Engine
23
+ config.autoload_paths += %W(
24
+ #{config.root}/app/models/concerns
25
+ )
22
26
  end
23
27
 
24
28
  module ModelMixins
@@ -30,5 +34,4 @@ module Hydra
30
34
  # This usually happens within a call to AccessControlsEnforcement#enforce_access_controls but can be
31
35
  # raised manually.
32
36
  class AccessDenied < ::CanCan::AccessDenied; end
33
-
34
37
  end
@@ -1,5 +1,7 @@
1
1
  # Repeats access controls evaluation methods, but checks against a governing "Policy" object (or "Collection" object) that provides inherited access controls.
2
2
  module Hydra::PolicyAwareAbility
3
+ extend ActiveSupport::Concern
4
+ include Hydra::Ability
3
5
 
4
6
  # Extends Hydra::Ability.test_edit to try policy controls if object-level controls deny access
5
7
  def test_edit(pid)
@@ -27,7 +27,7 @@ module Hydra::PolicyAwareAccessControlsEnforcement
27
27
  # Grant access based on user id & role
28
28
  user_access_filters += apply_policy_role_permissions(discovery_permissions)
29
29
  user_access_filters += apply_policy_individual_permissions(discovery_permissions)
30
- result = policy_class.find_with_conditions( user_access_filters.join(" OR "), :fl => "id" )
30
+ result = policy_class.find_with_conditions( user_access_filters.join(" OR "), :fl => "id", :rows => policy_class.count )
31
31
  logger.debug "get policies: #{result}\n\n"
32
32
  result.map {|h| h['id']}
33
33
  end
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  ENV["environment"] ||= "test"
2
2
 
3
3
  require 'rspec/mocks'
4
+ require 'rspec/autorun'
5
+ require 'hydra-access-controls'
4
6
 
5
7
  module Hydra
6
8
  # Stubbing Hydra.config[:policy_aware] so Hydra::PolicyAwareAbility will be loaded for tests.
@@ -12,6 +14,7 @@ end
12
14
 
13
15
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
16
  $LOAD_PATH.unshift(File.dirname(__FILE__))
17
+ Hydra::Engine.config.autoload_paths.each { |path| $LOAD_PATH.unshift path }
15
18
 
16
19
  if ENV['COVERAGE'] and RUBY_VERSION =~ /^1.9/
17
20
  require 'simplecov'
@@ -21,8 +24,6 @@ if ENV['COVERAGE'] and RUBY_VERSION =~ /^1.9/
21
24
  SimpleCov.start
22
25
  end
23
26
 
24
- require 'rspec/autorun'
25
- require 'hydra-access-controls'
26
27
  require 'support/mods_asset'
27
28
  require 'support/solr_document'
28
29
  require "support/user"
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hydra::AccessControls::AccessRight do
4
+ [
5
+ [false, Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_PUBLIC, nil, nil, true, false, false, false],
6
+ [false, Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_AUTHENTICATED, nil, nil, true, false, false, false],
7
+ [false, nil, nil, nil, true, false, false, false],
8
+ [false, nil, nil, 2.days.from_now, false, false, false, true],
9
+ [false, nil, nil, 2.days.ago, false, false, false, true],
10
+ [false, nil, Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PUBLIC, nil, true, false, false, false],
11
+ [false, nil, Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_AUTHENTICATED, nil, false, true, false, false],
12
+ [false, nil, Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PRIVATE, nil, false, false, true, false],
13
+ [false, nil, Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_EMBARGO, nil, false, false, false, true],
14
+ [true, Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_PUBLIC, nil, nil, true, false, false, false],
15
+ [true, Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_PUBLIC, nil, 2.days.from_now, false, false, false, true],
16
+ [true, Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_PUBLIC, nil, 2.days.ago, false, false, false, true],
17
+ [true, Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_AUTHENTICATED, nil, nil, false, true, false, false],
18
+ [true, nil, nil, nil, false, false, true, false],
19
+ [true, nil, Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PUBLIC, nil, true, false, false, false],
20
+ [true, nil, Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_AUTHENTICATED, nil, false, true, false, false],
21
+ [true, nil, Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PRIVATE, nil, false, false, true, false],
22
+ [true, nil, Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_EMBARGO, nil, false, false, false, true],
23
+ ].each do |given_persisted, givin_permission, given_visibility, given_embargo_release_date, expected_open_access, expected_authentication_only, expected_private, expected_open_access_with_embargo_release_date|
24
+ spec_text = <<-TEXT
25
+
26
+ GIVEN: {
27
+ persisted: #{given_persisted.inspect},
28
+ permission: #{givin_permission.inspect},
29
+ visibility: #{given_visibility.inspect},
30
+ embargo_release_date: #{given_embargo_release_date}
31
+ },
32
+ EXPECTED: {
33
+ open_access: #{expected_open_access.inspect},
34
+ restricted: #{expected_authentication_only.inspect},
35
+ private: #{expected_private.inspect},
36
+ open_access_with_embargo_release_date: #{expected_open_access_with_embargo_release_date}
37
+ },
38
+ TEXT
39
+
40
+ it spec_text do
41
+ permissions = [{access: :edit, name: givin_permission}]
42
+ permissionable = double(
43
+ 'permissionable',
44
+ permissions: permissions,
45
+ visibility: given_visibility,
46
+ persisted?: given_persisted,
47
+ embargo_release_date: given_embargo_release_date
48
+ )
49
+ access_right = Hydra::AccessControls::AccessRight.new(permissionable)
50
+
51
+ expect(access_right.open_access?).to eq(expected_open_access)
52
+ expect(access_right.authenticated_only?).to eq(expected_authentication_only)
53
+ expect(access_right.private?).to eq(expected_private)
54
+ expect(access_right.open_access_with_embargo_release_date?).to eq(expected_open_access_with_embargo_release_date)
55
+ end
56
+ end
57
+ end
@@ -129,7 +129,16 @@ describe Hydra::AdminPolicy do
129
129
  @user = FactoryGirl.build(:martia_morocco)
130
130
  RoleMapper.stub(:roles).with(@user.user_key).and_return(@user.roles)
131
131
  end
132
- subject { Ability.new(@user) }
132
+ before(:all) do
133
+ class TestAbility
134
+ include Hydra::PolicyAwareAbility
135
+ end
136
+ end
137
+
138
+ after(:all) do
139
+ Object.send(:remove_const, :TestAbility)
140
+ end
141
+ subject { TestAbility.new(@user) }
133
142
  context "Given a policy grants read access to a group I belong to" do
134
143
  before do
135
144
  @policy = Hydra::AdminPolicy.new
@@ -21,8 +21,6 @@ describe Hydra::PolicyAwareAbility do
21
21
  end
22
22
  before(:all) do
23
23
  class PolicyAwareClass
24
- include CanCan::Ability
25
- include Hydra::Ability
26
24
  include Hydra::PolicyAwareAbility
27
25
  end
28
26
  @policy = Hydra::AdminPolicy.new
@@ -40,7 +38,11 @@ describe Hydra::PolicyAwareAbility do
40
38
  @asset.admin_policy = @policy
41
39
  @asset.save
42
40
  end
43
- after(:all) { @policy.delete; @asset.delete }
41
+ after(:all) do
42
+ @policy.delete
43
+ @asset.delete
44
+ Object.send(:remove_const, :PolicyAwareClass)
45
+ end
44
46
  subject { PolicyAwareClass.new( User.new ) }
45
47
 
46
48
  describe "policy_pid_for" do
@@ -65,6 +65,14 @@ describe Hydra::PolicyAwareAccessControlsEnforcement do
65
65
  policy8.save
66
66
  @sample_policies << policy8
67
67
 
68
+ # user discover policies for testing that all are applied when over 10 are applicable
69
+ (9..11).each do |i|
70
+ policy = Hydra::AdminPolicy.create(:pid => "test:policy#{i}")
71
+ policy.default_permissions = [{:type=>"user", :access=>"discover", :name=>"sara_student"}]
72
+ policy.save
73
+ @sample_policies << policy
74
+ end
75
+
68
76
  # no access
69
77
  policy_no_access = Hydra::AdminPolicy.create(:pid=>"test:policy_no_access")
70
78
  @sample_policies << policy_no_access
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hydra::AccessControls::Visibility do
4
+ module VisibilityOverride
5
+ extend ActiveSupport::Concern
6
+ include Hydra::AccessControls::Permissions
7
+ def visibility; super; end
8
+ def visibility=(value); super(value); end
9
+ end
10
+ class MockParent < ActiveFedora::Base
11
+ include VisibilityOverride
12
+ end
13
+
14
+ it 'allows for overrides of visibility' do
15
+ expect{
16
+ MockParent.new(visibility: Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PRIVATE)
17
+ }.to_not raise_error
18
+ end
19
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hydra-access-controls
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.3.4
4
+ version: 6.4.0.pre1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Beer
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-08-27 00:00:00.000000000 Z
13
+ date: 2013-09-27 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
@@ -117,9 +117,15 @@ executables: []
117
117
  extensions: []
118
118
  extra_rdoc_files: []
119
119
  files:
120
+ - .rspec
120
121
  - README.textile
121
122
  - Rakefile
122
123
  - app/models/ability.rb
124
+ - app/models/concerns/hydra/access_controls.rb
125
+ - app/models/concerns/hydra/access_controls/access_right.rb
126
+ - app/models/concerns/hydra/access_controls/permissions.rb
127
+ - app/models/concerns/hydra/access_controls/visibility.rb
128
+ - app/models/concerns/hydra/access_controls/with_access_right.rb
123
129
  - app/models/role_mapper.rb
124
130
  - config/fedora.yml
125
131
  - config/solr.yml
@@ -151,6 +157,7 @@ files:
151
157
  - spec/support/user.rb
152
158
  - spec/unit/ability_spec.rb
153
159
  - spec/unit/access_controls_enforcement_spec.rb
160
+ - spec/unit/access_right_spec.rb
154
161
  - spec/unit/admin_policy_spec.rb
155
162
  - spec/unit/hydra_rights_metadata_persistence_spec.rb
156
163
  - spec/unit/hydra_rights_metadata_spec.rb
@@ -159,6 +166,7 @@ files:
159
166
  - spec/unit/policy_aware_access_controls_enforcement_spec.rb
160
167
  - spec/unit/rights_metadata_spec.rb
161
168
  - spec/unit/role_mapper_spec.rb
169
+ - spec/unit/visibility_spec.rb
162
170
  - tasks/hydra-access-controls.rake
163
171
  homepage: http://projecthydra.org
164
172
  licenses:
@@ -175,9 +183,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
175
183
  version: 1.9.3
176
184
  required_rubygems_version: !ruby/object:Gem::Requirement
177
185
  requirements:
178
- - - '>='
186
+ - - '>'
179
187
  - !ruby/object:Gem::Version
180
- version: '0'
188
+ version: 1.3.1
181
189
  requirements: []
182
190
  rubyforge_project:
183
191
  rubygems_version: 2.0.5
@@ -196,6 +204,7 @@ test_files:
196
204
  - spec/support/user.rb
197
205
  - spec/unit/ability_spec.rb
198
206
  - spec/unit/access_controls_enforcement_spec.rb
207
+ - spec/unit/access_right_spec.rb
199
208
  - spec/unit/admin_policy_spec.rb
200
209
  - spec/unit/hydra_rights_metadata_persistence_spec.rb
201
210
  - spec/unit/hydra_rights_metadata_spec.rb
@@ -204,4 +213,5 @@ test_files:
204
213
  - spec/unit/policy_aware_access_controls_enforcement_spec.rb
205
214
  - spec/unit/rights_metadata_spec.rb
206
215
  - spec/unit/role_mapper_spec.rb
216
+ - spec/unit/visibility_spec.rb
207
217
  has_rdoc: