restful-authentication 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/CHANGELOG +68 -0
  2. data/README.textile +227 -0
  3. data/Rakefile +33 -0
  4. data/TODO +15 -0
  5. data/init.rb +5 -0
  6. data/lib/authentication.rb +40 -0
  7. data/lib/authentication/by_cookie_token.rb +82 -0
  8. data/lib/authentication/by_password.rb +65 -0
  9. data/lib/authorization.rb +14 -0
  10. data/lib/authorization/aasm_roles.rb +74 -0
  11. data/lib/authorization/stateful_roles.rb +62 -0
  12. data/lib/generators/authenticated/USAGE +1 -0
  13. data/lib/generators/authenticated/authenticated_generator.rb +524 -0
  14. data/lib/generators/authenticated/templates/_model_partial.html.erb +8 -0
  15. data/lib/generators/authenticated/templates/activation.erb +3 -0
  16. data/lib/generators/authenticated/templates/authenticated_system.rb +189 -0
  17. data/lib/generators/authenticated/templates/authenticated_test_helper.rb +22 -0
  18. data/lib/generators/authenticated/templates/controller.rb +41 -0
  19. data/lib/generators/authenticated/templates/features/accounts.feature +109 -0
  20. data/lib/generators/authenticated/templates/features/sessions.feature +134 -0
  21. data/lib/generators/authenticated/templates/features/step_definitions/ra_env.rb +9 -0
  22. data/lib/generators/authenticated/templates/features/step_definitions/ra_navigation_steps.rb +48 -0
  23. data/lib/generators/authenticated/templates/features/step_definitions/ra_resource_steps.rb +178 -0
  24. data/lib/generators/authenticated/templates/features/step_definitions/ra_response_steps.rb +169 -0
  25. data/lib/generators/authenticated/templates/features/step_definitions/rest_auth_features_helper.rb +81 -0
  26. data/lib/generators/authenticated/templates/features/step_definitions/user_steps.rb +131 -0
  27. data/lib/generators/authenticated/templates/helper.rb +2 -0
  28. data/lib/generators/authenticated/templates/login.html.erb +16 -0
  29. data/lib/generators/authenticated/templates/mailer.rb +26 -0
  30. data/lib/generators/authenticated/templates/migration.rb +26 -0
  31. data/lib/generators/authenticated/templates/model.rb +87 -0
  32. data/lib/generators/authenticated/templates/model_controller.rb +83 -0
  33. data/lib/generators/authenticated/templates/model_helper.rb +93 -0
  34. data/lib/generators/authenticated/templates/model_helper_spec.rb +158 -0
  35. data/lib/generators/authenticated/templates/observer.rb +11 -0
  36. data/lib/generators/authenticated/templates/signup.html.erb +19 -0
  37. data/lib/generators/authenticated/templates/signup_notification.erb +8 -0
  38. data/lib/generators/authenticated/templates/site_keys.rb +38 -0
  39. data/lib/generators/authenticated/templates/spec/controllers/access_control_spec.rb +90 -0
  40. data/lib/generators/authenticated/templates/spec/controllers/authenticated_system_spec.rb +102 -0
  41. data/lib/generators/authenticated/templates/spec/controllers/sessions_controller_spec.rb +139 -0
  42. data/lib/generators/authenticated/templates/spec/controllers/users_controller_spec.rb +198 -0
  43. data/lib/generators/authenticated/templates/spec/fixtures/users.yml +60 -0
  44. data/lib/generators/authenticated/templates/spec/helpers/users_helper_spec.rb +141 -0
  45. data/lib/generators/authenticated/templates/spec/models/user_spec.rb +290 -0
  46. data/lib/generators/authenticated/templates/test/functional_test.rb +82 -0
  47. data/lib/generators/authenticated/templates/test/mailer_test.rb +32 -0
  48. data/lib/generators/authenticated/templates/test/model_functional_test.rb +93 -0
  49. data/lib/generators/authenticated/templates/test/unit_test.rb +164 -0
  50. data/lib/tasks/auth.rake +33 -0
  51. data/lib/trustification.rb +14 -0
  52. data/lib/trustification/email_validation.rb +20 -0
  53. metadata +105 -0
