Last active
January 25, 2022 16:05
-
-
Save bjeanes/ead1e6b0e7d729e7db06d2650a849362 to your computer and use it in GitHub Desktop.
Example of custom code to emulate a programmatic core in Rodauth
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
module Authentication | |
# Rodauth is pretty coupled to being in a request context, but this will provide the minimum necessary to be able | |
# to generate correct URLs | |
def self.rodauth(configuration_name = :user, params: {}) | |
url_options = Rails.application.config.action_mailer.default_url_options | |
host = url_options[:host] | |
host += ":#{url_options[:port]}" if url_options.key?(:port) | |
base_url = "#{url_options[:protocol] || 'http'}://#{host}" | |
scheme = Rails.env.production? ? 'https' : 'http' | |
env = {} | |
fake_scope = OpenStruct.new( | |
env: env, | |
request: OpenStruct.new( | |
env: env, | |
host: host, | |
base_url: base_url, | |
path: "/", | |
remaining_path: "", | |
params: params.stringify_keys, | |
) | |
) | |
RodauthConfig.rodauth(configuration_name).new(fake_scope) | |
end | |
def self.create_admin(email) | |
rodauth = self. | |
admin = Admin.new(email: email) | |
if admin.valid? | |
rodauth(:admin).instance_eval do | |
# Important to use Sequel's transaction management. The underlying connection is shared so it will cover | |
# ActiveRecord save, but the email send happens in a Sequel-owned `after_commit` hook. | |
transaction do | |
id = db[accounts_table].insert({ | |
email: email, | |
# We don't let admins change email address and we email them their initial password, so we can skip an | |
# account verification email and just create the account in a verified state: | |
status: 'verified' | |
}) | |
admin.id = id | |
admin.save! | |
# Load the internal @account var | |
account_from_login(email) | |
# Generate and store the password reset token | |
generate_reset_password_key_value | |
create_reset_password_key | |
# Email the new admin a password reset link | |
send_reset_password_email | |
admin | |
end | |
else | |
return admin.errors | |
end | |
end | |
end | |
# Rodauth is pretty coupled to the user triggering actions themselves. In order to allow a developer or admin to | |
# change an email or to change an email programmatically in a test, this splices together some internals from | |
# Rodauth's `change_login` and `verify_login_change` features. | |
# | |
# Because this has the risk of being brittle, there are some unit tests | |
def self.change_email(user:, to:, require_confirmation: true) | |
api = self | |
self.rodauth(:user, params: {'login' => to}).instance_eval do | |
transaction do | |
unless require_confirmation | |
def self.send_verify_login_change_email(*) | |
#noop | |
end | |
def self.send_login_changed_email(*) | |
#noop | |
end | |
end | |
account_from_id(user.id) | |
before_change_login | |
unless change_login(to) | |
user.errors.add(:email, "unable to be changed") | |
raise ActiveRecord::RecordInvalid(user) | |
end | |
after_change_login | |
unless require_confirmation | |
api.confirm_email_change(user: user, rodauth: self) | |
end | |
end | |
end | |
end | |
def self.confirm_email_change(user:, rodauth: self.rodauth(:user)) | |
rodauth.instance_eval do | |
transaction do | |
account_from_id(user.id) | |
@verify_login_change_new_login, @verify_login_change_key_value = | |
get_verify_login_change_login_and_key(user.id) | |
before_verify_login_change | |
unless @verify_login_change_new_login && verify_login_change | |
user.errors.add(:email, "unable to be changed") | |
raise ActiveRecord::RecordInvalid(user) | |
end | |
remove_verify_login_change_key | |
after_verify_login_change | |
end | |
end | |
end | |
def self.confirm_account(user:) | |
rodauth(:user).instance_eval do | |
transaction do | |
if account_from_id(user.id) | |
before_verify_account | |
verify_account | |
remove_verify_account_key | |
after_verify_account | |
elsif user.confirmed_at.nil? # un-migrated Devise user | |
user.touch(:confirmed_at) | |
end | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment