rails_simple_auth 1.0.1 → 1.0.2

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +77 -5
  3. data/app/controllers/rails_simple_auth/confirmations_controller.rb +19 -17
  4. data/app/controllers/rails_simple_auth/omniauth_callbacks_controller.rb +6 -4
  5. data/app/controllers/rails_simple_auth/passwords_controller.rb +13 -12
  6. data/app/controllers/rails_simple_auth/registrations_controller.rb +6 -4
  7. data/app/controllers/rails_simple_auth/sessions_controller.rb +21 -16
  8. data/app/mailers/rails_simple_auth/auth_mailer.rb +10 -7
  9. data/app/views/rails_simple_auth/confirmations/new.html.erb +2 -2
  10. data/app/views/rails_simple_auth/passwords/new.html.erb +2 -2
  11. data/app/views/rails_simple_auth/registrations/new.html.erb +5 -5
  12. data/app/views/rails_simple_auth/sessions/magic_link_form.html.erb +2 -2
  13. data/app/views/rails_simple_auth/sessions/new.html.erb +2 -2
  14. data/lib/generators/rails_simple_auth/css/css_generator.rb +20 -20
  15. data/lib/generators/rails_simple_auth/install/install_generator.rb +32 -32
  16. data/lib/generators/rails_simple_auth/install/templates/initializer.rb +3 -3
  17. data/lib/generators/rails_simple_auth/install/templates/migration.rb +2 -2
  18. data/lib/generators/rails_simple_auth/temporary_users/USAGE +21 -0
  19. data/lib/generators/rails_simple_auth/temporary_users/templates/add_temporary_to_users.rb.erb +8 -0
  20. data/lib/generators/rails_simple_auth/temporary_users/temporary_users_generator.rb +40 -0
  21. data/lib/generators/rails_simple_auth/views/views_generator.rb +8 -8
  22. data/lib/rails_simple_auth/configuration.rb +21 -7
  23. data/lib/rails_simple_auth/controllers/concerns/authentication.rb +17 -18
  24. data/lib/rails_simple_auth/controllers/concerns/session_management.rb +24 -0
  25. data/lib/rails_simple_auth/engine.rb +1 -1
  26. data/lib/rails_simple_auth/models/concerns/authenticatable.rb +13 -5
  27. data/lib/rails_simple_auth/models/concerns/confirmable.rb +38 -3
  28. data/lib/rails_simple_auth/models/concerns/oauth_connectable.rb +5 -5
  29. data/lib/rails_simple_auth/models/concerns/temporary_user.rb +105 -0
  30. data/lib/rails_simple_auth/models/session.rb +2 -4
  31. data/lib/rails_simple_auth/routes.rb +15 -15
  32. data/lib/rails_simple_auth/version.rb +1 -1
  33. data/lib/rails_simple_auth.rb +14 -12
  34. metadata +15 -11
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsSimpleAuth
4
+ module Models
5
+ module Concerns
6
+ module TemporaryUser
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ scope :temporary, -> { where(temporary: true) }
11
+ scope :permanent, -> { where(temporary: false) }
12
+ scope :temporary_expired, lambda { |days = nil|
13
+ cleanup_days = days || RailsSimpleAuth.configuration.temporary_user_cleanup_days
14
+ raise ConfigurationError, 'temporary_user_cleanup_days must be configured' unless cleanup_days&.positive?
15
+
16
+ temporary.where(created_at: ...cleanup_days.days.ago)
17
+ }
18
+ end
19
+
20
+ def temporary?
21
+ temporary == true
22
+ end
23
+
24
+ def permanent?
25
+ !temporary?
26
+ end
27
+
28
+ # Convert a temporary user to a permanent user with email and password
29
+ # Returns self on success, false on failure (with errors populated)
30
+ def convert_to_permanent!(email:, password:)
31
+ # Validate email uniqueness upfront (better UX than failing inside transaction)
32
+ if self.class.where.not(id: id).exists?(email: email)
33
+ errors.add(:email, 'has already been taken')
34
+ return false
35
+ end
36
+
37
+ transaction do
38
+ # Reload to discard any unpersisted changes from callbacks before locking
39
+ reload
40
+ lock!
41
+
42
+ unless temporary?
43
+ errors.add(:base, 'User is already permanent')
44
+ raise ActiveRecord::Rollback
45
+ end
46
+
47
+ attrs = {
48
+ email: email,
49
+ password: password,
50
+ temporary: false
51
+ }
52
+ # Reset confirmation so new email requires verification
53
+ attrs[:confirmed_at] = nil if respond_to?(:confirmed_at)
54
+
55
+ raise ActiveRecord::Rollback unless update(attrs)
56
+ end
57
+
58
+ # Check if transaction was rolled back
59
+ return false if errors.any? || temporary?
60
+
61
+ invalidate_all_sessions!
62
+ send_conversion_confirmation_email
63
+ Rails.logger.info("[RailsSimpleAuth] Converted temporary user #{id} to permanent")
64
+ self
65
+ rescue ActiveRecord::RecordNotUnique
66
+ errors.add(:email, 'has already been taken')
67
+ false
68
+ end
69
+
70
+ class_methods do
71
+ # Cleanup expired temporary users in batches
72
+ # @param days [Integer, nil] Override for cleanup_days config
73
+ # @param batch_size [Integer] Number of users to process per batch
74
+ # @return [Integer] Number of users destroyed
75
+ def cleanup_expired_temporary!(days: nil, batch_size: 100)
76
+ count = 0
77
+ temporary_expired(days).find_each(batch_size: batch_size) do |user|
78
+ user.destroy
79
+ count += 1
80
+ end
81
+ Rails.logger.info("[RailsSimpleAuth] Cleaned up #{count} expired temporary users")
82
+ count
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ def send_conversion_confirmation_email
89
+ return unless RailsSimpleAuth.configuration.email_confirmation_enabled
90
+ return unless respond_to?(:generate_confirmation_token)
91
+
92
+ token = generate_confirmation_token
93
+ RailsSimpleAuth.configuration.mailer.confirmation(self, token).deliver_later
94
+
95
+ Rails.logger.info("[RailsSimpleAuth] Queued confirmation email for converted user #{id}")
96
+ rescue ArgumentError, NoMethodError, RailsSimpleAuth::ConfigurationError => e
97
+ # Configuration or method errors - log but don't fail conversion
98
+ Rails.logger.error(
99
+ "[RailsSimpleAuth] Failed to send confirmation email for user #{id}: #{e.class}: #{e.message}"
100
+ )
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -1,14 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsSimpleAuth
4
- class Session < ActiveRecord::Base
5
- self.table_name = "sessions"
4
+ class Session < ::ApplicationRecord
5
+ self.table_name = 'sessions'
6
6
 
