authentication-zero 2.1.1 → 2.2.1

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/README.md +5 -3
  4. data/lib/authentication_zero/version.rb +1 -1
  5. data/lib/generators/authentication/authentication_generator.rb +3 -2
  6. data/lib/generators/authentication/templates/controllers/api/email_verifications_controller.rb.tt +18 -0
  7. data/lib/generators/authentication/templates/controllers/api/password_resets_controller.rb.tt +6 -6
  8. data/lib/generators/authentication/templates/controllers/api/registrations_controller.rb.tt +5 -1
  9. data/lib/generators/authentication/templates/controllers/api/sessions_controller.rb.tt +2 -2
  10. data/lib/generators/authentication/templates/controllers/html/email_verifications_controller.rb.tt +20 -0
  11. data/lib/generators/authentication/templates/controllers/html/password_resets_controller.rb.tt +6 -6
  12. data/lib/generators/authentication/templates/controllers/html/registrations_controller.rb.tt +6 -1
  13. data/lib/generators/authentication/templates/controllers/html/sessions_controller.rb.tt +2 -2
  14. data/lib/generators/authentication/templates/erb/emails/edit.html.erb.tt +7 -1
  15. data/lib/generators/authentication/templates/erb/identity_mailer/email_verify_confirmation.html.erb.tt +11 -0
  16. data/lib/generators/authentication/templates/erb/identity_mailer/email_verify_confirmation.text.erb.tt +9 -0
  17. data/lib/generators/authentication/templates/erb/{password_mailer/reset.html.erb.tt → identity_mailer/password_reset_provision.html.erb.tt} +1 -1
  18. data/lib/generators/authentication/templates/erb/{password_mailer/reset.text.erb.tt → identity_mailer/password_reset_provision.text.erb.tt} +1 -1
  19. data/lib/generators/authentication/templates/erb/session_mailer/{signed_in.html.erb.tt → signed_in_notification.html.erb.tt} +1 -1
  20. data/lib/generators/authentication/templates/erb/session_mailer/{signed_in.text.erb.tt → signed_in_notification.text.erb.tt} +1 -1
  21. data/lib/generators/authentication/templates/mailers/identity_mailer.rb.tt +15 -0
  22. data/lib/generators/authentication/templates/mailers/session_mailer.rb.tt +1 -1
  23. data/lib/generators/authentication/templates/migrations/create_sessions_migration.rb.tt +1 -0
  24. data/lib/generators/authentication/templates/migrations/create_table_migration.rb.tt +2 -0
  25. data/lib/generators/authentication/templates/models/current.rb.tt +1 -1
  26. data/lib/generators/authentication/templates/models/model.rb.tt +12 -0
  27. data/lib/generators/authentication/templates/models/session.rb.tt +1 -1
  28. data/lib/generators/authentication/templates/test_unit/controllers/api/email_verifications_controller_test.rb.tt +36 -0
  29. data/lib/generators/authentication/templates/test_unit/controllers/api/password_resets_controller_test.rb.tt +14 -3
  30. data/lib/generators/authentication/templates/test_unit/controllers/api/registrations_controller_test.rb.tt +15 -0
  31. data/lib/generators/authentication/templates/test_unit/controllers/api/sessions_controller_test.rb.tt +1 -1
  32. data/lib/generators/authentication/templates/test_unit/controllers/html/email_verifications_controller_test.rb.tt +35 -0
  33. data/lib/generators/authentication/templates/test_unit/controllers/html/password_resets_controller_test.rb.tt +14 -3
  34. data/lib/generators/authentication/templates/test_unit/controllers/html/registrations_controller_test.rb.tt +14 -0
  35. data/lib/generators/authentication/templates/test_unit/controllers/html/sessions_controller_test.rb.tt +1 -1
  36. data/lib/generators/authentication/templates/test_unit/fixtures.yml.tt +1 -0
  37. data/lib/generators/authentication/templates/test_unit/system/emails_test.rb.tt +9 -0
  38. data/lib/generators/authentication/templates/test_unit/system/registrations_test.rb.tt +20 -0
  39. metadata +13 -13
  40. data/lib/generators/authentication/templates/controllers/api/cancellations_controller.rb.tt +0 -5
  41. data/lib/generators/authentication/templates/controllers/html/cancellations_controller.rb.tt +0 -9
  42. data/lib/generators/authentication/templates/erb/cancellations/new.html.erb.tt +0 -11
  43. data/lib/generators/authentication/templates/mailers/password_mailer.rb.tt +0 -6
  44. data/lib/generators/authentication/templates/test_unit/controllers/api/cancellations_controller_test.rb.tt +0 -20
  45. data/lib/generators/authentication/templates/test_unit/controllers/html/cancellations_controller_test.rb.tt +0 -24
  46. data/lib/generators/authentication/templates/test_unit/system/cancellations_test.rb.tt +0 -23
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 44c36959694f55d09ae33d82d3dbe2091a49372c4792eda84bfddf94c62b636c
4
- data.tar.gz: 9d4b642209fe681865973ad1a5b13bd8bba1bf63140ae49acfe25923ce085514
3
+ metadata.gz: ed9892e61478e60ca189e6e835b59c9fd2ab63e2c342e1d67bbdfb57f60dd9ba
4
+ data.tar.gz: d890089e13104ec641c5d26ec5541e3ce9a4cb64cbe2d2276347f0c328efc713
5
5
  SHA512:
6
- metadata.gz: cbc64b8248e0bf392983bb19a3034b76471dc54511cb7ffee7ed122bb3c7f1424ec4211b11b5d0026395d622c1e6d6b35c3be09710f5617f45db2daece00ec49
7
- data.tar.gz: f3ccd41d8f2c417918cf65c7124fc597355d07bc96ba509bba12174d5161df33b2434a3af76a67f2e23de020f7cec549fc8a326619643373e4c05eb1b799c4bd
6
+ metadata.gz: f050cf8b766989090c9a4c415bdc7f91eebb2ff63b3d7632a5bdfa1923d68ebf6f110d8a2eba71af7387c708c6398ea365746d51fdd45903b1362fd5551588b7
7
+ data.tar.gz: 6ec0286f6ea33a9f95551e8808297ab4ffc4d7e609317e5a90c3442c36d7d4c4845bb9746c0e92bea5383ac0ff92f64f652c9453c5b16311ea1eda17b2b96642
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- authentication-zero (2.1.1)
4
+ authentication-zero (2.2.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -8,8 +8,10 @@ The purpose of authentication zero is to generate a pre-built authentication sys
8
8
  - Sign up
9
9
  - Email and password validations
10
10
  - Reset the user password and send reset instructions
11
+ - Reset the user password only from verified emails
11
12
  - Authentication by cookie (html)
12
13
  - Authentication by token (api)
14
+ - Send e-mail verification when change your email
13
15
  - Send e-mail when sign-in to your account
14
16
  - Manage multiple sessions
15
17
  - Cancel my account
@@ -55,11 +57,11 @@ Add these lines to your `app/views/home/index.html.erb`:
55
57
  <p>Signed as <%= Current.user.email %></p>
56
58
 
57
59
  <div>
58
- <%= link_to "Change password", edit_passwords_path %>
60
+ <%= link_to "Change password", edit_password_path %>
59
61
  </div>
60
62
 
61
63
  <div>
62
- <%= link_to "Change email", edit_emails_path %>
64
+ <%= link_to "Change email", edit_email_path %>
63
65
  </div>
64
66
 
65
67
  <div>
@@ -67,7 +69,7 @@ Add these lines to your `app/views/home/index.html.erb`:
67
69
  </div>
68
70
 
69
71
  <div>
70
- <%= link_to "Cancel my account & delete my data", new_cancellations_path %>
72
+ <%= button_to "Cancel my account", registration_path, method: :delete %>
71
73
  </div>
72
74
 
73
75
  <%= button_to "Log out", Current.session, method: :delete %>
@@ -1,3 +1,3 @@
1
1
  module AuthenticationZero
2
- VERSION = "2.1.1"
2
+ VERSION = "2.2.1"
3
3
  end
@@ -81,8 +81,8 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
81
81
 
82
82
  def create_views
83
83
  if options.api
84
+ directory "erb/identity_mailer", "app/views/identity_mailer"
84
85
  directory "erb/session_mailer", "app/views/session_mailer"
85
- directory "erb/password_mailer", "app/views/password_mailer"
86
86
  else
87
87
  directory "#{template_engine}", "app/views"
88
88
  end
@@ -94,9 +94,10 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
94
94
 
95
95
  def add_routes
96
96
  unless options.skip_routes
97
+ route "resource :registration, only: :destroy"
97
98
  route "resource :password_reset, only: [:new, :edit, :create, :update]"
98
- route "resource :cancellation, only: [:new, :create]"
99
99
  route "resource :password, only: [:edit, :update]"
100
+ route "resource :email_verification, only: [:new, :edit, :create, :update]"
100
101
  route "resource :email, only: [:edit, :update]"
101
102
  route "resources :sessions, only: [:index, :show, :destroy]"
102
103
  route "post 'sign_up', to: 'registrations#create'"
@@ -0,0 +1,18 @@
1
+ class EmailVerificationsController < ApplicationController
2
+ before_action :set_<%= singular_table_name %>, only: :update
3
+
4
+ def create
5
+ IdentityMailer.with(<%= singular_table_name %>: Current.<%= singular_table_name %>).email_verify_confirmation.deliver_later
6
+ end
7
+
8
+ def update
9
+ @<%= singular_table_name %>.update! verified: true
10
+ end
11
+
12
+ private
13
+ def set_<%= singular_table_name %>
14
+ @<%= singular_table_name %> = <%= class_name %>.find_signed!(params[:token], purpose: "verify_#{params[:email]}")
15
+ rescue ActiveSupport::MessageVerifier::InvalidSignature
16
+ render json: { error: "That email verification link is invalid" }, status: :bad_request
17
+ end
18
+ end
@@ -1,13 +1,13 @@
1
1
  class PasswordResetsController < ApplicationController
2
- skip_before_action :authenticate
3
-
4
2
  before_action :set_<%= singular_table_name %>, only: :update
5
3
 
4
+ skip_before_action :authenticate
5
+
6
6
  def create
7
- if @<%= singular_table_name %> = <%= class_name %>.find_by_email(params[:email])
8
- PasswordMailer.with(<%= singular_table_name %>: @<%= singular_table_name %>).reset.deliver_later
7
+ if @<%= singular_table_name %> = <%= class_name %>.find_by(email: params[:email], verified: true)
8
+ IdentityMailer.with(<%= singular_table_name %>: @<%= singular_table_name %>).password_reset_provision.deliver_later
9
9
  else
10
- render json: { error: "Sorry, we didn't recognize that email address" }, status: :not_found
10
+ render json: { error: "You can't reset your password until you verify your email" }, status: :not_found
11
11
  end
12
12
  end
13
13
 
@@ -23,7 +23,7 @@ class PasswordResetsController < ApplicationController
23
23
  def set_<%= singular_table_name %>
24
24
  @<%= singular_table_name %> = <%= class_name %>.find_signed!(params[:token], purpose: :password_reset)
25
25
  rescue ActiveSupport::MessageVerifier::InvalidSignature
26
- render json: { error: "Your token has expired, please request a new one" }, status: :bad_request
26
+ render json: { error: "That password reset link is invalid" }, status: :bad_request
27
27
  end
28
28
 
29
29
  def <%= "#{singular_table_name}_params" %>
@@ -1,5 +1,5 @@
1
1
  class RegistrationsController < ApplicationController
2
- skip_before_action :authenticate
2
+ skip_before_action :authenticate, only: :create
3
3
 
4
4
  def create
5
5
  @<%= singular_table_name %> = <%= class_name %>.new(<%= "#{singular_table_name}_params" %>)
@@ -11,6 +11,10 @@ class RegistrationsController < ApplicationController
11
11
  end
12
12
  end
13
13
 
14
+ def destroy
15
+ Current.<%= singular_table_name %>.destroy
16
+ end
17
+
14
18
  private
15
19
  def <%= "#{singular_table_name}_params" %>
16
20
  params.permit(:email, :password, :password_confirmation)
@@ -1,8 +1,8 @@
1
1
  class SessionsController < ApplicationController
2
- skip_before_action :authenticate, only: :create
3
-
4
2
  before_action :set_session, only: %i[ show destroy ]
5
3
 
4
+ skip_before_action :authenticate, only: :create
5
+
6
6
  def index
7
7
  render json: Current.<%= singular_table_name %>.sessions.order(created_at: :desc)
8
8
  end
@@ -0,0 +1,20 @@
1
+ class EmailVerificationsController < ApplicationController
2
+ before_action :set_<%= singular_table_name %>, only: :edit
3
+
4
+ def edit
5
+ @<%= singular_table_name %>.update! verified: true
6
+ redirect_to root_path, notice: "Thank you for verifying your email address"
7
+ end
8
+
9
+ def create
10
+ IdentityMailer.with(<%= singular_table_name %>: Current.<%= singular_table_name %>).email_verify_confirmation.deliver_later
11
+ redirect_to root_path, notice: "We sent a verification email to your email address"
12
+ end
13
+
14
+ private
15
+ def set_<%= singular_table_name %>
16
+ @<%= singular_table_name %> = <%= class_name %>.find_signed!(params[:token], purpose: "verify_#{params[:email]}")
17
+ rescue ActiveSupport::MessageVerifier::InvalidSignature
18
+ redirect_to edit_email_path, alert: "That email verification link is invalid"
19
+ end
20
+ end
@@ -1,8 +1,8 @@
1
1
  class PasswordResetsController < ApplicationController
2
- skip_before_action :authenticate
3
-
4
2
  before_action :set_<%= singular_table_name %>, only: %i[ edit update ]
5
3
 
4
+ skip_before_action :authenticate
5
+
6
6
  def new
7
7
  end
8
8
 
@@ -10,11 +10,11 @@ class PasswordResetsController < ApplicationController
10
10
  end
11
11
 
12
12
  def create
13
- if @<%= singular_table_name %> = <%= class_name %>.find_by_email(params[:email])
14
- PasswordMailer.with(<%= singular_table_name %>: @<%= singular_table_name %>).reset.deliver_later
13
+ if @<%= singular_table_name %> = <%= class_name %>.find_by(email: params[:email], verified: true)
14
+ IdentityMailer.with(<%= singular_table_name %>: @<%= singular_table_name %>).password_reset_provision.deliver_later
15
15
  redirect_to sign_in_path, notice: "Check your email for reset instructions"
16
16
  else
17
- redirect_to new_password_reset_path, alert: "Sorry, we didn't recognize that email address"
17
+ redirect_to new_password_reset_path, alert: "You can't reset your password until you verify your email"
18
18
  end
19
19
  end
20
20
 
@@ -30,7 +30,7 @@ class PasswordResetsController < ApplicationController
30
30
  def set_<%= singular_table_name %>
31
31
  @<%= singular_table_name %> = <%= class_name %>.find_signed!(params[:token], purpose: :password_reset)
32
32
  rescue ActiveSupport::MessageVerifier::InvalidSignature
33
- redirect_to new_password_reset_path, alert: "Your token has expired, please request a new one"
33
+ redirect_to new_password_reset_path, alert: "That password reset link is invalid"
34
34
  end
35
35
 
36
36
  def <%= "#{singular_table_name}_params" %>
@@ -1,5 +1,5 @@
1
1
  class RegistrationsController < ApplicationController
2
- skip_before_action :authenticate
2
+ skip_before_action :authenticate, only: %i[ new create ]
3
3
 
4
4
  def new
5
5
  @<%= singular_table_name %> = <%= class_name %>.new
@@ -15,6 +15,11 @@ class RegistrationsController < ApplicationController
15
15
  end
16
16
  end
17
17
 
18
+ def destroy
19
+ Current.<%= singular_table_name %>.destroy
20
+ redirect_to sign_in_path, notice: "Your account is closed"
21
+ end
22
+
18
23
  private
19
24
  def <%= "#{singular_table_name}_params" %>
20
25
  params.require(:<%= singular_table_name %>).permit(:email, :password, :password_confirmation)
@@ -1,8 +1,8 @@
1
1
  class SessionsController < ApplicationController
2
- skip_before_action :authenticate, only: %i[ new create ]
3
-
4
2
  before_action :set_session, only: :destroy
5
3
 
4
+ skip_before_action :authenticate, only: %i[ new create ]
5
+
6
6
  def index
7
7
  @sessions = Current.<%= singular_table_name %>.sessions.order(created_at: :desc)
8
8
  end
@@ -1,6 +1,12 @@
1
1
  <p style="color: red"><%%= alert %></p>
2
2
 
3
- <h1>Change your email</h1>
3
+ <%% if Current.<%= singular_table_name %>.verified? %>
4
+ <h1>Change your email</h1>
5
+ <%% else %>
6
+ <h1>Verify your email </h1>
7
+ <p>We sent a verification email to the address below. Check that email and follow those instructions to confirm it's your email address.</p>
8
+ <p><%%= button_to "Re-send verification email", email_verification_path %></p>
9
+ <%% end %>
4
10
 
5
11
  <%%= form_with(model: @<%= model_resource_name %>, url: email_path) do |form| %>
6
12
  <%% if @<%= singular_table_name %>.errors.any? %>
@@ -0,0 +1,11 @@
1
+ <p>Hey there,</p>
2
+
3
+ <p>This is to confirm that <%%= @<%= singular_table_name %>.email %> is the email you want to use on your account. If you ever lose your password, that's where we'll email a reset link.</p>
4
+
5
+ <p><strong>You must hit the link below to confirm that you received this email.</strong></p>
6
+
7
+ <%%= link_to "Yes, use this email for my account", edit_email_verification_url(token: @signed_id, email: @<%= singular_table_name %>.email) %>
8
+
9
+ <hr>
10
+
11
+ <p>Have questions or need help? Just reply to this email and our support team will help you sort it out.</p>
@@ -0,0 +1,9 @@
1
+ Hey there,
2
+
3
+ This is to confirm that <%%= @<%= singular_table_name %>.email %> is the email you want to use on your account. If you ever lose your password, that's where we'll email a reset link.
4
+
5
+ You must hit the link below to confirm that you received this email.
6
+
7
+ [Yes, use this email for my account]<%%= edit_email_verification_url(token: @signed_id, email: @<%= singular_table_name %>.email) %>
8
+
9
+ Have questions or need help? Just reply to this email and our support team will help you sort it out.
@@ -1,6 +1,6 @@
1
1
  <p>Hey there,</p>
2
2
 
3
- <p>Can't remember your password for <strong><%%= params[:<%= singular_table_name %>].email %></strong>? That's OK, it happens. Just hit the link below to set a new one.</p>
3
+ <p>Can't remember your password for <strong><%%= @session.<%= singular_table_name %>.email %></strong>? That's OK, it happens. Just hit the link below to set a new one.</p>
4
4
 
5
5
  <p><%%= link_to "Reset my password", edit_password_reset_url(token: @signed_id) %></p>
6
6
 
@@ -1,6 +1,6 @@
1
1
  Hey there,
2
2
 
3
- Can't remember your password for <%%= params[:<%= singular_table_name %>].email %>? That's OK, it happens. Just hit the link below to set a new one.
3
+ Can't remember your password for <%%= @session.<%= singular_table_name %>.email %>? That's OK, it happens. Just hit the link below to set a new one.
4
4
 
5
5
  [Reset my password]<%%= edit_password_reset_url(token: @signed_id) %>
6
6
 
@@ -10,7 +10,7 @@
10
10
  IP address: <%%= @session.ip_address %>
11
11
  </p>
12
12
 
13
- <p><strong>If this was you, carry on.</strong> We won't notify you about sign-ins from this device again.</p>
13
+ <p><strong>If this was you, carry on.</strong> We could notify you about sign-ins from this device again.</p>
14
14
 
15
15
  <p><strong>If you don't recognize this device</strong>, someone else may have accessed your account. You should immediately <%%= link_to "change your password", new_password_reset_url %>.</p>
16
16
 
@@ -8,7 +8,7 @@ A new device just signed in to your account (<%%= @session.<%= singular_table_na
8
8
 
9
9
  <%%= @session.ip_address %>
10
10
 
11
- If this was you, carry on. We won't notify you about sign-ins from this device again.
11
+ If this was you, carry on. We could notify you about sign-ins from this device again.
12
12
 
13
13
  If you don't recognize this device, someone else may have accessed your account. You should immediately [change your password]<%%= new_password_reset_url %>.
14
14
 
@@ -0,0 +1,15 @@
1
+ class IdentityMailer < ApplicationMailer
2
+ def password_reset_provision
3
+ @<%= singular_table_name %> = params[:<%= singular_table_name %>]
4
+ @signed_id = params[:<%= singular_table_name %>].signed_id(purpose: :password_reset, expires_in: 20.minutes)
5
+
6
+ mail to: @<%= singular_table_name %>.email, subject: "Reset your password"
7
+ end
8
+
9
+ def email_verify_confirmation
10
+ @<%= singular_table_name %> = params[:<%= singular_table_name %>]
11
+ @signed_id = params[:<%= singular_table_name %>].signed_id(purpose: "verify_#{@<%= singular_table_name %>.email}", expires_in: 20.minutes)
12
+
13
+ mail to: @<%= singular_table_name %>.email, subject: "Verify your email"
14
+ end
15
+ end
@@ -1,5 +1,5 @@
1
1
  class SessionMailer < ApplicationMailer
2
- def signed_in
2
+ def signed_in_notification
3
3
  @session = params[:session]
4
4
  mail to: @session.<%= singular_table_name %>.email, subject: "New sign-in to your account"
5
5
  end
@@ -2,6 +2,7 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
2
2
  def change
3
3
  create_table :sessions do |t|
4
4
  t.references :<%= singular_table_name %>, null: false, foreign_key: true
5
+
5
6
  t.string :user_agent
6
7
  t.string :ip_address
7
8
 
@@ -4,6 +4,8 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
4
4
  t.string :email, null: false
5
5
  t.string :password_digest, null: false
6
6
 
7
+ t.boolean :verified, default: false
8
+
7
9
  t.timestamps
8
10
  end
9
11
 
@@ -2,6 +2,6 @@ class Current < ActiveSupport::CurrentAttributes
2
2
  attribute :session, :<%= singular_table_name %>
3
3
 
4
4
  def session=(session)
5
- super; Current.<%= singular_table_name %> = session.<%= singular_table_name %>
5
+ super; self.<%= singular_table_name %> = session.<%= singular_table_name %>
6
6
  end
7
7
  end
@@ -10,4 +10,16 @@ class <%= class_name %> < ApplicationRecord
10
10
  before_validation do
11
11
  self.email = email.downcase.strip
12
12
  end
13
+
14
+ after_create_commit do
15
+ IdentityMailer.with(<%= singular_table_name %>: self).email_verify_confirmation.deliver_later
16
+ end
17
+
18
+ after_update_commit if: :email_previously_changed? do
19
+ update_columns verified: false
20
+ end
21
+
22
+ after_update_commit if: :email_previously_changed? do
23
+ IdentityMailer.with(<%= singular_table_name %>: self).email_verify_confirmation.deliver_later
24
+ end
13
25
  end
@@ -2,6 +2,6 @@ class Session < ApplicationRecord
2
2
  belongs_to :<%= singular_table_name %>
3
3
 
4
4
  after_create_commit do
5
- SessionMailer.with(session: self).signed_in.deliver_later
5
+ SessionMailer.with(session: self).signed_in_notification.deliver_later
6
6
  end
7
7
  end
@@ -0,0 +1,36 @@
1
+ require "test_helper"
2
+
3
+ class EmailVerificationsControllerTest < ActionDispatch::IntegrationTest
4
+ setup do
5
+ @<%= singular_table_name %>, @token = sign_in_as(<%= table_name %>(:lazaro_nixon))
6
+ @sid = @<%= singular_table_name %>.signed_id(purpose: "verify_#{@<%= singular_table_name %>.email}", expires_in: 20.minutes)
7
+ @sid_exp = @<%= singular_table_name %>.signed_id(purpose: "verify_#{@<%= singular_table_name %>.email}", expires_in: 0.minutes)
8
+
9
+ @<%= singular_table_name %>.update! verified: false
10
+ end
11
+
12
+ test "should send a verification email" do
13
+ assert_enqueued_email_with IdentityMailer, :email_verify_confirmation, args: { <%= singular_table_name %>: @<%= singular_table_name %> } do
14
+ post email_verification_url, headers: { "Authorization" => "Bearer #{@token}" }
15
+ end
16
+
17
+ assert_response :no_content
18
+ end
19
+
20
+ test "should verify email" do
21
+ patch email_verification_url, params: { token: @sid, email: @<%= singular_table_name %>.email }, headers: { "Authorization" => "Bearer #{@token}" }
22
+ assert_response :no_content
23
+ end
24
+
25
+ test "should not verify email with expired token" do
26
+ patch email_verification_url, params: { token: @sid_exp, email: @<%= singular_table_name %>.email }, headers: { "Authorization" => "Bearer #{@token}" }
27
+
28
+ assert_response :bad_request
29
+ assert_equal "That email verification link is invalid", response.parsed_body["error"]
30
+ end
31
+
32
+ def sign_in_as(<%= singular_table_name %>)
33
+ post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "secret123" })
34
+ [<%= singular_table_name %>, response.headers["X-Session-Token"]]
35
+ end
36
+ end
@@ -8,7 +8,7 @@ class PasswordResetsControllerTest < ActionDispatch::IntegrationTest
8
8
  end
9
9
 
10
10
  test "should send a password reset email" do
11
- assert_enqueued_email_with PasswordMailer, :reset, args: { <%= singular_table_name %>: @<%= singular_table_name %> } do
11
+ assert_enqueued_email_with IdentityMailer, :password_reset_provision, args: { <%= singular_table_name %>: @<%= singular_table_name %> } do
12
12
  post password_reset_url, params: { email: @<%= singular_table_name %>.email }
13
13
  end
14
14
 
@@ -21,7 +21,18 @@ class PasswordResetsControllerTest < ActionDispatch::IntegrationTest
21
21
  end
22
22
 
23
23
  assert_response :not_found
24
- assert_equal "Sorry, we didn't recognize that email address", response.parsed_body["error"]
24
+ assert_equal "You can't reset your password until you verify your email", response.parsed_body["error"]
25
+ end
26
+
27
+ test "should not send a password reset email to a unverified email" do
28
+ @<%= singular_table_name %>.update!(verified: false)
29
+
30
+ assert_no_enqueued_emails do
31
+ post password_reset_url, params: { email: @<%= singular_table_name %>.email }
32
+ end
33
+
34
+ assert_response :not_found
35
+ assert_equal "You can't reset your password until you verify your email", response.parsed_body["error"]
25
36
  end
