express_access 1.0.0.a

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.
Files changed (123) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +87 -0
  3. data/Rakefile +34 -0
  4. data/app/assets/javascripts/express_access/admin.js +1 -0
  5. data/app/assets/stylesheets/express_access/admin.css +5 -0
  6. data/app/assets/stylesheets/express_access/application.css +15 -0
  7. data/app/assets/stylesheets/express_access/main.sass +3 -0
  8. data/app/assets/stylesheets/express_access/sections/_role_dashboard.sass +29 -0
  9. data/app/assets/stylesheets/express_access.css +4 -0
  10. data/app/controllers/express_access/permissions_controller.rb +4 -0
  11. data/app/controllers/express_access/roles_controller.rb +14 -0
  12. data/app/controllers/express_access/routes_controller.rb +30 -0
  13. data/app/controllers/express_access/users_controller.rb +21 -0
  14. data/app/helpers/express_access/application_helper.rb +4 -0
  15. data/app/helpers/express_access/permissions_helper.rb +4 -0
  16. data/app/helpers/express_access/roles_helper.rb +4 -0
  17. data/app/models/express_access/audit_log.rb +27 -0
  18. data/app/models/express_access/permission.rb +130 -0
  19. data/app/models/express_access/role.rb +75 -0
  20. data/app/models/express_access/role_permission.rb +6 -0
  21. data/app/models/express_access/user_permission.rb +7 -0
  22. data/app/models/express_access/user_role.rb +7 -0
  23. data/app/views/express_access/permissions/index.html.et +13 -0
  24. data/app/views/express_access/permissions/show.html.et +33 -0
  25. data/app/views/express_access/roles/index.html.et +9 -0
  26. data/app/views/express_access/roles/show.html.et +68 -0
  27. data/app/views/express_access/routes/index.html.et +20 -0
  28. data/app/views/express_access/routes/show.html.et +46 -0
  29. data/app/views/express_access/users/index.html.et +26 -0
  30. data/app/views/express_access/users/show.html.et +55 -0
  31. data/app/views/layouts/express_access/admin.html.et +1 -0
  32. data/app/views/layouts/express_access/application.html.erb +14 -0
  33. data/config/initializers/mount_engine.rb +3 -0
  34. data/config/menu.yml +18 -0
  35. data/config/routes.rb +6 -0
  36. data/db/migrate/20141029223053_create_express_access_roles.rb +10 -0
  37. data/db/migrate/20141029223158_create_express_access_permissions.rb +9 -0
  38. data/db/migrate/20141029223233_create_express_access_role_permissions.rb +10 -0
  39. data/db/migrate/20141029223250_create_express_access_user_permissions.rb +10 -0
  40. data/db/migrate/20150528222337_create_express_access_user_roles.rb +9 -0
  41. data/db/migrate/20150609124815_add_description_to_role.rb +5 -0
  42. data/db/migrate/20150914023030_create_express_access_audit_logs.rb +15 -0
  43. data/db/migrate/20150921063153_add_after_sign_in_path_to_role.rb +5 -0
  44. data/lib/express_access/after_sign_in_filter.rb +7 -0
  45. data/lib/express_access/authorization_filter.rb +39 -0
  46. data/lib/express_access/engine.rb +12 -0
  47. data/lib/express_access/route.rb +127 -0
  48. data/lib/express_access/user.rb +79 -0
  49. data/lib/express_access/version.rb +3 -0
  50. data/lib/express_access.rb +51 -0
  51. data/lib/generators/express_access/install/USAGE +8 -0
  52. data/lib/generators/express_access/install/install_generator.rb +10 -0
  53. data/lib/tasks/express_access_tasks.rake +4 -0
  54. data/test/dummy/README.rdoc +28 -0
  55. data/test/dummy/Rakefile +6 -0
  56. data/test/dummy/app/assets/javascripts/application.js +13 -0
  57. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  58. data/test/dummy/app/controllers/application_controller.rb +5 -0
  59. data/test/dummy/app/controllers/posts_controller.rb +4 -0
  60. data/test/dummy/app/helpers/application_helper.rb +2 -0
  61. data/test/dummy/app/models/user.rb +9 -0
  62. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  63. data/test/dummy/app/views/posts/index.html.erb +0 -0
  64. data/test/dummy/bin/bundle +3 -0
  65. data/test/dummy/bin/rails +4 -0
  66. data/test/dummy/bin/rake +4 -0
  67. data/test/dummy/config/application.rb +25 -0
  68. data/test/dummy/config/boot.rb +5 -0
  69. data/test/dummy/config/database.yml +25 -0
  70. data/test/dummy/config/environment.rb +5 -0
  71. data/test/dummy/config/environments/development.rb +37 -0
  72. data/test/dummy/config/environments/production.rb +83 -0
  73. data/test/dummy/config/environments/test.rb +41 -0
  74. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  75. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  76. data/test/dummy/config/initializers/devise.rb +259 -0
  77. data/test/dummy/config/initializers/express_access.rb +1 -0
  78. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  79. data/test/dummy/config/initializers/inflections.rb +16 -0
  80. data/test/dummy/config/initializers/mime_types.rb +4 -0
  81. data/test/dummy/config/initializers/session_store.rb +3 -0
  82. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  83. data/test/dummy/config/locales/devise.en.yml +60 -0
  84. data/test/dummy/config/locales/en.yml +23 -0
  85. data/test/dummy/config/routes.rb +7 -0
  86. data/test/dummy/config/secrets.yml +22 -0
  87. data/test/dummy/config.ru +4 -0
  88. data/test/dummy/db/migrate/20150525001419_devise_create_users.rb +42 -0
  89. data/test/dummy/db/schema.rb +82 -0
  90. data/test/dummy/public/404.html +67 -0
  91. data/test/dummy/public/422.html +67 -0
  92. data/test/dummy/public/500.html +66 -0
  93. data/test/dummy/public/favicon.ico +0 -0
  94. data/test/dummy/test/fixtures/express_access/permissions.yml +28 -0
  95. data/test/dummy/test/fixtures/express_access/role_permissions.yml +21 -0
  96. data/test/dummy/test/fixtures/express_access/roles.yml +27 -0
  97. data/test/dummy/test/fixtures/express_access/user_permissions.yml +5 -0
  98. data/test/dummy/test/fixtures/express_access/user_roles.yml +15 -0
  99. data/test/dummy/test/fixtures/users.yml +19 -0
  100. data/test/dummy/test/initializer_test.rb +8 -0
  101. data/test/dummy/test/models/user_test.rb +7 -0
  102. data/test/express_access_test.rb +7 -0
  103. data/test/fixtures/express_access/audit_logs.yml +10 -0
  104. data/test/fixtures/express_access/permissions.yml +28 -0
  105. data/test/fixtures/express_access/role_permissions.yml +21 -0
  106. data/test/fixtures/express_access/roles.yml +34 -0
  107. data/test/fixtures/express_access/user_permissions.yml +5 -0
  108. data/test/fixtures/express_access/user_roles.yml +19 -0
  109. data/test/fixtures/users.yml +22 -0
  110. data/test/helpers/express_access/permissions_helper_test.rb +6 -0
  111. data/test/helpers/express_access/roles_helper_test.rb +6 -0
  112. data/test/integration/navigation_test.rb +33 -0
  113. data/test/lib/authorization_filter_test.rb +64 -0
  114. data/test/lib/generators/express_access/install/install_generator_test.rb +16 -0
  115. data/test/models/express_access/audit_log_test.rb +9 -0
  116. data/test/models/express_access/permission_test.rb +50 -0
  117. data/test/models/express_access/role_permission_test.rb +9 -0
  118. data/test/models/express_access/role_test.rb +36 -0
  119. data/test/models/express_access/user_permission_test.rb +9 -0
  120. data/test/models/express_access/user_role_test.rb +9 -0
  121. data/test/models/express_access/user_test.rb +77 -0
  122. data/test/test_helper.rb +19 -0
  123. 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>
@@ -0,0 +1,3 @@
1
+ ExpressAdmin::Routes.register do |routes|
2
+ routes.mount ExpressAccess::Engine, at: ExpressAccess::Engine.config.express_access_mount_point
3
+ end
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,6 @@
1
+ ExpressAccess::Engine.routes.draw do
2
+ resources :permissions, except: [:edit]
3
+ resources :users, except: [:edit]
4
+ resources :roles, except: [:edit]
5
+ resources :routes, except: [:edit]
6
+ end
@@ -0,0 +1,10 @@
1
+ class CreateExpressAccessRoles < ActiveRecord::Migration
2
+ def change
3
+ create_table :express_access_roles do |t|
4
+ t.string :name
5
+ t.integer :parent_id
6
+
7
+ t.timestamps null: false
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ class CreateExpressAccessPermissions < ActiveRecord::Migration
2
+ def change
3
+ create_table :express_access_permissions do |t|
4
+ t.string :name
5
+
6
+ t.timestamps null: false
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ class CreateExpressAccessRolePermissions < ActiveRecord::Migration
2
+ def change
3
+ create_table :express_access_role_permissions do |t|
4
+ t.integer :role_id
5
+ t.integer :permission_id
6
+
7
+ t.timestamps null: false
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ class CreateExpressAccessUserPermissions < ActiveRecord::Migration
2
+ def change
3
+ create_table :express_access_user_permissions do |t|
4
+ t.integer :user_id
5
+ t.integer :permission_id
6
+
7
+ t.timestamps null: false
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ class CreateExpressAccessUserRoles < ActiveRecord::Migration
2
+ def change
3
+ create_table :express_access_user_roles do |t|
4
+ t.integer :user_id
5
+ t.integer :role_id
6
+ t.timestamps null: false
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ class AddDescriptionToRole < ActiveRecord::Migration
2
+ def change
3
+ add_column :express_access_roles, :description, :string
4
+ end
5
+ end
@@ -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,5 @@
1
+ class AddAfterSignInPathToRole < ActiveRecord::Migration
2
+ def change
3
+ add_column :express_access_roles, :after_sign_in_path, :string
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ module ExpressAccess
2
+ module AfterSignInFilter
3
+ def after_sign_in_path_for(user)
4
+ stored_location_for(user) || user.after_sign_in_path || root_path
5
+ end
6
+ end
7
+ 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,3 @@
1
+ module ExpressAccess
2
+ VERSION = "1.0.0.a"
3
+ 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,8 @@
1
+ Description:
2
+ Explain the generator
3
+
4
+ Example:
5
+ rails generate install Thing
6
+
7
+ This will create:
8
+ what/will/it/create
@@ -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,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :express_rbac do
3
+ # # Task goes here
4
+ # 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>.
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require File.expand_path('../config/application', __FILE__)
5
+
6
+ Rails.application.load_tasks