plutonium 0.12.14 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
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