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.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/README.md +8 -43
  4. data/app/controllers/avocado/affirmations_controller.rb +11 -12
  5. data/app/controllers/avocado/base_controller.rb +12 -0
  6. data/app/controllers/avocado/emails_controller.rb +4 -4
  7. data/app/controllers/avocado/passwords_controller.rb +4 -4
  8. data/app/controllers/avocado/recoveries_controller.rb +9 -13
  9. data/app/controllers/avocado/registrations_controller.rb +4 -4
  10. data/app/controllers/avocado/sessions_controller.rb +4 -4
  11. data/app/controllers/avocado/verifications_controller.rb +5 -2
  12. data/app/views/avocado/affirmations/edit.html.erb +7 -0
  13. data/app/views/avocado/affirmations/new.html.erb +1 -1
  14. data/app/views/avocado/mailer/email_affirmation.text.erb +1 -1
  15. data/app/views/avocado/mailer/email_verification.text.erb +1 -1
  16. data/app/views/avocado/recoveries/new.html.erb +1 -1
  17. data/app/views/avocado/verifications/edit.html.erb +7 -0
  18. data/config/routes/avocado.rb +10 -0
  19. data/config/routes//360/237/245/221.rb +1 -0
  20. data/docs/USAGE.md +155 -0
  21. data/lib/avocado/authentication.rb +2 -2
  22. data/lib/avocado/engine.rb +5 -0
  23. data/lib/avocado/session.rb +6 -0
  24. data/lib/avocado/version.rb +1 -1
  25. data/lib/avocado.rb +1 -0
  26. data/lib/generators/avocado/migrations/migrations_generator.rb +36 -0
  27. data/lib/generators/avocado/migrations/templates/create_events.rb.tt +12 -0
  28. data/lib/generators/avocado/migrations/templates/create_sessions.rb.tt +12 -0
  29. data/lib/generators/avocado/migrations/templates/create_users.rb.tt +11 -0
  30. metadata +15 -35
  31. data/config/routes.rb +0 -12
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a530ebf9605c2bb861d2da09da546513e68c4f647fc97c80686e07b32985cabe
4
- data.tar.gz: 3be481be5c31ce2ee3bb1ea1a2d796bb7f8cbe850f7ccf2de6f296384a656bb2
3
+ metadata.gz: 393630ca933c51e34b00e2fe86bbcfb5caa4ea7764fc34882c21ef4f604bb938
4
+ data.tar.gz: bfc5362c53ecee86c6369a1318c68fddf2bbd7e457287cb5b9c6b57970ded8aa
5
5
  SHA512:
6
- metadata.gz: cf3320eb985cc65c05c2da2d007697b4b9016d9a85f7ebebbd0735d744d7f8ca77096d86182c6761b63ea6f51f4b942a3c2dd363bb102ccc4ed53da6f5702c4f
7
- data.tar.gz: f0b021b9e0f3433f2034e5cccdc751a446b50bc870474376e1a39b84e973bbabfaef95b59d96f60986bbddc7695afe88b860bd2d1568f991a17b3b654d7f3995
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
- # Avocado
1
+ # 🥑
2
2
 
3
- A collection of authentication tools for use in [Rails] 7.1+ applications.
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
- If you are nervous about using Rails features directly, preferring to consume
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. Then, run
54
- `rake spec` to run the tests. You can also run `bin/console` for an interactive
55
- prompt that will allow you to experiment.
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
- [the demo app schema]: https://github.com/tcuwp/avocado/blob/main/spec/internal/db/schema.rb
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: :show
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 user_from_params_email
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(user_from_params_email)
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
- PERMITTED_PARAMS = [:email]
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(user_params)
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 user_params
27
+ def update_parameters
28
28
  params
29
29
  .require(:user)
30
- .permit(PERMITTED_PARAMS)
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
- PERMITTED_PARAMS = [:password, :password_confirmation, :password_challenge]
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(user_params)
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 user_params
27
+ def update_parameters
28
28
  params
29
29
  .require(:user)
30
- .permit(PERMITTED_PARAMS)
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
- PERMITTED_PARAMS = %i[password password_confirmation]
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(user_params)
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 user_from_params_email
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 user_params
49
+ def update_parameters
50
50
  params
51
51
  .require(:user)
52
- .permit(PERMITTED_PARAMS)
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(user_from_params_email)
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
- PERMITTED_PARAMS = %i[email password password_confirmation]
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(user_params)
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 user_params
28
+ def initialization_parameters
29
29
  params
30
30
  .require(:user)
31
- .permit(PERMITTED_PARAMS)
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
- PERMITTED_PARAMS = %i[email password]
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 session_params
36
+ def authentication_parameters
37
37
  params
38
38
  .require(:session)
39
- .permit(PERMITTED_PARAMS)
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(session_params)
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: :show do
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 show
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
@@ -0,0 +1,7 @@
1
+ <h2>
2
+ Sign in without password
3
+ </h2>
4
+
5
+ <%= form_with url: affirmation_path(id: params[:id]), method: :patch do |form| %>
6
+ <%= form.button "Submit", name: nil %>
7
+ <% 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
 
@@ -1,3 +1,3 @@
1
1
  Sign in by following this link:
2
2
 
3
- <%= affirmation_url(id: @signed_id) %>
3
+ <%= edit_affirmation_url(id: @signed_id) %>
@@ -1,3 +1,3 @@
1
1
  Verify your email by following this link:
2
2
 
3
- <%= verification_url(id: @signed_id) %>
3
+ <%= edit_verification_url(id: @signed_id) %>
@@ -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,7 @@
1
+ <h2>
2
+ Verify your email
3
+ </h2>
4
+
5
+ <%= form_with url: verification_path(id: params[:id]), method: :patch do |form| %>
6
+ <%= form.button "Submit", name: nil %>
7
+ <% end -%>
@@ -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.id, httponly: true}
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.find_by_id(cookies.signed[:session_token])
45
+ ::Session.find_by_token(cookies.signed[:session_token])
46
46
  end
47
47
 
48
48
  def set_current_request_details
@@ -5,5 +5,10 @@ require "rails/engine"
5
5
 
6
6
  module Avocado
7
7
  class Engine < Rails::Engine
8
+ initializer :avocado_routing do
9
+ ActiveSupport.on_load(:action_dispatch_request) do
10
+ ActionDispatch::Routing::Mapper.define_method(:🥑) { :🥑 }
11
+ end
12
+ end
8
13
  end
9
14
  end
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Avocado
4
- VERSION = "0.5.0"
4
+ VERSION = "0.6.0"
5
5
  end
data/lib/avocado.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support"
3
4
  require_relative "avocado/engine"
4
5
 
5
6
  module Avocado
@@ -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.5.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-21 00:00:00.000000000 Z
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: '0'
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: '0'
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