plutonium 0.12.14 → 0.13.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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/Appraisals +1 -1
  3. data/app/assets/plutonium.css +1 -1
  4. data/app/views/application/_flash.html.erb +1 -1
  5. data/app/views/application/_flash_toasts.html.erb +1 -1
  6. data/app/views/layouts/rodauth.html.erb +7 -8
  7. data/app/views/rodauth/_email_auth_request_form.html.erb +2 -2
  8. data/app/views/rodauth/_login_form.html.erb +24 -18
  9. data/app/views/rodauth/_login_form_footer.html.erb +1 -1
  10. data/app/views/rodauth/change_login.html.erb +20 -11
  11. data/app/views/rodauth/change_password.html.erb +11 -11
  12. data/app/views/rodauth/close_account.html.erb +4 -4
  13. data/app/views/rodauth/create_account.html.erb +44 -18
  14. data/app/views/rodauth/email_auth.html.erb +2 -2
  15. data/app/views/rodauth/login.html.erb +3 -5
  16. data/app/views/rodauth/logout.html.erb +7 -4
  17. data/app/views/rodauth/otp_auth.html.erb +5 -6
  18. data/app/views/rodauth/otp_disable.html.erb +4 -5
  19. data/app/views/rodauth/otp_setup.html.erb +8 -8
  20. data/app/views/rodauth/recovery_auth.html.erb +5 -5
  21. data/app/views/rodauth/recovery_codes.html.erb +5 -5
  22. data/app/views/rodauth/remember.html.erb +2 -2
  23. data/app/views/rodauth/reset_password.html.erb +8 -8
  24. data/app/views/rodauth/reset_password_request.html.erb +14 -10
  25. data/app/views/rodauth/sms_auth.html.erb +4 -4
  26. data/app/views/rodauth/sms_confirm.html.erb +4 -4
  27. data/app/views/rodauth/sms_disable.html.erb +5 -5
  28. data/app/views/rodauth/sms_request.html.erb +2 -2
  29. data/app/views/rodauth/sms_setup.html.erb +7 -7
  30. data/app/views/rodauth/two_factor_disable.html.erb +4 -4
  31. data/app/views/rodauth/unlock_account.html.erb +8 -10
  32. data/app/views/rodauth/unlock_account_request.html.erb +5 -7
  33. data/app/views/rodauth/verify_account.html.erb +8 -8
  34. data/app/views/rodauth/verify_account_resend.html.erb +13 -10
  35. data/app/views/rodauth/verify_login_change.html.erb +2 -2
  36. data/app/views/rodauth/webauthn_auth.html.erb +2 -2
  37. data/app/views/rodauth/webauthn_remove.html.erb +5 -5
  38. data/app/views/rodauth/webauthn_setup.html.erb +5 -5
  39. data/lib/generators/pu/rodauth/install_generator.rb +0 -5
  40. data/lib/generators/pu/rodauth/migration/active_record/audit_logging.erb +2 -2
  41. data/lib/generators/pu/rodauth/migration_generator.rb +30 -51
  42. data/lib/generators/pu/rodauth/templates/app/mailers/rodauth_mailer.rb.tt +1 -0
  43. data/lib/generators/pu/rodauth/templates/app/models/account.rb.tt +0 -8
  44. data/lib/generators/pu/rodauth/templates/app/rodauth/rodauth_plugin.rb.tt +8 -2
  45. data/lib/generators/pu/rodauth/templates/db/migrate/create_rodauth.rb.tt +0 -8
  46. data/lib/plutonium/auth/rodauth.rb +3 -1
  47. data/lib/plutonium/core/controllers/base.rb +1 -1
  48. data/lib/plutonium/helpers/display_helper.rb +8 -6
  49. data/lib/plutonium/helpers/form_helper.rb +17 -5
  50. data/lib/plutonium/rodauth/controller_methods.rb +1 -0
  51. data/lib/plutonium/version.rb +1 -1
  52. metadata +2 -21
  53. data/lib/generators/pu/rodauth/migration/sequel/account_expiration.erb +0 -7
  54. data/lib/generators/pu/rodauth/migration/sequel/active_sessions.erb +0 -8
  55. data/lib/generators/pu/rodauth/migration/sequel/audit_logging.erb +0 -17
  56. data/lib/generators/pu/rodauth/migration/sequel/base.erb +0 -25
  57. data/lib/generators/pu/rodauth/migration/sequel/disallow_password_reuse.erb +0 -6
  58. data/lib/generators/pu/rodauth/migration/sequel/email_auth.erb +0 -7
  59. data/lib/generators/pu/rodauth/migration/sequel/jwt_refresh.erb +0 -8
  60. data/lib/generators/pu/rodauth/migration/sequel/lockout.erb +0 -11
  61. data/lib/generators/pu/rodauth/migration/sequel/otp.erb +0 -7
  62. data/lib/generators/pu/rodauth/migration/sequel/password_expiration.erb +0 -5
  63. data/lib/generators/pu/rodauth/migration/sequel/recovery_codes.erb +0 -6
  64. data/lib/generators/pu/rodauth/migration/sequel/remember.erb +0 -6
  65. data/lib/generators/pu/rodauth/migration/sequel/reset_password.erb +0 -7
  66. data/lib/generators/pu/rodauth/migration/sequel/separate_passwords.erb +0 -6
  67. data/lib/generators/pu/rodauth/migration/sequel/single_session.erb +0 -5
  68. data/lib/generators/pu/rodauth/migration/sequel/sms_codes.erb +0 -8
  69. data/lib/generators/pu/rodauth/migration/sequel/verify_account.erb +0 -7
  70. data/lib/generators/pu/rodauth/migration/sequel/verify_login_change.erb +0 -7
  71. data/lib/generators/pu/rodauth/migration/sequel/webauthn.erb +0 -13
@@ -1,17 +1,20 @@
1
- <%= form_with url: rodauth.verify_account_resend_path, method: :post, data: { turbo: false }, class: "w-full max-w-sm" do |form| %>
2
- <div class="mb-4 text-sm">
3
- <%== rodauth.verify_account_resend_explanatory_text %>
4
- </div>
5
-
1
+ <div class="mb-4 text-sm text-gray-500 dark:text-gray-400">
2
+ <%== rodauth.verify_account_resend_explanatory_text %>
3
+ </div>
4
+ <%= form_with url: rodauth.verify_account_resend_path, method: :post, data: { turbo: false }, class: "space-y-4" do |form| %>
6
5
  <% if params[rodauth.login_param] %>
7
6
  <%= form.hidden_field rodauth.login_param, value: params[rodauth.login_param] %>
8
7
  <% else %>
9
- <div class="mb-6">
10
- <%= form.label "login", rodauth.login_label, class: "block text-sm font-semibold" %>
11
- <%= form.email_field rodauth.login_param, value: params[rodauth.login_param], id: "login", autocomplete: "email", required: true, class: "mt-2 text-sm w-full px-3 py-2 border rounded-md dark:bg-gray-900 dark:text-gray-100 dark:focus:bg-gray-800 #{rodauth.field_error(rodauth.login_param) ? "border-red-600 focus:ring-red-600 focus:border-red-600 dark:border-red-400 dark:focus:ring-red-400" : "border-gray-300 dark:border-gray-700 dark:focus:border-emerald-400 dark:focus:ring-emerald-400" }", aria: ({ invalid: true, describedby: "login_error_message" } if rodauth.field_error(rodauth.login_param)) %>
8
+ <div>
9
+ <%= form.label "login", rodauth.login_label, class: "block mb-2 text-sm font-semibold text-gray-900 dark:text-white" %>
10
+ <%= form.email_field rodauth.login_param, value: params[rodauth.login_param],
11
+ id: "login",
12
+ autocomplete: "email",
13
+ required: true,
14
+ placeholder: "jane@acme.inc",
15
+ class: "bg-gray-50 border border-gray-300 text-gray-900 rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500 #{rodauth.field_error(rodauth.login_param) ? "border-red-600 focus:ring-red-600 focus:border-red-600 dark:border-red-400 dark:focus:ring-red-400" : "border-gray-300 dark:border-gray-700 dark:focus:border-emerald-400 dark:focus:ring-emerald-400" }", aria: ({ invalid: true, describedby: "login_error_message" } if rodauth.field_error(rodauth.login_param)) %>
12
16
  <%= content_tag(:span, rodauth.field_error(rodauth.login_param), class: "block mt-1 text-red-600 text-xs dark:text-red-400", id: "login_error_message") if rodauth.field_error(rodauth.login_param) %>
13
17
  </div>
14
18
  <% end %>
15
-
16
- <%= form.submit rodauth.verify_account_resend_button, class: "w-full px-8 py-3 cursor-pointer font-semibold text-sm rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-600 dark:bg-emerald-400 dark:hover:bg-emerald-500 dark:text-gray-900 dark:focus:ring-emerald-400 dark:focus:ring-offset-current" %>
19
+ <%= form.submit rodauth.verify_account_resend_button, class: "w-full text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-semibold rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800" %>
17
20
  <% end %>
@@ -1,3 +1,3 @@
1
- <%= form_with url: rodauth.verify_login_change_path, method: :post, data: { turbo: false }, class: "w-full max-w-sm" do |form| %>
2
- <%= form.submit rodauth.verify_login_change_button, class: "w-full px-8 py-3 cursor-pointer font-semibold text-sm rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-600 dark:bg-emerald-400 dark:hover:bg-emerald-500 dark:text-gray-900 dark:focus:ring-emerald-400 dark:focus:ring-offset-current" %>
1
+ <%= form_with url: rodauth.verify_login_change_path, method: :post, data: { turbo: false }, class: "space-y-4" do |form| %>
2
+ <%= form.submit rodauth.verify_login_change_button, class: "w-full text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-semibold rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800" %>
3
3
  <% end %>
@@ -1,12 +1,12 @@
1
1
  <% cred = rodauth.webauthn_credential_options_for_get %>
2
2
 