26
37
 
27
38
  test "should update password" do
@@ -33,6 +44,6 @@ class PasswordResetsControllerTest < ActionDispatch::IntegrationTest
33
44
  patch password_reset_url, params: { token: @sid_exp, password: "new_password", password_confirmation: "new_password" }
34
45
 
35
46
  assert_response :bad_request
36
- assert_equal "Your token has expired, please request a new one", response.parsed_body["error"]
47
+ assert_equal "That password reset link is invalid", response.parsed_body["error"]
37
48
  end
38
49
  end
@@ -8,4 +8,19 @@ class RegistrationsControllerTest < ActionDispatch::IntegrationTest
8
8
 
9
9
  assert_response :created
10
10
  end
11
+
12
+ test "should destroy account" do
13
+ @<%= singular_table_name %>, @token = sign_in_as(<%= table_name %>(:lazaro_nixon))
14
+
15
+ assert_difference("<%= class_name %>.count", -1) do
16
+ delete registration_url, headers: { "Authorization" => "Bearer #{@token}" }
17
+ end
18
+
19
+ assert_response :no_content
20
+ end
21
+
22
+ def sign_in_as(<%= singular_table_name %>)
23
+ post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "secret123" })
24
+ [<%= singular_table_name %>, response.headers["X-Session-Token"]]
25
+ end
11
26
  end
@@ -18,7 +18,7 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest
18
18
  test "should sign in" do
19
19
  post sign_in_url, params: { email: @<%= singular_table_name %>.email, password: "secret123" }
20
20
 
21
- assert_enqueued_email_with SessionMailer, :signed_in, args: { session: @<%= singular_table_name %>.sessions.last }
21
+ assert_enqueued_email_with SessionMailer, :signed_in_notification, args: { session: @<%= singular_table_name %>.sessions.last }
22
22
  assert_response :created
23
23
  end
24
24
 
@@ -0,0 +1,35 @@
1
+ require "test_helper"
2
+
3
+ class EmailVerificationsControllerTest < ActionDispatch::IntegrationTest
4
+ setup do
5
+ @<%= singular_table_name %> = sign_in_as(<%= table_name %>(:lazaro_nixon))
6
+ @sid = @<%= singular_table_name %>.signed_id(purpose: "verify_#{@<%= singular_table_name %>.email}", expires_in: 20.minutes)
7
+ @sid_exp = @<%= singular_table_name %>.signed_id(purpose: "verify_#{@<%= singular_table_name %>.email}", expires_in: 0.minutes)
8
+
9
+ @<%= singular_table_name %>.update! verified: false
10
+ end
11
+
12
+ test "should send a verification email" do
13
+ assert_enqueued_email_with IdentityMailer, :email_verify_confirmation, args: { <%= singular_table_name %>: @<%= singular_table_name %> } do
14
+ post email_verification_url
15
+ end
16
+
17
+ assert_redirected_to root_path
18
+ end
19
+
20
+ test "should verify email" do
21
+ get edit_email_verification_url(token: @sid, email: @<%= singular_table_name %>.email)
22
+ assert_redirected_to root_path
23
+ end
24
+
25
+ test "should not verify email with expired token" do
26
+ get edit_email_verification_url(token: @sid_exp, email: @<%= singular_table_name %>.email)
27
+
28
+ assert_redirected_to edit_email_path
29
+ assert_equal "That email verification link is invalid", flash[:alert]
30
+ end
31
+
32
+ def sign_in_as(<%= singular_table_name %>)
33
+ post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "secret123" }); <%= singular_table_name %>
34
+ end
35
+ end
@@ -18,7 +18,7 @@ class PasswordResetsControllerTest < ActionDispatch::IntegrationTest
18
18
  end
