authorizable 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +33 -0
  3. data/.travis.yml +14 -0
  4. data/Gemfile +6 -0
  5. data/Gemfile.lock +178 -0
  6. data/LICENSE +22 -0
  7. data/README.md +80 -0
  8. data/Rakefile +1 -0
  9. data/authorizable.gemspec +40 -0
  10. data/config/locales/en.yml +6 -0
  11. data/lib/authorizable.rb +31 -0
  12. data/lib/authorizable/controller.rb +156 -0
  13. data/lib/authorizable/model.rb +162 -0
  14. data/lib/authorizable/permission_utilities.rb +89 -0
  15. data/lib/authorizable/permissions.rb +112 -0
  16. data/lib/authorizable/version.rb +5 -0
  17. data/spec/integration/controller_spec.rb +127 -0
  18. data/spec/integration/model_spec.rb +169 -0
  19. data/spec/rails_helper.rb +14 -0
  20. data/spec/spec_helper.rb +48 -0
  21. data/spec/support/definitions.rb +16 -0
  22. data/spec/support/factories.rb +17 -0
  23. data/spec/support/factory_girl.rb +7 -0
  24. data/spec/support/rails_app/Rakefile +6 -0
  25. data/spec/support/rails_app/app/assets/images/.keep +0 -0
  26. data/spec/support/rails_app/app/assets/javascripts/application.js +16 -0
  27. data/spec/support/rails_app/app/assets/javascripts/some_resources.js +2 -0
  28. data/spec/support/rails_app/app/assets/javascripts/users.js +2 -0
  29. data/spec/support/rails_app/app/assets/stylesheets/application.css +15 -0
  30. data/spec/support/rails_app/app/assets/stylesheets/scaffold.css +56 -0
  31. data/spec/support/rails_app/app/assets/stylesheets/some_resources.css +4 -0
  32. data/spec/support/rails_app/app/assets/stylesheets/users.css +4 -0
  33. data/spec/support/rails_app/app/controllers/application_controller.rb +14 -0
  34. data/spec/support/rails_app/app/controllers/events_controller.rb +58 -0
  35. data/spec/support/rails_app/app/controllers/users_controller.rb +58 -0
  36. data/spec/support/rails_app/app/helpers/application_helper.rb +2 -0
  37. data/spec/support/rails_app/app/helpers/events_helper.rb +2 -0
  38. data/spec/support/rails_app/app/helpers/users_helper.rb +2 -0
  39. data/spec/support/rails_app/app/mailers/.keep +0 -0
  40. data/spec/support/rails_app/app/models/collaboration.rb +16 -0
  41. data/spec/support/rails_app/app/models/concerns/.keep +0 -0
  42. data/spec/support/rails_app/app/models/discount.rb +3 -0
  43. data/spec/support/rails_app/app/models/event.rb +5 -0
  44. data/spec/support/rails_app/app/models/user.rb +9 -0
  45. data/spec/support/rails_app/app/views/events/_form.html.erb +17 -0
  46. data/spec/support/rails_app/app/views/events/edit.html.erb +6 -0
  47. data/spec/support/rails_app/app/views/events/index.html.erb +25 -0
  48. data/spec/support/rails_app/app/views/events/new.html.erb +5 -0
  49. data/spec/support/rails_app/app/views/events/show.html.erb +4 -0
  50. data/spec/support/rails_app/app/views/layouts/application.html.erb +14 -0
  51. data/spec/support/rails_app/app/views/users/_form.html.erb +17 -0
  52. data/spec/support/rails_app/app/views/users/edit.html.erb +6 -0
  53. data/spec/support/rails_app/app/views/users/index.html.erb +25 -0
  54. data/spec/support/rails_app/app/views/users/new.html.erb +5 -0
  55. data/spec/support/rails_app/app/views/users/show.html.erb +4 -0
  56. data/spec/support/rails_app/bin/bundle +3 -0
  57. data/spec/support/rails_app/bin/rails +8 -0
  58. data/spec/support/rails_app/bin/rake +4 -0
  59. data/spec/support/rails_app/config.ru +0 -0
  60. data/spec/support/rails_app/config/application.rb +29 -0
  61. data/spec/support/rails_app/config/boot.rb +3 -0
  62. data/spec/support/rails_app/config/database.yml +25 -0
  63. data/spec/support/rails_app/config/environment.rb +5 -0
  64. data/spec/support/rails_app/config/environments/development.rb +41 -0
  65. data/spec/support/rails_app/config/environments/production.rb +79 -0
  66. data/spec/support/rails_app/config/environments/test.rb +42 -0
  67. data/spec/support/rails_app/config/initializers/assets.rb +11 -0
  68. data/spec/support/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  69. data/spec/support/rails_app/config/initializers/cookies_serializer.rb +3 -0
  70. data/spec/support/rails_app/config/initializers/filter_parameter_logging.rb +4 -0
  71. data/spec/support/rails_app/config/initializers/inflections.rb +16 -0
  72. data/spec/support/rails_app/config/initializers/mime_types.rb +4 -0
  73. data/spec/support/rails_app/config/initializers/session_store.rb +3 -0
  74. data/spec/support/rails_app/config/initializers/wrap_parameters.rb +14 -0
  75. data/spec/support/rails_app/config/locales/en.yml +23 -0
  76. data/spec/support/rails_app/config/routes.rb +60 -0
  77. data/spec/support/rails_app/config/secrets.yml +22 -0
  78. data/spec/support/rails_app/db/development.sqlite3 +0 -0
  79. data/spec/support/rails_app/db/migrate/20141231134904_create_users.rb +8 -0
  80. data/spec/support/rails_app/db/migrate/20150102221633_create_collaborations.rb +13 -0
  81. data/spec/support/rails_app/db/migrate/20150102225507_create_events.rb +9 -0
  82. data/spec/support/rails_app/db/migrate/20150104171110_create_discounts.rb +11 -0
  83. data/spec/support/rails_app/db/schema.rb +45 -0
  84. data/spec/support/rails_app/db/seeds.rb +7 -0
  85. data/spec/support/rails_app/db/test.sqlite3 +0 -0
  86. data/spec/support/rails_app/log/development.log +26296 -0
  87. data/spec/support/rails_app/public/404.html +67 -0
  88. data/spec/support/rails_app/public/422.html +67 -0
  89. data/spec/support/rails_app/public/500.html +66 -0
  90. data/spec/support/rails_app/public/favicon.ico +0 -0
  91. data/spec/support/rails_app/public/robots.txt +5 -0
  92. data/spec/unit/permission_utilities_spec.rb +157 -0
  93. data/spec/unit/permissions_spec.rb +65 -0
  94. metadata +352 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 77b3ab727e51ec220be5820eed631d12c66e9bc9
4
+ data.tar.gz: e613cfad5041f4419977489325edbe0054aca213
5
+ SHA512:
6
+ metadata.gz: c28114098c0412fe8238865421378c5c97a1f82b8a1499bfe6264658d71e0541410ed1eacaa26ff1623b6d6883733c0092f054fd31da8bd4f051597bf55a3ba7
7
+ data.tar.gz: 3ae8cd4b03c111c7e826b9bd102fa58b68c228818f3354fb538a604946389f2821edee2ddd74958e830a7f2a6829b0fa71fb10a9c65c0efa65fb01e117606bf3
@@ -0,0 +1,33 @@
1
+ *.rbc
2
+ capybara-*.html
3
+ .rspec
4
+ /log
5
+ /spec/rails_app/log
6
+ /tmp
7
+ /spec/rails_app/tmp
8
+ /db/*.sqlite3
9
+ /public/system
10
+ /coverage/
11
+ /spec/tmp
12
+ **.orig
13
+ rerun.txt
14
+ pickle-email-*.html
15
+
16
+ # TODO Comment out these rules if you are OK with secrets being uploaded to the repo
17
+ config/initializers/secret_token.rb
18
+ config/secrets.yml
19
+
20
+ ## Environment normalisation:
21
+ /.bundle
22
+ /vendor/bundle
23
+
24
+ # these should all be checked in to normalise the environment:
25
+ # Gemfile.lock, .ruby-version, .ruby-gemset
26
+
27
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
28
+ .rvmrc
29
+
30
+ # if using bower-rails ignore default bower_components path bower.json files
31
+ /vendor/assets/bower_components
32
+ *.bowerrc
33
+ bower.json
@@ -0,0 +1,14 @@
1
+ language: ruby
2
+ bundler_args: --without guard
3
+ rvm:
4
+ - "2.0"
5
+ - "2.1"
6
+ - ruby-head
7
+ script: "bundle exec rspec"
8
+ addons:
9
+ code_climate:
10
+ repo_token: 68f28e1d037ca7b58d24f943b59d82cd649e1f9b9f79437d4a5d864140dd4eb0
11
+ branches:
12
+ only: master
13
+ notifications:
14
+ email: false
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in authorizable.gemspec
4
+ gemspec
5
+
6
+ gem "codeclimate-test-reporter", git: "https://github.com/codeclimate/ruby-test-reporter.git", branch: "check_git_dir"
@@ -0,0 +1,178 @@
1
+ GIT
2
+ remote: https://github.com/codeclimate/ruby-test-reporter.git
3
+ revision: 7eeff8c596b1b540cb7ff004b93053265e4d8be5
4
+ branch: check_git_dir
5
+ specs:
6
+ codeclimate-test-reporter (0.4.4)
7
+ simplecov (>= 0.7.1, < 1.0.0)
8
+
9
+ PATH
10
+ remote: .
11
+ specs:
12
+ authorizable (0.9.0)
13
+ activesupport (>= 3.0.0)
14
+ i18n
15
+
16
+ GEM
17
+ remote: https://rubygems.org/
18
+ specs:
19
+ actionmailer (4.2.0)
20
+ actionpack (= 4.2.0)
21
+ actionview (= 4.2.0)
22
+ activejob (= 4.2.0)
23
+ mail (~> 2.5, >= 2.5.4)
24
+ rails-dom-testing (~> 1.0, >= 1.0.5)
25
+ actionpack (4.2.0)
26
+ actionview (= 4.2.0)
27
+ activesupport (= 4.2.0)
28
+ rack (~> 1.6.0)
29
+ rack-test (~> 0.6.2)
30
+ rails-dom-testing (~> 1.0, >= 1.0.5)
31
+ rails-html-sanitizer (~> 1.0, >= 1.0.1)
32
+ actionview (4.2.0)
33
+ activesupport (= 4.2.0)
34
+ builder (~> 3.1)
35
+ erubis (~> 2.7.0)
36
+ rails-dom-testing (~> 1.0, >= 1.0.5)
37
+ rails-html-sanitizer (~> 1.0, >= 1.0.1)
38
+ activejob (4.2.0)
39
+ activesupport (= 4.2.0)
40
+ globalid (>= 0.3.0)
41
+ activemodel (4.2.0)
42
+ activesupport (= 4.2.0)
43
+ builder (~> 3.1)
44
+ activerecord (4.2.0)
45
+ activemodel (= 4.2.0)
46
+ activesupport (= 4.2.0)
47
+ arel (~> 6.0)
48
+ activesupport (4.2.0)
49
+ i18n (~> 0.7)
50
+ json (~> 1.7, >= 1.7.7)
51
+ minitest (~> 5.1)
52
+ thread_safe (~> 0.3, >= 0.3.4)
53
+ tzinfo (~> 1.1)
54
+ arel (6.0.0)
55
+ awesome_print (1.6.1)
56
+ builder (3.2.2)
57
+ byebug (3.5.1)
58
+ columnize (~> 0.8)
59
+ debugger-linecache (~> 1.2)
60
+ slop (~> 3.6)
61
+ coderay (1.1.0)
62
+ columnize (0.9.0)
63
+ debugger-linecache (1.2.0)
64
+ diff-lcs (1.2.5)
65
+ docile (1.1.5)
66
+ erubis (2.7.0)
67
+ factory_girl (4.5.0)
68
+ activesupport (>= 3.0.0)
69
+ factory_girl_rails (4.5.0)
70
+ factory_girl (~> 4.5.0)
71
+ railties (>= 3.0.0)
72
+ globalid (0.3.0)
73
+ activesupport (>= 4.1.0)
74
+ hike (1.2.3)
75
+ i18n (0.7.0)
76
+ json (1.8.1)
77
+ loofah (2.0.1)
78
+ nokogiri (>= 1.5.9)
79
+ mail (2.6.3)
80
+ mime-types (>= 1.16, < 3)
81
+ method_source (0.8.2)
82
+ mime-types (2.4.3)
83
+ mini_portile (0.6.2)
84
+ minitest (5.5.0)
85
+ multi_json (1.10.1)
86
+ nokogiri (1.6.5)
87
+ mini_portile (~> 0.6.0)
88
+ pry (0.10.1)
89
+ coderay (~> 1.1.0)
90
+ method_source (~> 0.8.1)
91
+ slop (~> 3.4)
92
+ pry-byebug (2.0.0)
93
+ byebug (~> 3.4)
94
+ pry (~> 0.10)
95
+ rack (1.6.0)
96
+ rack-test (0.6.2)
97
+ rack (>= 1.0)
98
+ rails (4.2.0)
99
+ actionmailer (= 4.2.0)
100
+ actionpack (= 4.2.0)
101
+ actionview (= 4.2.0)
102
+ activejob (= 4.2.0)
103
+ activemodel (= 4.2.0)
104
+ activerecord (= 4.2.0)
105
+ activesupport (= 4.2.0)
106
+ bundler (>= 1.3.0, < 2.0)
107
+ railties (= 4.2.0)
108
+ sprockets-rails
109
+ rails-deprecated_sanitizer (1.0.3)
110
+ activesupport (>= 4.2.0.alpha)
111
+ rails-dom-testing (1.0.5)
112
+ activesupport (>= 4.2.0.beta, < 5.0)
113
+ nokogiri (~> 1.6.0)
114
+ rails-deprecated_sanitizer (>= 1.0.1)
115
+ rails-html-sanitizer (1.0.1)
116
+ loofah (~> 2.0)
117
+ railties (4.2.0)
118
+ actionpack (= 4.2.0)
119
+ activesupport (= 4.2.0)
120
+ rake (>= 0.8.7)
121
+ thor (>= 0.18.1, < 2.0)
122
+ rake (10.4.2)
123
+ rspec (3.1.0)
124
+ rspec-core (~> 3.1.0)
125
+ rspec-expectations (~> 3.1.0)
126
+ rspec-mocks (~> 3.1.0)
127
+ rspec-core (3.1.7)
128
+ rspec-support (~> 3.1.0)
129
+ rspec-expectations (3.1.2)
130
+ diff-lcs (>= 1.2.0, < 2.0)
131
+ rspec-support (~> 3.1.0)
132
+ rspec-mocks (3.1.3)
133
+ rspec-support (~> 3.1.0)
134
+ rspec-rails (3.1.0)
135
+ actionpack (>= 3.0)
136
+ activesupport (>= 3.0)
137
+ railties (>= 3.0)
138
+ rspec-core (~> 3.1.0)
139
+ rspec-expectations (~> 3.1.0)
140
+ rspec-mocks (~> 3.1.0)
141
+ rspec-support (~> 3.1.0)
142
+ rspec-support (3.1.2)
143
+ simplecov (0.9.1)
144
+ docile (~> 1.1.0)
145
+ multi_json (~> 1.0)
146
+ simplecov-html (~> 0.8.0)
147
+ simplecov-html (0.8.0)
148
+ slop (3.6.0)
149
+ sprockets (2.12.3)
150
+ hike (~> 1.2)
151
+ multi_json (~> 1.0)
152
+ rack (~> 1.0)
153
+ tilt (~> 1.1, != 1.3.0)
154
+ sprockets-rails (2.2.2)
155
+ actionpack (>= 3.0)
156
+ activesupport (>= 3.0)
157
+ sprockets (>= 2.8, < 4.0)
158
+ sqlite3 (1.3.10)
159
+ thor (0.19.1)
160
+ thread_safe (0.3.4)
161
+ tilt (1.4.1)
162
+ tzinfo (1.2.2)
163
+ thread_safe (~> 0.1)
164
+
165
+ PLATFORMS
166
+ ruby
167
+
168
+ DEPENDENCIES
169
+ authorizable!
170
+ awesome_print
171
+ bundler
172
+ codeclimate-test-reporter!
173
+ factory_girl_rails (~> 4.4)
174
+ pry-byebug
175
+ rails (>= 4)
176
+ rspec
177
+ rspec-rails
178
+ sqlite3
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 L. Preston Sego III
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,80 @@
1
+ authorizable
2
+ ============
3
+
4
+ A gem for rails giving vast flexibility in authorization management.
5
+
6
+ [![docs](https://img.shields.io/badge/docs-yardoc-blue.svg?style=flat-square)](http://www.rubydoc.info/github/NullVoxPopuli/authorizable)
7
+ [![Build Status](http://img.shields.io/travis/NullVoxPopuli/authorizable.svg?style=flat-square)](https://travis-ci.org/NullVoxPopuli/authorizable)
8
+ [![Code Climate](http://img.shields.io/codeclimate/github/NullVoxPopuli/authorizable.svg?style=flat-square)](https://codeclimate.com/github/NullVoxPopuli/authorizable)
9
+ [![Test Coverage](http://img.shields.io/codeclimate/coverage/github/NullVoxPopuli/authorizable.svg?style=flat-square)](https://codeclimate.com/github/NullVoxPopuli/authorizable)
10
+
11
+
12
+ ## Features
13
+
14
+ - Customizable Permissions
15
+ - Permissions are all defined in one place
16
+ - Role-Based
17
+ - Easy UI Generation
18
+ - Categorization for Organizing Permission in the UI
19
+ - Easily Extensible (e.g.: adding support for permission groups )
20
+ - Automatic controller response upon unauthorized status
21
+ - Controller response is customizable
22
+ - Controller behavior defined in one place (optionally in the controller)
23
+
24
+ ## Installation
25
+
26
+ Gemfile
27
+
28
+ gem "authorizable", github: "NullVoxPopuli/authorizable"
29
+
30
+ ## Configuration
31
+ ### Defining permissions
32
+
33
+ There are a couple ways that permissions can be defined.
34
+
35
+ If you like calling methods for configuration:
36
+
37
+ module Authorizable
38
+ class Permissions
39
+ can :delete_event
40
+ end
41
+ end
42
+
43
+ will create a permission definition called `delete_event` which can be accessed by calling
44
+ `user.can_delete_event?(@event)`
45
+
46
+ module Authorizable
47
+ class Permissions
48
+ can :edit_event, true, "Edit an Event", nil, ->(e, user){ e.user == user }
49
+ end
50
+ end
51
+
52
+ will create a permission definition called `edit_event` with an additional condition allowing editing only if the user owns the event
53
+
54
+ Authorizable::Permissions.set(
55
+ edit_organization: [Authorizable::OBJECT, true],
56
+ delete_organization: [Authorizable::OBJECT, [true, false], nil, ->(e, user){ e.user == user }, ->(e, user){ e.owner == user }]
57
+ )
58
+
59
+ This is how Authorizable references the permission definitions internally, just as raw permission: definition sets. Note that `Authorizable::Permissions.set` overrides the definitions list each time.
60
+
61
+ ### Customizing roles
62
+
63
+ coming soon...
64
+
65
+ ### Supporting group-based permissions
66
+
67
+ coming soon...
68
+
69
+ ## Why not CanCan?
70
+
71
+ Initially, I wanted something more customizable and that could aid in the generation of a UI where users
72
+ can customize permissions for various groups or organizations. My goal is to at least support everything CanCan has, but with the mindset and intention of customizing behavior and remaining DRY.
73
+
74
+ ## Contributing
75
+
76
+ 1. Fork the project
77
+ 2. Create a new, descriptively named branch
78
+ 3. Add Test(s)!
79
+ 4. Commit your proposed changes
80
+ 5. Submit a pull request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,40 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require "authorizable/version"
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = "authorizable"
9
+ s.version = Authorizable::VERSION
10
+ s.platform = Gem::Platform::RUBY
11
+ s.license = "MIT"
12
+ s.authors = ["L. Preston Sego III"]
13
+ s.email = "LPSego3+dev@gmail.com"
14
+ s.homepage = "https://github.com/NullVoxPopuli/authorizable"
15
+ s.summary = "Authorizable-#{Authorizable::VERSION}"
16
+ s.description = "A gem for rails giving vast flexibility in authorization management."
17
+
18
+
19
+ s.files = `git ls-files`.split($/)
20
+ s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
21
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
22
+ s.require_paths = ["lib"]
23
+
24
+
25
+ s.add_runtime_dependency "activesupport", ">= 3.0.0"
26
+ s.add_runtime_dependency "i18n"
27
+
28
+ # for testing a gem with a rails app (controller specs)
29
+ # https://codingdaily.wordpress.com/2011/01/14/test-a-gem-with-the-rails-3-stack/
30
+ s.add_development_dependency "bundler"
31
+ s.add_development_dependency "rails", ">= 4"
32
+ s.add_development_dependency "factory_girl_rails", "~> 4.4"
33
+ s.add_development_dependency "awesome_print"
34
+ s.add_development_dependency "rspec"
35
+ s.add_development_dependency "rspec-rails"
36
+ s.add_development_dependency "sqlite3"
37
+ s.add_development_dependency "pry-byebug"
38
+ # s.add_development_dependency "codeclimate-test-reporter", "0.4.3"
39
+
40
+ end
@@ -0,0 +1,6 @@
1
+ en:
2
+ authorizable:
3
+ redirect_path_must_be_proc: ":redirect_path must be a proc"
4
+ redirect_path_required: ":redirect_path is required"
5
+ permission_required: ":permission is required when :target is omitted"
6
+ not_authorized: You do not have permission to do that
@@ -0,0 +1,31 @@
1
+ require 'active_record'
2
+ require 'active_support'
3
+ require 'action_controller'
4
+
5
+ require 'authorizable/permission_utilities'
6
+ require 'authorizable/permissions'
7
+ require 'authorizable/controller'
8
+ require 'authorizable/model'
9
+ require 'authorizable/version'
10
+
11
+ module Authorizable
12
+ OBJECT = PermissionUtilities::OBJECT
13
+ ACCESS = PermissionUtilities::ACCESS
14
+
15
+ def self.definitions
16
+ Authorizable::Permissions.definitions || {}
17
+ end
18
+ end
19
+
20
+ # add authorizable method to ActionController
21
+ ActionController::Base.send(:include, Authorizable::Controller)
22
+ # class ActionController::Base
23
+ # include Authorizable::Controller
24
+
25
+ # def self.authorizable
26
+ # ap 'wat'
27
+ # end
28
+ # end
29
+
30
+ # add authorizable method to ActiveModel
31
+ # ActiveRecord::Base.send( :extend, Authorizable::Model )
@@ -0,0 +1,156 @@
1
+ module Authorizable
2
+ module Controller
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+
7
+ # where the config for this controller is stored
8
+ # after validation
9
+ class_attribute :authorizable_config
10
+ end
11
+
12
+ module ClassMethods
13
+ # sets up a before filter that will redirect if the permission
14
+ # condition fails
15
+ #
16
+ # @example
17
+ # authorizable(
18
+ # edit: { # implies current_user.can_edit?(@event)
19
+ # target: :event,
20
+ # redirect_path: Proc.new{ hosted_event_path(@event) }
21
+ # }
22
+ # )
23
+ #
24
+ # @example
25
+ # authorizable(
26
+ # create: {
27
+ # permission: :can_create_event?,
28
+ # redirect_path: Proc.new{ hosted_events_path }
29
+ # },
30
+ # destroy: { # implies current_user.can_delete?(@event)
31
+ # target: :event,
32
+ # redirect_path: Proc.new{ hosted_event_path(@event) }
33
+ # }
34
+ # )
35
+ #
36
+ # @param [Hash] config the list of options to configure actions to be authorizable
37
+ # @option config [Symbol] action the action to authorize with
38
+ # @option action [ActiveRecord::Base] :user (current_user) object to run the condition on
39
+ # @option action [Symbol] :permission (can_{action}?(target)) the condition to run on the :user
40
+ # @option action [Symbol] :target ("@#{target}") the name of the object passed to the :permission
41
+ # if no target is provided :permission becomes a required option
42
+ # @option action [Proc] :redirect_path where to go upon unauthorized
43
+ # @option action [String] :message (I18n.t('authorizable.not_authorized'))
44
+ # message to display as a flash message upon an unauthorized attempt
45
+ # @option action [Symbol] :flash_type (:alert) what flash type to use for displaying the :message
46
+ def authorizable(config = {})
47
+ Authorizable::Controller.parameters_are_valid?(config)
48
+
49
+ self.authorizable_config = config
50
+
51
+ self.send(:before_filter, :authorizable_authorized?)
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def authorizable_authorized?
58
+ result = false
59
+ action = params[:action].to_sym
60
+
61
+ if !self.class.authorizable_config[action]
62
+ action = Authorizable::Controller.alias_action(action)
63
+ end
64
+
65
+ settings_for_action = self.class.authorizable_config[action]
66
+
67
+ return true unless settings_for_action.present?
68
+
69
+ defaults = {
70
+ user: current_user,
71
+ permission: "can_#{action.to_s}?",
72
+ message: I18n.t('authorizable.not_authorized'),
73
+ flash_type: :alert
74
+ }
75
+
76
+ options = defaults.merge(settings_for_action)
77
+
78
+ # run permission
79
+ if options[:target]
80
+ object = instance_variable_get("@#{options[:target]}")
81
+ result = options[:user].send(options[:permission], object)
82
+ else
83
+ result = options[:user].send(options[:permission])
84
+ end
85
+
86
+ # redirect
87
+ unless result
88
+ authorizable_respond_with(
89
+ options[:flash_type],
90
+ options[:message],
91
+ options[:redirect_path]
92
+ )
93
+
94
+ # halt
95
+ return false
96
+ end
97
+
98
+ # proceed with execution
99
+ true
100
+ end
101
+
102
+
103
+ def authorizable_respond_with(flash_type, message, path)
104
+ flash[flash_type] = message
105
+
106
+ respond_to do |format|
107
+ format.html{
108
+ path = self.instance_eval(&path)
109
+ redirect_to path
110
+ }
111
+ format.json{
112
+ render json: {}, status: 401
113
+ }
114
+ end
115
+
116
+ end
117
+
118
+ def self.alias_action(action)
119
+ if action == :update
120
+ action = :edit
121
+ elsif action == :edit
122
+ action = :update
123
+ elsif action == :create
124
+ action = :new
125
+ elsif action == :new
126
+ action = :create
127
+ end
128
+
129
+ action
130
+ end
131
+
132
+ # @see @authorizable for options
133
+ # @return [Boolean]
134
+ def self.parameters_are_valid?(config)
135
+ config.each do |action, settings|
136
+ if !settings[:target]
137
+ # permission is required
138
+ if !settings[:permission]
139
+ raise ArgumentError.new(I18n.t('authorizable.permission_required'))
140
+ end
141
+ end
142
+
143
+ # redirect_path is always required
144
+ redirect_path = settings[:redirect_path]
145
+ if !redirect_path
146
+ raise ArgumentError.new(I18n.t('authorizable.redirect_path_required'))
147
+ else
148
+ if !redirect_path.is_a?(Proc)
149
+ raise ArgumentError.new(I18n.t("authorizable.redirect_path_must_be_proc"))
150
+ end
151
+ end
152
+ end
153
+ end
154
+
155
+ end
156
+ end