3
- <%= form_with url: rodauth.webauthn_auth_form_path, method: :post, id: "webauthn-auth-form", data: { credential_options: cred.as_json.to_json, turbo: false }, class: "w-full max-w-sm" do |form| %>
3
+ <%= form_with url: rodauth.webauthn_auth_form_path, method: :post, id: "webauthn-auth-form", data: { credential_options: cred.as_json.to_json, turbo: false }, class: "space-y-4" do |form| %>
4
4
  <%= form.hidden_field rodauth.login_param, value: params[rodauth.login_param] %>
5
5
  <%= form.hidden_field rodauth.webauthn_auth_challenge_param, value: cred.challenge %>
6
6
  <%= form.hidden_field rodauth.webauthn_auth_challenge_hmac_param, value: rodauth.compute_hmac(cred.challenge) %>
7
7
  <%= form.text_field rodauth.webauthn_auth_param, value: "", id: "webauthn-auth", class: "hidden", aria: { hidden: "true" } %>
8
8
  <div id="webauthn-auth-button">
9
- <%= form.submit rodauth.webauthn_auth_button, class: "w-full px-8 py-3 cursor-pointer font-semibold text-sm rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-600 dark:bg-emerald-400 dark:hover:bg-emerald-500 dark:text-gray-900 dark:focus:ring-emerald-400 dark:focus:ring-offset-current" %>
9
+ <%= form.submit rodauth.webauthn_auth_button, class: "w-full text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-semibold rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800" %>
10
10
  </div>
11
11
  <% end %>
12
12
 
@@ -1,8 +1,8 @@
1
- <%= form_with url: rodauth.webauthn_remove_path, method: :post, id: "webauthn-remove-form", data: { turbo: false }, class: "w-full max-w-sm" do |form| %>
1
+ <%= form_with url: rodauth.webauthn_remove_path, method: :post, id: "webauthn-remove-form", data: { turbo: false }, class: "space-y-4" do |form| %>
2
2
  <% if rodauth.two_factor_modifications_require_password? %>
3
- <div class="mb-6">
4
- <%= form.label "password", rodauth.password_label, class: "block text-sm font-semibold" %>
5
- <%= form.password_field rodauth.password_param, value: "", id: "password", autocomplete: rodauth.password_field_autocomplete_value, required: true, class: "mt-2 text-sm w-full px-3 py-2 border rounded-md dark:bg-gray-900 dark:text-gray-100 dark:focus:bg-gray-800 #{rodauth.field_error(rodauth.password_param) ? "border-red-600 focus:ring-red-600 focus:border-red-600 dark:border-red-400 dark:focus:ring-red-400" : "border-gray-300 dark:border-gray-700 dark:focus:border-emerald-400 dark:focus:ring-emerald-400" }", aria: ({ invalid: true, describedby: "password_error_message" } if rodauth.field_error(rodauth.password_param)) %>
3
+ <div>
4
+ <%= form.label "password", rodauth.password_label, class: "block mb-2 text-sm font-semibold text-gray-900 dark:text-white" %>
5
+ <%= form.password_field rodauth.password_param, value: "", id: "password", autocomplete: rodauth.password_field_autocomplete_value, required: true, class: "bg-gray-50 border border-gray-300 text-gray-900 rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500 #{rodauth.field_error(rodauth.password_param) ? "border-red-600 focus:ring-red-600 focus:border-red-600 dark:border-red-400 dark:focus:ring-red-400" : "border-gray-300 dark:border-gray-700 dark:focus:border-emerald-400 dark:focus:ring-emerald-400" }", aria: ({ invalid: true, describedby: "password_error_message" } if rodauth.field_error(rodauth.password_param)) %>
6
6
  <%= content_tag(:span, rodauth.field_error(rodauth.password_param), class: "block mt-1 text-red-600 text-xs dark:text-red-400", id: "password_error_message") if rodauth.field_error(rodauth.password_param) %>
7
7
  </div>
8
8
  <% end %>
@@ -17,5 +17,5 @@
17
17
  <%= content_tag(:span, rodauth.field_error(rodauth.webauthn_remove_param), class: "block mt-1 text-red-600 text-xs dark:text-red-400", id: "webauthn_remove_error_message") if rodauth.field_error(rodauth.webauthn_remove_param) %>
18
18
  </fieldset>
19
19
 
20
- <%= form.submit rodauth.webauthn_remove_button, class: "w-full px-8 py-3 cursor-pointer font-semibold text-sm rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-600 dark:bg-emerald-400 dark:hover:bg-emerald-500 dark:text-gray-900 dark:focus:ring-emerald-400 dark:focus:ring-offset-current" %>
20
+ <%= form.submit rodauth.webauthn_remove_button, class: "w-full text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-semibold rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800" %>
21
21
  <% end %>
@@ -1,20 +1,20 @@
1
1
  <% cred = rodauth.new_webauthn_credential %>
2
2
 
3
- <%= form_with url: request.path, method: :post, id: "webauthn-setup-form", data: { credential_options: cred.as_json.to_json, turbo: false }, class: "w-full max-w-sm" do |form| %>
3
+ <%= form_with url: request.path, method: :post, id: "webauthn-setup-form", data: { credential_options: cred.as_json.to_json, turbo: false }, class: "space-y-4" do |form| %>
4
4
  <%= form.hidden_field rodauth.webauthn_setup_challenge_param, value: cred.challenge %>
