rails_mvp_authentication 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +28 -0
  4. data/Rakefile +8 -0
  5. data/app/assets/config/rails_mvp_authentication_manifest.js +1 -0
  6. data/app/assets/stylesheets/rails_mvp_authentication/application.css +15 -0
  7. data/app/controllers/rails_mvp_authentication/application_controller.rb +4 -0
  8. data/app/helpers/rails_mvp_authentication/application_helper.rb +4 -0
  9. data/app/jobs/rails_mvp_authentication/application_job.rb +4 -0
  10. data/app/mailers/rails_mvp_authentication/application_mailer.rb +6 -0
  11. data/app/models/rails_mvp_authentication/application_record.rb +5 -0
  12. data/app/views/layouts/rails_mvp_authentication/application.html.erb +15 -0
  13. data/config/routes.rb +2 -0
  14. data/lib/generators/rails_mvp_authentication/USAGE +5 -0
  15. data/lib/generators/rails_mvp_authentication/install_generator.rb +251 -0
  16. data/lib/generators/rails_mvp_authentication/templates/README +7 -0
  17. data/lib/generators/rails_mvp_authentication/templates/authentication.rb.tt +58 -0
  18. data/lib/generators/rails_mvp_authentication/templates/confirmations_controller.rb.tt +32 -0
  19. data/lib/generators/rails_mvp_authentication/templates/current.rb.tt +3 -0
  20. data/lib/generators/rails_mvp_authentication/templates/passwords_controller.rb.tt +52 -0
  21. data/lib/generators/rails_mvp_authentication/templates/sessions_controller.rb.tt +30 -0
  22. data/lib/generators/rails_mvp_authentication/templates/test/controllers/active_sessions_controller_test.rb.tt +68 -0
  23. data/lib/generators/rails_mvp_authentication/templates/test/controllers/confirmations_controller_test.rb.tt +143 -0
  24. data/lib/generators/rails_mvp_authentication/templates/test/controllers/passwords_controller_test.rb.tt +119 -0
  25. data/lib/generators/rails_mvp_authentication/templates/test/controllers/sessions_controller_test.rb.tt +105 -0
  26. data/lib/generators/rails_mvp_authentication/templates/test/controllers/users_controller_test.rb.tt +150 -0
  27. data/lib/generators/rails_mvp_authentication/templates/test/integration/friendly_redirects_test.rb.tt +23 -0
  28. data/lib/generators/rails_mvp_authentication/templates/test/integration/user_interface_test.rb.tt +35 -0
  29. data/lib/generators/rails_mvp_authentication/templates/test/mailers/previews/user_mailer_preview.rb.tt +17 -0
  30. data/lib/generators/rails_mvp_authentication/templates/test/mailers/user_mailer_test.rb.tt +25 -0
  31. data/lib/generators/rails_mvp_authentication/templates/test/models/active_session_test.rb.tt +18 -0
  32. data/lib/generators/rails_mvp_authentication/templates/test/models/user_test.rb.tt +183 -0
  33. data/lib/generators/rails_mvp_authentication/templates/test/system/logins_test.rb.tt +18 -0
  34. data/lib/generators/rails_mvp_authentication/templates/user.rb.tt +96 -0
  35. data/lib/generators/rails_mvp_authentication/templates/user_mailer.rb.tt +22 -0
  36. data/lib/generators/rails_mvp_authentication/templates/users_controller.rb.tt +59 -0
  37. data/lib/generators/rails_mvp_authentication/templates/views/confirmations/new.html.erb.tt +4 -0
  38. data/lib/generators/rails_mvp_authentication/templates/views/passwords/edit.html.erb.tt +11 -0
  39. data/lib/generators/rails_mvp_authentication/templates/views/passwords/new.html.erb.tt +4 -0
  40. data/lib/generators/rails_mvp_authentication/templates/views/sessions/new.html.erb.tt +15 -0
  41. data/lib/generators/rails_mvp_authentication/templates/views/user_mailer/confirmation.html.erb.tt +3 -0
  42. data/lib/generators/rails_mvp_authentication/templates/views/user_mailer/confirmation.text.erb.tt +3 -0
  43. data/lib/generators/rails_mvp_authentication/templates/views/user_mailer/password_reset.html.erb.tt +3 -0
  44. data/lib/generators/rails_mvp_authentication/templates/views/user_mailer/password_reset.text.erb.tt +3 -0
  45. data/lib/generators/rails_mvp_authentication/templates/views/users/edit.html.erb.tt +42 -0
  46. data/lib/generators/rails_mvp_authentication/templates/views/users/new.html.erb.tt +16 -0
  47. data/lib/rails_mvp_authentication/engine.rb +5 -0
  48. data/lib/rails_mvp_authentication/version.rb +3 -0
  49. data/lib/rails_mvp_authentication.rb +6 -0
  50. data/lib/tasks/rails_mvp_authentication_tasks.rake +4 -0
  51. metadata +129 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4fa3c307eee6e61d01e318fe1453a30660e18f0e2eb1de7b725c22f93c6a60e6
