Migrate to Rais 8.0
- Remove all Rodauth stuff and implement simple custom auth - Migrate from sprockets to propshaft, hack some bootstrap stuff
This commit is contained in:
parent
0198a22278
commit
c35c7da6e0
66 changed files with 518 additions and 684 deletions
|
|
@ -1,2 +0,0 @@
|
|||
//= link_tree ../images
|
||||
//= link_tree ../builds
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
font-family: 'Lexend';
|
||||
src: url('Lexend-VariableFont_wght.ttf');
|
||||
font-display: swap;
|
||||
}
|
||||
}
|
||||
|
||||
$font-family-sans-serif:
|
||||
Lexend,
|
||||
|
||||
$font-family-sans-serif: Lexend,
|
||||
// Cross-platform generic font family (default user interface font)
|
||||
system-ui,
|
||||
// Safari for macOS and iOS (San Francisco)
|
||||
|
|
@ -29,6 +29,13 @@ $enable-rounded: false;
|
|||
@import 'bootstrap/scss/bootstrap';
|
||||
@import 'bootstrap-icons/font/bootstrap-icons';
|
||||
|
||||
@font-face {
|
||||
font-display: block;
|
||||
font-family: "bootstrap-icons";
|
||||
src: url("./bootstrap-icons.woff2") format("woff2"),
|
||||
url("./bootstrap-icons.woff") format("woff");
|
||||
}
|
||||
|
||||
.rails-bootstrap-forms-date-select select,
|
||||
.rails-bootstrap-forms-time-select select,
|
||||
.rails-bootstrap-forms-datetime-select select {
|
||||
|
|
@ -56,16 +63,17 @@ $enable-rounded: false;
|
|||
* <action-text-attachment> element we wrap around attachments. Otherwise,
|
||||
* images in galleries will be squished by the max-width: 33%; rule.
|
||||
*/
|
||||
.trix-content .attachment-gallery > action-text-attachment,
|
||||
.trix-content .attachment-gallery > .attachment {
|
||||
.trix-content .attachment-gallery>action-text-attachment,
|
||||
.trix-content .attachment-gallery>.attachment {
|
||||
flex: 1 0 33%;
|
||||
padding: 0 0.5em;
|
||||
max-width: 33%;
|
||||
}
|
||||
|
||||
.trix-content .attachment-gallery.attachment-gallery--2 > action-text-attachment,
|
||||
.trix-content .attachment-gallery.attachment-gallery--2 > .attachment, .trix-content .attachment-gallery.attachment-gallery--4 > action-text-attachment,
|
||||
.trix-content .attachment-gallery.attachment-gallery--4 > .attachment {
|
||||
.trix-content .attachment-gallery.attachment-gallery--2>action-text-attachment,
|
||||
.trix-content .attachment-gallery.attachment-gallery--2>.attachment,
|
||||
.trix-content .attachment-gallery.attachment-gallery--4>action-text-attachment,
|
||||
.trix-content .attachment-gallery.attachment-gallery--4>.attachment {
|
||||
flex-basis: 50%;
|
||||
max-width: 50%;
|
||||
}
|
||||
|
|
@ -79,25 +87,26 @@ $enable-rounded: false;
|
|||
/* Fix trix dark mode */
|
||||
.trix-button-row {
|
||||
.trix-button-group {
|
||||
border: var(--bs-border-width) solid var(--bs-border-color);
|
||||
border: var(--bs-border-width) solid var(--bs-border-color);
|
||||
|
||||
.trix-button {
|
||||
border: 0;
|
||||
padding: var(--bs-padding)
|
||||
}
|
||||
.trix-button {
|
||||
border: 0;
|
||||
padding: var(--bs-padding)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[data-bs-theme=dark] {
|
||||
.trix-button-row {
|
||||
.trix-button-group {
|
||||
.trix-button {
|
||||
background-color: transparent !important;
|
||||
filter: invert(100%) !important;
|
||||
}
|
||||
.trix-button-group {
|
||||
.trix-button {
|
||||
background-color: transparent !important;
|
||||
filter: invert(100%) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* end fix trix dark mode */
|
||||
|
||||
.trix-content {
|
||||
|
|
@ -107,9 +116,11 @@ $enable-rounded: false;
|
|||
border: var(--bs-border-width) solid var(--bs-border-color) !important;
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 0.6rem;
|
||||
}
|
||||
|
||||
p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
|
@ -121,7 +132,7 @@ trix-toolbar .trix-dialog {
|
|||
color: var(--bs-secondary-color) !important;
|
||||
border: var(--bs-border-width) solid var(--bs-border-color) !important;
|
||||
border-radius: 0 !important;
|
||||
box-shadow: none;
|
||||
box-shadow: none;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
|
|
@ -145,6 +156,7 @@ trix-toolbar .trix-input--dialog {
|
|||
trix-toolbar .trix-dialog--link {
|
||||
max-width: 900px;
|
||||
}
|
||||
|
||||
/* trix-editor.trix-content {
|
||||
min-height: 350px;
|
||||
overflow-y: auto;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ApplicationCable
|
||||
class Connection < ActionCable::Connection::Base
|
||||
identified_by :current_user
|
||||
|
||||
def connect
|
||||
set_current_user || reject_unauthorized_connection
|
||||
end
|
||||
|
||||
private
|
||||
def set_current_user
|
||||
if session = Session.find_by(id: cookies.signed[:session_id])
|
||||
self.current_user = session.user
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ApplicationController < ActionController::Base
|
||||
include Authentication
|
||||
include Pagy::Backend
|
||||
|
||||
# allow_browser versions: :modern
|
||||
|
|
@ -13,15 +14,29 @@ class ApplicationController < ActionController::Base
|
|||
def initialize_navbar
|
||||
return unless request.get?
|
||||
|
||||
@navbar_items = if rodauth.logged_in?
|
||||
@navbar_items = if authenticated?
|
||||
[
|
||||
{ label: "Dashboard", icon: :speedometer2, path: :root },
|
||||
{ label: Report.model_name.human(count: 2), icon: :'journal-text', path: :reports },
|
||||
{ label: I18n.t("backoffice"), icon: :gear, path: :backoffice, active: %w[backoffice checklists checks links link_categories].include?(controller_name) },
|
||||
{ label: Account.model_name.human, icon: :person, path: profile_path }
|
||||
{
|
||||
label: "Dashboard",
|
||||
icon: :speedometer2,
|
||||
path: :root
|
||||
},
|
||||
{
|
||||
label: Report.model_name.human(count: 2),
|
||||
icon: :'journal-text',
|
||||
path: :reports },
|
||||
{
|
||||
label: I18n.t("backoffice"),
|
||||
icon: :gear,
|
||||
path: :backoffice,
|
||||
active: %w[backoffice checklists checks links link_categories].include?(controller_name) },
|
||||
{
|
||||
label: "Konto",
|
||||
path: profile_path
|
||||
}
|
||||
]
|
||||
else
|
||||
[ { label: "Login", icon: :'door-closed', path: rodauth.login_path, label_class: "text-info" } ]
|
||||
[ { label: "Login", icon: :'door-closed', path: new_session_path, label_class: "text-info" } ]
|
||||
end
|
||||
@nav_path = controller_name
|
||||
@search_url = nil
|
||||
|
|
|
|||
55
app/controllers/concerns/authentication.rb
Normal file
55
app/controllers/concerns/authentication.rb
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
module Authentication
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
before_action :require_authentication
|
||||
helper_method :authenticated?
|
||||
end
|
||||
|
||||
class_methods do
|
||||
def allow_unauthenticated_access(**options)
|
||||
skip_before_action :require_authentication, **options
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def authenticated?
|
||||
resume_session
|
||||
end
|
||||
|
||||
def require_authentication
|
||||
resume_session || request_authentication
|
||||
end
|
||||
|
||||
|
||||
def resume_session
|
||||
Current.session ||= find_session_by_cookie
|
||||
end
|
||||
|
||||
def find_session_by_cookie
|
||||
Session.find_by(id: cookies.signed[:session_id])
|
||||
end
|
||||
|
||||
|
||||
def request_authentication
|
||||
session[:return_to_after_authenticating] = request.url
|
||||
redirect_to new_session_path
|
||||
end
|
||||
|
||||
def after_authentication_url
|
||||
session.delete(:return_to_after_authenticating) || root_url
|
||||
end
|
||||
|
||||
|
||||
def start_new_session_for(user)
|
||||
user.sessions.create!(user_agent: request.user_agent, ip_address: request.remote_ip).tap do |session|
|
||||
Current.session = session
|
||||
cookies.signed.permanent[:session_id] = { value: session.id, httponly: true, same_site: :lax }
|
||||
end
|
||||
end
|
||||
|
||||
def terminate_session
|
||||
Current.session.destroy
|
||||
cookies.delete(:session_id)
|
||||
end
|
||||
end
|
||||
|
|
@ -1,10 +1,36 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class HomeController < ApplicationController
|
||||
allow_unauthenticated_access only: [ :show ]
|
||||
|
||||
def show
|
||||
if rodauth.logged_in?
|
||||
else
|
||||
render :root
|
||||
end
|
||||
end
|
||||
|
||||
def profile
|
||||
end
|
||||
|
||||
private
|
||||
def initialize_sidebar_items
|
||||
return [] unless action_name == "profile"
|
||||
|
||||
[
|
||||
{
|
||||
label: "Profil",
|
||||
icon: :person,
|
||||
path: profile_path,
|
||||
active: action_name == "profile"
|
||||
},
|
||||
# {
|
||||
# label: "Passwort ändern",
|
||||
# path: new_password_path,
|
||||
# icon: :lock
|
||||
# },
|
||||
{
|
||||
label: "Logout",
|
||||
icon: :"box-arrow-right",
|
||||
path: session_path,
|
||||
method: :delete
|
||||
}
|
||||
]
|
||||
end
|
||||
end
|
||||
|
|
|
|||
33
app/controllers/passwords_controller.rb
Normal file
33
app/controllers/passwords_controller.rb
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
class PasswordsController < ApplicationController
|
||||
allow_unauthenticated_access
|
||||
before_action :set_user_by_token, only: %i[ edit update ]
|
||||
|
||||
def new
|
||||
end
|
||||
|
||||
def create
|
||||
if user = User.find_by(email_address: params[:email_address])
|
||||
PasswordsMailer.reset(user).deliver_later
|
||||
end
|
||||
|
||||
redirect_to new_session_path, notice: "Password reset instructions sent (if user with that email address exists)."
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
if @user.update(params.permit(:password, :password_confirmation))
|
||||
redirect_to new_session_path, notice: "Password has been reset."
|
||||
else
|
||||
redirect_to edit_password_path(params[:token]), alert: "Passwords did not match."
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def set_user_by_token
|
||||
@user = User.find_by_password_reset_token!(params[:token])
|
||||
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
||||
redirect_to new_password_path, alert: "Password reset link is invalid or has expired."
|
||||
end
|
||||
end
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
class RodauthController < ApplicationController
|
||||
# Used by Rodauth for rendering views, CSRF protection, running any
|
||||
# registered action callbacks and rescue handlers, instrumentation etc.
|
||||
|
||||
# Controller callbacks and rescue handlers will run around Rodauth endpoints.
|
||||
# before_action :verify_captcha, only: :login, if: -> { request.post? }
|
||||
# rescue_from("SomeError") { |exception| ... }
|
||||
|
||||
# Layout can be changed for all Rodauth pages or only certain pages.
|
||||
# layout "authentication"
|
||||
# layout -> do
|
||||
# case rodauth.current_route
|
||||
# when :login, :create_account, :verify_account, :verify_account_resend,
|
||||
# :reset_password, :reset_password_request
|
||||
# "authentication"
|
||||
# else
|
||||
# "application"
|
||||
# end
|
||||
# end
|
||||
#
|
||||
before_action do
|
||||
# Fix encoding in rodauth views.
|
||||
response.headers["Content-Type"] = "text/html; charset=utf-8" if request.format.html?
|
||||
end
|
||||
|
||||
def profile
|
||||
end
|
||||
|
||||
private
|
||||
def initialize_sidebar_items
|
||||
return unless rodauth.logged_in?
|
||||
|
||||
[
|
||||
{ label: "Profile", icon: :'person', path: profile_path, active: action_name == "profile" },
|
||||
{ label: "Passwort ändern", icon: :'lock', path: rodauth.change_password_path, active: action_name == "change_password" },
|
||||
{ label: "Logout", icon: :'box-arrow-right', path: rodauth.logout_path, active: action_name == "logout" }
|
||||
]
|
||||
end
|
||||
end
|
||||
24
app/controllers/sessions_controller.rb
Normal file
24
app/controllers/sessions_controller.rb
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
class SessionsController < ApplicationController
|
||||
allow_unauthenticated_access only: %i[ new create ]
|
||||
rate_limit to: 10, within: 3.minutes, only: :create, with: -> { redirect_to new_session_url, alert: "Try again later." }
|
||||
|
||||
def new
|
||||
redirect_to :root if authenticated?
|
||||
end
|
||||
|
||||
def create
|
||||
redirect_to :root if authenticated?
|
||||
|
||||
if user = User.authenticate_by(params.permit(:email_address, :password))
|
||||
start_new_session_for user
|
||||
redirect_to after_authentication_url
|
||||
else
|
||||
redirect_to new_session_path, alert: "Try another email address or password."
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
terminate_session
|
||||
redirect_to new_session_path
|
||||
end
|
||||
end
|
||||
6
app/mailers/passwords_mailer.rb
Normal file
6
app/mailers/passwords_mailer.rb
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
class PasswordsMailer < ApplicationMailer
|
||||
def reset(user)
|
||||
@user = user
|
||||
mail subject: "Reset your password", to: user.email_address
|
||||
end
|
||||
end
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
class RodauthApp < Rodauth::Rails::App
|
||||
# primary configuration
|
||||
configure RodauthMain
|
||||
|
||||
# secondary configuration
|
||||
# configure RodauthAdmin, :admin
|
||||
|
||||
route do |r|
|
||||
rodauth.load_memory # autologin remembered users
|
||||
|
||||
r.rodauth # route rodauth requests
|
||||
|
||||
# ==> Authenticating requests
|
||||
# Call `rodauth.require_account` for requests that you want to
|
||||
# require authentication for. For example:
|
||||
#
|
||||
# # authenticate /dashboard/* and /account/* requests
|
||||
# if r.path.start_with?("/dashboard") || r.path.start_with?("/account")
|
||||
# rodauth.require_account
|
||||
# end
|
||||
|
||||
# ==> Secondary configurations
|
||||
# r.rodauth(:admin) # route admin rodauth requests
|
||||
end
|
||||
end
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
require "sequel/core"
|
||||
|
||||
class RodauthMain < Rodauth::Rails::Auth
|
||||
configure do
|
||||
# List of authentication features that are loaded.
|
||||
# enable :create_account, :verify_account, :verify_account_grace_period,
|
||||
# :login, :logout, :remember,
|
||||
# :reset_password, :change_password, :change_login, :verify_login_change,
|
||||
# :close_account
|
||||
enable :login, :logout, :remember, :change_password
|
||||
|
||||
# See the Rodauth documentation for the list of available config options:
|
||||
# http://rodauth.jeremyevans.net/documentation.html
|
||||
|
||||
# ==> General
|
||||
# Initialize Sequel and have it reuse Active Record's database connection.
|
||||
db Sequel.sqlite(extensions: :activerecord_connection, keep_reference: false)
|
||||
# Avoid DB query that checks accounts table schema at boot time.
|
||||
convert_token_id_to_integer? { Account.columns_hash["id"].type == :integer }
|
||||
|
||||
# Change prefix of table and foreign key column names from default "account"
|
||||
# accounts_table :users
|
||||
# verify_account_table :user_verification_keys
|
||||
# verify_login_change_table :user_login_change_keys
|
||||
# reset_password_table :user_password_reset_keys
|
||||
# remember_table :user_remember_keys
|
||||
|
||||
# The secret key used for hashing public-facing tokens for various features.
|
||||
# Defaults to Rails `secret_key_base`, but you can use your own secret key.
|
||||
# hmac_secret "9180872c271f678dc279aabf6610187b7a11f2d23054ce38ebc66980971e993a25f5613ba255956c9ee7bc4afe724eef16abc411a6e2a8642d53b85531685de1"
|
||||
|
||||
# Use path prefix for all routes.
|
||||
# prefix "/auth"
|
||||
|
||||
# Specify the controller used for view rendering, CSRF, and callbacks.
|
||||
rails_controller { RodauthController }
|
||||
|
||||
# Make built-in page titles accessible in your views via an instance variable.
|
||||
title_instance_variable :@page_title
|
||||
|
||||
# Store account status in an integer column without foreign key constraint.
|
||||
account_status_column :status
|
||||
|
||||
# Store password hash in a column instead of a separate table.
|
||||
account_password_hash_column :password_hash
|
||||
|
||||
# Set password when creating account instead of when verifying.
|
||||
# verify_account_set_password? false
|
||||
|
||||
# Change some default param keys.
|
||||
login_param "email"
|
||||
login_confirm_param "email-confirm"
|
||||
# password_confirm_param "confirm_password"
|
||||
|
||||
# Redirect back to originally requested location after authentication.
|
||||
# login_return_to_requested_location? true
|
||||
# two_factor_auth_return_to_requested_location? true # if using MFA
|
||||
|
||||
# Autologin the user after they have reset their password.
|
||||
# reset_password_autologin? true
|
||||
|
||||
# Delete the account record when the user has closed their account.
|
||||
# delete_account_on_close? true
|
||||
|
||||
# Redirect to the app from login and registration pages if already logged in.
|
||||
# already_logged_in { redirect login_redirect }
|
||||
|
||||
# ==> Emails
|
||||
send_email do |email|
|
||||
# queue email delivery on the mailer after the transaction commits
|
||||
db.after_commit { email.deliver_later }
|
||||
end
|
||||
|
||||
# ==> Flash
|
||||
# Match flash keys with ones already used in the Rails app.
|
||||
# flash_notice_key :success # default is :notice
|
||||
# flash_error_key :error # default is :alert
|
||||
|
||||
# Override default flash messages.
|
||||
# create_account_notice_flash "Your account has been created. Please verify your account by visiting the confirmation link sent to your email address."
|
||||
# require_login_error_flash "Login is required for accessing this page"
|
||||
# login_notice_flash nil
|
||||
|
||||
# ==> Validation
|
||||
# Override default validation error messages.
|
||||
# no_matching_login_message "user with this email address doesn't exist"
|
||||
# already_an_account_with_this_login_message "user with this email address already exists"
|
||||
# password_too_short_message { "needs to have at least #{password_minimum_length} characters" }
|
||||
# login_does_not_meet_requirements_message { "invalid email#{", #{login_requirement_message}" if login_requirement_message}" }
|
||||
|
||||
# Passwords shorter than 8 characters are considered weak according to OWASP.
|
||||
password_minimum_length 8
|
||||
# bcrypt has a maximum input length of 72 bytes, truncating any extra bytes.
|
||||
password_maximum_bytes 72
|
||||
|
||||
# Custom password complexity requirements (alternative to password_complexity feature).
|
||||
# password_meets_requirements? do |password|
|
||||
# super(password) && password_complex_enough?(password)
|
||||
# end
|
||||
# auth_class_eval do
|
||||
# def password_complex_enough?(password)
|
||||
# return true if password.match?(/\d/) && password.match?(/[^a-zA-Z\d]/)
|
||||
# set_password_requirement_error_message(:password_simple, "requires one number and one special character")
|
||||
# false
|
||||
# end
|
||||
# end
|
||||
|
||||
# ==> Remember Feature
|
||||
# Remember all logged in users.
|
||||
after_login { remember_login }
|
||||
|
||||
# Or only remember users that have ticked a "Remember Me" checkbox on login.
|
||||
# after_login { remember_login if param_or_nil("remember") }
|
||||
|
||||
# Extend user's remember period when remembered via a cookie
|
||||
extend_remember_deadline? true
|
||||
|
||||
# ==> Hooks
|
||||
# Validate custom fields in the create account form.
|
||||
# before_create_account do
|
||||
# throw_error_status(422, "name", "must be present") if param("name").empty?
|
||||
# end
|
||||
|
||||
# Perform additional actions after the account is created.
|
||||
# after_create_account do
|
||||
# Profile.create!(account_id: account_id, name: param("name"))
|
||||
# end
|
||||
|
||||
# Do additional cleanup after the account is closed.
|
||||
# after_close_account do
|
||||
# Profile.find_by!(account_id: account_id).destroy
|
||||
# end
|
||||
|
||||
# ==> Redirects
|
||||
# Redirect to home page after logout.
|
||||
logout_redirect "/"
|
||||
|
||||
# Redirect to wherever login redirects to after account verification.
|
||||
# verify_account_redirect { login_redirect }
|
||||
|
||||
# Redirect to login page after password reset.
|
||||
# reset_password_redirect { login_path }
|
||||
|
||||
# Ensure requiring login follows login route changes.
|
||||
require_login_redirect { login_path }
|
||||
|
||||
# ==> Deadlines
|
||||
# Change default deadlines for some actions.
|
||||
# verify_account_grace_period 3.days.to_i
|
||||
# reset_password_deadline_interval Hash[hours: 6]
|
||||
# verify_login_change_deadline_interval Hash[days: 2]
|
||||
# remember_deadline_interval Hash[days: 30]
|
||||
end
|
||||
end
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
class Account < ApplicationRecord
|
||||
include Rodauth::Rails.model
|
||||
|
||||
enum :status, unverified: 1, verified: 2, closed: 3
|
||||
end
|
||||
4
app/models/current.rb
Normal file
4
app/models/current.rb
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
class Current < ActiveSupport::CurrentAttributes
|
||||
attribute :session
|
||||
delegate :user, to: :session, allow_nil: true
|
||||
end
|
||||
3
app/models/session.rb
Normal file
3
app/models/session.rb
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
class Session < ApplicationRecord
|
||||
belongs_to :user
|
||||
end
|
||||
6
app/models/user.rb
Normal file
6
app/models/user.rb
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
class User < ApplicationRecord
|
||||
has_secure_password
|
||||
has_many :sessions, dependent: :destroy
|
||||
|
||||
normalizes :email_address, with: ->(e) { e.strip.downcase }
|
||||
end
|
||||
2
app/views/home/profile.html.slim
Normal file
2
app/views/home/profile.html.slim
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
pre
|
||||
== JSON.pretty_generate(Current.session.attributes.merge(user: Current.session.user.attributes))
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
<% if @sidebar_items %>
|
||||
<% @sidebar_items.each do |sidebar_item| %>
|
||||
<% if sidebar_item[:method].present? && sidebar_item[:method] != :get %>
|
||||
<%= button_to(sidebar_item[:path], method: sidebar_item[:method], class: "list-group-item border-end-0 d-inline-block text-truncate") do %>
|
||||
<%= button_to(sidebar_item[:path], method: sidebar_item[:method], class: "list-group-item border-0 d-inline-block text-truncate") do %>
|
||||
<% if sidebar_item[:icon] %>
|
||||
<span aria-hidden="true" class="bi-<%= sidebar_item[:icon] %>"></span>
|
||||
<% end %>
|
||||
|
|
|
|||
9
app/views/passwords/edit.html.erb
Normal file
9
app/views/passwords/edit.html.erb
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<h1>Update your password</h1>
|
||||
|
||||
<%= tag.div(flash[:alert], style: "color:red") if flash[:alert] %>
|
||||
|
||||
<%= form_with url: password_path(params[:token]), method: :put do |form| %>
|
||||
<%= form.password_field :password, required: true, autocomplete: "new-password", placeholder: "Enter new password", maxlength: 72 %><br>
|
||||
<%= form.password_field :password_confirmation, required: true, autocomplete: "new-password", placeholder: "Repeat new password", maxlength: 72 %><br>
|
||||
<%= form.submit "Save" %>
|
||||
<% end %>
|
||||
8
app/views/passwords/new.html.erb
Normal file
8
app/views/passwords/new.html.erb
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<h1>Forgot your password?</h1>
|
||||
|
||||
<%= tag.div(flash[:alert], style: "color:red") if flash[:alert] %>
|
||||
|
||||
<%= form_with url: passwords_path do |form| %>
|
||||
<%= form.email_field :email_address, required: true, autofocus: true, autocomplete: "username", placeholder: "Enter your email address", value: params[:email_address] %><br>
|
||||
<%= form.submit "Email reset instructions" %>
|
||||
<% end %>
|
||||
4
app/views/passwords_mailer/reset.html.erb
Normal file
4
app/views/passwords_mailer/reset.html.erb
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<p>
|
||||
You can reset your password within the next 15 minutes on
|
||||
<%= link_to "this password reset page", edit_password_url(@user.password_reset_token) %>.
|
||||
</p>
|
||||
2
app/views/passwords_mailer/reset.text.erb
Normal file
2
app/views/passwords_mailer/reset.text.erb
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
You can reset your password within the next 15 minutes on this password reset page:
|
||||
<%= edit_password_url(@user.password_reset_token) %>
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
<%= form_with url: rodauth.login_path, method: :post, data: { turbo: false } do |form| %>
|
||||
<% if rodauth.skip_login_field_on_login? %>
|
||||
<div class="form-group mb-3">
|
||||
<%= form.label "login", rodauth.login_label, class: "form-label" %>
|
||||
<%= form.email_field rodauth.login_param, value: params[rodauth.login_param], id: "login", readonly: true, class: "form-control-plaintext" %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="form-group mb-3">
|
||||
<%= form.label "login", rodauth.login_label, class: "form-label" %>
|
||||
<%= form.email_field rodauth.login_param, value: params[rodauth.login_param], id: "login", autocomplete: rodauth.login_field_autocomplete_value, required: true, class: "form-control #{"is-invalid" if rodauth.field_error(rodauth.login_param)}", aria: ({ invalid: true, describedby: "login_error_message" } if rodauth.field_error(rodauth.login_param)) %>
|
||||
<%= content_tag(:span, rodauth.field_error(rodauth.login_param), class: "invalid-feedback", id: "login_error_message") if rodauth.field_error(rodauth.login_param) %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% unless rodauth.skip_password_field_on_login? %>
|
||||
<div class="form-group mb-3">
|
||||
<%= form.label "password", rodauth.password_label, class: "form-label" %>
|
||||
<%= form.password_field rodauth.password_param, value: "", id: "password", autocomplete: rodauth.password_field_autocomplete_value, required: true, class: "form-control #{"is-invalid" if rodauth.field_error(rodauth.password_param)}", aria: ({ invalid: true, describedby: "password_error_message" } if rodauth.field_error(rodauth.password_param)) %>
|
||||
<%= content_tag(:span, rodauth.field_error(rodauth.password_param), class: "invalid-feedback", id: "password_error_message") if rodauth.field_error(rodauth.password_param) %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<%= form.submit rodauth.login_button, class: "btn btn-primary" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
<% unless rodauth.login_form_footer_links.empty? %>
|
||||
<%== rodauth.login_form_footer_links_heading %>
|
||||
|
||||
<ul>
|
||||
<% rodauth.login_form_footer_links.sort.each do |_, link, text| %>
|
||||
<li><%= link_to text, link %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
<h1>Passwort ändern</h1>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<%= form_with url: rodauth.change_password_path, method: :post, data: { turbo: false } do |form| %>
|
||||
<% if rodauth.change_password_requires_password? %>
|
||||
<div class="form-group mb-3">
|
||||
<%= form.label "password", rodauth.password_label, class: "form-label" %>
|
||||
<%= form.password_field rodauth.password_param, value: "", id: "password", autocomplete: rodauth.password_field_autocomplete_value, required: true, class: "form-control #{"is-invalid" if rodauth.field_error(rodauth.password_param)}", aria: ({ invalid: true, describedby: "password_error_message" } if rodauth.field_error(rodauth.password_param)) %>
|
||||
<%= content_tag(:span, rodauth.field_error(rodauth.password_param), class: "invalid-feedback", id: "password_error_message") if rodauth.field_error(rodauth.password_param) %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<%= form.label "new-password", rodauth.new_password_label, class: "form-label" %>
|
||||
<%= form.password_field rodauth.new_password_param, value: "", id: "new-password", autocomplete: "new-password", required: true, class: "form-control #{"is-invalid" if rodauth.field_error(rodauth.new_password_param)}", aria: ({ invalid: true, describedby: "new-password_error_message" } if rodauth.field_error(rodauth.new_password_param)) %>
|
||||
<%= content_tag(:span, rodauth.field_error(rodauth.new_password_param), class: "invalid-feedback", id: "new-password_error_message") if rodauth.field_error(rodauth.new_password_param) %>
|
||||
</div>
|
||||
|
||||
<% if rodauth.require_password_confirmation? %>
|
||||
<div class="form-group mb-3">
|
||||
<%= form.label "password-confirm", rodauth.password_confirm_label, class: "form-label" %>
|
||||
<%= form.password_field rodauth.password_confirm_param, value: "", id: "password-confirm", autocomplete: "new-password", required: true, class: "form-control #{"is-invalid" if rodauth.field_error(rodauth.password_confirm_param)}", aria: ({ invalid: true, describedby: "password-confirm_error_message" } if rodauth.field_error(rodauth.password_confirm_param)) %>
|
||||
<%= content_tag(:span, rodauth.field_error(rodauth.password_confirm_param), class: "invalid-feedback", id: "password-confirm_error_message") if rodauth.field_error(rodauth.password_confirm_param) %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<%= form.submit rodauth.change_password_button, class: "btn btn-primary" %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
<%== rodauth.login_form_header %>
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<%= render "login_form" %>
|
||||
</div>
|
||||
</div>
|
||||
<%== rodauth.login_form_footer %>
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
<h1>Adieu</h1>
|
||||
<%= form_with url: rodauth.logout_path, method: :post, data: { turbo: false } do |form| %>
|
||||
<% if rodauth.features.include?(:active_sessions) %>
|
||||
<div class="form-group mb-3">
|
||||
<div class="form-check">
|
||||
<%= form.check_box rodauth.global_logout_param, id: "global-logout", class: "form-check-input", include_hidden: false %>
|
||||
<%= form.label "global-logout", rodauth.global_logout_label, class: "form-check-label" %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="form-group mb-3">
|
||||
<%= form.submit "Log out", class: "btn btn-warning" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
<%== rodauth.login_form_header %>
|
||||
<%== rodauth.render_multi_phase_login_forms %>
|
||||
<%== rodauth.login_form_footer %>
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
<h1><%= current_account.email %></h1>
|
||||
|
||||
<pre><%= JSON.pretty_generate current_account.attributes %></pre>
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
<%= form_with url: rodauth.remember_path, method: :post, data: { turbo: false } do |form| %>
|
||||
<fieldset class="form-group mb-3">
|
||||
<div class="form-check">
|
||||
<%= form.radio_button rodauth.remember_param, rodauth.remember_remember_param_value, id: "remember-remember", class: "form-check-input" %>
|
||||
<%= form.label "remember-remember", rodauth.remember_remember_label, class: "form-check-label" %>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<%= form.radio_button rodauth.remember_param, rodauth.remember_forget_param_value, id: "remember-forget", class: "form-check-input" %>
|
||||
<%= form.label "remember-forget", rodauth.remember_forget_label, class: "form-check-label" %>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<%= form.radio_button rodauth.remember_param, rodauth.remember_disable_param_value, id: "remember-disable", class: "form-check-input" %>
|
||||
<%= form.label "remember-disable", rodauth.remember_disable_label, class: "form-check-label" %>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<%= form.submit rodauth.remember_button, class: "btn btn-primary" %>
|
||||
</div>
|
||||
<% end %>
|
||||
13
app/views/sessions/new.html.slim
Normal file
13
app/views/sessions/new.html.slim
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
= tag.div(flash[:alert], style: "color:red") if flash[:alert]
|
||||
= tag.div(flash[:notice], style: "color:green") if flash[:notice]
|
||||
|
||||
h1 Login
|
||||
|
||||
= bootstrap_form_with url: session_path do |form|
|
||||
= form.email_field :email_address, required: true, autofocus: true, autocomplete: "username", placeholder: "Enter your email address", value: params[:email_address], label: User.human_attribute_name(:email_address)
|
||||
br
|
||||
= form.password_field :password, required: true, autocomplete: "current-password", placeholder: "Enter your password", maxlength: 72, label: User.human_attribute_name(:password)
|
||||
br
|
||||
= form.submit "Login"
|
||||
br
|
||||
= link_to "Forgot password?", new_password_path
|
||||
Loading…
Add table
Add a link
Reference in a new issue