5
5
  <%= form.hidden_field rodauth.webauthn_setup_challenge_hmac_param, value: rodauth.compute_hmac(cred.challenge) %>
6
6
  <%= form.text_field rodauth.webauthn_setup_param, value: "", id: "webauthn-setup", class: "hidden", aria: { hidden: "true" } %>
7
7
 
8
8
  <% if rodauth.two_factor_modifications_require_password? %>
9
- <div class="mb-6">
10
- <%= form.label "password", rodauth.password_label, class: "block text-sm font-semibold" %>
11
- <%= form.password_field rodauth.password_param, value: "", id: "password", autocomplete: rodauth.password_field_autocomplete_value, required: true, class: "mt-2 text-sm w-full px-3 py-2 border rounded-md dark:bg-gray-900 dark:text-gray-100 dark:focus:bg-gray-800 #{rodauth.field_error(rodauth.password_param) ? "border-red-600 focus:ring-red-600 focus:border-red-600 dark:border-red-400 dark:focus:ring-red-400" : "border-gray-300 dark:border-gray-700 dark:focus:border-emerald-400 dark:focus:ring-emerald-400" }", aria: ({ invalid: true, describedby: "password_error_message" } if rodauth.field_error(rodauth.password_param)) %>
9
+ <div>
10
+ <%= form.label "password", rodauth.password_label, class: "block mb-2 text-sm font-semibold text-gray-900 dark:text-white" %>
11
+ <%= form.password_field rodauth.password_param, value: "", id: "password", autocomplete: rodauth.password_field_autocomplete_value, required: true, class: "bg-gray-50 border border-gray-300 text-gray-900 rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500 #{rodauth.field_error(rodauth.password_param) ? "border-red-600 focus:ring-red-600 focus:border-red-600 dark:border-red-400 dark:focus:ring-red-400" : "border-gray-300 dark:border-gray-700 dark:focus:border-emerald-400 dark:focus:ring-emerald-400" }", aria: ({ invalid: true, describedby: "password_error_message" } if rodauth.field_error(rodauth.password_param)) %>
12
12
  <%= content_tag(:span, rodauth.field_error(rodauth.password_param), class: "block mt-1 text-red-600 text-xs dark:text-red-400", id: "password_error_message") if rodauth.field_error(rodauth.password_param) %>
13
13
  </div>
14
14
  <% end %>
15
15
 
16
16
  <div id="webauthn-setup-button">
17
- <%= form.submit rodauth.webauthn_setup_button, class: "w-full px-8 py-3 cursor-pointer font-semibold text-sm rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-600 dark:bg-emerald-400 dark:hover:bg-emerald-500 dark:text-gray-900 dark:focus:ring-emerald-400 dark:focus:ring-offset-current" %>
17
+ <%= form.submit rodauth.webauthn_setup_button, class: "w-full text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-semibold rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800" %>
18
18
  </div>
19
19
  <% end %>
20
20
 
@@ -61,11 +61,6 @@ module Pu
61
61
 
62
62
  private
63
63
 
64
- def sequel_activerecord_integration?
65
- defined?(ActiveRecord::Railtie) &&
66
- (!defined?(Sequel) || Sequel::DATABASES.empty?)
67
- end
68
-
69
64
  def sequel_adapter
70
65
  SEQUEL_ADAPTERS[activerecord_adapter] || activerecord_adapter
71
66
  end
@@ -11,6 +11,6 @@ create_table :<%= table_prefix %>_authentication_audit_logs<%= primary_key_type
11
11
  <% else -%>
12
12
  t.string :metadata
13
13
  <% end -%>
14
- t.index [:<%= table_prefix %>_id, :at], name: "audit_<%= table_prefix %>_at_idx"
15
- t.index :at, name: "audit_at_idx"
14
+ t.index [:<%= table_prefix %>_id, :at], name: "audit_<%= table_prefix %>_<%= table_prefix %>_id_at_idx"
15
+ t.index :at, name: "audit_<%= table_prefix %>_at_idx"
16
16
  end
@@ -11,9 +11,12 @@ require "#{__dir__}/concerns/account_selector"
11
11
  module Pu
12
12
  module Rodauth
13
13
  class MigrationGenerator < ::Rails::Generators::Base
14
+ include ::ActiveRecord::Generators::Migration
14
15
  include Concerns::Configuration
15
16
  include Concerns::AccountSelector
16
17
 
18
+ MIGRATION_DIR = "#{__dir__}/migration/active_record"
19
+
17
20
  source_root "#{__dir__}/templates"
18
21
 
19
22
  desc "Generate migrations for supported features\n\n" \
@@ -124,63 +127,39 @@ module Pu
124
127
  Dir["#{MIGRATION_DIR}/*.erb"].map { |filename| File.basename(filename, ".erb").to_sym }
125
128
  end
126
129
 