19
19
 
20
20
  test "should send a password reset email" do
21
- assert_enqueued_email_with PasswordMailer, :reset, args: { <%= singular_table_name %>: @<%= singular_table_name %> } do
21
+ assert_enqueued_email_with IdentityMailer, :password_reset_provision, args: { <%= singular_table_name %>: @<%= singular_table_name %> } do
22
22
  post password_reset_url, params: { email: @<%= singular_table_name %>.email }
23
23
  end
24
24
 
@@ -31,7 +31,18 @@ class PasswordResetsControllerTest < ActionDispatch::IntegrationTest
31
31
  end
32
32
 
33
33
  assert_redirected_to new_password_reset_url
34
- assert_equal "Sorry, we didn't recognize that email address", flash[:alert]
34
+ assert_equal "You can't reset your password until you verify your email", flash[:alert]
35
+ end
36
+
37
+ test "should not send a password reset email to a unverified email" do
38
+ @<%= singular_table_name %>.update!(verified: false)
39
+
40
+ assert_no_enqueued_emails do
41
+ post password_reset_url, params: { email: @<%= singular_table_name %>.email }
42
+ end
43
+
44
+ assert_redirected_to new_password_reset_url
45
+ assert_equal "You can't reset your password until you verify your email", flash[:alert]
35
46
  end
36
47
 
37
48
  test "should update password" do
@@ -43,6 +54,6 @@ class PasswordResetsControllerTest < ActionDispatch::IntegrationTest
43
54
  patch password_reset_url, params: { token: @sid_exp, password: "new_password", password_confirmation: "new_password" }
44
55
 
45
56
  assert_redirected_to new_password_reset_path
46
- assert_equal "Your token has expired, please request a new one", flash[:alert]
57
+ assert_equal "That password reset link is invalid", flash[:alert]
47
58
  end
48
59
  end
@@ -13,4 +13,18 @@ class RegistrationsControllerTest < ActionDispatch::IntegrationTest
13
13
 
14
14
  assert_redirected_to sign_in_url
15
15
  end
16
+
17
+ test "should destroy account" do
18
+ sign_in_as <%= table_name %>(:lazaro_nixon)
19
+
20
+ assert_difference("<%= class_name %>.count", -1) do
21
+ delete registration_path
22
+ end
23
+
24
+ assert_redirected_to sign_in_url
25
+ end
26
+
27
+ def sign_in_as(<%= singular_table_name %>)
28
+ post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "secret123" }); <%= singular_table_name %>
29
+ end
16
30
  end
@@ -19,7 +19,7 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest
19
19
 
20
20
  test "should sign in" do
21
21
  post sign_in_url, params: { email: @<%= singular_table_name %>.email, password: "secret123" }
22
- assert_enqueued_email_with SessionMailer, :signed_in, args: { session: @<%= singular_table_name %>.sessions.last }
22
+ assert_enqueued_email_with SessionMailer, :signed_in_notification, args: { session: @<%= singular_table_name %>.sessions.last }
23
23
 
24
24
  assert_redirected_to root_url
25
25
 
@@ -3,3 +3,4 @@
3
3
  lazaro_nixon:
4
4
  email: lazaronixon@hotmail.com
5
5
  password_digest: <%%= BCrypt::Password.create("secret123") %>
