avocado 0.5.0 → 0.6.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 +6 -0
- data/README.md +8 -43
- data/app/controllers/avocado/affirmations_controller.rb +11 -12
- data/app/controllers/avocado/base_controller.rb +12 -0
- data/app/controllers/avocado/emails_controller.rb +4 -4
- data/app/controllers/avocado/passwords_controller.rb +4 -4
- data/app/controllers/avocado/recoveries_controller.rb +9 -13
- data/app/controllers/avocado/registrations_controller.rb +4 -4
- data/app/controllers/avocado/sessions_controller.rb +4 -4
- data/app/controllers/avocado/verifications_controller.rb +5 -2
- data/app/views/avocado/affirmations/edit.html.erb +7 -0
- data/app/views/avocado/affirmations/new.html.erb +1 -1
- data/app/views/avocado/mailer/email_affirmation.text.erb +1 -1
- data/app/views/avocado/mailer/email_verification.text.erb +1 -1
- data/app/views/avocado/recoveries/new.html.erb +1 -1
- data/app/views/avocado/verifications/edit.html.erb +7 -0
- data/config/routes/avocado.rb +10 -0
- data/config/routes//360/237/245/221.rb +1 -0
- data/docs/USAGE.md +155 -0
- data/lib/avocado/authentication.rb +2 -2
- data/lib/avocado/engine.rb +5 -0
- data/lib/avocado/session.rb +6 -0
- data/lib/avocado/version.rb +1 -1
- data/lib/avocado.rb +1 -0
- data/lib/generators/avocado/migrations/migrations_generator.rb +36 -0
- data/lib/generators/avocado/migrations/templates/create_events.rb.tt +12 -0
- data/lib/generators/avocado/migrations/templates/create_sessions.rb.tt +12 -0
- data/lib/generators/avocado/migrations/templates/create_users.rb.tt +11 -0
- metadata +15 -35
- data/config/routes.rb +0 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 393630ca933c51e34b00e2fe86bbcfb5caa4ea7764fc34882c21ef4f604bb938
|
4
|
+
data.tar.gz: bfc5362c53ecee86c6369a1318c68fddf2bbd7e457287cb5b9c6b57970ded8aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: efbe7bfe5b298b207e65e7958e3167be69d6612bd50e8a4a880483ec1a1d9e2c30d45fdae86e0516d34bb00442c0cd16416ad77a00a50ac31c707295d1538709
|
7
|
+
data.tar.gz: b96ba925c445b78c92c560a01c395697dab736363a847c766e310879ded4ad58b97b7dae052a73ed1a267f7315bedd171d9f0097978760cb3de6a1e9b3c02969
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.6.0] - 2023-07-25
|
4
|
+
|
5
|
+
- Change affirmations and verifications to require user action
|
6
|
+
- Use session token instead of id for signed cookie value
|
7
|
+
- Add migration generators
|
8
|
+
|
3
9
|
## [0.5.0] - 2023-07-21
|
4
10
|
|
5
11
|
- Add controller for "passwordless" email-link sign-in
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
#
|
1
|
+
# 🥑
|
2
2
|
|
3
|
-
|
3
|
+
Authentication library for [Rails] 7.1+ applications.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -10,49 +10,13 @@ Add to the application's Gemfile by executing:
|
|
10
10
|
|
11
11
|
## Usage
|
12
12
|
|
13
|
-
|
14
|
-
such features via a packaged gem, you can include some Avocado modules into your
|
15
|
-
application to get authentication functionality.
|
16
|
-
|
17
|
-
As a prerequisite, you should have a database schema with columns that match the
|
18
|
-
users and sessions tables from [the demo app schema]. It's ok to have more
|
19
|
-
columns, but you need at least what is shown there.
|
20
|
-
|
21
|
-
With that set, include the modules into your classes:
|
22
|
-
|
23
|
-
```ruby
|
24
|
-
class User < ApplicationRecord
|
25
|
-
include Avocado::User
|
26
|
-
end
|
27
|
-
|
28
|
-
class Session < ApplicationRecord
|
29
|
-
include Avocado::Session
|
30
|
-
end
|
31
|
-
|
32
|
-
class Event < ApplicationRecord
|
33
|
-
include Avocado::Event
|
34
|
-
end
|
35
|
-
|
36
|
-
class ApplicationController < ActionController::Base
|
37
|
-
include Avocado::Authentication
|
38
|
-
end
|
39
|
-
```
|
40
|
-
|
41
|
-
This will enable a few things:
|
42
|
-
|
43
|
-
- Models will get validations, associations, and normalizations
|
44
|
-
- Rails built-in `has_secure_password` is called within `User`
|
45
|
-
- A mailer with signed token generators is created
|
46
|
-
- Controllers and Routes for sign up, sign in, password reset, email
|
47
|
-
verification, etc
|
48
|
-
|
49
|
-
The `spec/internal` app within this repo has some example usage.
|
13
|
+
Read the [documentation] for more details or the [wiki] for background.
|
50
14
|
|
51
15
|
## Development
|
52
16
|
|
53
|
-
After checking out the repo, run `bin/setup` to install dependencies.
|
54
|
-
`
|
55
|
-
|
17
|
+
After checking out the repo, run `bin/setup` to install dependencies. Use
|
18
|
+
`bin/rspec` to run the full spec suite and `bin/standardrb` to run the linter.
|
19
|
+
Running `bin/rake` will run specs & linter.
|
56
20
|
|
57
21
|
## Contributing
|
58
22
|
|
@@ -62,7 +26,8 @@ Bug reports and pull requests are welcome on [GitHub].
|
|
62
26
|
|
63
27
|
The gem is available as open source under the terms of the [MIT License].
|
64
28
|
|
29
|
+
[documentation]: https://github.com/tcuwp/avocado/blob/main/docs/USAGE.md
|
65
30
|
[GitHub]: https://github.com/tcuwp/avocado
|
66
31
|
[MIT License]: https://opensource.org/licenses/MIT
|
67
32
|
[Rails]: https://github.com/rails/rails
|
68
|
-
[
|
33
|
+
[wiki]: https://github.com/tcuwp/avocado/wiki
|
@@ -4,22 +4,25 @@ module Avocado
|
|
4
4
|
class AffirmationsController < BaseController
|
5
5
|
skip_before_action :authenticate
|
6
6
|
|
7
|
-
before_action :set_user, only:
|
7
|
+
before_action :set_user, only: %i[edit update]
|
8
8
|
before_action :verify_user, only: :create
|
9
9
|
|
10
10
|
def new
|
11
11
|
end
|
12
12
|
|
13
|
-
def show
|
14
|
-
sign_in(@user)
|
15
|
-
redirect_to(root_path, notice: "Signed in successfully")
|
16
|
-
end
|
17
|
-
|
18
13
|
def create
|
19
14
|
send_affirmation_email
|
20
15
|
redirect_to new_session_path, notice: "Check your email for sign in instructions"
|
21
16
|
end
|
22
17
|
|
18
|
+
def edit
|
19
|
+
end
|
20
|
+
|
21
|
+
def update
|
22
|
+
sign_in(@user)
|
23
|
+
redirect_to(root_path, notice: "Signed in successfully")
|
24
|
+
end
|
25
|
+
|
23
26
|
private
|
24
27
|
|
25
28
|
def set_user
|
@@ -33,19 +36,15 @@ module Avocado
|
|
33
36
|
end
|
34
37
|
|
35
38
|
def verify_user
|
36
|
-
unless
|
39
|
+
unless requested_verified_user
|
37
40
|
redirect_to new_affirmation_path, alert: "You can't sign in until you verify your email"
|
38
41
|
end
|
39
42
|
end
|
40
43
|
|
41
44
|
def send_affirmation_email
|
42
|
-
mailer_for(
|
45
|
+
mailer_for(requested_verified_user)
|
43
46
|
.email_affirmation
|
44
47
|
.deliver_later
|
45
48
|
end
|
46
|
-
|
47
|
-
def user_from_params_email
|
48
|
-
::User.verified.find_by(email: params[:email])
|
49
|
-
end
|
50
49
|
end
|
51
50
|
end
|
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
module Avocado
|
4
4
|
class BaseController < ApplicationController
|
5
|
+
FINDER_PARAMETERS = %i[email]
|
6
|
+
|
5
7
|
private
|
6
8
|
|
7
9
|
def verify_password_challenge
|
@@ -14,6 +16,16 @@ module Avocado
|
|
14
16
|
params.dig(:user, :password_challenge)
|
15
17
|
end
|
16
18
|
|
19
|
+
def requested_verified_user
|
20
|
+
::User.verified.find_by(email: finder_parameters[:email])
|
21
|
+
end
|
22
|
+
|
23
|
+
def finder_parameters
|
24
|
+
params
|
25
|
+
.require(:user)
|
26
|
+
.permit(FINDER_PARAMETERS)
|
27
|
+
end
|
28
|
+
|
17
29
|
def mailer_for(user)
|
18
30
|
Avocado::Mailer.with(user: user)
|
19
31
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Avocado
|
4
4
|
class EmailsController < BaseController
|
5
|
-
|
5
|
+
UPDATE_PARAMETERS = %i[email]
|
6
6
|
|
7
7
|
before_action :set_user
|
8
8
|
before_action :verify_password_challenge, only: :update
|
@@ -11,7 +11,7 @@ module Avocado
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def update
|
14
|
-
if @user.update(
|
14
|
+
if @user.update(update_parameters)
|
15
15
|
process_email_update
|
16
16
|
else
|
17
17
|
render :edit, status: :unprocessable_entity
|
@@ -24,10 +24,10 @@ module Avocado
|
|
24
24
|
@user = current_user
|
25
25
|
end
|
26
26
|
|
27
|
-
def
|
27
|
+
def update_parameters
|
28
28
|
params
|
29
29
|
.require(:user)
|
30
|
-
.permit(
|
30
|
+
.permit(UPDATE_PARAMETERS)
|
31
31
|
end
|
32
32
|
|
33
33
|
def process_email_update
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Avocado
|
4
4
|
class PasswordsController < BaseController
|
5
|
-
|
5
|
+
UPDATE_PARAMETERS = %i[password password_confirmation password_challenge]
|
6
6
|
|
7
7
|
before_action :set_user
|
8
8
|
before_action :verify_password_challenge, only: :update
|
@@ -11,7 +11,7 @@ module Avocado
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def update
|
14
|
-
if @user.update(
|
14
|
+
if @user.update(update_parameters)
|
15
15
|
redirect_to root_path, notice: "Your password has been changed"
|
16
16
|
else
|
17
17
|
render :edit, status: :unprocessable_entity
|
@@ -24,10 +24,10 @@ module Avocado
|
|
24
24
|
@user = current_user
|
25
25
|
end
|
26
26
|
|
27
|
-
def
|
27
|
+
def update_parameters
|
28
28
|
params
|
29
29
|
.require(:user)
|
30
|
-
.permit(
|
30
|
+
.permit(UPDATE_PARAMETERS)
|
31
31
|
.with_defaults(password_challenge: "")
|
32
32
|
end
|
33
33
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Avocado
|
4
4
|
class RecoveriesController < BaseController
|
5
|
-
|
5
|
+
UPDATE_PARAMETERS = %i[password password_confirmation]
|
6
6
|
|
7
7
|
skip_before_action :authenticate
|
8
8
|
|
@@ -12,16 +12,16 @@ module Avocado
|
|
12
12
|
def new
|
13
13
|
end
|
14
14
|
|
15
|
-
def edit
|
16
|
-
end
|
17
|
-
|
18
15
|
def create
|
19
16
|
send_password_reset_email
|
20
17
|
redirect_to new_session_path, notice: "Check your email for reset instructions."
|
21
18
|
end
|
22
19
|
|
20
|
+
def edit
|
21
|
+
end
|
22
|
+
|
23
23
|
def update
|
24
|
-
if @user.update(
|
24
|
+
if @user.update(update_parameters)
|
25
25
|
redirect_to new_session_path, notice: "Password reset successfully. Please sign in."
|
26
26
|
else
|
27
27
|
render :edit, status: :unprocessable_entity
|
@@ -41,23 +41,19 @@ module Avocado
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def verify_user
|
44
|
-
unless
|
44
|
+
unless requested_verified_user
|
45
45
|
redirect_to new_recovery_path, alert: "Verify email first before resetting password."
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
-
def
|
49
|
+
def update_parameters
|
50
50
|
params
|
51
51
|
.require(:user)
|
52
|
-
.permit(
|
53
|
-
end
|
54
|
-
|
55
|
-
def user_from_params_email
|
56
|
-
::User.find_by(email: params[:email], verified: true)
|
52
|
+
.permit(UPDATE_PARAMETERS)
|
57
53
|
end
|
58
54
|
|
59
55
|
def send_password_reset_email
|
60
|
-
mailer_for(
|
56
|
+
mailer_for(requested_verified_user)
|
61
57
|
.password_reset
|
62
58
|
.deliver_later
|
63
59
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Avocado
|
4
4
|
class RegistrationsController < BaseController
|
5
|
-
|
5
|
+
INITIALIZATION_PARAMETERS = %i[email password password_confirmation]
|
6
6
|
|
7
7
|
skip_before_action :authenticate
|
8
8
|
|
@@ -11,7 +11,7 @@ module Avocado
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def create
|
14
|
-
@user = ::User.new(
|
14
|
+
@user = ::User.new(initialization_parameters)
|
15
15
|
|
16
16
|
if @user.save
|
17
17
|
sign_in(@user)
|
@@ -25,10 +25,10 @@ module Avocado
|
|
25
25
|
|
26
26
|
private
|
27
27
|
|
28
|
-
def
|
28
|
+
def initialization_parameters
|
29
29
|
params
|
30
30
|
.require(:user)
|
31
|
-
.permit(
|
31
|
+
.permit(INITIALIZATION_PARAMETERS)
|
32
32
|
end
|
33
33
|
|
34
34
|
def send_email_verification
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Avocado
|
4
4
|
class SessionsController < BaseController
|
5
|
-
|
5
|
+
AUTHENTICATION_PARAMETERS = %i[email password]
|
6
6
|
|
7
7
|
skip_before_action :authenticate, only: %i[new create]
|
8
8
|
|
@@ -33,15 +33,15 @@ module Avocado
|
|
33
33
|
|
34
34
|
private
|
35
35
|
|
36
|
-
def
|
36
|
+
def authentication_parameters
|
37
37
|
params
|
38
38
|
.require(:session)
|
39
|
-
.permit(
|
39
|
+
.permit(AUTHENTICATION_PARAMETERS)
|
40
40
|
.with_defaults(email: "", password: "")
|
41
41
|
end
|
42
42
|
|
43
43
|
def authenticated_user
|
44
|
-
@_authenticated_user ||= ::User.authenticate_by(
|
44
|
+
@_authenticated_user ||= ::User.authenticate_by(authentication_parameters)
|
45
45
|
end
|
46
46
|
|
47
47
|
def verify_authentication_attempt
|
@@ -2,12 +2,15 @@
|
|
2
2
|
|
3
3
|
module Avocado
|
4
4
|
class VerificationsController < BaseController
|
5
|
-
with_options only:
|
5
|
+
with_options only: %i[edit update] do
|
6
6
|
skip_before_action :authenticate
|
7
7
|
before_action :set_user
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
10
|
+
def edit
|
11
|
+
end
|
12
|
+
|
13
|
+
def update
|
11
14
|
@user.update! verified: true
|
12
15
|
redirect_to root_path, notice: "Email address verified."
|
13
16
|
end
|
@@ -6,7 +6,7 @@
|
|
6
6
|
<%= link_to "Reset your password", new_recovery_path %>
|
7
7
|
</p>
|
8
8
|
|
9
|
-
<%= form_with url: affirmations_path do |form| %>
|
9
|
+
<%= form_with url: affirmations_path, scope: :user do |form| %>
|
10
10
|
<%= form.label :email %>
|
11
11
|
<%= form.email_field :email, autofocus: true, autocomplete: "email", required: true %>
|
12
12
|
|
@@ -6,7 +6,7 @@
|
|
6
6
|
<%= link_to "Sign in to your account", new_session_path %>
|
7
7
|
</p>
|
8
8
|
|
9
|
-
<%= form_with url: recoveries_path do |form| %>
|
9
|
+
<%= form_with url: recoveries_path, scope: :user do |form| %>
|
10
10
|
<%= form.label :email %>
|
11
11
|
<%= form.email_field :email, autofocus: true, autocomplete: "email", required: true %>
|
12
12
|
|
@@ -0,0 +1,10 @@
|
|
1
|
+
scope module: :avocado do
|
2
|
+
resource :email, only: %i[edit update]
|
3
|
+
resource :password, only: %i[edit update]
|
4
|
+
resources :affirmations, only: %i[new create edit update]
|
5
|
+
resources :events, only: %i[index]
|
6
|
+
resources :recoveries, only: %i[new create edit update]
|
7
|
+
resources :registrations, only: %i[new create]
|
8
|
+
resources :sessions, only: %i[index new create destroy]
|
9
|
+
resources :verifications, only: %i[create edit update]
|
10
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
avocado.rb
|
data/docs/USAGE.md
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
# Overview
|
2
|
+
|
3
|
+
The 🥑 gem is a [Rails Engine] composed of a mixture of Ruby modules that get
|
4
|
+
included into application classes and Ruby classes which will run directly from
|
5
|
+
the 🥑 gem itself. The classes are intended to provide good defaults for basic
|
6
|
+
scenarios, and can be subclassed and overridden for special cases.
|
7
|
+
|
8
|
+
## Requirements
|
9
|
+
|
10
|
+
Apps must be running Rails 7.1 or newer. The 🥑 gem uses features like
|
11
|
+
`authenticate_by`, `has_secure_password`, `generates_token_for`, and
|
12
|
+
`normalizes` which don't exist in earlier versions.
|
13
|
+
|
14
|
+
The database schema must have columns that match the `users`, `sessions`, and
|
15
|
+
`events` tables from the [demo app schema]. More columns in each table are
|
16
|
+
acceptable; the demo is just a minimum. Slight variations (using `uuid` instead
|
17
|
+
of `bigint` for example) are harmless, but large departures will break the
|
18
|
+
integration.
|
19
|
+
|
20
|
+
Run `bin/rails g avocado:migrations` to generate migrations for the tables.
|
21
|
+
|
22
|
+
The application must also have:
|
23
|
+
|
24
|
+
- An `ApplicationController` base controller class
|
25
|
+
- An `ApplicationMailer` base mailer class
|
26
|
+
- A `root_path` method (typically generated by application routes)
|
27
|
+
|
28
|
+
## Usage
|
29
|
+
|
30
|
+
### Models
|
31
|
+
|
32
|
+
Include these modules into `ActiveRecord` model classes:
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
class User < ApplicationRecord
|
36
|
+
include Avocado::User
|
37
|
+
end
|
38
|
+
|
39
|
+
class Session < ApplicationRecord
|
40
|
+
include Avocado::Session
|
41
|
+
end
|
42
|
+
|
43
|
+
class Event < ApplicationRecord
|
44
|
+
include Avocado::Event
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
This will set up some basic associations, validations, callbacks, and
|
49
|
+
normalizations for those models.
|
50
|
+
|
51
|
+
### Controllers
|
52
|
+
|
53
|
+
Add the `Avocado::Authentication` module to the top-level controller:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
class ApplicationController < ActionController::Base
|
57
|
+
include Avocado::Authentication
|
58
|
+
end
|
59
|
+
```
|
60
|
+
|
61
|
+
### Routes
|
62
|
+
|
63
|
+
The 🥑 gem does not add any routes to the application when initialized. To hook
|
64
|
+
up the controllers to routes, they must be added to the `config/routes.rb` of
|
65
|
+
the application. It's possible to add all of the routes, or just a subset.
|
66
|
+
|
67
|
+
Example that defines a root route and also pulls in every feature route:
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
Rails.application.routes.draw do
|
71
|
+
root to: "records#index"
|
72
|
+
draw(🥑)
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
Example that adds only the sign-up, sign-in, and sign-out actions:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
Rails.application.routes.draw do
|
80
|
+
root to: "records#index"
|
81
|
+
scope module: :avocado do
|
82
|
+
resources :registrations, only: %i[new create]
|
83
|
+
resources :sessions, only: %i[new create destroy]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
```
|
87
|
+
|
88
|
+
## Summary
|
89
|
+
|
90
|
+
### Routable controller features
|
91
|
+
|
92
|
+
The 🥑 gem will create REST-ful routes that go to the various controllers during
|
93
|
+
app initialization.
|
94
|
+
|
95
|
+
These external (unauthenticated) features are available:
|
96
|
+
|
97
|
+
- `Registrations` -- Fill out new form and create users
|
98
|
+
- `Sessions` -- Sign in and sign out features
|
99
|
+
- `Recoveries` -- Trigger password reset, click link, confirm
|
100
|
+
- `Verifications` -- Email confirmation on account creation or email change
|
101
|
+
- `Affirmations` -- Provides a "passwordless" auth via emailed link
|
102
|
+
|
103
|
+
These internal (authenticated) features are available:
|
104
|
+
|
105
|
+
- `Sessions` -- List active sessions, click to destroy untrusted ones
|
106
|
+
- `Events` -- List view of user activity audit log
|
107
|
+
- `Passwords` -- Edit and update user password
|
108
|
+
- `Emails` -- Edit and update user email
|
109
|
+
|
110
|
+
Linking to any of these internal pages is optional. Apps can use them as-is,
|
111
|
+
override their views, or even ignore them entirely and make local versions.
|
112
|
+
|
113
|
+
### Mailers
|
114
|
+
|
115
|
+
There is an `Avocado::Mailer` which gets called to send emails. The mailer views
|
116
|
+
here are very basic, and should be overriden within applications. Place views
|
117
|
+
within `app/views/avocado/mailer/` to make this happen.
|
118
|
+
|
119
|
+
### Before actions
|
120
|
+
|
121
|
+
There is an `authenticate` method installed as a default `before_action`. Any
|
122
|
+
actions which do not need to be authenticated should disable this with
|
123
|
+
`skip_before_action`.
|
124
|
+
|
125
|
+
There is a `set_current_request_details` method installed as a default
|
126
|
+
`before_action` which takes some loggable request meta information (user agent,
|
127
|
+
IP address) and sets its value in `Current` so that its accesible to code
|
128
|
+
elsewhere in the 🥑 gem.
|
129
|
+
|
130
|
+
### Helpers
|
131
|
+
|
132
|
+
The `Avocado::Authentication` module included into the application controller
|
133
|
+
provides some helper methods available in controllers, views, and helpers:
|
134
|
+
|
135
|
+
- `signed_in?` is true if the session has a signed in user
|
136
|
+
- `current_session` provides the DB record for the session, if one exists
|
137
|
+
- `current_user` returns the user belonging to that session
|
138
|
+
|
139
|
+
Usage of these can be seen in the views in the [demo app].
|
140
|
+
|
141
|
+
## Customization
|
142
|
+
|
143
|
+
There is not any configuration. To override functionality:
|
144
|
+
|
145
|
+
- Redefine a method created in one of the models by the included module
|
146
|
+
- Subclass a controller and update the routing to go to the subclass
|
147
|
+
- Place views in the app where avocado expects them to override the defaults
|
148
|
+
|
149
|
+
## Examples
|
150
|
+
|
151
|
+
There is a [demo app] used by the specs which has some example usage.
|
152
|
+
|
153
|
+
[demo app schema]: https://github.com/tcuwp/avocado/blob/main/spec/internal/db/schema.rb
|
154
|
+
[demo app]: https://github.com/tcuwp/avocado/blob/main/spec/internal
|
155
|
+
[Rails Engine]: https://guides.rubyonrails.org/engines.html#what-are-engines-questionmark
|
@@ -37,12 +37,12 @@ module Avocado
|
|
37
37
|
|
38
38
|
def sign_in(user)
|
39
39
|
::Session.create!(user: user).tap do |session|
|
40
|
-
cookies.signed.permanent[:session_token] = {value: session.
|
40
|
+
cookies.signed.permanent[:session_token] = {value: session.token, httponly: true}
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
44
|
def session_from_token
|
45
|
-
::Session.
|
45
|
+
::Session.find_by_token(cookies.signed[:session_token])
|
46
46
|
end
|
47
47
|
|
48
48
|
def set_current_request_details
|
data/lib/avocado/engine.rb
CHANGED
data/lib/avocado/session.rb
CHANGED
@@ -4,11 +4,17 @@ module Avocado
|
|
4
4
|
module Session
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
|
+
SECURE_TOKEN_LENGTH = 64
|
8
|
+
|
7
9
|
included do
|
8
10
|
include SessionCallbacks
|
9
11
|
|
12
|
+
has_secure_token length: SECURE_TOKEN_LENGTH, on: :initialize
|
13
|
+
|
10
14
|
belongs_to :user
|
11
15
|
|
16
|
+
validates :token, presence: true
|
17
|
+
|
12
18
|
scope :newest_first, -> { order(created_at: :desc) }
|
13
19
|
scope :non_current, -> { where.not(id: Current.session) }
|
14
20
|
end
|
data/lib/avocado/version.rb
CHANGED
data/lib/avocado.rb
CHANGED
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators/base"
|
4
|
+
require "rails/generators/active_record"
|
5
|
+
|
6
|
+
module Avocado
|
7
|
+
class MigrationsGenerator < Rails::Generators::Base
|
8
|
+
include ActiveRecord::Generators::Migration
|
9
|
+
|
10
|
+
source_root File.expand_path("templates", __dir__)
|
11
|
+
|
12
|
+
def create_migrations
|
13
|
+
migration_template "create_users.rb", "#{db_migrate_path}/create_users.rb"
|
14
|
+
migration_template "create_sessions.rb", "#{db_migrate_path}/create_sessions.rb"
|
15
|
+
migration_template "create_events.rb", "#{db_migrate_path}/create_events.rb"
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def primary_and_foreign_key_types
|
21
|
+
config = Rails.configuration.generators
|
22
|
+
setting = config.options[config.orm][:primary_key_type]
|
23
|
+
primary_key_type = setting || :primary_key
|
24
|
+
foreign_key_type = setting || :bigint
|
25
|
+
[primary_key_type, foreign_key_type]
|
26
|
+
end
|
27
|
+
|
28
|
+
def primary_key_type
|
29
|
+
primary_and_foreign_key_types.first
|
30
|
+
end
|
31
|
+
|
32
|
+
def foreign_key_type
|
33
|
+
primary_and_foreign_key_types.last
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
|
2
|
+
def change
|
3
|
+
create_table :events, id: :<%= primary_key_type %> do |t|
|
4
|
+
t.references :user, null: false, foreign_key: true, type: :<%= foreign_key_type %>
|
5
|
+
t.string :action, null: false
|
6
|
+
t.string :user_agent
|
7
|
+
t.string :ip_address
|
8
|
+
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
|
2
|
+
def change
|
3
|
+
create_table :sessions, id: :<%= primary_key_type %> do |t|
|
4
|
+
t.references :user, null: false, foreign_key: true, type: :<%= foreign_key_type %>
|
5
|
+
t.string :token, null: false, index: {unique: true}
|
6
|
+
t.string :user_agent
|
7
|
+
t.string :ip_address
|
8
|
+
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
|
2
|
+
def change
|
3
|
+
create_table :users, id: :<%= primary_key_type %> do |t|
|
4
|
+
t.string :email, null: false, index: {unique: true}
|
5
|
+
t.string :password_digest, null: false
|
6
|
+
t.boolean :verified, null: false, default: false, index: true
|
7
|
+
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: avocado
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.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-07-
|
11
|
+
date: 2023-07-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bcrypt
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '3.1'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '3.1'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rails
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,34 +38,6 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 7.1.0.alpha
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: combustion
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '1.3'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '1.3'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: sqlite3
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
41
|
description:
|
70
42
|
email:
|
71
43
|
- matt@jankowski.online
|
@@ -89,6 +61,7 @@ files:
|
|
89
61
|
- app/controllers/avocado/registrations_controller.rb
|
90
62
|
- app/controllers/avocado/sessions_controller.rb
|
91
63
|
- app/controllers/avocado/verifications_controller.rb
|
64
|
+
- app/views/avocado/affirmations/edit.html.erb
|
92
65
|
- app/views/avocado/affirmations/new.html.erb
|
93
66
|
- app/views/avocado/emails/edit.html.erb
|
94
67
|
- app/views/avocado/events/_event.html.erb
|
@@ -103,8 +76,11 @@ files:
|
|
103
76
|
- app/views/avocado/sessions/_session.html.erb
|
104
77
|
- app/views/avocado/sessions/index.html.erb
|
105
78
|
- app/views/avocado/sessions/new.html.erb
|
79
|
+
- app/views/avocado/verifications/edit.html.erb
|
106
80
|
- config.ru
|
107
|
-
- config/routes.rb
|
81
|
+
- config/routes/avocado.rb
|
82
|
+
- "config/routes/\U0001F951.rb"
|
83
|
+
- docs/USAGE.md
|
108
84
|
- lib/avocado.rb
|
109
85
|
- lib/avocado/authentication.rb
|
110
86
|
- lib/avocado/current.rb
|
@@ -118,6 +94,10 @@ files:
|
|
118
94
|
- lib/avocado/user_tokens.rb
|
119
95
|
- lib/avocado/user_validations.rb
|
120
96
|
- lib/avocado/version.rb
|
97
|
+
- lib/generators/avocado/migrations/migrations_generator.rb
|
98
|
+
- lib/generators/avocado/migrations/templates/create_events.rb.tt
|
99
|
+
- lib/generators/avocado/migrations/templates/create_sessions.rb.tt
|
100
|
+
- lib/generators/avocado/migrations/templates/create_users.rb.tt
|
121
101
|
- sig/avocado.rbs
|
122
102
|
homepage: https://github.com/tcuwp/avocado
|
123
103
|
licenses:
|
data/config/routes.rb
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
Rails.application.routes.draw do
|
2
|
-
scope module: :avocado do
|
3
|
-
resource :email, only: %i[edit update]
|
4
|
-
resource :password, only: %i[edit update]
|
5
|
-
resources :affirmations, only: %i[new show create]
|
6
|
-
resources :events, only: %i[index]
|
7
|
-
resources :recoveries, only: %i[new create edit update]
|
8
|
-
resources :registrations, only: %i[new create]
|
9
|
-
resources :sessions, only: %i[index new create destroy]
|
10
|
-
resources :verifications, only: %i[show create]
|
11
|
-
end
|
12
|
-
end
|