127
- if defined?(::ActiveRecord::Railtie) # Active Record
128
- include ::ActiveRecord::Generators::Migration
129
-
130
- MIGRATION_DIR = "#{__dir__}/migration/active_record"
131
-
132
- def activerecord_adapter
133
- if ActiveRecord::Base.respond_to?(:connection_db_config)
134
- ActiveRecord::Base.connection_db_config.adapter
135
- else
136
- ActiveRecord::Base.connection_config.fetch(:adapter)
137
- end
130
+ def activerecord_adapter
131
+ if ActiveRecord::Base.respond_to?(:connection_db_config)
132
+ ActiveRecord::Base.connection_db_config.adapter
133
+ else
134
+ ActiveRecord::Base.connection_config.fetch(:adapter)
138
135
  end
136
+ end
139
137
 
140
- def primary_key_type(key = :id)
141
- generators = ::Rails.application.config.generators
142
- column_type = generators.options[:active_record][:primary_key_type]
143
- if key
144
- ", #{key}: :#{column_type}" if column_type
145
- else
146
- column_type || default_primary_key_type
147
- end
148
- end
149
-
150
- def default_primary_key_type
151
- if ActiveRecord.version >= Gem::Version.new("5.1")
152
- :bigint
153
- else
154
- :integer
155
- end
156
- end
157
-
158
- # Active Record 7+ sets default precision to 6 for timestamp columns,
159
- # so we need to ensure we match this when setting the default value.
160
- def current_timestamp
161
- if ActiveRecord.version >= Gem::Version.new("7.0") && ["mysql2", "trilogy"].include?(activerecord_adapter) && ActiveRecord::Base.connection.supports_datetime_with_precision?
162
- "CURRENT_TIMESTAMP(6)"
163
- else
164
- "CURRENT_TIMESTAMP"
165
- end
166
- end
167
- else # Sequel
168
- include ::Rails::Generators::Migration
169
-
170
- MIGRATION_DIR = "#{__dir__}/migration/sequel"
171
-
172
- def self.next_migration_number(dirname)
173
- next_migration_number = current_migration_number(dirname) + 1
174
- [Time.now.utc.strftime("%Y%m%d%H%M%S"), format("%.14d", next_migration_number)].max
138
+ def primary_key_type(key = :id)
139
+ generators = ::Rails.application.config.generators
140
+ column_type = generators.options[:active_record][:primary_key_type]
141
+ if key
142
+ ", #{key}: :#{column_type}" if column_type
143
+ else
144
+ column_type || default_primary_key_type
175
145
  end
146
+ end
176
147
 
177
- def db_migrate_path
178
- "db/migrate"
148
+ def default_primary_key_type
149
+ if ActiveRecord.version >= Gem::Version.new("5.1")
150
+ :bigint
151
+ else
152
+ :integer
179
153
  end
154
+ end
180
155
 
181
- def db
182
- db = ::Sequel::DATABASES.first if defined?(::Sequel)
183
- db or fail Rodauth::Rails::Error, "missing Sequel database connection"
156
+ # Active Record 7+ sets default precision to 6 for timestamp columns,
157
+ # so we need to ensure we match this when setting the default value.
158
+ def current_timestamp
159
+ if ActiveRecord.version >= Gem::Version.new("7.0") && ["mysql2", "trilogy"].include?(activerecord_adapter) && ActiveRecord::Base.connection.supports_datetime_with_precision?
160
+ "CURRENT_TIMESTAMP(6)"
161
+ else
162
+ "CURRENT_TIMESTAMP"
184
163
  end
185
164
  end
186
165
  end
@@ -55,6 +55,7 @@ class RodauthMailer < ApplicationMailer
55
55
 
56
56
  def rodauth(name, account_id, &block)
57
57
  instance = RodauthApp.rodauth(name).allocate
58
+ instance.url_options = default_url_options
58
59
  instance.instance_eval { @account = account_ds(account_id).first! }
59
60
  instance.instance_eval(&block) if block
60
61
  instance
@@ -1,4 +1,3 @@
1
- <% if defined?(ActiveRecord::Railtie) -%>
2
1
  class <%= account_path.classify %> < ResourceRecord
3
2
  include Rodauth::Rails.model<%= "(:#{table_prefix})" unless primary? %>
4
3
  # add concerns above.
@@ -30,10 +29,3 @@ class <%= account_path.classify %> < ResourceRecord
30
29
 
31
30
  # add methods above.
32
31
  end
33
- <% else -%>
34
- class <%= table_prefix.camelize %> < Sequel::Model
35
- include Rodauth::Rails.model
36
- plugin :enum
37
- enum :status, unverified: 1, verified: 2, closed: 3
38
- end
39
- <% end -%>
@@ -1,6 +1,8 @@
1
1
  require "sequel/core"
2
2
 
3
3
  class RodauthPlugin < Rodauth::Rails::Auth
4
+ attr_accessor :url_options
5
+
4
6
  configure do
5
7
  # ==> Features
6
8
  # See the Rodauth documentation for the list of available config options:
@@ -14,7 +16,6 @@ class RodauthPlugin < Rodauth::Rails::Auth
14
16
 