6
+ verified: true
@@ -15,6 +15,15 @@ class EmailsTest < ApplicationSystemTestCase
15
15
  assert_text "Your email has been changed"
16
16
  end
17
17
 
18
+ test "sending a verification email" do
19
+ @<%= singular_table_name %>.update! verified: false
20
+
21
+ click_on "Change email"
22
+ click_on "Re-send verification email"
23
+
24
+ assert_text "We sent a verification email to your email address"
25
+ end
26
+
18
27
  def sign_in_as(<%= singular_table_name %>)
19
28
  visit sign_in_url
20
29
  fill_in :email, with: <%= singular_table_name %>.email
@@ -1,6 +1,10 @@
1
1
  require "application_system_test_case"
2
2
 
3
3
  class RegistrationsTest < ApplicationSystemTestCase
4
+ setup do
5
+ @<%= singular_table_name %> = <%= table_name %>(:lazaro_nixon)
6
+ end
7
+
4
8
  test "signing up" do
5
9
  visit sign_in_url
6
10
  click_on "Sign up"
@@ -12,4 +16,20 @@ class RegistrationsTest < ApplicationSystemTestCase
12
16
 
13
17
  assert_text "Welcome! You have signed up successfully"
14
18
  end
19
+
20
+ test "cancelling my account" do
21
+ sign_in_as @<%= singular_table_name %>
22
+ click_on "Cancel my account"
23
+
24
+ assert_text "Your account is closed"
25
+ end
26
+
27
+ def sign_in_as(<%= singular_table_name %>)
28
+ visit sign_in_url
29
+ fill_in :email, with: <%= singular_table_name %>.email
30
+ fill_in :password, with: "secret123"
31
+ click_on "Sign in"
32
+
33
+ return <%= singular_table_name %>
34
+ end
15
35
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: authentication-zero
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nixon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-23 00:00:00.000000000 Z
11
+ date: 2022-02-24 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -31,44 +31,45 @@ files:
31
31
  - lib/authentication_zero/version.rb
32
32
  - lib/generators/authentication/USAGE
33
33
  - lib/generators/authentication/authentication_generator.rb
34
- - lib/generators/authentication/templates/controllers/api/cancellations_controller.rb.tt
34
+ - lib/generators/authentication/templates/controllers/api/email_verifications_controller.rb.tt
35
35
  - lib/generators/authentication/templates/controllers/api/emails_controller.rb.tt
36
36
  - lib/generators/authentication/templates/controllers/api/password_resets_controller.rb.tt
37
37
  - lib/generators/authentication/templates/controllers/api/passwords_controller.rb.tt
38
38
  - lib/generators/authentication/templates/controllers/api/registrations_controller.rb.tt
39
39
  - lib/generators/authentication/templates/controllers/api/sessions_controller.rb.tt
40
- - lib/generators/authentication/templates/controllers/html/cancellations_controller.rb.tt
40
+ - lib/generators/authentication/templates/controllers/html/email_verifications_controller.rb.tt
41
41
  - lib/generators/authentication/templates/controllers/html/emails_controller.rb.tt
42
42
  - lib/generators/authentication/templates/controllers/html/password_resets_controller.rb.tt
43
43
  - lib/generators/authentication/templates/controllers/html/passwords_controller.rb.tt
44
44
  - lib/generators/authentication/templates/controllers/html/registrations_controller.rb.tt
45
45
  - lib/generators/authentication/templates/controllers/html/sessions_controller.rb.tt
46
- - lib/generators/authentication/templates/erb/cancellations/new.html.erb.tt
47
46
  - lib/generators/authentication/templates/erb/emails/edit.html.erb.tt
48
- - lib/generators/authentication/templates/erb/password_mailer/reset.html.erb.tt
49
- - lib/generators/authentication/templates/erb/password_mailer/reset.text.erb.tt
47
+ - lib/generators/authentication/templates/erb/identity_mailer/email_verify_confirmation.html.erb.tt
48
+ - lib/generators/authentication/templates/erb/identity_mailer/email_verify_confirmation.text.erb.tt
49
+ - lib/generators/authentication/templates/erb/identity_mailer/password_reset_provision.html.erb.tt
50
+ - lib/generators/authentication/templates/erb/identity_mailer/password_reset_provision.text.erb.tt
50
51
  - lib/generators/authentication/templates/erb/password_resets/edit.html.erb.tt
51
52
  - lib/generators/authentication/templates/erb/password_resets/new.html.erb.tt
52
53
  - lib/generators/authentication/templates/erb/passwords/edit.html.erb.tt
53
54
  - lib/generators/authentication/templates/erb/registrations/new.html.erb.tt
54
- - lib/generators/authentication/templates/erb/session_mailer/signed_in.html.erb.tt
55
- - lib/generators/authentication/templates/erb/session_mailer/signed_in.text.erb.tt
55
+ - lib/generators/authentication/templates/erb/session_mailer/signed_in_notification.html.erb.tt
56
+ - lib/generators/authentication/templates/erb/session_mailer/signed_in_notification.text.erb.tt
56
57
  - lib/generators/authentication/templates/erb/sessions/index.html.erb.tt
57
58
  - lib/generators/authentication/templates/erb/sessions/new.html.erb.tt
58
- - lib/generators/authentication/templates/mailers/password_mailer.rb.tt
59
+ - lib/generators/authentication/templates/mailers/identity_mailer.rb.tt
59
60
  - lib/generators/authentication/templates/mailers/session_mailer.rb.tt
60
61
  - lib/generators/authentication/templates/migrations/create_sessions_migration.rb.tt
61
62
  - lib/generators/authentication/templates/migrations/create_table_migration.rb.tt
62
63
  - lib/generators/authentication/templates/models/current.rb.tt
63
64
  - lib/generators/authentication/templates/models/model.rb.tt
