headstart 0.1.0

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 (105) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +117 -0
  3. data/Rakefile +95 -0
  4. data/VERSION +1 -0
  5. data/app/controllers/headstart/confirmations_controller.rb +76 -0
  6. data/app/controllers/headstart/impersonations_controller.rb +44 -0
  7. data/app/controllers/headstart/passwords_controller.rb +93 -0
  8. data/app/controllers/headstart/sessions_controller.rb +76 -0
  9. data/app/controllers/headstart/users_controller.rb +85 -0
  10. data/app/models/deliver_change_password_job.rb +19 -0
  11. data/app/models/deliver_welcome_job.rb +17 -0
  12. data/app/models/generic_mailer.rb +31 -0
  13. data/app/models/headstart_mailer.rb +28 -0
  14. data/app/models/impersonation.rb +26 -0
  15. data/app/models/mimi_mailer.rb +30 -0
  16. data/app/views/generic_mailer/change_password.html.erb +9 -0
  17. data/app/views/generic_mailer/confirmation.html.erb +5 -0
  18. data/app/views/generic_mailer/welcome.html.erb +1 -0
  19. data/app/views/impersonations/index.html.erb +5 -0
  20. data/app/views/passwords/edit.html.erb +23 -0
  21. data/app/views/passwords/new.html.erb +15 -0
  22. data/app/views/sessions/new.html.erb +48 -0
  23. data/app/views/users/_form.html.erb +21 -0
  24. data/app/views/users/edit.html.erb +6 -0
  25. data/app/views/users/new.html.erb +6 -0
  26. data/app/views/users/show.html.erb +8 -0
  27. data/generators/headstart/USAGE +1 -0
  28. data/generators/headstart/headstart_generator.rb +86 -0
  29. data/generators/headstart/lib/insert_commands.rb +33 -0
  30. data/generators/headstart/lib/rake_commands.rb +22 -0
  31. data/generators/headstart/templates/README +20 -0
  32. data/generators/headstart/templates/app/controllers/sessions_controller.rb +6 -0
  33. data/generators/headstart/templates/app/views/sessions/index.html.erb +1 -0
  34. data/generators/headstart/templates/application.html.erb +75 -0
  35. data/generators/headstart/templates/factories.rb +23 -0
  36. data/generators/headstart/templates/headstart.rb +25 -0
  37. data/generators/headstart/templates/headstart.yml +45 -0
  38. data/generators/headstart/templates/layout.css +353 -0
  39. data/generators/headstart/templates/migrations/create_users.rb +26 -0
  40. data/generators/headstart/templates/migrations/update_users.rb +44 -0
  41. data/generators/headstart/templates/report.css +69 -0
  42. data/generators/headstart/templates/reset.css +1 -0
  43. data/generators/headstart/templates/style.css +31 -0
  44. data/generators/headstart/templates/text.css +1 -0
  45. data/generators/headstart/templates/user.rb +3 -0
  46. data/generators/headstart/templates/xd_receiver.html +10 -0
  47. data/generators/headstart/templates/xd_receiver_ssl.html +10 -0
  48. data/generators/headstart_admin/USAGE +1 -0
  49. data/generators/headstart_admin/headstart_admin_generator.rb +32 -0
  50. data/generators/headstart_admin/lib/insert_commands.rb +33 -0
  51. data/generators/headstart_admin/templates/README +16 -0
  52. data/generators/headstart_admin/templates/app/controllers/admin/admin_controller.rb +17 -0
  53. data/generators/headstart_admin/templates/app/controllers/admin/users_controller.rb +52 -0
  54. data/generators/headstart_admin/templates/app/views/admin/admin/index.html.erb +2 -0
  55. data/generators/headstart_admin/templates/app/views/admin/users/_form.html.erb +25 -0
  56. data/generators/headstart_admin/templates/app/views/admin/users/edit.html.erb +6 -0
  57. data/generators/headstart_admin/templates/app/views/admin/users/index.html.erb +7 -0
  58. data/generators/headstart_admin/templates/app/views/admin/users/new.html.erb +6 -0
  59. data/generators/headstart_admin/templates/app/views/admin/users/show.html.erb +10 -0
  60. data/generators/headstart_admin/templates/test/integration/admin/users_test.rb +201 -0
  61. data/generators/headstart_tests/USAGE +1 -0
  62. data/generators/headstart_tests/headstart_tests_generator.rb +21 -0
  63. data/generators/headstart_tests/templates/README +58 -0
  64. data/generators/headstart_tests/templates/test/integration/edit_profile_test.rb +35 -0
  65. data/generators/headstart_tests/templates/test/integration/facebook_test.rb +61 -0
  66. data/generators/headstart_tests/templates/test/integration/impersonation_test.rb +39 -0
  67. data/generators/headstart_tests/templates/test/integration/password_reset_test.rb +128 -0
  68. data/generators/headstart_tests/templates/test/integration/sign_in_test.rb +66 -0
  69. data/generators/headstart_tests/templates/test/integration/sign_out_test.rb +28 -0
  70. data/generators/headstart_tests/templates/test/integration/sign_up_test.rb +47 -0
  71. data/lib/headstart/authentication.rb +138 -0
  72. data/lib/headstart/configuration.rb +34 -0
  73. data/lib/headstart/extensions/errors.rb +6 -0
  74. data/lib/headstart/extensions/rescue.rb +5 -0
  75. data/lib/headstart/routes.rb +67 -0
  76. data/lib/headstart/user.rb +279 -0
  77. data/lib/headstart.rb +7 -0
  78. data/rails/init.rb +4 -0
  79. data/shoulda_macros/headstart.rb +244 -0
  80. data/test/controllers/passwords_controller_test.rb +184 -0
  81. data/test/controllers/sessions_controller_test.rb +129 -0
  82. data/test/controllers/users_controller_test.rb +57 -0
  83. data/test/models/headstart_mailer_test.rb +52 -0
  84. data/test/models/impersonation_test.rb +25 -0
  85. data/test/models/user_test.rb +213 -0
  86. data/test/rails_root/app/controllers/accounts_controller.rb +10 -0
  87. data/test/rails_root/app/controllers/application_controller.rb +6 -0
  88. data/test/rails_root/app/helpers/application_helper.rb +5 -0
  89. data/test/rails_root/app/helpers/confirmations_helper.rb +2 -0
  90. data/test/rails_root/app/helpers/passwords_helper.rb +2 -0
  91. data/test/rails_root/config/boot.rb +110 -0
  92. data/test/rails_root/config/environment.rb +22 -0
  93. data/test/rails_root/config/environments/development.rb +19 -0
  94. data/test/rails_root/config/environments/production.rb +1 -0
  95. data/test/rails_root/config/environments/test.rb +37 -0
  96. data/test/rails_root/config/initializers/inflections.rb +10 -0
  97. data/test/rails_root/config/initializers/mime_types.rb +5 -0
  98. data/test/rails_root/config/initializers/requires.rb +13 -0
  99. data/test/rails_root/config/initializers/time_formats.rb +4 -0
  100. data/test/rails_root/config/routes.rb +9 -0
  101. data/test/rails_root/public/dispatch.rb +10 -0
  102. data/test/rails_root/script/create_project.rb +52 -0
  103. data/test/rails_root/test/functional/accounts_controller_test.rb +23 -0
  104. data/test/test_helper.rb +21 -0
  105. metadata +232 -0
@@ -0,0 +1,66 @@
1
+ require 'test_helper'
2
+
3
+ class SignInTest < ActionController::IntegrationTest
4
+
5
+ context 'Signing in as a User' do
6
+
7
+ context 'who is not in the system' do
8
+
9
+ should 'see a failure message' do
10
+ sign_in_as('someone@somewhere.com', 'password')
11
+ assert_match(/Bad email or password/, response.body)
12
+ end
13
+
14
+ should 'not be signed in' do
15
+ sign_in_as "someone@somewhere.com", 'password'
16
+ assert !controller.signed_in?
17
+ end
18
+
19
+ end
20
+
21
+ context 'when confirmed' do
22
+
23
+ setup do
24
+ @user = Factory(:user, :email => "bob@bob.bob", :password => "password")
25
+ end
26
+
27
+ should 'be signed in' do
28
+ sign_in_as 'bob@bob.bob', 'password'
29
+ assert controller.signed_in?
30
+ end
31
+
32
+ should 'see "Signed In"' do
33
+ sign_in_as 'bob@bob.bob', 'password'
34
+ assert_match %r{Signed in}, @response.body
35
+ end
36
+
37
+ should 'be signed in on subsequent requests' do
38
+ sign_in_as 'bob@bob.bob', 'password'
39
+ reset_session
40
+ visit root_url
41
+ assert controller.signed_in?
42
+ end
43
+
44
+ end
45
+
46
+ context 'when confirmed but with bad credentials' do
47
+
48
+ setup do
49
+ @user = Factory(:user, :email => 'bob@bob.bob', :password => 'password')
50
+ end
51
+
52
+ should 'not be signed in' do
53
+ sign_in_as 'bob@bob.bob', 'badpassword'
54
+ assert !controller.signed_in?
55
+ end
56
+
57
+ should 'see "Bad email or password"' do
58
+ sign_in_as 'bob@bob.bob', 'badpassword'
59
+ assert_match /Bad email or password/, response.body
60
+ end
61
+
62
+ end
63
+
64
+ end
65
+
66
+ end
@@ -0,0 +1,28 @@
1
+ require 'test_helper'
2
+
3
+ class SignOutTest < ActionController::IntegrationTest
4
+
5
+ context 'Signing out as a user' do
6
+
7
+ should 'see "Signed out"' do
8
+ sign_up(:email => 'bob@bob.bob')
9
+ sign_out
10
+ assert_match(/Signed out/, response.body)
11
+ end
12
+
13
+ should 'be signed out' do
14
+ sign_up(:email => 'bob@bob.bob')
15
+ sign_out
16
+ assert !controller.signed_in?
17
+ end
18
+
19
+ should 'be signed out when I return' do
20
+ sign_up(:email => 'bob@bob.bob')
21
+ sign_out
22
+ visit root_url
23
+ assert !controller.signed_in?
24
+ end
25
+
26
+ end
27
+
28
+ end
@@ -0,0 +1,47 @@
1
+ require 'test_helper'
2
+
3
+ class SignUpTest < ActionController::IntegrationTest
4
+
5
+ context 'Signing up as a new user' do
6
+
7
+ setup do
8
+ ActionMailer::Base.deliveries.clear
9
+ end
10
+
11
+ teardown do
12
+ ActionMailer::Base.deliveries.clear
13
+ end
14
+
15
+ context 'with invalid data' do
16
+
17
+ should 'show error messages' do
18
+ sign_up(:email => 'invalidemail', :password_confirmation => '', :first_name => '', :last_name => '')
19
+ assert_match /Email is invalid/, response.body
20
+ assert_match /First name.*blank/, response.body
21
+ assert_match /Last name.*blank/, response.body
22
+ assert_match /Password doesn't match confirmation/, response.body
23
+ end
24
+
25
+ end
26
+
27
+ context 'with valid data' do
28
+
29
+ should 'sign in the user' do
30
+ sign_up(:email => 'bob@bob.bob', :password => 'password', :password_confirmation => 'password')
31
+ assert controller.signed_in?
32
+ end
33
+
34
+ should 'send a welcome email' do
35
+ sign_up(:email => 'bob@bob.bob', :password => 'password', :password_confirmation => 'password')
36
+ user = User.find_by_email('bob@bob.bob')
37
+ Delayed::Job.work_off
38
+ sent = ActionMailer::Base.deliveries.last
39
+ assert_equal user.email, sent.recipients
40
+ assert_match /welcome/i, sent.subject
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+
47
+ end
@@ -0,0 +1,138 @@
1
+ module Headstart
2
+ module Authentication
3
+
4
+ def self.included(controller) # :nodoc:
5
+ controller.send(:include, InstanceMethods)
6
+ controller.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+ def self.extended(controller)
11
+ controller.helper_method :current_user, :signed_in?,
12
+ :signed_out?, :impersonating?
13
+ controller.hide_action :current_user, :current_user=,
14
+ :signed_in?, :signed_out?,
15
+ :sign_in, :sign_out,
16
+ :authenticate, :deny_access,
17
+ :impersonating?
18
+ end
19
+ end
20
+
21
+ module InstanceMethods
22
+ # User in the current cookie
23
+ #
24
+ # @return [User, nil]
25
+ def current_user
26
+ @_current_user ||= user_from_cookie
27
+ end
28
+
29
+ # Set the current user
30
+ #
31
+ # @param [User]
32
+ def current_user=(user)
33
+ @_current_user = user
34
+ end
35
+
36
+ # Is the current user signed in?
37
+ #
38
+ # @return [true, false]
39
+ def signed_in?
40
+ ! current_user.nil?
41
+ end
42
+
43
+ # Is the current user signed out?
44
+ #
45
+ # @return [true, false]
46
+ def signed_out?
47
+ current_user.nil?
48
+ end
49
+
50
+ # Deny the user access if they are signed out.
51
+ #
52
+ # @example
53
+ # before_filter :authenticate
54
+ def authenticate
55
+ deny_access unless signed_in?
56
+ end
57
+
58
+ # Sign user in to cookie.
59
+ #
60
+ # @param [User]
61
+ #
62
+ # @example
63
+ # sign_in(@user)
64
+ def sign_in(user)
65
+ if user
66
+ cookies[:remember_token] = {
67
+ :value => user.remember_token,
68
+ :expires => 1.year.from_now.utc
69
+ }
70
+ self.current_user = user
71
+ end
72
+ end
73
+
74
+ # Sign user out of cookie.
75
+ #
76
+ # @example
77
+ # sign_out
78
+ def sign_out
79
+ current_user.reset_remember_token! if current_user
80
+ cookies.delete(:remember_token)
81
+ self.current_user = nil
82
+ end
83
+
84
+ # Store the current location and redirect to sign in.
85
+ # Display a failure flash message if included.
86
+ #
87
+ # @param [String] optional flash message to display to denied user
88
+ def deny_access(flash_message = nil)
89
+ store_location
90
+ flash[:failure] = flash_message if flash_message
91
+ redirect_to(sign_in_url)
92
+ end
93
+
94
+ def impersonating?
95
+ !session[:admin_user_id].blank?
96
+ end
97
+
98
+
99
+ protected
100
+
101
+ def user_from_cookie
102
+ if token = cookies[:remember_token]
103
+ ::User.find_by_remember_token(token)
104
+ end
105
+ end
106
+
107
+ def sign_user_in(user)
108
+ warn "[DEPRECATION] sign_user_in: unnecessary. use sign_in(user) instead."
109
+ sign_in(user)
110
+ end
111
+
112
+ def store_location
113
+ if request.get?
114
+ session[:return_to] = request.request_uri
115
+ end
116
+ end
117
+
118
+ def redirect_back_or(default)
119
+ redirect_to(return_to || default)
120
+ clear_return_to
121
+ end
122
+
123
+ def return_to
124
+ session[:return_to] || params[:return_to]
125
+ end
126
+
127
+ def clear_return_to
128
+ session[:return_to] = nil
129
+ end
130
+
131
+ def redirect_to_root
132
+ redirect_to('/')
133
+ end
134
+
135
+ end
136
+
137
+ end
138
+ end
@@ -0,0 +1,34 @@
1
+ module Headstart
2
+ class Configuration
3
+ attr_accessor :mailer_sender
4
+ attr_accessor :impersonation_hash
5
+ attr_accessor :use_facebook_connect
6
+ attr_accessor :facebook_api_key
7
+ attr_accessor :facebook_secret_key
8
+ attr_accessor :use_delayed_job
9
+
10
+ def initialize
11
+ @mailer_sender = 'donotreply@example.com'
12
+ @impersonation_hash = 'e76e05e1ddf74560ffb64c02a1c1b26c'
13
+ @user_facebook_connect = false
14
+ @use_delayed_job = true
15
+ end
16
+ end
17
+
18
+ class << self
19
+ attr_accessor :configuration
20
+ end
21
+
22
+ # Configure Headstart someplace sensible,
23
+ # like config/initializers/headstart.rb
24
+ #
25
+ # @example
26
+ # Headstart.configure do |config|
27
+ # config.mailer_sender = 'donotreply@example.com'
28
+ # config.impersonation_hash = 'abc123def456...'
29
+ # end
30
+ def self.configure
31
+ self.configuration ||= Configuration.new
32
+ yield(configuration)
33
+ end
34
+ end
@@ -0,0 +1,6 @@
1
+ if defined?(ActionController)
2
+ module ActionController
3
+ class Forbidden < StandardError
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ if defined?(ActionDispatch::ShowExceptions) # Rails 3
2
+ ActionDispatch::ShowExceptions.rescue_responses.update('ActionController::Forbidden' => :forbidden)
3
+ elsif defined?(ActionController::Base)
4
+ ActionController::Base.rescue_responses.update('ActionController::Forbidden' => :forbidden)
5
+ end
@@ -0,0 +1,67 @@
1
+ module Headstart
2
+ class Routes
3
+
4
+ # In your application's config/routes.rb, draw Headstart's routes:
5
+ #
6
+ # @example
7
+ # map.resources :posts
8
+ # Headstart::Routes.draw(map)
9
+ #
10
+ # If you need to override a Headstart route, invoke your app route
11
+ # earlier in the file so Rails' router short-circuits when it finds
12
+ # your route:
13
+ #
14
+ # @example
15
+ # map.resources :users, :only => [:new, :create]
16
+ # Headstart::Routes.draw(map)
17
+ def self.draw(map)
18
+ map.resources :passwords,
19
+ :controller => 'headstart/passwords',
20
+ :only => [:new, :create]
21
+
22
+ map.resource :session,
23
+ :controller => 'headstart/sessions',
24
+ :only => [:new, :create, :destroy]
25
+
26
+ map.resources :users, :controller => 'headstart/users' do |users|
27
+ users.resource :password,
28
+ :controller => 'headstart/passwords',
29
+ :only => [:create, :edit, :update]
30
+
31
+ users.resource :confirmation,
32
+ :controller => 'headstart/confirmations',
33
+ :only => [:new, :create]
34
+ end
35
+
36
+ map.resource :impersonation,
37
+ :controller => 'headstart/impersonations',
38
+ :only => [:create, :destroy]
39
+ map.resources :impersonations,
40
+ :controller => 'headstart/impersonations',
41
+ :only => :index
42
+
43
+ map.sign_up 'sign_up',
44
+ :controller => 'headstart/users',
45
+ :action => 'new'
46
+ map.sign_in 'sign_in',
47
+ :controller => 'headstart/sessions',
48
+ :action => 'new'
49
+ map.fb_connect 'fb_connect',
50
+ :controller => 'headstart/sessions',
51
+ :action => 'create'
52
+ map.fb_disconnect 'fb_disconnect',
53
+ :controller => 'headstart/users',
54
+ :action => 'facebook_remove'
55
+ map.sign_out 'sign_out',
56
+ :controller => 'headstart/sessions',
57
+ :action => 'destroy',
58
+ :method => :delete
59
+ map.admin 'admin',
60
+ :controller => '/admin/admin',
61
+ :action => :index
62
+
63
+ map.root :controller => "sessions", :action => 'index'
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,279 @@
1
+ require 'digest/sha1'
2
+
3
+ module Headstart
4
+ module User
5
+
6
+ Admin = 'admin'
7
+
8
+ # Hook for all Headstart::User modules.
9
+ #
10
+ # If you need to override parts of Headstart::User,
11
+ # extend and include à la carte.
12
+ #
13
+ # @example
14
+ # extend ClassMethods
15
+ # include InstanceMethods
16
+ # include AttrAccessor
17
+ # include Callbacks
18
+ #
19
+ # @see ClassMethods
20
+ # @see InstanceMethods
21
+ # @see AttrAccessible
22
+ # @see AttrAccessor
23
+ # @see Validations
24
+ # @see Callbacks
25
+ def self.included(model)
26
+ model.extend(ClassMethods)
27
+
28
+ model.send(:include, InstanceMethods)
29
+ model.send(:include, AttrAccessor)
30
+ model.send(:include, Validations)
31
+ model.send(:include, Callbacks)
32
+ end
33
+
34
+ module AttrAccessor
35
+ # Hook for attr_accessor virtual attributes.
36
+ #
37
+ # :password, :password_confirmation
38
+ def self.included(model)
39
+ model.class_eval do
40
+ attr_accessor :password, :password_confirmation
41
+ end
42
+ end
43
+ end
44
+
45
+ module Validations
46
+ # Hook for validations.
47
+ #
48
+ # :email must be present, unique, formatted
49
+ #
50
+ # If password is required,
51
+ # :password must be present, confirmed
52
+ def self.included(model)
53
+ model.class_eval do
54
+ validates_presence_of :email, :unless => :email_optional?
55
+ validates_uniqueness_of :email, :case_sensitive => false, :allow_blank => true
56
+ validates_format_of :email, :with => %r{.+@.+\..+}, :allow_blank => true
57
+
58
+ validates_presence_of :password, :unless => :password_optional?
59
+ validates_confirmation_of :password, :unless => :password_optional?
60
+
61
+ validates_presence_of :first_name, :last_name
62
+ end
63
+ end
64
+ end
65
+
66
+ module Callbacks
67
+ # Hook for callbacks.
68
+ #
69
+ # salt, token, password encryption are handled before_save.
70
+ def self.included(model)
71
+ model.class_eval do
72
+ before_save :initialize_salt,
73
+ :encrypt_password
74
+ before_create :generate_confirmation_token,
75
+ :generate_remember_token
76
+ after_create :send_welcome_email, :unless => :suppress_receive_welcome_email?
77
+ end
78
+ end
79
+ end
80
+
81
+ module InstanceMethods
82
+ # Am I authenticated with given password?
83
+ #
84
+ # @param [String] plain-text password
85
+ # @return [true, false]
86
+ # @example
87
+ # user.authenticated?('password')
88
+ def authenticated?(password)
89
+ encrypted_password == encrypt(password)
90
+ end
91
+
92
+ # Don't send welcome email if email already confirmed, or
93
+ # use is a facebook connect user
94
+ def suppress_receive_welcome_email?
95
+ return true if email_confirmed?
96
+ if self.facebook_uid.present?
97
+ self.email_confirmed = true
98
+ self.confirmation_token = nil
99
+ self.save
100
+ return true
101
+ end
102
+ return false
103
+ end
104
+
105
+ # Set the remember token.
106
+ #
107
+ # @deprecated Use {#reset_remember_token!} instead
108
+ def remember_me!
109
+ warn "[DEPRECATION] remember_me!: use reset_remember_token! instead"
110
+ reset_remember_token!
111
+ end
112
+
113
+ # Reset the remember token.
114
+ #
115
+ # @example
116
+ # user.reset_remember_token!
117
+ def reset_remember_token!
118
+ generate_remember_token
119
+ save(false)
120
+ end
121
+
122
+ # Confirm my email.
123
+ #
124
+ # @example
125
+ # user.confirm_email!
126
+ def confirm_email!
127
+ self.email_confirmed = true
128
+ self.confirmation_token = nil
129
+ save(false)
130
+ end
131
+
132
+ # Mark my account as forgotten password.
133
+ #
134
+ # @example
135
+ # user.forgot_password!
136
+ def forgot_password!
137
+ generate_password_reset_token
138
+ save(false)
139
+ end
140
+
141
+ # Update my password.
142
+ #
143
+ # @param [String, String] password and password confirmation
144
+ # @return [true, false] password was updated or not
145
+ # @example
146
+ # user.update_password('new-password', 'new-password')
147
+ def update_password(new_password, new_password_confirmation)
148
+ self.password = new_password
149
+ self.password_confirmation = new_password_confirmation
150
+ if valid?
151
+ self.password_reset_token = nil
152
+ end
153
+ save
154
+ end
155
+
156
+ def facebook_user?
157
+ !self.facebook_uid.blank?
158
+ end
159
+
160
+ ##
161
+ # Returns +true+ if the user is an admin.
162
+ #
163
+ def admin?
164
+ self.role == Admin
165
+ end
166
+
167
+ ##
168
+ # Returns the user's full name.
169
+ #
170
+ def name
171
+ "#{self.first_name} #{self.last_name}"
172
+ end
173
+
174
+ protected
175
+
176
+ def generate_hash(string)
177
+ Digest::SHA1.hexdigest(string)
178
+ end
179
+
180
+ def initialize_salt
181
+ if new_record?
182
+ self.salt = generate_hash("--#{Time.now.utc}--#{password}--#{rand}--")
183
+ end
184
+ end
185
+
186
+ def encrypt_password
187
+ return if password.blank?
188
+ self.encrypted_password = encrypt(password)
189
+ end
190
+
191
+ def encrypt(string)
192
+ generate_hash("--#{salt}--#{string}--")
193
+ end
194
+
195
+ def generate_confirmation_token
196
+ self.confirmation_token = encrypt("--#{Time.now.utc}--#{password}--#{rand}--")
197
+ end
198
+
199
+ def generate_password_reset_token
200
+ self.password_reset_token = encrypt("--#{Time.now.utc}--#{password}--#{rand}--")
201
+ end
202
+
203
+ def generate_remember_token
204
+ self.remember_token = encrypt("--#{Time.now.utc}--#{encrypted_password}--#{id}--#{rand}--")
205
+ end
206
+
207
+ # Always false. Override to allow other forms of authentication
208
+ # (username, facebook, etc).
209
+ # @return [Boolean] true if the email field be left blank for this user
210
+ def email_optional?
211
+ false
212
+ end
213
+
214
+ # True if the password has been set and the password is not being
215
+ # updated. Override to allow other forms of # authentication (username,
216
+ # facebook, etc).
217
+ # @return [Boolean] true if the password field can be left blank for this user
218
+ def password_optional?
219
+ facebook_user? || (encrypted_password.present? && password.blank?)
220
+ end
221
+
222
+ def password_required?
223
+ # warn "[DEPRECATION] password_required?: use !password_optional? instead"
224
+ !password_optional?
225
+ end
226
+
227
+ def send_welcome_email
228
+ if Headstart.configuration.use_delayed_job
229
+ Delayed::Job.enqueue DeliverWelcomeJob.new(self.id)
230
+ else
231
+ if user = ::User.find_by_id(self.id)
232
+ HeadstartMailer.deliver_welcome(user)
233
+ end
234
+ end
235
+ end
236
+
237
+ def send_confirmation_email
238
+ HeadstartMailer.deliver_confirmation self
239
+ end
240
+
241
+ end
242
+
243
+ module ClassMethods
244
+ # Authenticate with email and password.
245
+ #
246
+ # @param [String, String] email and password
247
+ # @return [User, nil] authenticated user or nil
248
+ # @example
249
+ # User.authenticate("email@example.com", "password")
250
+ def authenticate(email, password)
251
+ return nil unless user = find_by_email(email)
252
+ return user if user.authenticated?(password)
253
+ end
254
+
255
+ def find_facebook_user(facebook_session, facebook_uid)
256
+ return nil unless Headstart.configuration.use_facebook_connect && facebook_session && facebook_uid
257
+
258
+ begin
259
+ facebook_user = MiniFB::Session.new(Headstart.configuration.facebook_api_key,
260
+ Headstart.configuration.facebook_secret_key,
261
+ facebook_session, facebook_uid).user
262
+ rescue MiniFB::FaceBookError
263
+ facebook_user = nil
264
+ end
265
+ return nil unless facebook_user
266
+
267
+ user = ::User.find_by_facebook_uid(facebook_uid) || ::User.find_by_email(facebook_user['email']) || ::User.new
268
+ user.tap do |user|
269
+ user.facebook_uid = facebook_uid
270
+ user.email = facebook_user['email']
271
+ user.first_name = facebook_user['first_name']
272
+ user.last_name = facebook_user['last_name']
273
+ user.save
274
+ end
275
+ end
276
+ end
277
+
278
+ end
279
+ end
data/lib/headstart.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'headstart/extensions/errors'
2
+ require 'headstart/extensions/rescue'
3
+
4
+ require 'headstart/configuration'
5
+ require 'headstart/routes'
6
+ require 'headstart/authentication'
7
+ require 'headstart/user'
data/rails/init.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'delayed_job'
2
+ require 'mini_fb'
3
+ require 'mad_mimi_mailer'
4
+ require 'headstart'