15
17
  # ==> General
16
18
 
17
- <% if sequel_activerecord_integration? -%>
18
19
  # Initialize Sequel and have it reuse Active Record's database connection.
19
20
  <% if RUBY_ENGINE == "jruby" -%>
20
21
  db Sequel.connect("jdbc:<%= sequel_adapter %>://", extensions: :activerecord_connection, keep_reference: false)
@@ -26,7 +27,6 @@ class RodauthPlugin < Rodauth::Rails::Auth
26
27
  # https://github.com/janko/rodauth-rails/issues/244
27
28
  convert_token_id_to_integer? true
28
29
 
29
- <% end -%>
30
30
  # Change prefix of table and foreign key column names from default "account"
31
31
  # accounts_table :users
32
32
  # verify_account_table :user_verification_keys
@@ -228,4 +228,10 @@ class RodauthPlugin < Rodauth::Rails::Auth
228
228
  # Does not work with only_json?
229
229
  # remember_deadline_interval Hash[days: 30]
230
230
  end
231
+
232
+ private
233
+
234
+ def rails_url_options
235
+ url_options || super
236
+ end
231
237
  end
@@ -1,13 +1,5 @@
1
- <% if defined?(::ActiveRecord::Railtie) -%>
2
1
  class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
3
2
  def change
4
3
  <%= migration_content -%>
5
4
  end
6
5
  end
7
- <% else -%>
8
- Sequel.migration do
9
- change do
10
- <%= migration_content -%>
11
- end
12
- end
13
- <% end -%>
@@ -14,7 +14,9 @@ module Plutonium
14
14
  private
15
15
 