64
65
  - lib/generators/authentication/templates/models/session.rb.tt
65
- - lib/generators/authentication/templates/test_unit/controllers/api/cancellations_controller_test.rb.tt
66
+ - lib/generators/authentication/templates/test_unit/controllers/api/email_verifications_controller_test.rb.tt
66
67
  - lib/generators/authentication/templates/test_unit/controllers/api/emails_controller_test.rb.tt
67
68
  - lib/generators/authentication/templates/test_unit/controllers/api/password_resets_controller_test.rb.tt
68
69
  - lib/generators/authentication/templates/test_unit/controllers/api/passwords_controller_test.rb.tt
69
70
  - lib/generators/authentication/templates/test_unit/controllers/api/registrations_controller_test.rb.tt
70
71
  - lib/generators/authentication/templates/test_unit/controllers/api/sessions_controller_test.rb.tt
71
- - lib/generators/authentication/templates/test_unit/controllers/html/cancellations_controller_test.rb.tt
72
+ - lib/generators/authentication/templates/test_unit/controllers/html/email_verifications_controller_test.rb.tt
72
73
  - lib/generators/authentication/templates/test_unit/controllers/html/emails_controller_test.rb.tt
73
74
  - lib/generators/authentication/templates/test_unit/controllers/html/password_resets_controller_test.rb.tt
74
75
  - lib/generators/authentication/templates/test_unit/controllers/html/passwords_controller_test.rb.tt
@@ -76,7 +77,6 @@ files:
76
77
  - lib/generators/authentication/templates/test_unit/controllers/html/sessions_controller_test.rb.tt
77
78
  - lib/generators/authentication/templates/test_unit/fixtures.yml.tt
78
79
  - lib/generators/authentication/templates/test_unit/sessions.yml.tt
79
- - lib/generators/authentication/templates/test_unit/system/cancellations_test.rb.tt
80
80
  - lib/generators/authentication/templates/test_unit/system/emails_test.rb.tt
81
81
  - lib/generators/authentication/templates/test_unit/system/password_resets_test.rb.tt
82
82
  - lib/generators/authentication/templates/test_unit/system/passwords_test.rb.tt
@@ -1,5 +0,0 @@
1
- class CancellationsController < ApplicationController
2
- def create
3
- Current.<%= singular_table_name %>.destroy
4
- end
5
- end
@@ -1,9 +0,0 @@
1
- class CancellationsController < ApplicationController
2
- def new
3
- end
4
-
5
- def create
6
- Current.<%= singular_table_name %>.destroy
7
- redirect_to sign_in_path, notice: "Your account is closed"
8
- end
9
- end
@@ -1,11 +0,0 @@
1
- <h1>Want to close your account?</h1>
2
-
3
- <p>Your account will be immediately closed. You won't be able to sign in anymore.</p>
4
- <p>Your data will be permanently deleted from our servers.</p>
5
- <p><%%= link_to "Back", root_path %></p>
6
-
7
- <br>
8
-
9
- <div>
10
- <%%= button_to "OK, close my account", cancellation_path %>
11
- </div>
@@ -1,6 +0,0 @@
1
- class PasswordMailer < ApplicationMailer
2
- def reset
3
- @signed_id = params[:<%= singular_table_name %>].signed_id(purpose: :password_reset, expires_in: 20.minutes)
4
- mail to: params[:<%= singular_table_name %>].email, subject: "Reset your password"
5
- end
6
- end
@@ -1,20 +0,0 @@
1
- require "test_helper"
2
-
3
- class CancellationsControllerTest < ActionDispatch::IntegrationTest
4
- setup do
5
- @<%= singular_table_name %>, @token = sign_in_as(<%= table_name %>(:lazaro_nixon))
6
- end
7
-
8
- test "should create cancellation" do
9
- assert_difference("<%= class_name %>.count", -1) do
10
- post cancellation_url, headers: { "Authorization" => "Bearer #{@token}" }
11
- end
12
-
13
- assert_response :no_content
14
- end
15
-
16
- def sign_in_as(<%= singular_table_name %>)
17
- post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "secret123" })
18
- [<%= singular_table_name %>, response.headers["X-Session-Token"]]
19
- end
20
- end
@@ -1,24 +0,0 @@
1
- require "test_helper"
2
-
3
- class CancellationsControllerTest < ActionDispatch::IntegrationTest
4
- setup do
5
- @<%= singular_table_name %> = sign_in_as(<%= table_name %>(:lazaro_nixon))
6
- end
7
-
8
- test "should get new" do
9
- get new_cancellation_url
10
- assert_response :success
11
- end
12
-
13
- test "should create cancellation" do
14
- assert_difference("<%= class_name %>.count", -1) do
15
- post cancellation_url
16
- end
17
-
18
- assert_redirected_to sign_in_url
19
- end
20
-
21
- def sign_in_as(<%= singular_table_name %>)
22
- post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "secret123" }); <%= singular_table_name %>
23
- end
24
- end
@@ -1,23 +0,0 @@
1
- require "application_system_test_case"
2
-
3
- class CancellationsTest < ApplicationSystemTestCase
4
- setup do
5
- @<%= singular_table_name %> = sign_in_as(<%= table_name %>(:lazaro_nixon))
6
- end
7
-
8
- test "cancelling my account" do
9
- click_on "Cancel my account & delete my data"
10
- click_on "OK, close my account"
11
-
12
- assert_text "Your account is closed"
13
- end
14
-
15
- def sign_in_as(<%= singular_table_name %>)
16
- visit sign_in_url
17
- fill_in :email, with: <%= singular_table_name %>.email
18
- fill_in :password, with: "secret123"
19
- click_on "Sign in"
20
-
21
- return <%= singular_table_name %>
22
- end
23
- end