avocado 0.6.0 → 0.7.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +56 -17
- data/Rakefile +0 -2
- data/app/controllers/avocado/affirmations_controller.rb +12 -8
- data/app/controllers/avocado/base_controller.rb +15 -6
- data/app/controllers/avocado/credentials_controller.rb +41 -0
- data/app/controllers/avocado/emails_controller.rb +5 -13
- data/app/controllers/avocado/events_controller.rb +3 -3
- data/app/controllers/avocado/passwords_controller.rb +4 -4
- data/app/controllers/avocado/recoveries_controller.rb +6 -35
- data/app/controllers/avocado/registrations_controller.rb +3 -10
- data/app/controllers/avocado/sessions_controller.rb +18 -10
- data/app/controllers/avocado/verifications_controller.rb +9 -13
- data/app/views/avocado/affirmations/_form.html.erb +4 -0
- data/app/views/avocado/affirmations/new.html.erb +1 -3
- data/app/views/avocado/{recoveries/edit.html.erb → credentials/_form.html.erb} +4 -13
- data/app/views/avocado/credentials/edit.html.erb +12 -0
- data/app/views/avocado/emails/_form.html.erb +8 -0
- data/app/views/avocado/emails/edit.html.erb +1 -6
- data/app/views/avocado/mailer/password_reset.text.erb +1 -1
- data/app/views/avocado/passwords/_form.html.erb +12 -0
- data/app/views/avocado/passwords/edit.html.erb +1 -9
- data/app/views/avocado/recoveries/_form.html.erb +4 -0
- data/app/views/avocado/recoveries/new.html.erb +1 -3
- data/app/views/avocado/registrations/_form.html.erb +12 -0
- data/app/views/avocado/registrations/new.html.erb +1 -12
- data/app/views/avocado/sessions/_form.html.erb +8 -0
- data/app/views/avocado/sessions/new.html.erb +1 -4
- data/config/locales/en.yml +45 -0
- data/config/routes/avocado.rb +2 -1
- data/config.ru +0 -2
- data/docs/USAGE.md +38 -29
- data/lib/avocado/authentication.rb +0 -2
- data/lib/avocado/current.rb +0 -2
- data/lib/avocado/engine.rb +1 -3
- data/lib/avocado/event.rb +0 -2
- data/lib/avocado/mailer.rb +0 -2
- data/lib/avocado/session.rb +0 -2
- data/lib/avocado/session_callbacks.rb +0 -2
- data/lib/avocado/user.rb +0 -2
- data/lib/avocado/user_callbacks.rb +0 -2
- data/lib/avocado/user_tokens.rb +0 -2
- data/lib/avocado/user_validations.rb +0 -2
- data/lib/avocado/version.rb +1 -3
- data/lib/avocado.rb +0 -2
- data/lib/generators/avocado/migrations/migrations_generator.rb +0 -2
- data/lib/generators/avocado/views/views_generator.rb +21 -0
- metadata +15 -6
- data/config/routes//360/237/245/221.rb +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e9ec8adfbc4563b5bbcddd5d5406963b4a9fe7d5a38765e35a86c9a3d35a09a0
|
4
|
+
data.tar.gz: 6db1dfa3a370661017533e44f2278a09daeece5c145267f05f0bced8943ea910
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9761662e0cf44fab571f6f6003aed2c0be2ae56424afbc1cc4b3ccb2f0d856a3e4d3b7a67c8a9e82b7d408977ebb30b4f1f61d9af0fd24db17c3fcb5c944cd89
|
7
|
+
data.tar.gz: a8021001d0f4864a36c981b2c5d18b71bca432f4f4b6fcde4ff6f07c38e7fc39f766dd39670041582cacb9a80526423eafd8156b5d8fc0580189679a1b67d144
|
data/CHANGELOG.md
CHANGED
@@ -1,39 +1,78 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
1
3
|
## [Unreleased]
|
2
4
|
|
5
|
+
## [0.7.0] - 2023-08-10
|
6
|
+
|
7
|
+
### Added
|
8
|
+
|
9
|
+
- An `avocado:views` generator copies engine views into application
|
10
|
+
|
11
|
+
### Changed
|
12
|
+
|
13
|
+
- Flash messages for controllers moved to i18n yml
|
14
|
+
- View forms updated to use `_form` partials
|
15
|
+
- Move the reset phase of password recovery to a `Credentials` controller
|
16
|
+
|
3
17
|
## [0.6.0] - 2023-07-25
|
4
18
|
|
5
|
-
|
6
|
-
|
7
|
-
-
|
19
|
+
### Added
|
20
|
+
|
21
|
+
- Migration generator
|
22
|
+
|
23
|
+
### Changed
|
24
|
+
|
25
|
+
- Affirmation and Verification paths require user action
|
26
|
+
- Use session `token` instead of `id` for signed cookie value
|
8
27
|
|
9
28
|
## [0.5.0] - 2023-07-21
|
10
29
|
|
11
|
-
|
12
|
-
|
13
|
-
-
|
14
|
-
-
|
15
|
-
-
|
30
|
+
### Added
|
31
|
+
|
32
|
+
- Controller for "passwordless" email-link sign-in
|
33
|
+
- `Event` class to log user auth events
|
34
|
+
- User-facing email and password edit pages
|
35
|
+
- Misc event logging callbacks
|
36
|
+
|
37
|
+
### Changed
|
38
|
+
|
39
|
+
- Sign out all non-current sessions when password changes
|
16
40
|
|
17
41
|
## [0.4.0] - 2023-07-19
|
18
42
|
|
43
|
+
### Added
|
44
|
+
|
45
|
+
- Controllers for signing up, signing in, password reset and email verification
|
46
|
+
|
47
|
+
### Changed
|
48
|
+
|
19
49
|
- Convert the `Avocado::Mailer` module into a class
|
20
|
-
- Add controllers for signing up, signing in, password reset and email
|
21
|
-
verification
|
22
50
|
|
23
51
|
## [0.3.0] - 2023-07-17
|
24
52
|
|
25
|
-
|
53
|
+
### Added
|
54
|
+
|
55
|
+
- `Avocado::Mailer` which generates each of the signed ids
|
56
|
+
|
57
|
+
### Changed
|
58
|
+
|
26
59
|
- Rename `password_recovery` to `password_reset`
|
27
60
|
|
28
61
|
## [0.2.0] - 2023-07-15
|
29
62
|
|
30
|
-
|
31
|
-
|
32
|
-
-
|
33
|
-
-
|
63
|
+
### Added
|
64
|
+
|
65
|
+
- Validations for presence, uniqueness, and format on `email` attribute
|
66
|
+
- Normalizer for email value during save
|
67
|
+
- Validations on password format and length
|
68
|
+
- Token generator for password recovery
|
69
|
+
|
70
|
+
### Changed
|
71
|
+
|
34
72
|
- Rename `Avocado::UserConcern` to `Avocado::User`
|
35
73
|
|
36
74
|
## [0.1.0] - 2023-07-14
|
37
75
|
|
38
|
-
|
39
|
-
|
76
|
+
### Added
|
77
|
+
|
78
|
+
- `Avocado::UserConcern` which calls `has_secure_password`
|
data/Rakefile
CHANGED
@@ -1,18 +1,19 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module Avocado
|
4
2
|
class AffirmationsController < BaseController
|
5
3
|
skip_before_action :authenticate
|
6
4
|
|
7
|
-
before_action :set_user,
|
8
|
-
|
5
|
+
before_action :set_user,
|
6
|
+
only: %i[edit update]
|
7
|
+
before_action :verify_user,
|
8
|
+
only: :create
|
9
9
|
|
10
10
|
def new
|
11
11
|
end
|
12
12
|
|
13
13
|
def create
|
14
14
|
send_affirmation_email
|
15
|
-
redirect_to new_session_path,
|
15
|
+
redirect_to new_session_path,
|
16
|
+
notice: t(".success")
|
16
17
|
end
|
17
18
|
|
18
19
|
def edit
|
@@ -20,7 +21,8 @@ module Avocado
|
|
20
21
|
|
21
22
|
def update
|
22
23
|
sign_in(@user)
|
23
|
-
redirect_to
|
24
|
+
redirect_to root_path,
|
25
|
+
notice: t(".success")
|
24
26
|
end
|
25
27
|
|
26
28
|
private
|
@@ -28,7 +30,8 @@ module Avocado
|
|
28
30
|
def set_user
|
29
31
|
@user = user_from_signed_affirmation_token
|
30
32
|
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
31
|
-
redirect_to new_affirmation_path,
|
33
|
+
redirect_to new_affirmation_path,
|
34
|
+
alert: t(".errors.invalid_token")
|
32
35
|
end
|
33
36
|
|
34
37
|
def user_from_signed_affirmation_token
|
@@ -37,7 +40,8 @@ module Avocado
|
|
37
40
|
|
38
41
|
def verify_user
|
39
42
|
unless requested_verified_user
|
40
|
-
redirect_to new_affirmation_path,
|
43
|
+
redirect_to new_affirmation_path,
|
44
|
+
alert: t(".errors.unverified_email")
|
41
45
|
end
|
42
46
|
end
|
43
47
|
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module Avocado
|
4
2
|
class BaseController < ApplicationController
|
5
3
|
FINDER_PARAMETERS = %i[email]
|
@@ -8,16 +6,20 @@ module Avocado
|
|
8
6
|
|
9
7
|
def verify_password_challenge
|
10
8
|
unless current_user.authenticate(params_password_challenge)
|
11
|
-
redirect_back
|
9
|
+
redirect_back fallback_location: root_path,
|
10
|
+
alert: t("avocado.filters.invalid_password_challenge")
|
12
11
|
end
|
13
12
|
end
|
14
13
|
|
15
14
|
def params_password_challenge
|
16
|
-
params
|
15
|
+
params
|
16
|
+
.dig(:user, :password_challenge)
|
17
17
|
end
|
18
18
|
|
19
19
|
def requested_verified_user
|
20
|
-
::User
|
20
|
+
::User
|
21
|
+
.verified
|
22
|
+
.find_by(email: finder_parameters[:email])
|
21
23
|
end
|
22
24
|
|
23
25
|
def finder_parameters
|
@@ -27,7 +29,14 @@ module Avocado
|
|
27
29
|
end
|
28
30
|
|
29
31
|
def mailer_for(user)
|
30
|
-
Avocado::Mailer
|
32
|
+
Avocado::Mailer
|
33
|
+
.with(user: user)
|
34
|
+
end
|
35
|
+
|
36
|
+
def send_email_verification(user)
|
37
|
+
mailer_for(user)
|
38
|
+
.email_verification
|
39
|
+
.deliver_later
|
31
40
|
end
|
32
41
|
end
|
33
42
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Avocado
|
2
|
+
class CredentialsController < BaseController
|
3
|
+
UPDATE_PARAMETERS = %i[password password_confirmation]
|
4
|
+
|
5
|
+
skip_before_action :authenticate
|
6
|
+
|
7
|
+
before_action :set_user
|
8
|
+
|
9
|
+
def edit
|
10
|
+
end
|
11
|
+
|
12
|
+
def update
|
13
|
+
if @user.update(update_parameters)
|
14
|
+
redirect_to new_session_path,
|
15
|
+
notice: t(".success")
|
16
|
+
else
|
17
|
+
render :edit, status: :unprocessable_entity
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def set_user
|
24
|
+
@user = user_from_signed_password_reset_token
|
25
|
+
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
26
|
+
redirect_to new_recovery_path,
|
27
|
+
alert: t(".errors.invalid_token")
|
28
|
+
end
|
29
|
+
|
30
|
+
def user_from_signed_password_reset_token
|
31
|
+
::User
|
32
|
+
.find_by_token_for!(:password_reset, params[:id])
|
33
|
+
end
|
34
|
+
|
35
|
+
def update_parameters
|
36
|
+
params
|
37
|
+
.require(:user)
|
38
|
+
.permit(UPDATE_PARAMETERS)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -1,11 +1,10 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module Avocado
|
4
2
|
class EmailsController < BaseController
|
5
3
|
UPDATE_PARAMETERS = %i[email]
|
6
4
|
|
7
5
|
before_action :set_user
|
8
|
-
before_action :verify_password_challenge,
|
6
|
+
before_action :verify_password_challenge,
|
7
|
+
only: :update
|
9
8
|
|
10
9
|
def edit
|
11
10
|
end
|
@@ -13,6 +12,8 @@ module Avocado
|
|
13
12
|
def update
|
14
13
|
if @user.update(update_parameters)
|
15
14
|
process_email_update
|
15
|
+
redirect_to root_path,
|
16
|
+
notice: t(".success")
|
16
17
|
else
|
17
18
|
render :edit, status: :unprocessable_entity
|
18
19
|
end
|
@@ -32,17 +33,8 @@ module Avocado
|
|
32
33
|
|
33
34
|
def process_email_update
|
34
35
|
if @user.email_previously_changed?
|
35
|
-
|
36
|
-
redirect_to root_path, notice: "Your email has been changed"
|
37
|
-
else
|
38
|
-
redirect_to root_path
|
36
|
+
send_email_verification(@user)
|
39
37
|
end
|
40
38
|
end
|
41
|
-
|
42
|
-
def resend_email_verification
|
43
|
-
mailer_for(@user)
|
44
|
-
.email_verification
|
45
|
-
.deliver_later
|
46
|
-
end
|
47
39
|
end
|
48
40
|
end
|
@@ -1,18 +1,18 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module Avocado
|
4
2
|
class PasswordsController < BaseController
|
5
3
|
UPDATE_PARAMETERS = %i[password password_confirmation password_challenge]
|
6
4
|
|
7
5
|
before_action :set_user
|
8
|
-
before_action :verify_password_challenge,
|
6
|
+
before_action :verify_password_challenge,
|
7
|
+
only: :update
|
9
8
|
|
10
9
|
def edit
|
11
10
|
end
|
12
11
|
|
13
12
|
def update
|
14
13
|
if @user.update(update_parameters)
|
15
|
-
redirect_to root_path,
|
14
|
+
redirect_to root_path,
|
15
|
+
notice: t(".success")
|
16
16
|
else
|
17
17
|
render :edit, status: :unprocessable_entity
|
18
18
|
end
|
@@ -1,57 +1,28 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module Avocado
|
4
2
|
class RecoveriesController < BaseController
|
5
|
-
UPDATE_PARAMETERS = %i[password password_confirmation]
|
6
|
-
|
7
3
|
skip_before_action :authenticate
|
8
4
|
|
9
|
-
before_action :
|
10
|
-
|
5
|
+
before_action :verify_user,
|
6
|
+
only: :create
|
11
7
|
|
12
8
|
def new
|
13
9
|
end
|
14
10
|
|
15
11
|
def create
|
16
12
|
send_password_reset_email
|
17
|
-
redirect_to new_session_path,
|
18
|
-
|
19
|
-
|
20
|
-
def edit
|
21
|
-
end
|
22
|
-
|
23
|
-
def update
|
24
|
-
if @user.update(update_parameters)
|
25
|
-
redirect_to new_session_path, notice: "Password reset successfully. Please sign in."
|
26
|
-
else
|
27
|
-
render :edit, status: :unprocessable_entity
|
28
|
-
end
|
13
|
+
redirect_to new_session_path,
|
14
|
+
notice: t(".success")
|
29
15
|
end
|
30
16
|
|
31
17
|
private
|
32
18
|
|
33
|
-
def set_user
|
34
|
-
@user = user_from_signed_password_reset_token
|
35
|
-
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
36
|
-
redirect_to new_recovery_path, alert: "Password reset link is invalid."
|
37
|
-
end
|
38
|
-
|
39
|
-
def user_from_signed_password_reset_token
|
40
|
-
::User.find_by_token_for!(:password_reset, params[:id])
|
41
|
-
end
|
42
|
-
|
43
19
|
def verify_user
|
44
20
|
unless requested_verified_user
|
45
|
-
redirect_to new_recovery_path,
|
21
|
+
redirect_to new_recovery_path,
|
22
|
+
alert: t(".errors.unverified_email")
|
46
23
|
end
|
47
24
|
end
|
48
25
|
|
49
|
-
def update_parameters
|
50
|
-
params
|
51
|
-
.require(:user)
|
52
|
-
.permit(UPDATE_PARAMETERS)
|
53
|
-
end
|
54
|
-
|
55
26
|
def send_password_reset_email
|
56
27
|
mailer_for(requested_verified_user)
|
57
28
|
.password_reset
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module Avocado
|
4
2
|
class RegistrationsController < BaseController
|
5
3
|
INITIALIZATION_PARAMETERS = %i[email password password_confirmation]
|
@@ -16,8 +14,9 @@ module Avocado
|
|
16
14
|
if @user.save
|
17
15
|
sign_in(@user)
|
18
16
|
|
19
|
-
send_email_verification
|
20
|
-
redirect_to root_path,
|
17
|
+
send_email_verification(@user)
|
18
|
+
redirect_to root_path,
|
19
|
+
notice: t(".success")
|
21
20
|
else
|
22
21
|
render :new, status: :unprocessable_entity
|
23
22
|
end
|
@@ -30,11 +29,5 @@ module Avocado
|
|
30
29
|
.require(:user)
|
31
30
|
.permit(INITIALIZATION_PARAMETERS)
|
32
31
|
end
|
33
|
-
|
34
|
-
def send_email_verification
|
35
|
-
mailer_for(@user)
|
36
|
-
.email_verification
|
37
|
-
.deliver_later
|
38
|
-
end
|
39
32
|
end
|
40
33
|
end
|
@@ -1,19 +1,21 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module Avocado
|
4
2
|
class SessionsController < BaseController
|
5
3
|
AUTHENTICATION_PARAMETERS = %i[email password]
|
6
4
|
|
7
|
-
skip_before_action :authenticate,
|
5
|
+
skip_before_action :authenticate,
|
6
|
+
only: %i[new create]
|
8
7
|
|
9
8
|
with_options only: :create do
|
10
9
|
before_action :verify_authentication_attempt
|
11
10
|
end
|
12
11
|
|
13
|
-
before_action :set_session,
|
12
|
+
before_action :set_session,
|
13
|
+
only: :destroy
|
14
14
|
|
15
15
|
def index
|
16
|
-
@sessions = current_user
|
16
|
+
@sessions = current_user
|
17
|
+
.sessions
|
18
|
+
.newest_first
|
17
19
|
end
|
18
20
|
|
19
21
|
def new
|
@@ -23,12 +25,14 @@ module Avocado
|
|
23
25
|
def create
|
24
26
|
sign_in(authenticated_user)
|
25
27
|
|
26
|
-
redirect_to root_path,
|
28
|
+
redirect_to root_path,
|
29
|
+
notice: t(".success")
|
27
30
|
end
|
28
31
|
|
29
32
|
def destroy
|
30
33
|
@session.destroy
|
31
|
-
redirect_to sessions_path,
|
34
|
+
redirect_to sessions_path,
|
35
|
+
notice: t(".success")
|
32
36
|
end
|
33
37
|
|
34
38
|
private
|
@@ -41,17 +45,21 @@ module Avocado
|
|
41
45
|
end
|
42
46
|
|
43
47
|
def authenticated_user
|
44
|
-
@_authenticated_user ||= ::User
|
48
|
+
@_authenticated_user ||= ::User
|
49
|
+
.authenticate_by(authentication_parameters)
|
45
50
|
end
|
46
51
|
|
47
52
|
def verify_authentication_attempt
|
48
53
|
if authenticated_user.blank?
|
49
|
-
redirect_to new_session_path,
|
54
|
+
redirect_to new_session_path,
|
55
|
+
alert: t(".errors.authentication")
|
50
56
|
end
|
51
57
|
end
|
52
58
|
|
53
59
|
def set_session
|
54
|
-
@session = current_user
|
60
|
+
@session = current_user
|
61
|
+
.sessions
|
62
|
+
.find(params[:id])
|
55
63
|
end
|
56
64
|
end
|
57
65
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module Avocado
|
4
2
|
class VerificationsController < BaseController
|
5
3
|
with_options only: %i[edit update] do
|
@@ -12,12 +10,14 @@ module Avocado
|
|
12
10
|
|
13
11
|
def update
|
14
12
|
@user.update! verified: true
|
15
|
-
redirect_to root_path,
|
13
|
+
redirect_to root_path,
|
14
|
+
notice: t(".success")
|
16
15
|
end
|
17
16
|
|
18
17
|
def create
|
19
|
-
send_email_verification
|
20
|
-
redirect_to root_path,
|
18
|
+
send_email_verification(current_user)
|
19
|
+
redirect_to root_path,
|
20
|
+
notice: t(".success")
|
21
21
|
end
|
22
22
|
|
23
23
|
private
|
@@ -25,17 +25,13 @@ module Avocado
|
|
25
25
|
def set_user
|
26
26
|
@user = user_from_signed_email_verification_token
|
27
27
|
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
28
|
-
redirect_to root_path,
|
28
|
+
redirect_to root_path,
|
29
|
+
alert: t(".errors.invalid_token")
|
29
30
|
end
|
30
31
|
|
31
32
|
def user_from_signed_email_verification_token
|
32
|
-
::User
|
33
|
-
|
34
|
-
|
35
|
-
def send_email_verification
|
36
|
-
mailer_for(current_user)
|
37
|
-
.email_verification
|
38
|
-
.deliver_later
|
33
|
+
::User
|
34
|
+
.find_by_token_for!(:email_verification, params[:id])
|
39
35
|
end
|
40
36
|
end
|
41
37
|
end
|
@@ -7,8 +7,6 @@
|
|
7
7
|
</p>
|
8
8
|
|
9
9
|
<%= form_with url: affirmations_path, scope: :user do |form| %>
|
10
|
-
<%= form
|
11
|
-
<%= form.email_field :email, autofocus: true, autocomplete: "email", required: true %>
|
12
|
-
|
10
|
+
<%= render form %>
|
13
11
|
<%= form.button "Submit", name: nil %>
|
14
12
|
<% end -%>
|
@@ -1,17 +1,8 @@
|
|
1
|
-
<
|
2
|
-
Change your password
|
3
|
-
</h2>
|
4
|
-
|
5
|
-
<p>
|
6
|
-
<%= link_to "Sign in to your account" %>
|
7
|
-
</p>
|
8
|
-
|
9
|
-
<%= form_with model: @user, url: recovery_path(id: params[:id]), method: :patch do |form| %>
|
1
|
+
<div>
|
10
2
|
<%= form.label :password %>
|
11
3
|
<%= form.password_field :password, autocomplete: "new-password", required: true %>
|
12
|
-
|
4
|
+
</div>
|
5
|
+
<div>
|
13
6
|
<%= form.label :password_confirmation %>
|
14
7
|
<%= form.password_field :password_confirmation, autocomplete: "new-password", required: true %>
|
15
|
-
|
16
|
-
<%= form.button "Submit", name: nil %>
|
17
|
-
<% end %>
|
8
|
+
</div>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<h2>
|
2
|
+
Change your password
|
3
|
+
</h2>
|
4
|
+
|
5
|
+
<p>
|
6
|
+
<%= link_to "Sign in to your account" %>
|
7
|
+
</p>
|
8
|
+
|
9
|
+
<%= form_with model: @user, url: credential_path(id: params[:id]), method: :patch do |form| %>
|
10
|
+
<%= render form %>
|
11
|
+
<%= form.button "Submit", name: nil %>
|
12
|
+
<% end %>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<div>
|
2
|
+
<%= form.label :email %>
|
3
|
+
<%= form.email_field :email, autocomplete: "email", required: true %>
|
4
|
+
</div>
|
5
|
+
<div>
|
6
|
+
<%= form.label :password_challenge, "Current password" %>
|
7
|
+
<%= form.password_field :password_challenge, autocomplete: "current-password", required: true %>
|
8
|
+
</div>
|
@@ -10,11 +10,6 @@
|
|
10
10
|
<% end %>
|
11
11
|
|
12
12
|
<%= form_with model: @user, url: email_path, method: :patch do |form| %>
|
13
|
-
<%= form
|
14
|
-
<%= form.email_field :email, autocomplete: "email", required: true %>
|
15
|
-
|
16
|
-
<%= form.label :password_challenge, "Current password" %>
|
17
|
-
<%= form.password_field :password_challenge, autocomplete: "current-password", required: true %>
|
18
|
-
|
13
|
+
<%= render form %>
|
19
14
|
<%= form.button "Submit", name: nil %>
|
20
15
|
<% end %>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<div>
|
2
|
+
<%= form.label :password_challenge, "Current password" %>
|
3
|
+
<%= form.password_field :password_challenge, autocomplete: "current-password", required: true %>
|
4
|
+
</div>
|
5
|
+
<div>
|
6
|
+
<%= form.label :password %>
|
7
|
+
<%= form.password_field :password, autocomplete: "new-password", required: true %>
|
8
|
+
</div>
|
9
|
+
<div>
|
10
|
+
<%= form.label :password_confirmation %>
|
11
|
+
<%= form.password_field :password_confirmation, autocomplete: "new-password", required: true %>
|
12
|
+
</div>
|
@@ -3,14 +3,6 @@
|
|
3
3
|
</h2>
|
4
4
|
|
5
5
|
<%= form_with model: @user, url: password_path, method: :patch do |form| %>
|
6
|
-
<%= form
|
7
|
-
<%= form.password_field :password_challenge, autocomplete: "current-password", required: true %>
|
8
|
-
|
9
|
-
<%= form.label :password %>
|
10
|
-
<%= form.password_field :password, autocomplete: "new-password", required: true %>
|
11
|
-
|
12
|
-
<%= form.label :password_confirmation %>
|
13
|
-
<%= form.password_field :password_confirmation, autocomplete: "new-password", required: true %>
|
14
|
-
|
6
|
+
<%= render form %>
|
15
7
|
<%= form.button "Submit", name: nil %>
|
16
8
|
<% end %>
|
@@ -7,8 +7,6 @@
|
|
7
7
|
</p>
|
8
8
|
|
9
9
|
<%= form_with url: recoveries_path, scope: :user do |form| %>
|
10
|
-
<%= form
|
11
|
-
<%= form.email_field :email, autofocus: true, autocomplete: "email", required: true %>
|
12
|
-
|
10
|
+
<%= render form %>
|
13
11
|
<%= form.button "Submit", name: nil %>
|
14
12
|
<% end -%>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<div>
|
2
|
+
<%= form.label :email %>
|
3
|
+
<%= form.email_field :email, autofocus: true, autocomplete: "email", required: true %>
|
4
|
+
</div>
|
5
|
+
<div>
|
6
|
+
<%= form.label :password %>
|
7
|
+
<%= form.password_field :password, autocomplete: "new-password", required: true %>
|
8
|
+
</div>
|
9
|
+
<div>
|
10
|
+
<%= form.label :password_confirmation %>
|
11
|
+
<%= form.password_field :password_confirmation, autocomplete: "new-password", required: true %>
|
12
|
+
</div>
|
@@ -7,17 +7,6 @@
|
|
7
7
|
</p>
|
8
8
|
|
9
9
|
<%= form_with model: @user, url: registrations_path do |form| %>
|
10
|
-
|
11
|
-
<%= form.label :email %>
|
12
|
-
<%= form.email_field :email, autofocus: true, autocomplete: "email", required: true %>
|
13
|
-
</div>
|
14
|
-
<div>
|
15
|
-
<%= form.label :password %>
|
16
|
-
<%= form.password_field :password, autocomplete: "new-password", required: true %>
|
17
|
-
</div>
|
18
|
-
<div>
|
19
|
-
<%= form.label :password_confirmation %>
|
20
|
-
<%= form.password_field :password_confirmation, autocomplete: "new-password", required: true %>
|
21
|
-
</div>
|
10
|
+
<%= render form %>
|
22
11
|
<%= form.button "Submit", name: nil %>
|
23
12
|
<% end %>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<div>
|
2
|
+
<%= form.label :email %>
|
3
|
+
<%= form.email_field :email, autofocus: true, autocomplete: "email", required: true %>
|
4
|
+
</div>
|
5
|
+
<div>
|
6
|
+
<%= form.label :password %>
|
7
|
+
<%= form.password_field :password, autocomplete: "current-password", required: true %>
|
8
|
+
</div>
|
@@ -7,9 +7,6 @@
|
|
7
7
|
</p>
|
8
8
|
|
9
9
|
<%= form_with model: @session do |form| %>
|
10
|
-
<%= form
|
11
|
-
<%= form.email_field :email, autofocus: true, autocomplete: "email", required: true %>
|
12
|
-
<%= form.label :password %>
|
13
|
-
<%= form.password_field :password, autocomplete: "current-password", required: true %>
|
10
|
+
<%= render form %>
|
14
11
|
<%= form.button "Submit", name: nil %>
|
15
12
|
<% end -%>
|
@@ -0,0 +1,45 @@
|
|
1
|
+
en:
|
2
|
+
avocado:
|
3
|
+
affirmations:
|
4
|
+
create:
|
5
|
+
success: Check email for sign in instructions.
|
6
|
+
errors:
|
7
|
+
invalid_token: Sign in link is invalid.
|
8
|
+
unverified_email: Verify email first before signing in.
|
9
|
+
update:
|
10
|
+
success: Signed in successfully.
|
11
|
+
credentials:
|
12
|
+
update:
|
13
|
+
success: Password reset successfully.
|
14
|
+
errors:
|
15
|
+
invalid_token: Password reset link is invalid.
|
16
|
+
emails:
|
17
|
+
update:
|
18
|
+
success: Email has been changed.
|
19
|
+
filters:
|
20
|
+
invalid_password_challenge: Password challenge failed.
|
21
|
+
passwords:
|
22
|
+
update:
|
23
|
+
success: Password has been changed.
|
24
|
+
recoveries:
|
25
|
+
create:
|
26
|
+
success: Check email for reset instructions.
|
27
|
+
errors:
|
28
|
+
unverified_email: Verify email first before resetting password.
|
29
|
+
registrations:
|
30
|
+
create:
|
31
|
+
success: Registration successful.
|
32
|
+
sessions:
|
33
|
+
create:
|
34
|
+
success: Session created.
|
35
|
+
destroy:
|
36
|
+
success: Session destroyed.
|
37
|
+
errors:
|
38
|
+
authentication: Authentication failed.
|
39
|
+
verifications:
|
40
|
+
create:
|
41
|
+
success: Verification email sent.
|
42
|
+
errors:
|
43
|
+
invalid_token: Email verification link is invalid.
|
44
|
+
update:
|
45
|
+
success: Email address verified.
|
data/config/routes/avocado.rb
CHANGED
@@ -2,8 +2,9 @@ scope module: :avocado do
|
|
2
2
|
resource :email, only: %i[edit update]
|
3
3
|
resource :password, only: %i[edit update]
|
4
4
|
resources :affirmations, only: %i[new create edit update]
|
5
|
+
resources :credentials, only: %i[edit update]
|
5
6
|
resources :events, only: %i[index]
|
6
|
-
resources :recoveries, only: %i[new create
|
7
|
+
resources :recoveries, only: %i[new create]
|
7
8
|
resources :registrations, only: %i[new create]
|
8
9
|
resources :sessions, only: %i[index new create destroy]
|
9
10
|
resources :verifications, only: %i[create edit update]
|
data/config.ru
CHANGED
data/docs/USAGE.md
CHANGED
@@ -8,8 +8,8 @@ scenarios, and can be subclassed and overridden for special cases.
|
|
8
8
|
## Requirements
|
9
9
|
|
10
10
|
Apps must be running Rails 7.1 or newer. The 🥑 gem uses features like
|
11
|
-
`authenticate_by`, `
|
12
|
-
`normalizes` which don't exist in earlier versions.
|
11
|
+
`authenticate_by`, the `password_challenge` feature of `has_secure_password`,
|
12
|
+
`generates_token_for`, and `normalizes` which don't exist in earlier versions.
|
13
13
|
|
14
14
|
The database schema must have columns that match the `users`, `sessions`, and
|
15
15
|
`events` tables from the [demo app schema]. More columns in each table are
|
@@ -21,9 +21,12 @@ Run `bin/rails g avocado:migrations` to generate migrations for the tables.
|
|
21
21
|
|
22
22
|
The application must also have:
|
23
23
|
|
24
|
-
- An `ApplicationController` base controller class
|
25
|
-
|
26
|
-
-
|
24
|
+
- An `ApplicationController` base controller class for the controllers to
|
25
|
+
inherit from.
|
26
|
+
- An `ApplicationMailer` base mailer class which sets a layout and default
|
27
|
+
`from` value.
|
28
|
+
- A `root_path` route helper method (typically generated by routes configured in
|
29
|
+
the application).
|
27
30
|
|
28
31
|
## Usage
|
29
32
|
|
@@ -60,11 +63,11 @@ end
|
|
60
63
|
|
61
64
|
### Routes
|
62
65
|
|
63
|
-
|
64
|
-
up the controllers to routes, they must be added to the `config/routes.rb`
|
65
|
-
the application. It's possible to add all of the routes, or just a subset.
|
66
|
+
By defalt, 🥑 does not add any routes to the application when initialized. To
|
67
|
+
hook up the controllers to routes, they must be added to the `config/routes.rb`
|
68
|
+
of the application. It's possible to add all of the routes, or just a subset.
|
66
69
|
|
67
|
-
|
70
|
+
This example defines a `root` route and also pulls in every feature route:
|
68
71
|
|
69
72
|
```ruby
|
70
73
|
Rails.application.routes.draw do
|
@@ -73,12 +76,12 @@ Rails.application.routes.draw do
|
|
73
76
|
end
|
74
77
|
```
|
75
78
|
|
76
|
-
|
79
|
+
This example defines a `root` route and adds only a subset of feature routes:
|
77
80
|
|
78
81
|
```ruby
|
79
82
|
Rails.application.routes.draw do
|
80
83
|
root to: "records#index"
|
81
|
-
scope module:
|
84
|
+
scope module: 🥑 do
|
82
85
|
resources :registrations, only: %i[new create]
|
83
86
|
resources :sessions, only: %i[new create destroy]
|
84
87
|
end
|
@@ -94,18 +97,19 @@ app initialization.
|
|
94
97
|
|
95
98
|
These external (unauthenticated) features are available:
|
96
99
|
|
97
|
-
- `Registrations` -- Fill out new form and create users
|
98
|
-
- `Sessions` -- Sign in and sign out
|
99
|
-
- `Recoveries` --
|
100
|
-
- `
|
101
|
-
- `
|
100
|
+
- `Registrations` -- Fill out new user form and create users
|
101
|
+
- `Sessions` -- Sign in and sign out
|
102
|
+
- `Recoveries` -- Triggers password reset via emailed expiring link
|
103
|
+
- `Credentials` -- Use expiring token link from recovery to update password
|
104
|
+
- `Verifications` -- Confirm email address on account creation or email change
|
105
|
+
- `Affirmations` -- "Passwordless" authentication via emailed expiring link
|
102
106
|
|
103
107
|
These internal (authenticated) features are available:
|
104
108
|
|
105
|
-
- `Sessions` --
|
106
|
-
- `Events` --
|
107
|
-
- `Passwords` -- Edit and update user password
|
108
|
-
- `Emails` -- Edit and update user email
|
109
|
+
- `Sessions` -- Index view of active sessions, ability to destroy sessions
|
110
|
+
- `Events` -- Index view of the user activity audit log
|
111
|
+
- `Passwords` -- Edit and update a user password
|
112
|
+
- `Emails` -- Edit and update a user email
|
109
113
|
|
110
114
|
Linking to any of these internal pages is optional. Apps can use them as-is,
|
111
115
|
override their views, or even ignore them entirely and make local versions.
|
@@ -118,14 +122,15 @@ within `app/views/avocado/mailer/` to make this happen.
|
|
118
122
|
|
119
123
|
### Before actions
|
120
124
|
|
121
|
-
There is an `authenticate` method installed as
|
122
|
-
actions which do not need to be authenticated
|
123
|
-
`skip_before_action
|
125
|
+
There is an `authenticate` method installed as default controller behavior using
|
126
|
+
`before_action :authenticate`. Any actions which do not need to be authenticated
|
127
|
+
should disable this with `skip_before_action :authenticate`, or inherit from a
|
128
|
+
controller which performs the skip.
|
124
129
|
|
125
|
-
There is a `set_current_request_details` method installed as a default
|
126
|
-
`before_action` which takes some loggable request meta information (
|
127
|
-
IP
|
128
|
-
elsewhere in the 🥑 gem.
|
130
|
+
There is also a `set_current_request_details` method installed as a default
|
131
|
+
`before_action` which takes some loggable request meta information (User Agent,
|
132
|
+
IP Address) and sets their values in `Current` so that they are accesible to
|
133
|
+
code elsewhere in the 🥑 gem.
|
129
134
|
|
130
135
|
### Helpers
|
131
136
|
|
@@ -144,7 +149,11 @@ There is not any configuration. To override functionality:
|
|
144
149
|
|
145
150
|
- Redefine a method created in one of the models by the included module
|
146
151
|
- Subclass a controller and update the routing to go to the subclass
|
147
|
-
- Place views in the app where avocado expects them to
|
152
|
+
- Place views in the app where avocado expects (`app/views/avocado`) them to
|
153
|
+
override the defaults
|
154
|
+
|
155
|
+
There is an `avocado:views` generator which will copy all the views as a
|
156
|
+
starting point for further modification.
|
148
157
|
|
149
158
|
## Examples
|
150
159
|
|
@@ -152,4 +161,4 @@ There is a [demo app] used by the specs which has some example usage.
|
|
152
161
|
|
153
162
|
[demo app schema]: https://github.com/tcuwp/avocado/blob/main/spec/internal/db/schema.rb
|
154
163
|
[demo app]: https://github.com/tcuwp/avocado/blob/main/spec/internal
|
155
|
-
[Rails Engine]: https://guides.rubyonrails.org/engines.html#what-are-engines-questionmark
|
164
|
+
[Rails Engine]: https://guides.rubyonrails.org/engines.html#what-are-engines-questionmark
|
data/lib/avocado/current.rb
CHANGED
data/lib/avocado/engine.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
require "avocado"
|
4
2
|
require "rails/engine"
|
5
3
|
|
@@ -7,7 +5,7 @@ module Avocado
|
|
7
5
|
class Engine < Rails::Engine
|
8
6
|
initializer :avocado_routing do
|
9
7
|
ActiveSupport.on_load(:action_dispatch_request) do
|
10
|
-
ActionDispatch::Routing::Mapper.define_method(:🥑) {
|
8
|
+
ActionDispatch::Routing::Mapper.define_method(:🥑) { :avocado }
|
11
9
|
end
|
12
10
|
end
|
13
11
|
end
|
data/lib/avocado/event.rb
CHANGED
data/lib/avocado/mailer.rb
CHANGED
data/lib/avocado/session.rb
CHANGED
data/lib/avocado/user.rb
CHANGED
data/lib/avocado/user_tokens.rb
CHANGED
data/lib/avocado/version.rb
CHANGED
data/lib/avocado.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
require "rails/generators/base"
|
2
|
+
|
3
|
+
module Avocado
|
4
|
+
class ViewsGenerator < Rails::Generators::Base
|
5
|
+
source_root File.expand_path("../../../..", __dir__)
|
6
|
+
|
7
|
+
def create_views
|
8
|
+
directory source_directory, target_directory
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def source_directory
|
14
|
+
"app/views/avocado"
|
15
|
+
end
|
16
|
+
|
17
|
+
def target_directory
|
18
|
+
Rails.root.join("app/views/avocado")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: avocado
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Jankowski
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-08-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bcrypt
|
@@ -40,7 +40,7 @@ dependencies:
|
|
40
40
|
version: 7.1.0.alpha
|
41
41
|
description:
|
42
42
|
email:
|
43
|
-
-
|
43
|
+
- info@tcuwp.co
|
44
44
|
executables: []
|
45
45
|
extensions: []
|
46
46
|
extra_rdoc_files: []
|
@@ -54,6 +54,7 @@ files:
|
|
54
54
|
- Rakefile
|
55
55
|
- app/controllers/avocado/affirmations_controller.rb
|
56
56
|
- app/controllers/avocado/base_controller.rb
|
57
|
+
- app/controllers/avocado/credentials_controller.rb
|
57
58
|
- app/controllers/avocado/emails_controller.rb
|
58
59
|
- app/controllers/avocado/events_controller.rb
|
59
60
|
- app/controllers/avocado/passwords_controller.rb
|
@@ -61,25 +62,32 @@ files:
|
|
61
62
|
- app/controllers/avocado/registrations_controller.rb
|
62
63
|
- app/controllers/avocado/sessions_controller.rb
|
63
64
|
- app/controllers/avocado/verifications_controller.rb
|
65
|
+
- app/views/avocado/affirmations/_form.html.erb
|
64
66
|
- app/views/avocado/affirmations/edit.html.erb
|
65
67
|
- app/views/avocado/affirmations/new.html.erb
|
68
|
+
- app/views/avocado/credentials/_form.html.erb
|
69
|
+
- app/views/avocado/credentials/edit.html.erb
|
70
|
+
- app/views/avocado/emails/_form.html.erb
|
66
71
|
- app/views/avocado/emails/edit.html.erb
|
67
72
|
- app/views/avocado/events/_event.html.erb
|
68
73
|
- app/views/avocado/events/index.html.erb
|
69
74
|
- app/views/avocado/mailer/email_affirmation.text.erb
|
70
75
|
- app/views/avocado/mailer/email_verification.text.erb
|
71
76
|
- app/views/avocado/mailer/password_reset.text.erb
|
77
|
+
- app/views/avocado/passwords/_form.html.erb
|
72
78
|
- app/views/avocado/passwords/edit.html.erb
|
73
|
-
- app/views/avocado/recoveries/
|
79
|
+
- app/views/avocado/recoveries/_form.html.erb
|
74
80
|
- app/views/avocado/recoveries/new.html.erb
|
81
|
+
- app/views/avocado/registrations/_form.html.erb
|
75
82
|
- app/views/avocado/registrations/new.html.erb
|
83
|
+
- app/views/avocado/sessions/_form.html.erb
|
76
84
|
- app/views/avocado/sessions/_session.html.erb
|
77
85
|
- app/views/avocado/sessions/index.html.erb
|
78
86
|
- app/views/avocado/sessions/new.html.erb
|
79
87
|
- app/views/avocado/verifications/edit.html.erb
|
80
88
|
- config.ru
|
89
|
+
- config/locales/en.yml
|
81
90
|
- config/routes/avocado.rb
|
82
|
-
- "config/routes/\U0001F951.rb"
|
83
91
|
- docs/USAGE.md
|
84
92
|
- lib/avocado.rb
|
85
93
|
- lib/avocado/authentication.rb
|
@@ -98,6 +106,7 @@ files:
|
|
98
106
|
- lib/generators/avocado/migrations/templates/create_events.rb.tt
|
99
107
|
- lib/generators/avocado/migrations/templates/create_sessions.rb.tt
|
100
108
|
- lib/generators/avocado/migrations/templates/create_users.rb.tt
|
109
|
+
- lib/generators/avocado/views/views_generator.rb
|
101
110
|
- sig/avocado.rbs
|
102
111
|
homepage: https://github.com/tcuwp/avocado
|
103
112
|
licenses:
|
@@ -121,7 +130,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
121
130
|
- !ruby/object:Gem::Version
|
122
131
|
version: '0'
|
123
132
|
requirements: []
|
124
|
-
rubygems_version: 3.4.
|
133
|
+
rubygems_version: 3.4.18
|
125
134
|
signing_key:
|
126
135
|
specification_version: 4
|
127
136
|
summary: Simple authentication for Rails (7.1+) applications
|
@@ -1 +0,0 @@
|
|
1
|
-
avocado.rb
|