rails_mvp_authentication 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 (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