16
16
  def rodauth(name = :#{name})
17
- super(name)
17
+ instance = super(name)
18
+ instance.url_options = default_url_options.presence
19
+ instance
18
20
  end
19
21
 
20
22
  def current_user
@@ -78,7 +78,7 @@ module Plutonium
78
78
  end
79
79
  end
80
80
  end
81
- url_args[:controller] = controller_chain.join("::").underscore
81
+ url_args[:controller] = "/#{controller_chain.join("::").underscore}"
82
82
 
83
83
  if scoped_to_entity? && scoped_entity_strategy == :path
84
84
  url_args[scoped_entity_param_key] = current_scoped_entity
@@ -45,12 +45,14 @@ module Plutonium
45
45
  tag.span rendered, title:
46
46
  end
47
47
 
48
- def display_association_value(association_class)
49
- display_name = display_name_of(association_class)
50
- link_to display_name, resource_url_for(association_class, parent: nil),
51
- class: "font-medium text-primary-600 dark:text-primary-500"
52
- rescue NoMethodError
53
- display_name
48
+ def display_association_value(association)
49
+ display_name = display_name_of(association)
50
+ if registered_resources.include?(association.class)
51
+ link_to display_name, resource_url_for(association, parent: nil),
52
+ class: "font-medium text-primary-600 dark:text-primary-500"
53
+ else
54
+ display_name
55
+ end
54
56
  end
55
57
 
56
58
  def display_numeric_value(value)
@@ -6,17 +6,21 @@ module Plutonium
6
6
  include ActionView::Helpers::FormHelper
7
7
 
8
8
  def resource_form_for(record, **options, &block)
9
- options[:url] ||= resource_url_args_for(record, action: record.new_record? ? :create : :update)
10
- options[:builder] ||= PlutoniumUi::FormBuilder
11
- options[:wrapper] ||= :default_resource_form
12
- options[:html] ||= {}
13
- options[:html][:novalidate] = false unless options[:html].key?(:novalidate)
9
+ options[:url] ||= resource_url_for(record, action: record.new_record? ? :create : :update)
10
+ options = build_form_options(options)
14
11
 
15
12
  with_resource_form_field_error_proc do
16
13
  form_for(record, options, &block)
17
14
  end
18
15
  end
19
16
 
17
+ def resource_form_with(**options, &block)
18
+ options = build_form_options(options)
19
+ with_resource_form_field_error_proc do
20
+ form_with(**options, &block)
21
+ end
22
+ end
23
+
20
24
  def token_tag(...)
21
25
  # needed to workaround https://github.com/tailwindlabs/tailwindcss/issues/3350
22
26
  super(...).sub(" />", " hidden />").html_safe
@@ -24,6 +28,14 @@ module Plutonium
24
28
 
25
29
  private
26
30
 
31
+ def build_form_options(options)
32
+ options[:builder] ||= PlutoniumUi::FormBuilder
33
+ options[:wrapper] ||= :default_resource_form
34
+ options[:html] ||= {}
35
+ options[:html][:novalidate] = false unless options[:html].key?(:novalidate)
36
+ options
37
+ end
38
+
27
39
  def with_resource_form_field_error_proc
28
40
  # borrowed from https://github.com/heartcombo/simple_form/blob/main/lib/simple_form/action_view_extensions/form_helper.rb#L40C1-L50C10
29
41
  # this does not look threadsafe
@@ -7,6 +7,7 @@ module Plutonium
7
7
  helper Plutonium::Helpers::ApplicationHelper
8
8
  helper Plutonium::Helpers::ComponentHelper
9
9
  helper Plutonium::Helpers::AssetsHelper
10
+ helper Plutonium::Helpers::FormHelper
10
11
 
11
12
  layout "rodauth"
12
13
  append_view_path File.expand_path("app/views", Plutonium.root)
@@ -1,3 +1,3 @@
1
1
  module Plutonium
2
- VERSION = "0.12.14"
2
+ VERSION = "0.13.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: plutonium
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.14
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stefan Froelich
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-06-19 00:00:00.000000000 Z
11
+ date: 2024-06-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: zeitwerk
@@ -1088,25 +1088,6 @@ files:
1088
1088
  - lib/generators/pu/rodauth/migration/active_record/verify_account.erb
1089
1089
  - lib/generators/pu/rodauth/migration/active_record/verify_login_change.erb
1090
1090
  - lib/generators/pu/rodauth/migration/active_record/webauthn.erb
1091
- - lib/generators/pu/rodauth/migration/sequel/account_expiration.erb
1092
- - lib/generators/pu/rodauth/migration/sequel/active_sessions.erb
1093
- - lib/generators/pu/rodauth/migration/sequel/audit_logging.erb
1094
- - lib/generators/pu/rodauth/migration/sequel/base.erb
1095
- - lib/generators/pu/rodauth/migration/sequel/disallow_password_reuse.erb
1096
- - lib/generators/pu/rodauth/migration/sequel/email_auth.erb
1097
- - lib/generators/pu/rodauth/migration/sequel/jwt_refresh.erb
1098
- - lib/generators/pu/rodauth/migration/sequel/lockout.erb
1099
- - lib/generators/pu/rodauth/migration/sequel/otp.erb
1100
- - lib/generators/pu/rodauth/migration/sequel/password_expiration.erb
1101
- - lib/generators/pu/rodauth/migration/sequel/recovery_codes.erb
1102
- - lib/generators/pu/rodauth/migration/sequel/remember.erb
1103
- - lib/generators/pu/rodauth/migration/sequel/reset_password.erb
1104
- - lib/generators/pu/rodauth/migration/sequel/separate_passwords.erb
1105
- - lib/generators/pu/rodauth/migration/sequel/single_session.erb
1106
- - lib/generators/pu/rodauth/migration/sequel/sms_codes.erb
1107
- - lib/generators/pu/rodauth/migration/sequel/verify_account.erb
1108
- - lib/generators/pu/rodauth/migration/sequel/verify_login_change.erb
1109
- - lib/generators/pu/rodauth/migration/sequel/webauthn.erb
1110
1091
  - lib/generators/pu/rodauth/migration_generator.rb
1111
1092
  - lib/generators/pu/rodauth/templates/INSTRUCTIONS
1112
1093
  - lib/generators/pu/rodauth/templates/app/controllers/plugin_controller.rb.tt
@@ -1,7 +0,0 @@
1
- # Used by the account expiration feature
2
- create_table :<%= table_prefix %>_activity_times do
3
- foreign_key :id, :<%= table_prefix.pluralize %>, primary_key: true, type: :Bignum
4
- DateTime :last_activity_at, null: false
5
- DateTime :last_login_at, null: false
6
- DateTime :expired_at
7
- end
@@ -1,8 +0,0 @@
1
- # Used by the active sessions feature
2
- create_table :<%= table_prefix %>_active_session_keys do
3
- foreign_key :<%= table_prefix %>_id, :<%= table_prefix.pluralize %>, type: :Bignum
4
- String :session_id
5
- Time :created_at, null: false, default: Sequel::CURRENT_TIMESTAMP
6
- Time :last_use, null: false, default: Sequel::CURRENT_TIMESTAMP
7
- primary_key [:<%= table_prefix %>_id, :session_id]
8
- end
@@ -1,17 +0,0 @@
1
- # Used by the audit logging feature
2
- create_table :<%= table_prefix %>_authentication_audit_logs do
3
- primary_key :id, type: :Bignum
4
- foreign_key :<%= table_prefix %>_id, :<%= table_prefix.pluralize %>, null: false, type: :Bignum
5
- DateTime :at, null: false, default: Sequel::CURRENT_TIMESTAMP
6
- String :message, null: false
7
- <% case db.database_type -%>
8
- <% when :postgres -%>
9
- jsonb :metadata
10
- <% when :sqlite, :mysql -%>
11
- json :metadata
12
- <% else -%>
13
- String :metadata
14
- <% end -%>
15
- index [:<%= table_prefix %>_id, :at], name: :<%= table_prefix %>_audit_<%= table_prefix %>_at_idx
16
- index :at, name: :<%= table_prefix %>_audit_at_idx
17
- end
@@ -1,25 +0,0 @@
1
- <% if db.database_type == :postgres -%>
2
- begin
3
- run "CREATE EXTENSION IF NOT EXISTS citext"
4
- rescue NoMethodError # migration is being reverted
5
- end
6
-
7
- <% end -%>
8
- create_table :<%= table_prefix.pluralize %> do
9
- primary_key :id, type: :Bignum
10
- <% if db.database_type == :postgres -%>
11
- citext :email, null: false
12
- constraint :valid_email, email: /^[^,;@ \r\n]+@[^,@; \r\n]+\.[^,@; \r\n]+$/
13
- <% else -%>
14
- String :email, null: false
15
- <% end -%>
16
- Integer :status, null: false, default: 1
17
- <% if db.supports_partial_indexes? -%>
18
- index :email, unique: true, where: { status: [1, 2] }
19
- <% else -%>
20
- index :email, unique: true
21
- <% end -%>
22
- <% unless separate_passwords? -%>
23
- String :password_hash
24
- <% end -%>
25
- end
@@ -1,6 +0,0 @@
1
- # Used by the disallow password reuse feature
2
- create_table :<%= table_prefix %>_previous_password_hashes do
3
- primary_key :id, type: :Bignum
4
- foreign_key :<%= table_prefix %>_id, :<%= table_prefix.pluralize %>, type: :Bignum
5
- String :password_hash, null: false
6
- end
@@ -1,7 +0,0 @@
1
- # Used by the email auth feature
2
- create_table :<%= table_prefix %>_email_auth_keys do
3
- foreign_key :id, :<%= table_prefix.pluralize %>, primary_key: true, type: :Bignum
4
- String :key, null: false
5
- DateTime :deadline, null: false
6
- DateTime :email_last_sent, null: false, default: Sequel::CURRENT_TIMESTAMP
7
- end
@@ -1,8 +0,0 @@
1
- # Used by the jwt refresh feature
2
- create_table :<%= table_prefix %>_jwt_refresh_keys do
3
- primary_key :id, type: :Bignum
4
- foreign_key :<%= table_prefix %>_id, :<%= table_prefix.pluralize %>, null: false, type: :Bignum
5
- String :key, null: false
6
- DateTime :deadline, null: false
7
- index :<%= table_prefix %>_id, name: :<%= table_prefix %>_jwt_rk_<%= table_prefix %>_id_idx
8
- end
@@ -1,11 +0,0 @@
1
- # Used by the lockout feature
2
- create_table :<%= table_prefix %>_login_failures do
3
- foreign_key :id, :<%= table_prefix.pluralize %>, primary_key: true, type: :Bignum
4
- Integer :number, null: false, default: 1
5
- end
6
- create_table :<%= table_prefix %>_lockouts do
7
- foreign_key :id, :<%= table_prefix.pluralize %>, primary_key: true, type: :Bignum
8
- String :key, null: false
9
- DateTime :deadline, null: false
10
- DateTime :email_last_sent
11
- end
@@ -1,7 +0,0 @@
1
- # Used by the otp feature
2
- create_table :<%= table_prefix %>_otp_keys do
3
- foreign_key :id, :<%= table_prefix.pluralize %>, primary_key: true, type: :Bignum
4
- String :key, null: false
5
- Integer :num_failures, null: false, default: 0
6
- Time :last_use, null: false, default: Sequel::CURRENT_TIMESTAMP
7
- end
@@ -1,5 +0,0 @@
1
- # Used by the password expiration feature
2
- create_table :<%= table_prefix %>_password_change_times do
3
- foreign_key :id, :<%= table_prefix.pluralize %>, primary_key: true, type: :Bignum
4
- DateTime :changed_at, null: false, default: Sequel::CURRENT_TIMESTAMP
5
- end
@@ -1,6 +0,0 @@
1
- # Used by the recovery codes feature
2
- create_table :<%= table_prefix %>_recovery_codes do
3
- foreign_key :id, :<%= table_prefix.pluralize %>, type: :Bignum
4
- String :code
5
- primary_key [:id, :code]
6
- end
@@ -1,6 +0,0 @@
1
- # Used by the remember me feature
2
- create_table :<%= table_prefix %>_remember_keys do
3
- foreign_key :id, :<%= table_prefix.pluralize %>, primary_key: true, type: :Bignum
4
- String :key, null: false
5
- DateTime :deadline, null: false
6
- end
@@ -1,7 +0,0 @@
1
- # Used by the password reset feature
2
- create_table :<%= table_prefix %>_password_reset_keys do
3
- foreign_key :id, :<%= table_prefix.pluralize %>, primary_key: true, type: :Bignum
4
- String :key, null: false
5
- DateTime :deadline, null: false
6
- DateTime :email_last_sent, null: false, default: Sequel::CURRENT_TIMESTAMP
7
- end
@@ -1,6 +0,0 @@
1
- # Stores password hashes separate from the account table
2
- create_table :<%= table_prefix %>_password_hashes do
3
- primary_key :id, type: :Bignum
4
- foreign_key :<%= table_prefix %>_id, :<%= table_prefix.pluralize %>, type: :Bignum
5
- String :password_hash, null: false
6
- end
@@ -1,5 +0,0 @@
1
- # Used by the single session feature
2
- create_table :<%= table_prefix %>_session_keys do
3
- foreign_key :id, :<%= table_prefix.pluralize %>, primary_key: true, type: :Bignum
4
- String :key, null: false
5
- end