admin: user management, invites, password reset, audit log
Add /admin/users to create, edit, disable and delete accounts with the per-area permission grid. New users get a one-time invite link (48 h) by email; the admin also sees it once, so an account without email can still be onboarded. Forgotten passwords get a 1 h reset link with the same answer for unknown accounts. Only token hashes are stored. Guards against escalation and lockout: a user manager can only grant flags they hold and cannot touch flags they lack; only superusers change superuser accounts; nobody can disable or delete themselves; the last active superuser stays. Logins, user changes, and bingo and invoice actions are recorded in an audit log at /admin/audit. Read timestamps as UTC: they are all written with Time.now.utc, and on a UTC+4 host a fresh 1 h token read back as already expired. Assisted-by: Claude:opus-5
This commit is contained in:
parent
8471570187
commit
d91a72f603
17 changed files with 686 additions and 0 deletions
|
|
@ -24,6 +24,7 @@ require_relative 'lib/db'
|
|||
require_relative 'lib/admin_auth'
|
||||
require_relative 'lib/s3'
|
||||
require_relative 'lib/bingo_admin'
|
||||
require_relative 'lib/users_admin'
|
||||
|
||||
# Invoice model needs a live Sequel connection at class-definition time.
|
||||
if ENV['DATABASE_URL']
|
||||
|
|
@ -38,6 +39,7 @@ if ENV['DATABASE_URL']
|
|||
require_relative 'lib/bingo'
|
||||
Bingo.seed!
|
||||
require_relative 'lib/user'
|
||||
require_relative 'lib/audit'
|
||||
User.bootstrap!(ENV['ADMIN_USER'], ENV['ADMIN_PASSWORD'])
|
||||
else
|
||||
$logger.warn('DATABASE_URL not set — invoicing disabled')
|
||||
|
|
@ -67,6 +69,7 @@ class AsxpioWeb < Sinatra::Base
|
|||
use Rack::Protection::AuthenticityToken
|
||||
register AdminAuth
|
||||
register BingoAdmin
|
||||
register UsersAdmin
|
||||
|
||||
Mailer.configure!
|
||||
|
||||
|
|
@ -288,6 +291,7 @@ class AsxpioWeb < Sinatra::Base
|
|||
retry
|
||||
end
|
||||
|
||||
audit!('invoice.create', invoice.number, "#{invoice.client_name}, #{invoice.currency} #{'%.2f' % invoice.total}")
|
||||
redirect "/admin/invoices/#{invoice.uuid}"
|
||||
end
|
||||
|
||||
|
|
@ -302,6 +306,7 @@ class AsxpioWeb < Sinatra::Base
|
|||
invoice = Invoice[uuid: params[:uuid]] or halt 404
|
||||
invoice.paid_at = invoice.paid? ? nil : Time.now.utc
|
||||
invoice.save_changes
|
||||
audit!(invoice.paid? ? 'invoice.paid' : 'invoice.unpaid', invoice.number)
|
||||
redirect "/admin/invoices/#{invoice.uuid}"
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue