express_access 1.0.0.a
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +87 -0
- data/Rakefile +34 -0
- data/app/assets/javascripts/express_access/admin.js +1 -0
- data/app/assets/stylesheets/express_access/admin.css +5 -0
- data/app/assets/stylesheets/express_access/application.css +15 -0
- data/app/assets/stylesheets/express_access/main.sass +3 -0
- data/app/assets/stylesheets/express_access/sections/_role_dashboard.sass +29 -0
- data/app/assets/stylesheets/express_access.css +4 -0
- data/app/controllers/express_access/permissions_controller.rb +4 -0
- data/app/controllers/express_access/roles_controller.rb +14 -0
- data/app/controllers/express_access/routes_controller.rb +30 -0
- data/app/controllers/express_access/users_controller.rb +21 -0
- data/app/helpers/express_access/application_helper.rb +4 -0
- data/app/helpers/express_access/permissions_helper.rb +4 -0
- data/app/helpers/express_access/roles_helper.rb +4 -0
- data/app/models/express_access/audit_log.rb +27 -0
- data/app/models/express_access/permission.rb +130 -0
- data/app/models/express_access/role.rb +75 -0
- data/app/models/express_access/role_permission.rb +6 -0
- data/app/models/express_access/user_permission.rb +7 -0
- data/app/models/express_access/user_role.rb +7 -0
- data/app/views/express_access/permissions/index.html.et +13 -0
- data/app/views/express_access/permissions/show.html.et +33 -0
- data/app/views/express_access/roles/index.html.et +9 -0
- data/app/views/express_access/roles/show.html.et +68 -0
- data/app/views/express_access/routes/index.html.et +20 -0
- data/app/views/express_access/routes/show.html.et +46 -0
- data/app/views/express_access/users/index.html.et +26 -0
- data/app/views/express_access/users/show.html.et +55 -0
- data/app/views/layouts/express_access/admin.html.et +1 -0
- data/app/views/layouts/express_access/application.html.erb +14 -0
- data/config/initializers/mount_engine.rb +3 -0
- data/config/menu.yml +18 -0
- data/config/routes.rb +6 -0
- data/db/migrate/20141029223053_create_express_access_roles.rb +10 -0
- data/db/migrate/20141029223158_create_express_access_permissions.rb +9 -0
- data/db/migrate/20141029223233_create_express_access_role_permissions.rb +10 -0
- data/db/migrate/20141029223250_create_express_access_user_permissions.rb +10 -0
- data/db/migrate/20150528222337_create_express_access_user_roles.rb +9 -0
- data/db/migrate/20150609124815_add_description_to_role.rb +5 -0
- data/db/migrate/20150914023030_create_express_access_audit_logs.rb +15 -0
- data/db/migrate/20150921063153_add_after_sign_in_path_to_role.rb +5 -0
- data/lib/express_access/after_sign_in_filter.rb +7 -0
- data/lib/express_access/authorization_filter.rb +39 -0
- data/lib/express_access/engine.rb +12 -0
- data/lib/express_access/route.rb +127 -0
- data/lib/express_access/user.rb +79 -0
- data/lib/express_access/version.rb +3 -0
- data/lib/express_access.rb +51 -0
- data/lib/generators/express_access/install/USAGE +8 -0
- data/lib/generators/express_access/install/install_generator.rb +10 -0
- data/lib/tasks/express_access_tasks.rake +4 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/controllers/posts_controller.rb +4 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/models/user.rb +9 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/app/views/posts/index.html.erb +0 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/config/application.rb +25 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +37 -0
- data/test/dummy/config/environments/production.rb +83 -0
- data/test/dummy/config/environments/test.rb +41 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/devise.rb +259 -0
- data/test/dummy/config/initializers/express_access.rb +1 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/devise.en.yml +60 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +7 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/db/migrate/20150525001419_devise_create_users.rb +42 -0
- data/test/dummy/db/schema.rb +82 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/test/fixtures/express_access/permissions.yml +28 -0
- data/test/dummy/test/fixtures/express_access/role_permissions.yml +21 -0
- data/test/dummy/test/fixtures/express_access/roles.yml +27 -0
- data/test/dummy/test/fixtures/express_access/user_permissions.yml +5 -0
- data/test/dummy/test/fixtures/express_access/user_roles.yml +15 -0
- data/test/dummy/test/fixtures/users.yml +19 -0
- data/test/dummy/test/initializer_test.rb +8 -0
- data/test/dummy/test/models/user_test.rb +7 -0
- data/test/express_access_test.rb +7 -0
- data/test/fixtures/express_access/audit_logs.yml +10 -0
- data/test/fixtures/express_access/permissions.yml +28 -0
- data/test/fixtures/express_access/role_permissions.yml +21 -0
- data/test/fixtures/express_access/roles.yml +34 -0
- data/test/fixtures/express_access/user_permissions.yml +5 -0
- data/test/fixtures/express_access/user_roles.yml +19 -0
- data/test/fixtures/users.yml +22 -0
- data/test/helpers/express_access/permissions_helper_test.rb +6 -0
- data/test/helpers/express_access/roles_helper_test.rb +6 -0
- data/test/integration/navigation_test.rb +33 -0
- data/test/lib/authorization_filter_test.rb +64 -0
- data/test/lib/generators/express_access/install/install_generator_test.rb +16 -0
- data/test/models/express_access/audit_log_test.rb +9 -0
- data/test/models/express_access/permission_test.rb +50 -0
- data/test/models/express_access/role_permission_test.rb +9 -0
- data/test/models/express_access/role_test.rb +36 -0
- data/test/models/express_access/user_permission_test.rb +9 -0
- data/test/models/express_access/user_role_test.rb +9 -0
- data/test/models/express_access/user_test.rb +77 -0
- data/test/test_helper.rb +19 -0
- metadata +375 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
pane(
|
2
|
+
title: "Routes for #{Rails.application.class.to_s.titleize}",
|
3
|
+
status: "#{ExpressAccess::Route.all.count} routes",
|
4
|
+
class: ['large-table-container']
|
5
|
+
) {
|
6
|
+
smart_table(:routes,
|
7
|
+
actions: false,
|
8
|
+
sortable: ['Path', 'Endpoint', 'Description'],
|
9
|
+
columns: {
|
10
|
+
"Path" => :path_link,
|
11
|
+
"Endpoint" => :endp_link,
|
12
|
+
"Description" => :description_link,
|
13
|
+
"Applicable Permission" => -> (route) { route.permission ? (helpers.link_to route.permission.name, permission_path(route.permission.id)) : 'Any'},
|
14
|
+
"Roles" => -> (route) { route.permission ?
|
15
|
+
(route.permission.all_roles.map do |role|
|
16
|
+
helpers.link_to role.name, role_path(role.id)
|
17
|
+
end.join(", ")) : 'Anyone'
|
18
|
+
}
|
19
|
+
})
|
20
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
pane(title: "Resource: #{route.verb} #{route.path}") {
|
2
|
+
dl {
|
3
|
+
dt { "Action:" }
|
4
|
+
dd { route.description }
|
5
|
+
|
6
|
+
dt { "Scope:" }
|
7
|
+
dd { "#{route.path.split('/').select {|part| part.match(/:/) }.join(', ')}" }
|
8
|
+
|
9
|
+
dt { "Endpoint:"}
|
10
|
+
dd { route.endp }
|
11
|
+
|
12
|
+
dt { "Protected by:" }
|
13
|
+
dd { route.permission ? link_to(route.permission.name, permission_path(route.permission)) : 'Not protected'}
|
14
|
+
|
15
|
+
dt { "Roles Permitted:" }
|
16
|
+
dd { route.permission ? route.permission.all_roles.map {|role| helpers.link_to role.name, role_path(role)}.join(", ").html_safe : "Anyone"}
|
17
|
+
|
18
|
+
dt { "Access Log:" }
|
19
|
+
dd {
|
20
|
+
if route.log.any?
|
21
|
+
route.log.each do |log|
|
22
|
+
if log.any?
|
23
|
+
log.each do |day, logs|
|
24
|
+
ul(class: 'circle'){
|
25
|
+
li { "#{day.strftime("%B %d, %Y")}" }
|
26
|
+
logs.each do |each_log|
|
27
|
+
ul(class: 'no-bullet') {
|
28
|
+
pane(status: each_log.created_at.strftime("%H:%M %Z")) {
|
29
|
+
li { "By: #{each_log.user_email}" }
|
30
|
+
li { "With Permission: #{each_log.permission_name}"}
|
31
|
+
}
|
32
|
+
}
|
33
|
+
end
|
34
|
+
}
|
35
|
+
end
|
36
|
+
else
|
37
|
+
li { "none" }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
else
|
41
|
+
"none"
|
42
|
+
end
|
43
|
+
}
|
44
|
+
|
45
|
+
}
|
46
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
main_region {
|
2
|
+
h2 { 'Users' }
|
3
|
+
smart_table(:users, resource_class: "::User", resource_path: -> (user) { express_access.user_path(user) },
|
4
|
+
columns: {
|
5
|
+
"Email" => :email_link,
|
6
|
+
"Sign In Count" => :sign_in_count,
|
7
|
+
"Current Sign in At" => :current_sign_in_at,
|
8
|
+
"Last Sign In At" => :last_sign_in_at
|
9
|
+
})
|
10
|
+
}
|
11
|
+
sidebar_region {
|
12
|
+
pane(title: "User") {
|
13
|
+
smart_form(:user, resource_class: "::User", collection_path: -> { express_access.users_path },
|
14
|
+
resource_path: -> (user) { express_access.user_path(user) },
|
15
|
+
virtual: [:password, :password_confirmation],
|
16
|
+
exclude: [:encrypted_password,
|
17
|
+
:reset_password_token,
|
18
|
+
:reset_password_sent_at,
|
19
|
+
:remember_created_at,
|
20
|
+
:sign_in_count,
|
21
|
+
:current_sign_in_at,
|
22
|
+
:last_sign_in_at,
|
23
|
+
:current_sign_in_ip,
|
24
|
+
:last_sign_in_ip])
|
25
|
+
}
|
26
|
+
}
|
@@ -0,0 +1,55 @@
|
|
1
|
+
v_box {
|
2
|
+
h_box{
|
3
|
+
pane(title: "<strong>#{user.email}</strong>".html_safe) {
|
4
|
+
dl {
|
5
|
+
dt { "User Created At:" }
|
6
|
+
dd { user.created_at ? user.created_at.to_date : "unknown"}
|
7
|
+
|
8
|
+
dt { "Last Sign In:" }
|
9
|
+
dd { user.last_sign_in_at ? "#{time_ago_in_words(user.last_sign_in_at) << ' ago'}" : "never"}
|
10
|
+
}
|
11
|
+
}
|
12
|
+
v_box{
|
13
|
+
pane(title: "Roles of #{user.email}") {
|
14
|
+
smart_table(:user_roles,
|
15
|
+
collection: -> { user.user_roles },
|
16
|
+
columns: {"Name" => -> (role) { helpers.link_to role.name, role_path(role.role_id) },
|
17
|
+
"Date Assigned" => :created_at_in_words})
|
18
|
+
}
|
19
|
+
|
20
|
+
pane(title: "All Permissions for #{user.email}") {
|
21
|
+
smart_table(:user_permissions, actions: false,
|
22
|
+
collection: -> { user.user_permissions.sort_by(&:name) },
|
23
|
+
columns: {
|
24
|
+
'Permissions' => -> (permission) { helpers.link_to permission.name, permission_path(permission.permission_id)},
|
25
|
+
'Date Assigned' => :created_at_in_words }) # not yet correct date
|
26
|
+
}
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
pane(title: "Resources Access for #{user.email}", class: 'large-table-container') {
|
31
|
+
smart_table(:routes, actions: false,
|
32
|
+
collection: -> { user.permissions.flat_map { |permission| permission.all_routes } },
|
33
|
+
columns: {
|
34
|
+
"Path" => :path_link,
|
35
|
+
"Endpoint" => :endp_link,
|
36
|
+
"Description" => :description_link
|
37
|
+
})
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
v_box {
|
42
|
+
pane(title: 'Edit User') {
|
43
|
+
smart_form(:user, resource_class: "::User", resource_path: -> (user) { express_access.user_path(user) },
|
44
|
+
virtual: [:password, :password_confirmation],
|
45
|
+
exclude: [:encrypted_password,
|
46
|
+
:reset_password_token,
|
47
|
+
:reset_password_sent_at,
|
48
|
+
:remember_created_at,
|
49
|
+
:sign_in_count,
|
50
|
+
:current_sign_in_at,
|
51
|
+
:last_sign_in_at,
|
52
|
+
:current_sign_in_ip,
|
53
|
+
:last_sign_in_ip])
|
54
|
+
}
|
55
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
render(template: 'layouts/express_admin/admin')
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>ExpressAccess</title>
|
5
|
+
<%= stylesheet_link_tag "express_access/application", media: "all" %>
|
6
|
+
<%= javascript_include_tag "express_access/application" %>
|
7
|
+
<%= csrf_meta_tags %>
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
|
11
|
+
<%= yield %>
|
12
|
+
|
13
|
+
</body>
|
14
|
+
</html>
|
data/config/menu.yml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
title: 'Express Access'
|
2
|
+
path: 'express_access.users_path'
|
3
|
+
items:
|
4
|
+
-
|
5
|
+
title: 'Users'
|
6
|
+
path: 'express_access.users_path'
|
7
|
+
|
8
|
+
-
|
9
|
+
title: 'Roles'
|
10
|
+
path: 'express_access.roles_path'
|
11
|
+
|
12
|
+
-
|
13
|
+
title: 'Permissions'
|
14
|
+
path: 'express_access.permissions_path'
|
15
|
+
|
16
|
+
-
|
17
|
+
title: 'Routes'
|
18
|
+
path: 'express_access.routes_path'
|
data/config/routes.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
class CreateExpressAccessAuditLogs < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :express_access_audit_logs do |t|
|
4
|
+
t.string :user_email
|
5
|
+
t.string :permission_name
|
6
|
+
t.string :request_path
|
7
|
+
t.boolean :granted
|
8
|
+
t.string :controller_name
|
9
|
+
t.string :action_name
|
10
|
+
t.string :ip_address
|
11
|
+
|
12
|
+
t.timestamps null: false
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module ExpressAccess
|
2
|
+
class AuthorizationFilter
|
3
|
+
def self.before(controller)
|
4
|
+
if permission = ExpressAccess::Permission.for(controller: controller.request.params[:controller],
|
5
|
+
action: controller.request.params[:action],
|
6
|
+
path: controller.request.path)
|
7
|
+
if controller.current_user
|
8
|
+
unless controller.current_user.has?(permission)
|
9
|
+
Rails.logger.info("DOES NOT HAVE PERMISSION #{permission.name}")
|
10
|
+
AuditLog.create(user_email: controller.current_user.email,
|
11
|
+
permission_name: permission.name,
|
12
|
+
request_path: controller.request.path,
|
13
|
+
granted: false,
|
14
|
+
controller_name: controller.controller_path,
|
15
|
+
action_name: controller.action_name,
|
16
|
+
ip_address: controller.request.env['REMOTE_ADDR'])
|
17
|
+
controller.access_authorization_failed!
|
18
|
+
else
|
19
|
+
Rails.logger.info("HAS PERMISSION #{permission.name}")
|
20
|
+
AuditLog.create(user_email: controller.current_user.email,
|
21
|
+
permission_name: permission.name,
|
22
|
+
request_path: controller.request.path,
|
23
|
+
granted: true,
|
24
|
+
controller_name: controller.controller_path,
|
25
|
+
action_name: controller.action_name,
|
26
|
+
ip_address: controller.request.env['REMOTE_ADDR'])
|
27
|
+
nil # success
|
28
|
+
end
|
29
|
+
else
|
30
|
+
if defined?(Devise)
|
31
|
+
controller.authenticate_user!
|
32
|
+
else
|
33
|
+
controller.access_authorization_failed!
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'express_admin'
|
2
|
+
|
3
|
+
module ExpressAccess
|
4
|
+
class Engine < ::Rails::Engine
|
5
|
+
ExpressAccess::Engine.config.express_access_mount_point = '/admin/access'
|
6
|
+
initializer :assets do |config|
|
7
|
+
Rails.application.config.assets.precompile += %w( express_access.css express_access/admin.js express_access/admin.css )
|
8
|
+
end
|
9
|
+
include ::ExpressAdmin::Menu::Loader
|
10
|
+
isolate_namespace ExpressAccess
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'request_store'
|
2
|
+
module ExpressAccess
|
3
|
+
class Route
|
4
|
+
attr :name, :verb, :path, :endp, :reqs
|
5
|
+
|
6
|
+
def initialize(name, verb, path, endp, reqs = nil)
|
7
|
+
@name, @verb, @path, @endp, @reqs = name, verb, path, endp, reqs
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.find(id)
|
11
|
+
@routes ||= all.inject({}) {|hash, route| hash[route.id] = route; hash}
|
12
|
+
@routes[id]
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.columns
|
16
|
+
[OpenStruct.new(name: :name),
|
17
|
+
OpenStruct.new(name: :verb),
|
18
|
+
OpenStruct.new(name: :path),
|
19
|
+
OpenStruct.new(name: :endp),
|
20
|
+
OpenStruct.new(name: :reqs)]
|
21
|
+
end
|
22
|
+
|
23
|
+
def status_for_role(role)
|
24
|
+
if perm = permission
|
25
|
+
if role.permissions.include?(perm)
|
26
|
+
"granted"
|
27
|
+
else
|
28
|
+
"denied"
|
29
|
+
end
|
30
|
+
else
|
31
|
+
""
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def id
|
36
|
+
path.slice(1..-1).split('/').unshift(verb).join('-').downcase
|
37
|
+
end
|
38
|
+
|
39
|
+
alias :to_param :id
|
40
|
+
|
41
|
+
# these should be decorators
|
42
|
+
def description
|
43
|
+
if action.eql?('index')
|
44
|
+
"#{action_phrase.capitalize} #{object_phrase.titleize.pluralize}"
|
45
|
+
else
|
46
|
+
"#{action_phrase.capitalize} #{object_phrase.titleize}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def article
|
51
|
+
(object_phrase.match(/^[aeiou]/) &&
|
52
|
+
!object_phrase.match(/^user/)) ? 'an' : 'a'
|
53
|
+
end
|
54
|
+
|
55
|
+
def action_phrase
|
56
|
+
({
|
57
|
+
'new' => "view the form for a new",
|
58
|
+
'edit' => "view the form to edit #{article}",
|
59
|
+
'update' => "update #{article}",
|
60
|
+
'show' => "show details for #{article}",
|
61
|
+
'destroy'=> "delete #{article}",
|
62
|
+
'create' => "create a new",
|
63
|
+
'index' => "view a list of"
|
64
|
+
}[action] || action.pluralize)
|
65
|
+
end
|
66
|
+
|
67
|
+
def object_phrase
|
68
|
+
controller.split('/').last.singularize rescue 'Unknown'
|
69
|
+
end
|
70
|
+
|
71
|
+
def controller
|
72
|
+
endp.split('#').first || 'None'
|
73
|
+
end
|
74
|
+
|
75
|
+
def action
|
76
|
+
endp.split('#').last || 'None'
|
77
|
+
end
|
78
|
+
|
79
|
+
def permission
|
80
|
+
@permission ||= Permission.for(controller: controller, action: action, path: path)
|
81
|
+
end
|
82
|
+
|
83
|
+
def log
|
84
|
+
@log ||= AuditLog.for(endp)
|
85
|
+
end
|
86
|
+
|
87
|
+
class Formatter
|
88
|
+
attr :routes
|
89
|
+
attr :engines
|
90
|
+
def initialize
|
91
|
+
@routes = []
|
92
|
+
@engine_paths = {}
|
93
|
+
end
|
94
|
+
def result
|
95
|
+
@routes
|
96
|
+
end
|
97
|
+
|
98
|
+
def header(routes) ; end
|
99
|
+
def section_title(title) ; end
|
100
|
+
def no_routes ; end
|
101
|
+
|
102
|
+
def section(routes)
|
103
|
+
@routes += routes.map do |route|
|
104
|
+
endpoint = route[:reqs].match(/^(\S+)/).try(:[], 0)
|
105
|
+
requirements = route[:reqs].match(/^\S+\s(.*)/).try(:[], 1)
|
106
|
+
path = route[:path].gsub(/\(\.:format\)/, '')
|
107
|
+
if possible_engine = (endpoint.classify.constantize rescue nil)
|
108
|
+
if possible_engine.ancestors.include?(::Rails::Engine)
|
109
|
+
@engine_paths[endpoint.split("::").first.underscore] = path
|
110
|
+
end
|
111
|
+
end
|
112
|
+
if engine_path = @engine_paths[endpoint.split(/[\#\/]/).first]
|
113
|
+
path = [engine_path, path].join unless engine_path.eql?('/')
|
114
|
+
end
|
115
|
+
Route.new(route[:name], route[:verb], path, endpoint, requirements)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.all
|
121
|
+
RequestStore.store[:all_routes] ||= begin
|
122
|
+
inspector = ActionDispatch::Routing::RoutesInspector.new(Rails.application.routes.set)
|
123
|
+
inspector.format(Formatter.new)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'set'
|
2
|
+
module ExpressAccess
|
3
|
+
module User
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval do
|
6
|
+
include InstanceMethods
|
7
|
+
|
8
|
+
has_many :user_permissions, class_name: "::ExpressAccess::UserPermission"
|
9
|
+
|
10
|
+
has_many :direct_permissions, through: :user_permissions,
|
11
|
+
source: :permission,
|
12
|
+
class_name: "::ExpressAccess::Permission"
|
13
|
+
|
14
|
+
has_many :user_roles, class_name: "::ExpressAccess::UserRole"
|
15
|
+
|
16
|
+
has_many :roles, through: :user_roles,
|
17
|
+
source: :role,
|
18
|
+
class_name: "::ExpressAccess::Role"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module InstanceMethods
|
23
|
+
|
24
|
+
def role_permissions
|
25
|
+
roles.map(&:permissions).flatten
|
26
|
+
end
|
27
|
+
|
28
|
+
def permissions
|
29
|
+
(direct_permissions + role_permissions).to_set
|
30
|
+
end
|
31
|
+
|
32
|
+
def may?(permission_name)
|
33
|
+
if Permission[permission_name].nil?
|
34
|
+
true
|
35
|
+
else
|
36
|
+
permissions.map(&:name).include?(permission_name.to_s)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
alias may_do? may?
|
41
|
+
alias may_use? may?
|
42
|
+
|
43
|
+
def has?(permission)
|
44
|
+
raise "not a permission" unless permission.kind_of?(Permission)
|
45
|
+
may?(permission.name)
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def method_missing(*args)
|
50
|
+
name = args.first
|
51
|
+
if (action = name.to_s.match(/^may_(\w+)?/).try(:[], 1)) && args.size.eql?(2)
|
52
|
+
may?("#{args[1]}##{action}")
|
53
|
+
else
|
54
|
+
super(*args)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def name
|
59
|
+
super.send(:name) rescue email
|
60
|
+
end
|
61
|
+
|
62
|
+
def after_sign_in_path
|
63
|
+
return nil if role_with_after_sign_in_paths.nil?
|
64
|
+
|
65
|
+
role_with_after_sign_in_paths.after_sign_in_path
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
# The decision to keep this simple for now assume two things:
|
71
|
+
# 1. The user, more often than not, would only contain the most specific role. This means that it is unlikely that a user would have roles which have an ancestor-descendant relationship with each other. It would get a bit more complex though when we think about adding direct permissions to the roles.
|
72
|
+
# 2. If we have roles which are unrelated to each other and is possessed by a user, we wouldn't really be able to determine the user's preffered after_sign_in_path. This means that we just choose from any of those. We could also allow a per-user after_sign_in_path setting if possible for better fine tuning.
|
73
|
+
|
74
|
+
def role_with_after_sign_in_paths
|
75
|
+
roles.where.not(after_sign_in_path: nil).first
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "express_access/engine"
|
2
|
+
require 'express_access/user'
|
3
|
+
require 'express_access/authorization_filter'
|
4
|
+
require 'express_access/route'
|
5
|
+
require 'express_access/after_sign_in_filter'
|
6
|
+
|
7
|
+
module ExpressAccess
|
8
|
+
def self.initialize!
|
9
|
+
setup!
|
10
|
+
|
11
|
+
ActionDispatch::Reloader.to_prepare do
|
12
|
+
ExpressAccess.setup!
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.initialize_user!
|
17
|
+
User unless defined? ::User
|
18
|
+
|
19
|
+
::User.include ExpressAccess::User unless ::User.ancestors.include?(ExpressAccess::User)
|
20
|
+
puts "Added ExpressAccess::User to User" unless Rails.env.test?
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.initialize_filter!
|
24
|
+
unless ActionController::Base.method_defined? 'access_authorization_failed!'
|
25
|
+
ActionController::Base.class_eval do
|
26
|
+
before_filter ExpressAccess::AuthorizationFilter
|
27
|
+
|
28
|
+
def access_authorization_failed!
|
29
|
+
render :not_authorized, body: "Not authorized"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
puts "Added ExpressAccess::AuthorizationFilter to ActionController::Base" unless Rails.env.test?
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.initialize_after_sign_in_filter!
|
37
|
+
return nil if !defined?(Devise)
|
38
|
+
|
39
|
+
ApplicationController.include ExpressAccess::AfterSignInFilter
|
40
|
+
puts "Added ExpressAccess::AfterSignInFilter to ApplicationController" unless Rails.env.test?
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def self.setup!
|
46
|
+
initialize_user!
|
47
|
+
initialize_filter!
|
48
|
+
initialize_after_sign_in_filter!
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class ExpressAccess::InstallGenerator < Rails::Generators::Base
|
2
|
+
source_root File.expand_path('../templates', __FILE__)
|
3
|
+
|
4
|
+
desc "install express_access engine"
|
5
|
+
def install
|
6
|
+
rake "express_access:install:migrations"
|
7
|
+
create_file "config/initializers/express_access.rb", "ExpressAccess.initialize!"
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
== README
|
2
|
+
|
3
|
+
This README would normally document whatever steps are necessary to get the
|
4
|
+
application up and running.
|
5
|
+
|
6
|
+
Things you may want to cover:
|
7
|
+
|
8
|
+
* Ruby version
|
9
|
+
|
10
|
+
* System dependencies
|
11
|
+
|
12
|
+
* Configuration
|
13
|
+
|
14
|
+
* Database creation
|
15
|
+
|
16
|
+
* Database initialization
|
17
|
+
|
18
|
+
* How to run the test suite
|
19
|
+
|
20
|
+
* Services (job queues, cache servers, search engines, etc.)
|
21
|
+
|
22
|
+
* Deployment instructions
|
23
|
+
|
24
|
+
* ...
|
25
|
+
|
26
|
+
|
27
|
+
Please feel free to use a different markup language if you do not plan to run
|
28
|
+
<tt>rake doc:app</tt>.
|
data/test/dummy/Rakefile
ADDED