7
7
  # Use lambda to defer class resolution until runtime
8
8
  belongs_to :user, class_name: -> { RailsSimpleAuth.configuration.user_class_name }
9
9
 
10
- validates :user_id, presence: true
11
-
12
10
  scope :recent, -> { order(created_at: :desc) }
13
11
  scope :active, -> { where(created_at: RailsSimpleAuth.configuration.session_expiry.ago..) }
14
12
  scope :expired, -> { where(created_at: ...RailsSimpleAuth.configuration.session_expiry.ago) }
@@ -4,11 +4,11 @@ module RailsSimpleAuth
4
4
  module Routes
5
5
  def rails_simple_auth_routes(options = {})
6
6
  controllers = {
7
- sessions: options.fetch(:sessions_controller, "rails_simple_auth/sessions"),
8
- registrations: options.fetch(:registrations_controller, "rails_simple_auth/registrations"),
9
- passwords: options.fetch(:passwords_controller, "rails_simple_auth/passwords"),
10
- confirmations: options.fetch(:confirmations_controller, "rails_simple_auth/confirmations"),
11
- omniauth: options.fetch(:omniauth_controller, "rails_simple_auth/omniauth_callbacks")
7
+ sessions: options.fetch(:sessions_controller, 'rails_simple_auth/sessions'),
8
+ registrations: options.fetch(:registrations_controller, 'rails_simple_auth/registrations'),
9
+ passwords: options.fetch(:passwords_controller, 'rails_simple_auth/passwords'),
10
+ confirmations: options.fetch(:confirmations_controller, 'rails_simple_auth/confirmations'),
11
+ omniauth: options.fetch(:omniauth_controller, 'rails_simple_auth/omniauth_callbacks')
12
12
  }
13
13
 
14
14
  config = RailsSimpleAuth.configuration
@@ -16,29 +16,29 @@ module RailsSimpleAuth
16
16
  # Core authentication routes (always registered)
17
17
  resource :session, only: %i[new create destroy], controller: controllers[:sessions]
18
18
 
19
- get "sign_up", to: "#{controllers[:registrations]}#new", as: :sign_up
20
- post "sign_up", to: "#{controllers[:registrations]}#create"
19
+ get 'sign_up', to: "#{controllers[:registrations]}#new", as: :sign_up
20
+ post 'sign_up', to: "#{controllers[:registrations]}#create"
21
21
 
22
22
  resources :passwords, param: :token, only: %i[new create edit update], controller: controllers[:passwords]
23
23
 
24
24
  # Email confirmation routes (only when enabled)
25
25
  if config.email_confirmation_enabled
26
26
  resources :confirmations, only: %i[new create], controller: controllers[:confirmations]
27
- get "confirmations/:token", to: "#{controllers[:confirmations]}#show", as: :confirmation
27
+ get 'confirmations/:token', to: "#{controllers[:confirmations]}#show", as: :confirmation
28
28
  end
29
29
 
30
30
  # Magic link routes (only when enabled)
31
31
  if config.magic_link_enabled
32
- get "magic_link_form", to: "#{controllers[:sessions]}#magic_link_form", as: :magic_link_form
33
- post "request_magic_link", to: "#{controllers[:sessions]}#request_magic_link", as: :request_magic_link
34
- get "magic_link", to: "#{controllers[:sessions]}#magic_link_login", as: :magic_link
32
+ get 'magic_link_form', to: "#{controllers[:sessions]}#magic_link_form", as: :magic_link_form
33
+ post 'request_magic_link', to: "#{controllers[:sessions]}#request_magic_link", as: :request_magic_link
34
+ get 'magic_link', to: "#{controllers[:sessions]}#magic_link_login", as: :magic_link
35
35
  end
36
36
 
37
37
  # OAuth routes (only when enabled)
38
- if config.oauth_enabled
39
- get "/auth/:provider/callback", to: "#{controllers[:omniauth]}#create", as: :omniauth_callback
40
- get "/auth/failure", to: "#{controllers[:omniauth]}#failure", as: :omniauth_failure
41
- end
38
+ return unless config.oauth_enabled
39
+
40
+ get '/auth/:provider/callback', to: "#{controllers[:omniauth]}#create", as: :omniauth_callback
41
+ get '/auth/failure', to: "#{controllers[:omniauth]}#failure", as: :omniauth_failure
42
42
  end
43
43
  end
44
44
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsSimpleAuth
4
- VERSION = "1.0.1"
4
+ VERSION = '1.0.2'
5
5
  end
@@ -1,23 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rails_simple_auth/version"
4
- require "rails_simple_auth/configuration"
5
- require "rails_simple_auth/engine"
3
+ require 'rails_simple_auth/version'
4
+ require 'rails_simple_auth/configuration'
5
+ require 'rails_simple_auth/engine'
6
6
 
7
7
  # Model concerns
8
- require "rails_simple_auth/models/concerns/authenticatable"
9
- require "rails_simple_auth/models/concerns/confirmable"
10
- require "rails_simple_auth/models/concerns/magic_linkable"
11
- require "rails_simple_auth/models/concerns/oauth_connectable"
12
- require "rails_simple_auth/models/current"
13
- require "rails_simple_auth/models/session"
8
+ require 'rails_simple_auth/models/concerns/authenticatable'
9
+ require 'rails_simple_auth/models/concerns/confirmable'
10
+ require 'rails_simple_auth/models/concerns/magic_linkable'
11
+ require 'rails_simple_auth/models/concerns/oauth_connectable'
12
+ require 'rails_simple_auth/models/concerns/temporary_user'
13
+ require 'rails_simple_auth/models/current'
14
+ # Session is NOT required here - it depends on ApplicationRecord which isn't available at gem load time
15
+ # It will be autoloaded by the engine when Rails is ready
14
16
 
15
17
  # Controller concerns
16
- require "rails_simple_auth/controllers/concerns/authentication"
17
- require "rails_simple_auth/controllers/concerns/session_management"
18
+ require 'rails_simple_auth/controllers/concerns/authentication'
19
+ require 'rails_simple_auth/controllers/concerns/session_management'
18
20
 
19
21
  # Routes
20
- require "rails_simple_auth/routes"
22
+ require 'rails_simple_auth/routes'
21
23
 
22
24
  module RailsSimpleAuth
23
25
  class Error < StandardError; end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_simple_auth
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ivan Kuznetsov
@@ -10,33 +10,33 @@ cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
- name: rails
13
+ name: bcrypt
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
- - - ">="
16
+ - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: '8.0'
18
+ version: '3.1'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
- - - ">="
23
+ - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: '8.0'
25
+ version: '3.1'
26
26
  - !ruby/object:Gem::Dependency
27
- name: bcrypt
27
+ name: rails
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
- - - "~>"
30
+ - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: '3.1'
32
+ version: '8.0'
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - "~>"
37
+ - - ">="
38
38
  - !ruby/object:Gem::Version
39
- version: '3.1'
39
+ version: '8.0'
40
40
  description: 'A lightweight authentication gem built on Rails primitives: has_secure_password,
41
41
  signed cookies, rate limiting. Supports email/password, magic links, email confirmation,
42
42
  and OAuth.'
@@ -72,6 +72,9 @@ files:
72
72
  - lib/generators/rails_simple_auth/install/install_generator.rb
73
73
  - lib/generators/rails_simple_auth/install/templates/initializer.rb
74
74
  - lib/generators/rails_simple_auth/install/templates/migration.rb
75
+ - lib/generators/rails_simple_auth/temporary_users/USAGE
76
+ - lib/generators/rails_simple_auth/temporary_users/templates/add_temporary_to_users.rb.erb
77
+ - lib/generators/rails_simple_auth/temporary_users/temporary_users_generator.rb
75
78
  - lib/generators/rails_simple_auth/views/views_generator.rb
76
79
  - lib/rails_simple_auth.rb
77
80
  - lib/rails_simple_auth/configuration.rb
@@ -82,6 +85,7 @@ files:
82
85
  - lib/rails_simple_auth/models/concerns/confirmable.rb
83
86
  - lib/rails_simple_auth/models/concerns/magic_linkable.rb
84
87
  - lib/rails_simple_auth/models/concerns/oauth_connectable.rb
88
+ - lib/rails_simple_auth/models/concerns/temporary_user.rb
85
89
  - lib/rails_simple_auth/models/current.rb
86
90
  - lib/rails_simple_auth/models/session.rb
87
91
  - lib/rails_simple_auth/routes.rb