@@ -0,0 +1,65 @@
1
+ module Authentication
2
+ module ByPassword
3
+ # Stuff directives into including module
4
+ def self.included(recipient)
5
+ recipient.extend(ModelClassMethods)
6
+ recipient.class_eval do
7
+ include ModelInstanceMethods
8
+
9
+ # Virtual attribute for the unencrypted password
10
+ attr_accessor :password
11
+ validates_presence_of :password, :if => :password_required?
12
+ validates_presence_of :password_confirmation, :if => :password_required?
13
+ validates_confirmation_of :password, :if => :password_required?
14
+ validates_length_of :password, :within => 6..40, :if => :password_required?
15
+ before_save :encrypt_password
16
+ end
17
+ end # #included directives
18
+
19
+ #
20
+ # Class Methods
21
+ #
22
+ module ModelClassMethods
23
+ # This provides a modest increased defense against a dictionary attack if
24
+ # your db were ever compromised, but will invalidate existing passwords.
25
+ # See the README and the file config/initializers/site_keys.rb
26
+ #
27
+ # It may not be obvious, but if you set REST_AUTH_SITE_KEY to nil and
28
+ # REST_AUTH_DIGEST_STRETCHES to 1 you'll have backwards compatibility with
29
+ # older versions of restful-authentication.
30
+ def password_digest(password, salt)
31
+ digest = REST_AUTH_SITE_KEY
32
+ REST_AUTH_DIGEST_STRETCHES.times do
33
+ digest = secure_digest(digest, salt, password, REST_AUTH_SITE_KEY)
34
+ end
35
+ digest
36
+ end
37
+ end # class methods
38
+
39
+ #
40
+ # Instance Methods
41
+ #
42
+ module ModelInstanceMethods
43
+
44
+ # Encrypts the password with the user salt
45
+ def encrypt(password)
46
+ self.class.password_digest(password, salt)
47
+ end
48
+
49
+ def authenticated?(password)
50
+ crypted_password == encrypt(password)
51
+ end
52
+
53
+ # before filter
54
+ def encrypt_password
55
+ return if password.blank?
56
+ self.salt = self.class.make_token if new_record?
57
+ self.crypted_password = encrypt(password)
58
+ end
59
+ def password_required?
60
+ #crypted_password.blank? || !password.blank?
61
+ !password.nil?
62
+ end
63
+ end # instance methods
64
+ end
65
+ end
@@ -0,0 +1,14 @@
1
+ module Authorization
2
+ def self.included(recipient)
3
+ recipient.extend(ModelClassMethods)
4
+ recipient.class_eval do
5
+ include ModelInstanceMethods
6
+ end
7
+ end
8
+
9
+ module ModelClassMethods
10
+ end # class methods
11
+
12
+ module ModelInstanceMethods
13
+ end # instance methods
14
+ end
@@ -0,0 +1,74 @@
1
+ module Authorization
2
+ module AasmRoles
3
+ unless Object.constants.include? "STATEFUL_ROLES_CONSTANTS_DEFINED"
4
+ STATEFUL_ROLES_CONSTANTS_DEFINED = 'yup' # sorry for the C idiom
5
+ end
6
+
7
+
8
+ def self.included( recipient )
9
+ recipient.extend( StatefulRolesClassMethods )
10
+ recipient.class_eval do
11
+ include StatefulRolesInstanceMethods
12
+ include ActiveRecord::Transitions
13
+
14
+ state_machine do
15
+
16
+ state :passive
17
+ state :active #, :enter => :do_activate
18
+ state :suspended
19
+ state :deleted, :enter => :do_delete
20
+
21
+ event :register do
22
+ # transitions :from => :passive, :to => :pending, :guard => Proc.new {|u| !(u.crypted_password.blank? && u.password.blank?) }
23
+ transitions :from => :passive, :to => :active#, :guard => Proc.new {|u| !(u.crypted_password.blank? && u.password.blank?) }
24
+ end
25
+
26
+ # event :activate do
27
+ # transitions :from => :pending, :to => :active
28
+ # end
29
+
30
+ event :suspend do
31
+ # transitions :from => [:passive, :pending, :active], :to => :suspended
32
+ transitions :from => [:passive, :active], :to => :suspended
33
+ end
34
+
35
+ event :delete do
36
+ # transitions :from => [:passive, :pending, :active, :suspended], :to => :deleted
37
+ transitions :from => [:passive, :active, :suspended], :to => :deleted
38
+ end
39
+
40
+ event :unsuspend do
41
+ # transitions :from => :suspended, :to => :active, :guard => Proc.new {|u| !u.activated_at.blank? }
42
+ transitions :from => :suspended, :to => :active, :guard => Proc.new {|u| !u.crypted_password.blank? }
43
+ # transitions :from => :suspended, :to => :pending, :guard => Proc.new {|u| !u.activation_code.blank? }
44
+ transitions :from => :suspended, :to => :passive
45
+ end
46
+
47
+
48
+ end
49
+
50
+ end
51
+ end
52
+
53
+ module StatefulRolesClassMethods
54
+
55
+ end # class methods
56
+
57
+ module StatefulRolesInstanceMethods
58
+ # Returns true if the user has just been activated.
59
+ # def recently_activated?
60
+ # @activated
61
+ # end
62
+
63
+ def do_delete
64
+ self.deleted_at = Time.now.utc
65
+ end
66
+
67
+ # def do_activate
68
+ # @activated = true
69
+ # self.activated_at = Time.now.utc
70
+ # self.deleted_at = self.activation_code = nil
71
+ # end
72
+ end # instance methods
73
+ end
74
+ end
@@ -0,0 +1,62 @@
1
+ module Authorization
2
+ module StatefulRoles
3
+ unless Object.constants.include? "STATEFUL_ROLES_CONSTANTS_DEFINED"
4
+ STATEFUL_ROLES_CONSTANTS_DEFINED = true # sorry for the C idiom
5
+ end
6
+
7
+ def self.included( recipient )
8
+ recipient.extend( StatefulRolesClassMethods )
9
+ recipient.class_eval do
10
+ include StatefulRolesInstanceMethods
11
+
12
+ acts_as_state_machine :initial => :pending
13
+ state :passive
14
+ state :pending, :enter => :make_activation_code
15
+ state :active, :enter => :do_activate
16
+ state :suspended
17
+ state :deleted, :enter => :do_delete
18
+
19
+ event :register do
20
+ transitions :from => :passive, :to => :pending, :guard => Proc.new {|u| !(u.crypted_password.blank? && u.password.blank?) }
21
+ end
22
+
23
+ event :activate do
24
+ transitions :from => :pending, :to => :active
25
+ end
26
+
27
+ event :suspend do
28
+ transitions :from => [:passive, :pending, :active], :to => :suspended
29
+ end
30
+
31
+ event :delete do
32
+ transitions :from => [:passive, :pending, :active, :suspended], :to => :deleted
33
+ end
34
+
35
+ event :unsuspend do
36
+ transitions :from => :suspended, :to => :active, :guard => Proc.new {|u| !u.activated_at.blank? }
37
+ transitions :from => :suspended, :to => :pending, :guard => Proc.new {|u| !u.activation_code.blank? }
38
+ transitions :from => :suspended, :to => :passive
39
+ end
40
+ end
41
+ end
42
+
43
+ module StatefulRolesClassMethods
44
+ end # class methods
45
+
46
+ module StatefulRolesInstanceMethods
47
+ # Returns true if the user has just been activated.
48
+ def recently_activated?
49
+ @activated
50
+ end
51
+ def do_delete
52
+ self.deleted_at = Time.now.utc
53
+ end
54
+
55
+ def do_activate
56
+ @activated = true
57
+ self.activated_at = Time.now.utc
58
+ self.deleted_at = self.activation_code = nil
59
+ end
60
+ end # instance methods
61
+ end
62
+ end
@@ -0,0 +1 @@
1
+ rails g(generate) authenticated USERMODEL CONTROLLERNAME
@@ -0,0 +1,524 @@
1
+ require 'digest/sha1'
2
+ require 'rails/generators/migration'
3
+ class AuthenticatedGenerator < Rails::Generators::NamedBase
4
+
5
+ include Rails::Generators::Migration
6
+
7
+ argument :controller_name, :type => :string, :default => 'sessions', :banner => 'ControllerName'
8
+
9
+ class_option :skip_routes, :type => :boolean, :desc => "Don't generate a resource line in config/routes.rb."
10
+ class_option :skip_migration, :type => :boolean, :desc => "Don't generate a migration file for this model."
11
+ class_option :aasm, :type => :boolean, :desc => "Works the same as stateful but uses the updated aasm gem"
12
+ class_option :stateful, :type => :boolean, :desc => "Builds in support for acts_as_state_machine and generatesactivation code."
13
+ class_option :rspec, :type => :boolean, :desc => "Generate RSpec tests and Stories in place of standard rails tests."
14
+ class_option :old_passwords, :type => :boolean, :desc => "Use the older password scheme"
15
+ class_option :include_activation, :type => :boolean, :desc => "Skip the code for a ActionMailer and its respective Activation Code through email"
16
+ class_option :dump_generator_attrs, :type => :boolean, :desc => "Dump Generator Attrs"
17
+
18
+ def self.source_root
19
+ @source_root ||= File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
20
+ end
21
+
22
+ def initialize(*args, &block)
23
+ super
24
+ controller_base_name
25
+ model_controller_base_name
26
+ load_or_initialize_site_keys()
27
+ end
28
+
29
+ # def check_class_naming_collisions
30
+ # # Check for class naming collisions.
31
+ # class_collisions controller_class_path, "#{ controller_class_name }Controller",
32
+ # "#{ controller_class_name }Helper" # Sessions Controller
33
+ #
34
+ # class_collisions model_controller_class_path, "#{ model_controller_class_name }Controller",
35
+ # "#{ model_controller_class_name }Helper" # Model Controller
36
+ #
37
+ # class_collisions class_path, "#{ class_name }",
38
+ # "#{ class_name }Mailer",
39
+ # "#{ class_name }MailerTest",
40
+ # "#{ class_name }Observer"
41
+ #
42
+ # class_collisions [], 'AuthenticatedSystem', 'AuthenticatedTestHelper'
43
+ # end
44
+
45
+ def create_model_files
46
+ template 'model.rb', File.join('app/models', class_path, "#{ file_name }.rb")
47
+ if options.include_activation?
48
+ template "mailer.rb", File.join('app/mailers', class_path, "#{ file_name }_mailer.rb")
49
+ template "observer.rb", File.join('app/models', class_path, "#{ file_name }_observer.rb")
50
+ end
51
+ end
52
+
53
+ def create_controller_files
54
+ template 'controller.rb', File.join('app/controllers', controller_class_path, "#{ controller_file_name }_controller.rb")
55
+ template 'model_controller.rb', File.join('app/controllers', model_controller_class_path, "#{ model_controller_file_name }_controller.rb")
56
+ end
57
+
58
+ def create_lib_files
59
+ template 'authenticated_system.rb', File.join('lib', 'authenticated_system.rb')
60
+ template 'authenticated_test_helper.rb', File.join('lib', 'authenticated_test_helper.rb')
61
+ end
62
+
63
+ def create_site_key
64
+ template 'site_keys.rb', site_keys_file
65
+ end
66
+
67
+ def create_test_files
68
+ if has_rspec?
69
+ # RSpec Specs
70
+ template 'spec/controllers/users_controller_spec.rb', File.join('spec/controllers', model_controller_class_path, "#{ model_controller_file_name }_controller_spec.rb")
71
+ template 'spec/controllers/sessions_controller_spec.rb', File.join('spec/controllers', controller_class_path, "#{ controller_file_name }_controller_spec.rb")
72
+ template 'spec/controllers/access_control_spec.rb', File.join('spec/controllers', controller_class_path, "access_control_spec.rb")
73
+ template 'spec/controllers/authenticated_system_spec.rb', File.join('spec/controllers', controller_class_path, "authenticated_system_spec.rb")
74
+ template 'spec/helpers/users_helper_spec.rb', File.join('spec/helpers', model_controller_class_path, "#{ table_name }_helper_spec.rb")
75
+ template 'spec/models/user_spec.rb', File.join('spec/models' , class_path, "#{ file_name }_spec.rb")
76
+ #if fixtures_required?
77
+ template 'spec/fixtures/users.yml', File.join('spec/fixtures', class_path, "#{ table_name }.yml")
78
+ #end
79
+ # Cucumber features
80
+ template 'features/step_definitions/ra_navigation_steps.rb', File.join('features/step_definitions/ra_navigation_steps.rb')
81
+ template 'features/step_definitions/ra_response_steps.rb', File.join('features/step_definitions/ra_response_steps.rb')
82
+ template 'features/step_definitions/ra_resource_steps.rb', File.join('features/step_definitions/ra_resource_steps.rb')
83
+ template 'features/step_definitions/user_steps.rb', File.join('features/step_definitions/', "#{ file_name }_steps.rb")
84
+ template 'features/accounts.feature', File.join('features', 'accounts.feature')
85
+ template 'features/sessions.feature', File.join('features', 'sessions.feature')
86
+ template 'features/step_definitions/rest_auth_features_helper.rb', File.join('features', 'step_definitions', 'rest_auth_features_helper.rb')
87
+ template 'features/step_definitions/ra_env.rb', File.join('features', 'step_definitions', 'ra_env.rb')
88
+ else
89
+ template 'test/functional_test.rb', File.join('test/functional', controller_class_path, "#{ controller_file_name }_controller_test.rb")
90
+ template 'test/model_functional_test.rb', File.join('test/functional', model_controller_class_path, "#{ model_controller_file_name }_controller_test.rb")
91
+ template 'test/unit_test.rb', File.join('test/unit', class_path, "#{ file_name }_test.rb")
92
+ if options.include_activation?
93
+ template 'test/mailer_test.rb', File.join('test/functional', class_path, "#{ file_name }_mailer_test.rb")
94
+ end
95
+ #if fixtures_required?
96
+ template 'spec/fixtures/users.yml', File.join('test/fixtures', class_path, "#{ table_name }.yml")
97
+ #end
98
+ end
99
+ end
100
+
101
+ def crete_helper_files
102
+ template 'helper.rb', File.join('app/helpers', controller_class_path, "#{ controller_file_name }_helper.rb")
103
+ template 'model_helper.rb', File.join('app/helpers', model_controller_class_path, "#{ model_controller_file_name }_helper.rb")
104
+ end
105
+
106
+ def create_view_files
107
+ # Controller templates
108
+ template 'login.html.erb', File.join('app/views', controller_class_path, controller_file_name, "new.html.erb")
109
+ template 'signup.html.erb', File.join('app/views', model_controller_class_path, model_controller_file_name, "new.html.erb")
110
+ template '_model_partial.html.erb', File.join('app/views', model_controller_class_path, model_controller_file_name, "_#{ file_name }_bar.html.erb")
111
+
112
+ if options.include_activation?
113
+ # Mailer templates
114
+ %w( activation signup_notification ).each do |action|
115
+ template "#{ action }.erb", File.join('app/views', "#{ file_name }_mailer", "#{ action }.html.erb")
116
+ end
117
+ end
118
+ end
119
+
120
+ def create_migration
121
+ unless options.skip_migration?
122
+ migration_template 'migration.rb', "db/migrate/create_#{ migration_file_name }.rb"
123
+ end
124
+ end
125
+
126
+ def create_routes
127
+ unless options.skip_routes?
128
+ # Note that this fails for nested classes -- you're on your own with setting up the routes.
129
+ route "match '/activate/:activation_code' => '#{ model_controller_plural_name }#activate', :as => :activate, :activation_code => nil"
130
+ route "match 'logout' => '#{ controller_controller_name }#destroy', :as => :logout"
131
+ route "match 'login' => '#{ controller_controller_name }#new', :as => :login"
132
+ route "match 'register' => '#{ model_controller_plural_name }#create', :as => :register"
133
+ route "match 'signup' => '#{ model_controller_plural_name }#new', :as => :signup"
134
+ route "resource #{ controller_singular_name.to_sym.inspect }, :only => [:new, :create, :destroy]"
135
+ route "resources #{ model_controller_plural_name.to_sym.inspect }"
136
+ end
137
+ end
138
+
139
+ # Post-install notes
140
+ def create_notes
141
+ case behavior
142
+ when :invoke
143
+ puts "Ready to generate."
144
+ puts ("-" * 70)
145
+ puts "Once finished, don't forget to:"
146
+ puts
147
+ puts "- Install the dynamic_form plugin(error_messages_for was removed from Rails and is now available as a plugin):"
148
+ puts " Install it with rails plugin install git://github.com/rails/dynamic_form.git"
149
+ if options.include_activation?
150
+ puts "- Add an observer to config/environment.rb"
151
+ puts " config.active_record.observers = :#{ file_name }_observer"
152
+ end
153
+ if options.aasm?
154
+ puts "- Install the acts_as_state_machine gem:"
155
+ puts " sudo gem sources -a http://gems.github.com (If you haven't already)"
156
+ puts " sudo gem install rubyist-aasm"
157
+ elsif options.stateful?
158
+ puts "- Install the acts_as_state_machine plugin:"
159
+ puts " svn export http://elitists.textdriven.com/svn/plugins/acts_as_state_machine/trunk vendor/plugins/acts_as_state_machine"
160
+ end
161
+ puts "- Add routes to these resources. In config/routes.rb, insert routes like:"
162
+ puts %( match 'login' => '#{ controller_file_name }#new', :as => :login)
163
+ puts %( match 'logout' => '#{ controller_file_name }#destroy', :as => :logout)
164
+ puts %( match 'signup' => '#{ model_controller_file_name }#new', :as => :signup)
165
+ if options.include_activation?
166
+ puts %( match 'activate/:activation_code' => '#{ model_controller_file_name }#activate', :as => :activate, :activation_code => nil)
167
+ end
168
+ if options.stateful?
169
+ puts " and modify the resources :#{ model_controller_file_name } line to include these actions:"
170
+ puts " resources :#{ model_controller_file_name } do"
171
+ puts " member do"
172
+ puts " put :suspend"
173
+ puts " put :unsuspend"
174
+ puts " delete :purge"
175
+ puts " end"
176
+ puts " end"
177
+ end
178
+ puts
179
+ puts ("-" * 70)
180
+ puts
181
+ if $rest_auth_site_key_from_generator.blank?
182
+ puts "You've set a nil site key. This preserves existing users' passwords,"
183
+ puts "but allows dictionary attacks in the unlikely event your database is"
184
+ puts "compromised and your site code is not. See the README for more."
185
+ elsif $rest_auth_keys_are_new
186
+ puts "We've create a new site key in #{ site_keys_file }. If you have existing"
187
+ puts "user accounts their passwords will no longer work (see README). As always,"
188
+ puts "keep this file safe but don't post it in public."
189
+ else
190
+ puts "We've reused the existing site key in #{ site_keys_file }. As always,"
191
+ puts "keep this file safe but don't post it in public."
192
+ end
193
+ puts
194
+ puts ("-" * 70)
195
+ when :revoke
196
+ puts
197
+ puts ("-" * 70)
198
+ puts
199
+ puts "Thanks for using restful_authentication"
200
+ puts
201
+ puts "Don't forget to comment out the observer line in environment.rb"
202
+ puts " (This was optional so it may not even be there)"
203
+ puts " # config.active_record.observers = :#{ file_name }_observer"
204
+ puts
205
+ puts ("-" * 70)
206
+ puts
207
+ else
208
+ puts "Didn't understand the action '#{ action }' -- you might have missed the 'after running me' instructions."
209
+ end
210
+ end
211
+
212
+ def print_generator_attribute_names
213
+ if options.dump_generator_attrs?
214
+ dump_generator_attribute_names
215
+ end
216
+ end
217
+
218
+ protected
219
+
220
+ # Override with your own usage banner.
221
+ def banner
222
+ "Usage: #{$0} authenticated ModelName [ControllerName]"
223
+ end
224
+
225
+ def controller_class_path
226
+ controller_modules.map { |m| m.underscore }
227
+ end
228
+
229
+ def controller_file_path
230
+ (controller_class_path + [controller_base_name.underscore]).join('/')
231
+ end
232
+
233
+ def controller_class_nesting
234
+ controller_modules.map { |m| m.camelize }.join('::')
235
+ end
236
+
237
+ def controller_class_nesting_depth
238
+ controller_modules.size
239
+ end
240
+
241
+ def controller_class_name_without_nesting
242
+ camelcase_name(controller_base_name)
243
+ end
244
+
245
+ def controller_file_name
246
+ underscored_name(controller_base_name)
247
+ end
248
+
249
+ def controller_plural_name
250
+ pluralized_name(controller_base_name)
251
+ end
252
+
253
+ def controller_singular_name
254
+ controller_file_name.singularize
255
+ end
256
+
257
+ def controller_class_name
258
+ controller_class_nesting.empty? ? controller_class_name_without_nesting : "#{ controller_class_nesting }::#{ controller_class_name_without_nesting }"
259
+ end
260
+
261
+ def controller_routing_name # new_session_path
262
+ controller_singular_name
263
+ end
264
+
265
+ def controller_routing_path # /session/new
266
+ controller_file_path.singularize
267
+ end
268
+
269
+ def controller_controller_name # sessions
270
+ controller_plural_name
271
+ end
272
+
273
+ alias_method :controller_table_name, :controller_plural_name
274
+
275
+
276
+ def model_controller_class_path
277
+ model_controller_modules.map { |m| m.underscore }
278
+ end
279
+
280
+ def model_controller_file_path
281
+ (model_controller_class_path + [model_controller_base_name.underscore]).join('/')
282
+ end
283
+
284
+ def model_controller_class_nesting
285
+ model_controller_modules.map { |m| m.camelize }.join('::')
286
+ end
287
+
288
+ def model_controller_class_nesting_depth
289
+ model_controller_modules.size
290
+ end
291
+
292
+ def model_controller_class_name_without_nesting
293
+ camelcase_name(model_controller_base_name)
294
+ end
295
+
296
+ def model_controller_singular_name
297
+ underscored_name(model_controller_base_name)
298
+ end
299
+
300
+ def model_controller_plural_name
301
+ pluralized_name(model_controller_base_name)
302
+ end
303
+
304
+ def model_controller_class_name
305
+ model_controller_class_nesting.empty? ? model_controller_class_name_without_nesting : "#{ model_controller_class_nesting }::#{ model_controller_class_name_without_nesting }"
306
+ end
307
+
308
+ def model_controller_routing_name # new_user_path
309
+ table_name
310
+ end
311
+
312
+ def model_controller_routing_path # /users/new
313
+ model_controller_file_path
314
+ end
315
+
316
+ def model_controller_controller_name # users
317
+ model_controller_plural_name
318
+ end
319
+
320
+ alias_method :model_controller_file_name, :model_controller_singular_name
321
+ alias_method :model_controller_table_name, :model_controller_plural_name
322
+
323
+ private
324
+
325
+ def controller_base_name
326
+ @controller_base_name ||= controller_modules.pop
327
+ end
328
+
329
+ def controller_modules
330
+ @controller_modules ||= modules(pluralized_controller_name)
331
+ end
332
+
333
+ def pluralized_controller_name
334
+ controller_name.pluralize
335
+ end
336
+
337
+ def model_controller_name
338
+ name.pluralize
339
+ end
340
+
341
+ def model_controller_base_name
342
+ @model_controller_base_name ||= model_controller_modules.pop
343
+ end
344
+
345
+ def model_controller_modules
346
+ @model_controller_modules ||= modules(model_controller_name)
347
+ end
348
+
349
+ def modules(name)
350
+ name.include?('/') ? name.split('/') : name.split('::')
351
+ end
352
+
353
+ def camelcase_name(name)
354
+ name.camelize
355
+ end
356
+
357
+ def underscored_name(name)
358
+ camelcase_name(name).underscore
359
+ end
360
+
361
+ def pluralized_name(name)
362
+ underscored_name(name).pluralize
363
+ end
364
+
365
+ def has_rspec?
366
+ @rspec ||= (options.rspec? && File.exist?(destination_path("spec")))
367
+ end
368
+
369
+ # def test_framework?(name)
370
+ # name == test_framework.to_s
371
+ # end
372
+ #
373
+ # def fixtures_required?
374
+ # test_framework && Rails::Application.config.generators.options[test_framework][:fixture] != false
375
+ # end
376
+ #
377
+ # def test_framework
378
+ # Rails::Application.config.generators.rails[:test_framework]
379
+ # end
380
+
381
+ def destination_path(path)
382
+ File.join(destination_root, path)
383
+ end
384
+
385
+ #
386
+ # !! These must match the corresponding routines in by_password.rb !!
387
+ #
388
+ def secure_digest(*args)
389
+ Digest::SHA1.hexdigest(args.flatten.join('--'))
390
+ end
391
+
392
+ def make_token
393
+ secure_digest(Time.now, (1..10).map{ rand.to_s })
394
+ end
395
+ def password_digest(password, salt)
396
+ digest = $rest_auth_site_key_from_generator
397
+ $rest_auth_digest_stretches_from_generator.times do
398
+ digest = secure_digest(digest, salt, password, $rest_auth_site_key_from_generator)
399
+ end
400
+ digest
401
+ end
402
+
403
+ #
404
+ # Try to be idempotent:
405
+ # pull in the existing site key if any,
406
+ # seed it with reasonable defaults otherwise
407
+ #
408
+ def load_or_initialize_site_keys
409
+ case
410
+ when defined? REST_AUTH_SITE_KEY
411
+ if (options.old_passwords?) && ((! REST_AUTH_SITE_KEY.blank?) || (REST_AUTH_DIGEST_STRETCHES != 1))
412
+ raise "You have a site key, but --old-passwords will overwrite it. If this is really what you want, move the file #{site_keys_file} and re-run."
413
+ end
414
+ $rest_auth_site_key_from_generator = REST_AUTH_SITE_KEY
415
+ $rest_auth_digest_stretches_from_generator = REST_AUTH_DIGEST_STRETCHES
416
+ when options.old_passwords?
417
+ $rest_auth_site_key_from_generator = nil
418
+ $rest_auth_digest_stretches_from_generator = 1
419
+ $rest_auth_keys_are_new = true
420
+ else
421
+ $rest_auth_site_key_from_generator = make_token
422
+ $rest_auth_digest_stretches_from_generator = 10
423
+ $rest_auth_keys_are_new = true
424
+ end
425
+ end
426
+
427
+ def site_keys_file
428
+ File.join("config", "initializers", "site_keys.rb")
429
+ end
430
+
431
+ def migration_name
432
+ "Create#{ class_name.pluralize.gsub(/::/, '') }"
433
+ end
434
+
435
+ def migration_file_name
436
+ "#{ file_path.gsub(/\//, '_').pluralize }"
437
+ end
438
+
439
+ #
440
+ # Implement the required interface for Rails::Generators::Migration.
441
+ # taken from http://github.com/rails/rails/blob/master/activerecord/lib/generators/active_record.rb
442
+ #
443
+ def self.next_migration_number(dirname) #:nodoc:
444
+ if ActiveRecord::Base.timestamped_migrations
445
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
446
+ else
447
+ "%.3d" % (current_migration_number(dirname) + 1)
448
+ end
449
+ end
450
+
451
+ def dump_generator_attribute_names
452
+ generator_attribute_names = [
453
+ :table_name,
454
+ :file_name,
455
+ :class_name,
456
+ :controller_name,
457
+ :controller_class_path,
458
+ :controller_file_path,
459
+ :controller_class_nesting,
460
+ :controller_class_nesting_depth,
461
+ :controller_class_name,
462
+ :controller_singular_name,
463
+ :controller_plural_name,
464
+ :controller_routing_name, # new_session_path
465
+ :controller_routing_path, # /session/new
466
+ :controller_controller_name, # sessions
467
+ :controller_file_name,
468
+ :controller_table_name, :controller_plural_name,
469
+ :model_controller_name,
470
+ :model_controller_class_path,
471
+ :model_controller_file_path,
472
+ :model_controller_class_nesting,
473
+ :model_controller_class_nesting_depth,
474
+ :model_controller_class_name,
475
+ :model_controller_singular_name,
476
+ :model_controller_plural_name,
477
+ :model_controller_routing_name, # new_user_path
478
+ :model_controller_routing_path, # /users/new
479
+ :model_controller_controller_name, # users
480
+ :model_controller_file_name, :model_controller_singular_name,
481
+ :model_controller_table_name, :model_controller_plural_name,
482
+ ]
483
+
484
+ generator_attribute_names.each do |attr|
485
+ puts "%-40s %s" % ["#{attr}:", self.send(attr.to_s)] # instance_variable_get("@#{attr.to_s}"
486
+ end
487
+
488
+ end
489
+
490
+ end
491
+
492
+ # rails g authenticated FoonParent::Foon SporkParent::Spork -p --force --rspec --dump-generator-attrs
493
+ # table_name: foon_parent_foons
494
+ # file_name: foon
495
+ # class_name: FoonParent::Foon
496
+ # controller_name: SporkParent::Sporks
497
+ # controller_class_path: spork_parent
498
+ # controller_file_path: spork_parent/sporks
499
+ # controller_class_nesting: SporkParent
500
+ # controller_class_nesting_depth: 1
501
+ # controller_class_name: SporkParent::Sporks
502
+ # controller_singular_name: spork
503
+ # controller_plural_name: sporks
504
+ # controller_routing_name: spork
505
+ # controller_routing_path: spork_parent/spork
506
+ # controller_controller_name: sporks
507
+ # controller_file_name: sporks
508
+ # controller_table_name: sporks
509
+ # controller_plural_name: sporks
510
+ # model_controller_name: FoonParent::Foons
511
+ # model_controller_class_path: foon_parent
512
+ # model_controller_file_path: foon_parent/foons
513
+ # model_controller_class_nesting: FoonParent
514
+ # model_controller_class_nesting_depth: 1
515
+ # model_controller_class_name: FoonParent::Foons
516
+ # model_controller_singular_name: foons
517
+ # model_controller_plural_name: foons
518
+ # model_controller_routing_name: foon_parent_foons
519
+ # model_controller_routing_path: foon_parent/foons
520
+ # model_controller_controller_name: foons
521
+ # model_controller_file_name: foons
522
+ # model_controller_singular_name: foons
523
+ # model_controller_table_name: foons
524
+ # model_controller_plural_name: foons