hydra-role-management 1.0.0 → 1.0.1
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 +5 -5
- data/.circleci/config.yml +68 -0
- data/.rubocop.yml +50 -0
- data/CONTRIBUTING.md +22 -20
- data/Gemfile +3 -3
- data/README.md +33 -1
- data/Rakefile +14 -17
- data/SUPPORT.md +6 -0
- data/app/controllers/concerns/hydra/role_management/roles_behavior.rb +15 -16
- data/app/controllers/concerns/hydra/role_management/user_roles_behavior.rb +9 -8
- data/app/controllers/roles_controller.rb +2 -1
- data/app/controllers/user_roles_controller.rb +2 -2
- data/app/models/concerns/hydra/role_management/legacy_attribute_handling.rb +2 -0
- data/app/models/concerns/hydra/role_management/user_roles.rb +5 -4
- data/app/models/role.rb +8 -5
- data/app/views/roles/edit.html.erb +1 -1
- data/config/routes.rb +2 -2
- data/hydra-role-management.gemspec +19 -14
- data/lib/generators/roles/roles_generator.rb +30 -32
- data/lib/generators/roles/templates/hydra_role_management_rails3.rb +2 -1
- data/lib/generators/roles/templates/migrations/user_roles.rb +3 -2
- data/lib/hydra-role-management.rb +9 -3
- data/lib/hydra/role_management.rb +4 -2
- data/lib/hydra/role_management/version.rb +2 -1
- data/spec/controllers/roles_controller_spec.rb +27 -30
- data/spec/controllers/user_roles_controller_spec.rb +15 -13
- data/spec/lib/user_roles_spec.rb +21 -21
- data/spec/models/role_spec.rb +22 -20
- data/spec/routing/role_management_routes_spec.rb +29 -44
- data/spec/spec_helper.rb +4 -2
- data/spec/test_app_templates/app/models/sample.rb +7 -8
- data/spec/test_app_templates/app/models/solr_document.rb +2 -2
- data/spec/test_app_templates/config/initializers/hydra_config.rb +6 -6
- data/spec/test_app_templates/lib/generators/test_app_generator.rb +6 -5
- metadata +88 -17
- data/.travis.yml +0 -11
@@ -1,30 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Hydra
|
2
3
|
module RoleManagement
|
4
|
+
# Module offering methods for user behavior managing roles and groups
|
3
5
|
module UserRoles
|
4
6
|
extend ActiveSupport::Concern
|
7
|
+
|
5
8
|
included do
|
6
9
|
has_and_belongs_to_many :roles
|
7
10
|
end
|
8
11
|
|
9
12
|
def groups
|
10
13
|
g = roles.map(&:name)
|
11
|
-
g += ['registered'] unless new_record? || guest?
|
14
|
+
g += ['registered'] unless new_record? || guest?
|
12
15
|
g
|
13
16
|
end
|
14
17
|
|
15
18
|
def guest?
|
16
19
|
if defined?(DeviseGuests)
|
17
|
-
|
20
|
+
self[:guest]
|
18
21
|
else
|
19
22
|
false
|
20
23
|
end
|
21
24
|
end
|
22
|
-
|
23
25
|
|
24
26
|
def admin?
|
25
27
|
roles.where(name: 'admin').exists?
|
26
28
|
end
|
27
|
-
|
28
29
|
end
|
29
30
|
end
|
30
31
|
end
|
data/app/models/role.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Class modeling Roles within the application
|
1
3
|
class Role < ActiveRecord::Base
|
2
4
|
has_and_belongs_to_many :users
|
3
5
|
|
4
|
-
validates :name,
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
validates :name,
|
7
|
+
uniqueness: true,
|
8
|
+
format: {
|
9
|
+
with: /\A[a-zA-Z0-9._-]+\z/,
|
10
|
+
message: 'Only letters, numbers, hyphens, underscores and periods are allowed'
|
11
|
+
}
|
9
12
|
end
|
@@ -13,7 +13,7 @@
|
|
13
13
|
<% @role.users.each do |user| %>
|
14
14
|
<li><%= user.user_key %>
|
15
15
|
<% if can? :remove_user, Role %>
|
16
|
-
<%= button_to t('role-management.edit.remove'), role_management.role_user_path(@role, user), :method=>:delete, :class=>'btn btn-danger' %>
|
16
|
+
<%= button_to t('role-management.edit.remove'), role_management.role_user_path(@role, user.id), :method=>:delete, :class=>'btn btn-danger' %>
|
17
17
|
<% end %>
|
18
18
|
</li>
|
19
19
|
<% end %>
|
data/config/routes.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
Hydra::RoleManagement::Engine.routes.draw do
|
2
3
|
# Generic file routes
|
3
4
|
resources :roles, Hydra::RoleManagement.route_options do
|
4
|
-
resources :users, :
|
5
|
+
resources :users, only: [:create, :destroy], controller: "user_roles"
|
5
6
|
end
|
6
7
|
end
|
7
|
-
|
@@ -1,27 +1,32 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
require File.expand_path('../lib/hydra/role_management/version', __FILE__)
|
3
3
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
|
-
gem.authors = [
|
6
|
-
gem.email = [
|
7
|
-
gem.description =
|
8
|
-
gem.summary =
|
9
|
-
gem.homepage =
|
5
|
+
gem.authors = ['Justin Coyne']
|
6
|
+
gem.email = ['justin@curationexperts.com']
|
7
|
+
gem.description = 'Rails engine to do user roles in an RDBMS for hydra-head'
|
8
|
+
gem.summary = 'Rails engine to do user roles in an RDBMS for hydra-head'
|
9
|
+
gem.homepage = 'https://github.com/samvera/hydra-role-management'
|
10
10
|
|
11
|
-
gem.files = `git ls-files`.split(
|
12
|
-
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
11
|
+
gem.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
13
13
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
-
gem.name =
|
15
|
-
gem.require_paths = [
|
14
|
+
gem.name = 'hydra-role-management'
|
15
|
+
gem.require_paths = ['lib']
|
16
16
|
gem.version = Hydra::RoleManagement::VERSION
|
17
17
|
gem.license = 'Apache 2.0'
|
18
18
|
|
19
|
-
gem.add_dependency 'bootstrap_form'
|
20
19
|
gem.add_dependency 'blacklight'
|
20
|
+
gem.add_dependency 'bootstrap_form'
|
21
|
+
gem.add_dependency 'bundler', '>= 1.5'
|
21
22
|
gem.add_dependency 'cancancan'
|
23
|
+
gem.add_dependency 'json', '~> 1.8'
|
24
|
+
gem.add_development_dependency 'bixby', '~> 1.0.0'
|
25
|
+
gem.add_development_dependency 'engine_cart', '~> 2.1'
|
26
|
+
gem.add_development_dependency 'pry-byebug'
|
27
|
+
gem.add_development_dependency 'rails-controller-testing', '~> 0'
|
22
28
|
gem.add_development_dependency 'rake'
|
23
|
-
gem.add_development_dependency 'rspec-rails'
|
24
29
|
gem.add_development_dependency 'rspec-its'
|
25
|
-
gem.add_development_dependency 'rails
|
26
|
-
gem.add_development_dependency '
|
30
|
+
gem.add_development_dependency 'rspec-rails'
|
31
|
+
gem.add_development_dependency 'rspec_junit_formatter'
|
27
32
|
end
|
@@ -1,27 +1,29 @@
|
|
1
|
-
|
1
|
+
|
2
|
+
# frozen_string_literal: true
|
2
3
|
require 'rails/generators'
|
3
4
|
require 'rails/generators/migration'
|
4
5
|
|
6
|
+
# Class definition for the Rails Generator integrating Roles
|
5
7
|
class RolesGenerator < Rails::Generators::Base
|
6
8
|
include Rails::Generators::Migration
|
7
9
|
|
8
10
|
source_root File.expand_path('../templates', __FILE__)
|
9
11
|
|
10
|
-
argument
|
11
|
-
desc
|
12
|
+
argument :model_name, type: :string, default: 'user'
|
13
|
+
desc '
|
12
14
|
This generator makes the following changes to your application:
|
13
15
|
1. Creates several database migrations if they do not exist in /db/migrate
|
14
16
|
2. Adds user behavior to the user model
|
15
17
|
2. Adds routes
|
16
|
-
|
18
|
+
'
|
17
19
|
|
18
20
|
# Implement the required interface for Rails::Generators::Migration.
|
19
21
|
# taken from http://github.com/rails/rails/blob/master/activerecord/lib/generators/active_record.rb
|
20
|
-
def self.next_migration_number(
|
21
|
-
|
22
|
-
@prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
|
23
|
-
else
|
22
|
+
def self.next_migration_number(_path)
|
23
|
+
if @prev_migration_nr
|
24
24
|
@prev_migration_nr += 1
|
25
|
+
else
|
26
|
+
@prev_migration_nr = Time.now.utc.strftime('%Y%m%d%H%M%S').to_i
|
25
27
|
end
|
26
28
|
@prev_migration_nr.to_s
|
27
29
|
end
|
@@ -29,7 +31,7 @@ This generator makes the following changes to your application:
|
|
29
31
|
# Setup the database migrations
|
30
32
|
def copy_migrations
|
31
33
|
# Can't get this any more DRY, because we need this order.
|
32
|
-
%w
|
34
|
+
%w[user_roles.rb].each do |f|
|
33
35
|
better_migration_template f
|
34
36
|
end
|
35
37
|
end
|
@@ -37,49 +39,45 @@ This generator makes the following changes to your application:
|
|
37
39
|
# Add behaviors to the user model
|
38
40
|
def inject_user_roles_behavior
|
39
41
|
file_path = "app/models/#{model_name.underscore}.rb"
|
40
|
-
if File.
|
41
|
-
place_marker = if File.read(file_path).match(/include Hydra::User/)
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
if File.exist?(file_path)
|
43
|
+
place_marker = if File.read(file_path).match?(/include Hydra::User/)
|
44
|
+
/include Hydra::User/
|
45
|
+
elsif File.read(file_path).match?(/include Blacklight::User/)
|
46
|
+
/include Blacklight::User/
|
47
|
+
end
|
46
48
|
if place_marker
|
47
|
-
code = "\n # Connects this user object to Role-management behaviors.\n"
|
48
|
-
|
49
|
-
inject_into_file file_path, code,
|
49
|
+
code = "\n # Connects this user object to Role-management behaviors.\n" \
|
50
|
+
" include Hydra::RoleManagement::UserRoles\n\n"
|
51
|
+
inject_into_file file_path, code, after: place_marker
|
50
52
|
else
|
51
|
-
|
53
|
+
Rails.logger.error " \e[31mFailure\e[0m Hydra::User is not included in #{file_path}. Add 'include Hydra::User' and rerun."
|
52
54
|
end
|
53
55
|
else
|
54
|
-
|
56
|
+
Rails.logger.error " \e[31mFailure\e[0m hydra-role-management requires a user object. This generators assumes that the model is defined in the file #{file_path}, which does not exist. If you used a different name, please re-run the generator and provide that name as an argument. Such as \b rails -g roles client"
|
55
57
|
end
|
56
58
|
end
|
57
59
|
|
58
60
|
# The engine routes have to come after the devise routes so that /users/sign_in will work
|
59
61
|
def inject_routes
|
60
62
|
routing_code = "mount Hydra::RoleManagement::Engine => '/'"
|
61
|
-
sentinel = /devise_for :users
|
62
|
-
inject_into_file 'config/routes.rb', "\n #{routing_code}\n",
|
63
|
+
sentinel = /devise_for :users(.*)$/
|
64
|
+
inject_into_file 'config/routes.rb', "\n #{routing_code}\n", after: sentinel, verbose: false
|
63
65
|
end
|
64
66
|
|
65
67
|
# If this gem is installed under Rails 3, an attr_accessible method is required for the Role model. This
|
66
68
|
# file will be added to config/initializers and the correct code will be added to the model at runtime.
|
67
69
|
def rails3_attr_accessible
|
68
|
-
if
|
69
|
-
|
70
|
-
|
71
|
-
end
|
70
|
+
return if ActionController.const_defined? :StrongParameters
|
71
|
+
Rails.logger.info 'Role model will include attr_accessible :name because you are installing this gem in a Rails 3 app.'
|
72
|
+
copy_file 'hydra_role_management_rails3.rb', 'config/initializers/hydra_role_management_rails3.rb'
|
72
73
|
end
|
73
74
|
|
74
75
|
private
|
75
76
|
|
76
|
-
|
77
|
-
begin
|
77
|
+
def better_migration_template(file)
|
78
78
|
sleep 1 # ensure scripts have different time stamps
|
79
79
|
migration_template "migrations/#{file}", "db/migrate/#{file}"
|
80
|
-
rescue
|
81
|
-
|
80
|
+
rescue StandardError
|
81
|
+
Rails.logger.error " \e[1m\e[34mMigrations\e[0m " + $ERROR_INFO.message
|
82
82
|
end
|
83
|
-
end
|
84
|
-
|
85
83
|
end
|
@@ -1 +1,2 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
Role.send :include, Hydra::RoleManagement::LegacyAttributeHandling
|
@@ -1,9 +1,10 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class UserRoles < ActiveRecord::Migration[5.0]
|
2
3
|
def up
|
3
4
|
create_table :roles do |t|
|
4
5
|
t.string :name
|
5
6
|
end
|
6
|
-
create_table :roles_users, :
|
7
|
+
create_table :roles_users, id: false do |t|
|
7
8
|
t.references :role
|
8
9
|
t.references :user
|
9
10
|
end
|
@@ -1,12 +1,18 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'hydra/role_management'
|
2
3
|
require 'bootstrap_form'
|
3
4
|
|
4
5
|
module Hydra
|
5
6
|
module RoleManagement
|
6
7
|
mattr_accessor :route_options
|
7
8
|
self.route_options = {}
|
8
|
-
|
9
|
-
|
9
|
+
|
10
|
+
# Draws the routes with custom arguments passed to the #mount invocation
|
11
|
+
# @param router [ActionDispatch::Routing::Mapper] the Rails routing mapper
|
12
|
+
# @param opts [Hash] the argument passed to ActionDispatch::Routing::Mapper#mount
|
13
|
+
# @see http://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Base.html
|
14
|
+
# (see ActionDispatch::Routing::Mapper::Base)
|
15
|
+
def self.draw_routes(router, opts = {})
|
10
16
|
self.route_options = opts
|
11
17
|
router.instance_exec do
|
12
18
|
mount Hydra::RoleManagement::Engine => '/'
|
@@ -1,12 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'cancan'
|
2
3
|
module Hydra
|
3
4
|
module RoleManagement
|
5
|
+
# Class definition for the Rails Engine
|
4
6
|
class Engine < ::Rails::Engine
|
5
7
|
engine_name 'role_management'
|
6
8
|
|
7
9
|
# Rails 4 should do this automatically:
|
8
|
-
config.paths.add
|
9
|
-
config.paths.add
|
10
|
+
config.paths.add 'app/controllers/concerns', eager_load: true
|
11
|
+
config.paths.add 'app/models/concerns', eager_load: true
|
10
12
|
end
|
11
13
|
end
|
12
14
|
end
|
@@ -1,51 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
describe RolesController do
|
3
|
+
routes { Hydra::RoleManagement::Engine.routes }
|
2
4
|
let(:ability) do
|
3
5
|
ability = Object.new
|
4
6
|
ability.extend(CanCan::Ability)
|
5
7
|
allow(controller).to receive(:current_ability).and_return(ability)
|
6
8
|
ability
|
7
9
|
end
|
8
|
-
|
9
10
|
let(:role) do
|
10
11
|
Role.create(name: 'foo')
|
11
12
|
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
describe "with a user who cannot edit roles" do
|
18
|
-
it "should not be able to view role index" do
|
14
|
+
describe 'with a user who cannot edit roles' do
|
15
|
+
it 'is not able to view role index' do
|
19
16
|
expect { get :index, params: {} }.to raise_error CanCan::AccessDenied
|
20
17
|
end
|
21
|
-
it
|
18
|
+
it 'is not able to view role' do
|
22
19
|
expect { get :show, params: { id: role } }.to raise_error CanCan::AccessDenied
|
23
20
|
end
|
24
|
-
it
|
21
|
+
it 'is not able to view new role form' do
|
25
22
|
expect { get :new }.to raise_error CanCan::AccessDenied
|
26
23
|
end
|
27
|
-
it
|
24
|
+
it 'is not able to create a role' do
|
28
25
|
expect { post :create, params: { role: { name: 'my_role' } } }.to raise_error CanCan::AccessDenied
|
29
26
|
end
|
30
|
-
it
|
27
|
+
it 'is not able to update a role' do
|
31
28
|
expect { put :update, params: { id: role } }.to raise_error CanCan::AccessDenied
|
32
29
|
end
|
33
|
-
it
|
30
|
+
it 'is not able to remove a role' do
|
34
31
|
expect { delete :destroy, params: { id: role } }.to raise_error CanCan::AccessDenied
|
35
32
|
end
|
36
33
|
end
|
37
34
|
|
38
|
-
describe
|
35
|
+
describe 'with a user who can read roles' do
|
39
36
|
before do
|
40
37
|
ability.can :read, Role
|
41
38
|
end
|
42
|
-
it
|
39
|
+
it 'is able to see the list of roles' do
|
43
40
|
get :index
|
44
41
|
expect(response).to be_successful
|
45
42
|
expect(assigns[:roles]).to eq [role]
|
46
43
|
end
|
47
44
|
|
48
|
-
it
|
45
|
+
it 'is able to see a single role' do
|
49
46
|
get :show, params: { id: role }
|
50
47
|
expect(response).to be_successful
|
51
48
|
expect(assigns[:role]).to eq role
|
@@ -53,31 +50,31 @@ describe RolesController do
|
|
53
50
|
end
|
54
51
|
|
55
52
|
describe "with a user who can only update role 'foo'" do
|
56
|
-
it
|
53
|
+
it 'is redirected to edit' do
|
57
54
|
ability.can :read, Role
|
58
55
|
ability.can :update, Role, id: role.id
|
59
56
|
get :show, params: { id: role }
|
60
|
-
expect(response).to redirect_to
|
57
|
+
expect(response).to redirect_to routes.url_helpers.edit_role_path(assigns[:role])
|
61
58
|
end
|
62
59
|
end
|
63
60
|
|
64
|
-
describe
|
61
|
+
describe 'with a user who can create roles' do
|
65
62
|
before do
|
66
63
|
ability.can :create, Role
|
67
64
|
end
|
68
|
-
it
|
65
|
+
it 'is able to make a new role' do
|
69
66
|
get :new
|
70
67
|
expect(response).to be_successful
|
71
68
|
expect(assigns[:role]).to be_kind_of Role
|
72
69
|
end
|
73
70
|
|
74
|
-
it
|
71
|
+
it 'is able to create a new role' do
|
75
72
|
post :create, params: { role: { name: 'my_role' } }
|
76
|
-
expect(response).to redirect_to
|
73
|
+
expect(response).to redirect_to routes.url_helpers.edit_role_path(assigns[:role])
|
77
74
|
expect(assigns[:role]).not_to be_new_record
|
78
75
|
expect(assigns[:role].name).to eq 'my_role'
|
79
76
|
end
|
80
|
-
it
|
77
|
+
it 'does not create role with an error' do
|
81
78
|
post :create, params: { role: { name: 'my role' } }
|
82
79
|
expect(assigns[:role].name).to eq 'my role'
|
83
80
|
expect(assigns[:role].errors[:name]).to eq ['Only letters, numbers, hyphens, underscores and periods are allowed']
|
@@ -85,33 +82,33 @@ describe RolesController do
|
|
85
82
|
end
|
86
83
|
end
|
87
84
|
|
88
|
-
describe
|
85
|
+
describe 'with a user who can update roles' do
|
89
86
|
before do
|
90
87
|
ability.can :update, Role
|
91
88
|
end
|
92
89
|
|
93
|
-
it
|
90
|
+
it 'is able to update a role' do
|
94
91
|
put :update, params: { id: role, role: { name: 'my_role' } }
|
95
|
-
expect(response).to redirect_to
|
92
|
+
expect(response).to redirect_to routes.url_helpers.edit_role_path(assigns[:role])
|
96
93
|
expect(assigns[:role]).not_to be_new_record
|
97
94
|
expect(assigns[:role].name).to eq 'my_role'
|
98
95
|
end
|
99
|
-
it
|
100
|
-
put :update,
|
96
|
+
it 'does not update role with an error' do
|
97
|
+
put :update, params: { id: role, role: { name: 'my role' } }
|
101
98
|
expect(assigns[:role].name).to eq 'my role'
|
102
99
|
expect(assigns[:role].errors[:name]).to eq ['Only letters, numbers, hyphens, underscores and periods are allowed']
|
103
100
|
expect(response).to be_successful
|
104
101
|
end
|
105
102
|
end
|
106
103
|
|
107
|
-
describe
|
104
|
+
describe 'with a user who can remove roles' do
|
108
105
|
before do
|
109
106
|
ability.can :destroy, Role
|
110
107
|
end
|
111
108
|
|
112
|
-
it
|
109
|
+
it 'is able to destroy a role' do
|
113
110
|
delete :destroy, params: { id: role }
|
114
|
-
expect(response).to redirect_to
|
111
|
+
expect(response).to redirect_to routes.url_helpers.roles_path
|
115
112
|
end
|
116
113
|
end
|
117
114
|
end
|