Skip to content

Instantly share code, notes, and snippets.

@bjeanes
Last active January 25, 2022 16:05
Show Gist options
  • Save bjeanes/ead1e6b0e7d729e7db06d2650a849362 to your computer and use it in GitHub Desktop.
Save bjeanes/ead1e6b0e7d729e7db06d2650a849362 to your computer and use it in GitHub Desktop.
Example of custom code to emulate a programmatic core in Rodauth
# 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