4
+ data.tar.gz: 8ac56c76c7dd2f316ef9b19c81e8c78987cade71cee289f2e1b3ef8c1dc22d0e
5
+ SHA512:
6
+ metadata.gz: da4f0c62616acff46d67f8ca95ae1b7606710a23e99dfab4b6225b24ab90dca5dab8aec39c64d5749d4b608a21a9ea6ed3891f7ecb5586c8b568b3d71f394bfc
7
+ data.tar.gz: c6a117f9c7f8cb7168087329e21a62636b2b8bb74561f28e77dcb5ce8052f5add760b3254f43dfd051cfd8198103f57703d364c547134edcb0d8706365db0c94
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2022 Steve Polito
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # RailsMvpAuthentication
2
+ Short description and motivation.
3
+
4
+ ## Usage
5
+ How to use my plugin.
6
+
7
+ ## Installation
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem "rails_mvp_authentication"
12
+ ```
13
+
14
+ And then execute:
15
+ ```bash
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+ ```bash
21
+ $ gem install rails_mvp_authentication
22
+ ```
23
+
24
+ ## Contributing
25
+ Contribution directions go here.
26
+
27
+ ## License
28
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
@@ -0,0 +1 @@
1
+ //= link_directory ../stylesheets/rails_mvp_authentication .css
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,4 @@
1
+ module RailsMvpAuthentication
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module RailsMvpAuthentication
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module RailsMvpAuthentication
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module RailsMvpAuthentication
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: "from@example.com"
4
+ layout "mailer"
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module RailsMvpAuthentication
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Rails mvp authentication</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+
8
+ <%= stylesheet_link_tag "rails_mvp_authentication/application", media: "all" %>
9
+ </head>
10
+ <body>
11
+
12
+ <%= yield %>
13
+
14
+ </body>
15
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,2 @@
1
+ RailsMvpAuthentication::Engine.routes.draw do
2
+ end
@@ -0,0 +1,5 @@
1
+ Description:
2
+ Rails authentication via a generator.
3
+
4
+ Example:
5
+ bin/rails generate rails_mvp_authentication:install
@@ -0,0 +1,251 @@
1
+ module RailsMvpAuthentication
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path("templates", __dir__)
5
+
6
+ desc "Rails authentication via a generator."
7
+
8
+ def perform
9
+ create_users_table
10
+ modify_users_table
11
+ create_user_model
12
+ add_bcrypt
13
+ add_routes
14
+ create_current_model
15
+ create_users_controller
16
+ create_user_views
17
+ create_confirmations_controller
18
+ create_confirmation_views
19
+ ceate_user_mailer
20
+ ceate_user_mailer_views
21
+ configure_hosts
22
+ create_authentication_concern
23
+ modify_application_controller
24
+ create_sessions_controller
25
+ create_session_views
26
+ create_passwords_controller
27
+ create_password_views
28
+ if using_default_test_suite
29
+ create_tests
30
+ modify_test_helper
31
+ end
32
+ add_links
33
+ print_instructions
34
+ end
35
+
36
+ private
37
+
38
+ def add_bcrypt
39
+ return unless gemfile_exists
40
+
41
+ if bcrypt_is_commented_out
42
+ uncomment_lines(gemfile, /gem "bcrypt", "~> 3.1.7"/)
43
+ else
44
+ gem "bcrypt", "~> 3.1.7"
45
+ end
46
+ end
47
+
48
+ def add_links
49
+ inject_into_file "app/views/layouts/application.html.erb", after: "<body>\n" do
50
+ <<-ERB
51
+ <ul>
52
+ <% if user_signed_in? %>
53
+ <li><%= link_to "My Acount", account_path %></li>
54
+ <li><%= button_to "Logout", logout_path, method: :delete %></li>
55
+ <% else %>
56
+ <li><%= link_to "Login", login_path %></li>
57
+ <li><%= link_to "Sign Up", sign_up_path %></li>
58
+ <li><%= link_to "Forgot my password", new_password_path %></li>
59
+ <li><%= link_to "Didn't receive confirmation instructions", new_confirmation_path %></li>
60
+ <% end %>
61
+ </ul>
62
+ ERB
63
+ end
64
+ end
65
+
66
+ def add_routes
67
+ route %(
68
+ post "sign_up", to: "users#create"
69
+ get "sign_up", to: "users#new"
70
+ put "account", to: "users#update"
71
+ get "account", to: "users#edit"
72
+ delete "account", to: "users#destroy"
73
+ resources :confirmations, only: [:create, :edit, :new], param: :confirmation_token
74
+ post "login", to: "sessions#create"
75
+ delete "logout", to: "sessions#destroy"
76
+ get "login", to: "sessions#new"
77
+ resources :passwords, only: [:create, :edit, :new, :update], param: :password_reset_token
78
+ resources :active_sessions, only: [:destroy] do
79
+ collection do
80
+ delete "destroy_all"
81
+ end
82
+ end
83
+ )
84
+ end
85
+
86
+ def bcrypt_is_commented_out
87
+ gemfile = path_to("Gemfile")
88
+
89
+ File.open(gemfile).each_line do |line|
90
+ return true if line == '# gem "bcrypt", "~> 3.1.7"'
91
+ end
92
+
93
+ false
94
+ end
95
+
96
+ def configure_hosts
97
+ application(nil, env: "test") do
98
+ 'config.action_mailer.default_url_options = {host: "example.com"}'
99
+ end
100
+ application(nil, env: "development") do
101
+ 'config.action_mailer.default_url_options = {host: "localhost", port: 3000}'
102
+ end
103
+ end
104
+
105
+ def create_authentication_concern
106
+ template "authentication.rb", "app/controllers/concerns/authentication.rb"
107
+ end
108
+
109
+ def create_confirmations_controller
110
+ template "confirmations_controller.rb", "app/controllers/confirmations_controller.rb"
111
+ end
112
+
113
+ def create_confirmation_views
114
+ template "views/confirmations/new.html.erb", "app/views/confirmations/new.html.erb"
115
+ end
116
+
117
+ def create_current_model
118
+ template "current.rb", "app/models/current.rb"
119
+ end
120
+
121
+ def create_passwords_controller
122
+ template "passwords_controller.rb", "app/controllers/passwords_controller.rb"
123
+ end
124
+
125
+ def create_password_views
126
+ template "views/passwords/new.html.erb", "app/views/passwords/new.html.erb"
127
+ template "views/passwords/edit.html.erb", "app/views/passwords/edit.html.erb"
128
+ end
129
+
130
+ def create_sessions_controller
131
+ template "sessions_controller.rb", "app/controllers/sessions_controller.rb"
132
+ end
133
+
134
+ def create_session_views
135
+ template "views/sessions/new.html.erb", "app/views/sessions/new.html.erb"
136
+ end
137
+
138
+ def create_users_controller
139
+ template "users_controller.rb", "app/controllers/users_controller.rb"
140
+ end
141
+
142
+ def create_tests
143
+ template "test/controllers/active_sessions_controller_test.rb", "test/controllers/active_sessions_controller_test.rb"
144
+ template "test/controllers/confirmations_controller_test.rb", "test/controllers/confirmations_controller_test.rb"
145
+ template "test/controllers/active_sessions_controller_test.rb", "test/controllers/active_sessions_controller_test.rb"
146
+ template "test/controllers/passwords_controller_test.rb", "test/controllers/passwords_controller_test.rb"
147
+ template "test/controllers/sessions_controller_test.rb", "test/controllers/sessions_controller_test.rb"
148
+ template "test/controllers/users_controller_test.rb", "test/controllers/users_controller_test.rb"
149
+
150
+ template "test/integration/friendly_redirects_test.rb", "test/integration/friendly_redirects_test.rb"
151
+ template "test/integration/user_interface_test.rb", "test/integration/user_interface_test.rb"
152
+
153
+ template "test/mailers/previews/user_mailer_preview.rb", "test/mailers/previews/user_mailer_preview.rb"
154
+ template "test/mailers/user_mailer_test.rb", "test/mailers/user_mailer_test.rb"
155
+
156
+ template "test/models/user_test.rb", "test/models/user_test.rb"
157
+ template "test/models/active_session_test.rb", "test/models/active_session_test.rb"
158
+
159
+ template "test/system/logins_test.rb", "test/system/logins_test.rb"
160
+ end
161
+
162
+ def ceate_user_mailer
163
+ template "user_mailer.rb", "app/mailers/user_mailer.rb"
164
+ end
165
+
166
+ def ceate_user_mailer_views
167
+ template "views/user_mailer/confirmation.html.erb", "app/views/user_mailer/confirmation.html.erb"
168
+ template "views/user_mailer/confirmation.text.erb", "app/views/user_mailer/confirmation.text.erb"
169
+ template "views/user_mailer/password_reset.html.erb", "app/views/user_mailer/password_reset.html.erb"
170
+ template "views/user_mailer/password_reset.text.erb", "app/views/user_mailer/password_reset.text.erb"
171
+ end
172
+
173
+ def create_user_model
174
+ template "user.rb", "app/models/user.rb"
175
+ end
176
+
177
+ def create_users_table
178
+ generate "migration", "create_users_table email:string:index confirmed_at:datetime password_digest:string unconfirmed_email:string"
179
+ end
180
+
181
+ def create_user_views
182
+ template "views/users/edit.html.erb", "app/views/users/edit.html.erb"
183
+ template "views/users/new.html.erb", "app/views/users/new.html.erb"
184
+ end
185
+
186
+ def directory_exists(directory)
187
+ File.directory?(directory)
188
+ end
189
+
190
+ def gemfile
191
+ path_to("Gemfile")
192
+ end
193
+
194
+ def gemfile_exists
195
+ File.exist?(gemfile)
196
+ end
197
+
198
+ def modify_application_controller
199
+ inject_into_file "app/controllers/application_controller.rb", "\tinclude Authentication\n", after: "class ApplicationController < ActionController::Base\n"
200
+ end
201
+
202
+ def modify_test_helper
203
+ inject_into_class "test/test_helper.rb", "ActiveSupport::TestCase" do
204
+ <<-RUBY
205
+ def current_user
206
+ if session[:current_active_session_id].present?
207
+ ActiveSession.find_by(id: session[:current_active_session_id])&.user
208
+ else
209
+ cookies[:remember_token].present?
210
+ ActiveSession.find_by(remember_token: cookies[:remember_token])&.user
211
+ end
212
+ end
213
+
214
+ def login(user, remember_user: nil)
215
+ post login_path, params: {
216
+ user: {
217
+ email: user.email,
218
+ password: user.password,
219
+ remember_me: remember_user == true ? 1 : 0
220
+ }
221
+ }
222
+ end
223
+
224
+ def logout
225
+ session.delete(:current_active_session_id)
226
+ end
227
+ RUBY
228
+ end
229
+ end
230
+
231
+ def modify_users_table
232
+ migration = Dir.glob(Rails.root.join("db/migrate/*")).max_by { |f| File.mtime(f) }
233
+ gsub_file migration, /t.string :email/, "t.string :email, null: false"
234
+ gsub_file migration, /t.string :password_digest/, "t.string :password_digest, null: false"
235
+ gsub_file migration, /add_index :users_tables, :email/, "add_index :users_tables, :email, unique: true"
236
+ end
237
+
238
+ def path_to(path)
239
+ Rails.root.join(path)
240
+ end
241
+
242
+ def print_instructions
243
+ readme "README"
244
+ end
245
+
246
+ def using_default_test_suite
247
+ directory_exists(path_to("test"))
248
+ end
249
+ end
250
+ end
251
+ end
@@ -0,0 +1,7 @@
1
+ ========== Setup complete! 🎉 ==========
2
+
3
+ Next steps 👇
4
+
5
+ 🏗 Run bundle install
6
+ 💿 Run rails db:migrate
7
+ 🔗 Add a root path in config/routes.rb
@@ -0,0 +1,58 @@
1
+ module Authentication
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ before_action :current_user
6
+ helper_method :current_user
7
+ helper_method :user_signed_in?
8
+ end
9
+
10
+ def authenticate_user!
11
+ store_location
12
+ redirect_to login_path, alert: "You need to login to access that page." unless user_signed_in?
13
+ end
14
+
15
+ def login(user)
16
+ reset_session
17
+ active_session = user.active_sessions.create!(user_agent: request.user_agent, ip_address: request.ip)
18
+ session[:current_active_session_id] = active_session.id
19
+
20
+ active_session
21
+ end
22
+
23
+ def forget_active_session
24
+ cookies.delete :remember_token
25
+ end
26
+
27
+ def logout
28
+ active_session = ActiveSession.find_by(id: session[:current_active_session_id])
29
+ reset_session
30
+ active_session.destroy! if active_session.present?
31
+ end
32
+
33
+ def redirect_if_authenticated
34
+ redirect_to root_path, alert: "You are already logged in." if user_signed_in?
35
+ end
36
+
37
+ def remember(active_session)
38
+ cookies.permanent.encrypted[:remember_token] = active_session.remember_token
39
+ end
40
+
41
+ private
42
+
43
+ def current_user
44
+ Current.user = if session[:current_active_session_id].present?
45
+ ActiveSession.find_by(id: session[:current_active_session_id])&.user
46
+ elsif cookies.permanent.encrypted[:remember_token].present?
47
+ ActiveSession.find_by(remember_token: cookies.permanent.encrypted[:remember_token])&.user
48
+ end
49
+ end
50
+
51
+ def user_signed_in?
52
+ Current.user.present?
53
+ end
54
+
55
+ def store_location
56
+ session[:user_return_to] = request.original_url if request.get? && request.local?
57
+ end
58
+ end
@@ -0,0 +1,32 @@
1
+ class ConfirmationsController < ApplicationController
2
+ before_action :redirect_if_authenticated, only: [:create, :new]
3
+
4
+ def create
5
+ @user = User.find_by(email: params[:user][:email].downcase)
6
+
7
+ if @user.present? && @user.unconfirmed?
8
+ @user.send_confirmation_email!
9
+ redirect_to root_path, notice: "Check your email for confirmation instructions."
10
+ else
11
+ redirect_to new_confirmation_path, alert: "We could not find a user with that email or that email has already been confirmed."
12
+ end
13
+ end
14
+
15
+ def edit
16
+ @user = User.find_signed(params[:confirmation_token], purpose: :confirm_email)
17
+ if @user.present? && @user.unconfirmed_or_reconfirming?
18
+ if @user.confirm!
19
+ login @user
20
+ redirect_to root_path, notice: "Your account has been confirmed."
21
+ else
22
+ redirect_to new_confirmation_path, alert: "Something went wrong."
23
+ end
24
+ else
25
+ redirect_to new_confirmation_path, alert: "Invalid token."
26
+ end
27
+ end
28
+
29
+ def new
30
+ @user = User.new
31
+ end
32
+ end
@@ -0,0 +1,3 @@
1
+ class Current < ActiveSupport::CurrentAttributes
2
+ attribute :user
3
+ end
@@ -0,0 +1,52 @@
1
+ class PasswordsController < ApplicationController
2
+ before_action :redirect_if_authenticated
3
+
4
+ def create
5
+ @user = User.find_by(email: params[:user][:email].downcase)
6
+ if @user.present?
7
+ if @user.confirmed?
8
+ @user.send_password_reset_email!
9
+ redirect_to root_path, notice: "If that user exists we've sent instructions to their email."
10
+ else
11
+ redirect_to new_confirmation_path, alert: "Please confirm your email first."
12
+ end
13
+ else
14
+ redirect_to root_path, notice: "If that user exists we've sent instructions to their email."
15
+ end
16
+ end
17
+
18
+ def edit
19
+ @user = User.find_signed(params[:password_reset_token], purpose: :reset_password)
20
+ if @user.present? && @user.unconfirmed?
21
+ redirect_to new_confirmation_path, alert: "You must confirm your email before you can sign in."
22
+ elsif @user.nil?
23
+ redirect_to new_password_path, alert: "Invalid or expired token."
24
+ end
25
+ end
26
+
27
+ def new
28
+ end
29
+
30
+ def update
31
+ @user = User.find_signed(params[:password_reset_token], purpose: :reset_password)
32
+ if @user
33
+ if @user.unconfirmed?
34
+ redirect_to new_confirmation_path, alert: "You must confirm your email before you can sign in."
35
+ elsif @user.update(password_params)
36
+ redirect_to login_path, notice: "Sign in."
37
+ else
38
+ flash.now[:alert] = @user.errors.full_messages.to_sentence
39
+ render :edit, status: :unprocessable_entity
40
+ end
41
+ else
42
+ flash.now[:alert] = "Invalid or expired token."
43
+ render :new, status: :unprocessable_entity
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def password_params
50
+ params.require(:user).permit(:password, :password_confirmation)
51
+ end
52
+ end
@@ -0,0 +1,30 @@
1
+ class SessionsController < ApplicationController
2
+ before_action :redirect_if_authenticated, only: [:create, :new]
3
+ before_action :authenticate_user!, only: [:destroy]
4
+
5
+ def create
6
+ @user = User.authenticate_by(email: params[:user][:email].downcase, password: params[:user][:password])
7
+ if @user
8
+ if @user.unconfirmed?
9
+ redirect_to new_confirmation_path, alert: "Incorrect email or password."
10
+ else
11
+ after_login_path = session[:user_return_to] || root_path
12
+ active_session = login @user
13
+ remember(active_session) if params[:user][:remember_me] == "1"
14
+ redirect_to after_login_path, notice: "Signed in."
15
+ end
16
+ else
17
+ flash.now[:alert] = "Incorrect email or password."
18
+ render :new, status: :unprocessable_entity
19
+ end
20
+ end
21
+
22
+ def destroy
23
+ forget_active_session
24
+ logout
25
+ redirect_to root_path, notice: "Signed out."
26
+ end
27
+
28
+ def new
29
+ end
30
+ end
@@ -0,0 +1,68 @@
1
+ require "test_helper"
2
+
3
+ class ActiveSessionsControllerTest < ActionDispatch::IntegrationTest
4
+ setup do
5
+ @confirmed_user = User.create!(email: "confirmed_user@example.com", password: "password", password_confirmation: "password", confirmed_at: Time.current)
6
+ end
7
+
8
+ test "should destroy all active sessions" do
9
+ login @confirmed_user
10
+ @confirmed_user.active_sessions.create!
11
+
12
+ assert_difference("ActiveSession.count", -2) do
13
+ delete destroy_all_active_sessions_path
14
+ end
15
+
16
+ assert_redirected_to root_path
17
+ assert_nil current_user
18
+ assert_not_nil flash[:notice]
19
+ end
20
+
21
+ test "should destroy all active sessions and forget active sessions" do
22
+ login @confirmed_user, remember_user: true
23
+ @confirmed_user.active_sessions.create!
24
+
25
+ assert_difference("ActiveSession.count", -2) do
26
+ delete destroy_all_active_sessions_path
27
+ end
28
+
29
+ assert_nil current_user
30
+ assert cookies[:remember_token].blank?
31
+ end
32
+
33
+ test "should destroy another session" do
34
+ login @confirmed_user
35
+ @confirmed_user.active_sessions.create!
36
+
37
+ assert_difference("ActiveSession.count", -1) do
38
+ delete active_session_path(@confirmed_user.active_sessions.last)
39
+ end
40
+
41
+ assert_redirected_to account_path
42
+ assert_not_nil current_user
43
+ assert_not_nil flash[:notice]
44
+ end
45
+
46
+ test "should destroy current session" do
47
+ login @confirmed_user
48
+
49
+ assert_difference("ActiveSession.count", -1) do
50
+ delete active_session_path(@confirmed_user.active_sessions.last)
51
+ end
52
+
53
+ assert_redirected_to root_path
54
+ assert_nil current_user
55
+ assert_not_nil flash[:notice]
56
+ end
57
+
58
+ test "should destroy current session and forget current active session" do
59
+ login @confirmed_user, remember_user: true
60
+
61
+ assert_difference("ActiveSession.count", -1) do
62
+ delete active_session_path(@confirmed_user.active_sessions.last)
63
+ end
64
+
65
+ assert_nil current_user
66
+ assert cookies[:remember_token].blank?
67
+ end
68
+ end