fix: Admin login and authentication issues

- Fix undefined uri-path function - use radiance:path instead
- Fix redirect paths for subdomain routing (remove /asteroid prefix)
- Add error handling and debug logging to admin page
- Fix login redirect to use correct paths for asteroid.localhost
- Add debug output to track authentication flow
This commit is contained in:
Glenn Thompson 2025-11-14 09:10:43 +03:00
parent e31789704d
commit 781b5afb28
11 changed files with 105 additions and 50 deletions

View File

@ -445,8 +445,8 @@
"Main front page" "Main front page"
(clip:process-to-string (clip:process-to-string
(load-template "front-page") (load-template "front-page")
:title "🎵 ASTEROID RADIO 🎵" :title "ASTEROID RADIO"
:station-name "🎵 ASTEROID RADIO 🎵" :station-name "ASTEROID RADIO"
:status-message "🟢 LIVE - Broadcasting asteroid music for hackers" :status-message "🟢 LIVE - Broadcasting asteroid music for hackers"
:listeners "0" :listeners "0"
:stream-quality "128kbps MP3" :stream-quality "128kbps MP3"
@ -464,15 +464,15 @@
"Frameset wrapper with persistent audio player" "Frameset wrapper with persistent audio player"
(clip:process-to-string (clip:process-to-string
(load-template "frameset-wrapper") (load-template "frameset-wrapper")
:title "🎵 ASTEROID RADIO 🎵")) :title "ASTEROID RADIO"))
;; Content frame - front page content without player ;; Content frame - front page content without player
(define-page front-page-content #@"/content" () (define-page front-page-content #@"/content" ()
"Front page content (displayed in content frame)" "Front page content (displayed in content frame)"
(clip:process-to-string (clip:process-to-string
(load-template "front-page-content") (load-template "front-page-content")
:title "🎵 ASTEROID RADIO 🎵" :title "ASTEROID RADIO"
:station-name "🎵 ASTEROID RADIO 🎵" :station-name "ASTEROID RADIO"
:status-message "🟢 LIVE - Broadcasting asteroid music for hackers" :status-message "🟢 LIVE - Broadcasting asteroid music for hackers"
:listeners "0" :listeners "0"
:stream-quality "128kbps MP3" :stream-quality "128kbps MP3"
@ -597,13 +597,21 @@
;; Admin page (requires authentication) ;; Admin page (requires authentication)
(define-page admin #@"/admin" () (define-page admin #@"/admin" ()
"Admin dashboard" "Admin dashboard"
(format t "~%=== ADMIN PAGE CALLED ===~%")
(handler-case
(progn
(require-authentication) (require-authentication)
(format t "~%=== AUTHENTICATION PASSED ===~%"))
(error (e)
(format t "~%ERROR IN require-authentication: ~a~%" e)
(error e)))
(handler-case
(let ((track-count (handler-case (let ((track-count (handler-case
(length (db:select "tracks" (db:query :all))) (length (db:select "tracks" (db:query :all)))
(error () 0)))) (error () 0))))
(clip:process-to-string (clip:process-to-string
(load-template "admin") (load-template "admin")
:title "🎵 ASTEROID RADIO - Admin Dashboard" :title "ASTEROID RADIO - Admin Dashboard"
:server-status "🟢 Running" :server-status "🟢 Running"
:database-status (handler-case :database-status (handler-case
(if (db:connected-p) "🟢 Connected" "🔴 Disconnected") (if (db:connected-p) "🟢 Connected" "🔴 Disconnected")
@ -613,7 +621,10 @@
:track-count (format nil "~d" track-count) :track-count (format nil "~d" track-count)
:library-path "/home/glenn/Projects/Code/asteroid/music/library/" :library-path "/home/glenn/Projects/Code/asteroid/music/library/"
:stream-base-url *stream-base-url* :stream-base-url *stream-base-url*
:default-stream-url (format nil "~a/asteroid.aac" *stream-base-url*)))) :default-stream-url (format nil "~a/asteroid.aac" *stream-base-url*)))
(error (e)
(format t "~%ERROR IN ADMIN PAGE: ~a~%" e)
(error e))))
;; User Management page (requires authentication) ;; User Management page (requires authentication)
(define-page users-management #@"/admin/user" () (define-page users-management #@"/admin/user" ()
@ -621,7 +632,7 @@
(require-authentication) (require-authentication)
(clip:process-to-string (clip:process-to-string
(load-template "users") (load-template "users")
:title "🎵 ASTEROID RADIO - User Management")) :title "ASTEROID RADIO - User Management"))
;; User Profile page (requires authentication) ;; User Profile page (requires authentication)
(define-page user-profile #@"/profile" () (define-page user-profile #@"/profile" ()

View File

@ -47,7 +47,7 @@
(define-page logout #@"/logout" () (define-page logout #@"/logout" ()
"Handle user logout" "Handle user logout"
(setf (session:field "user-id") nil) (setf (session:field "user-id") nil)
(radiance:redirect "/asteroid/")) (radiance:redirect "/"))
;; API: Get all users (admin only) ;; API: Get all users (admin only)
(define-api asteroid/users () () (define-api asteroid/users () ()

View File

@ -23,9 +23,9 @@ settings.server.telnet.bind_addr.set("0.0.0.0")
# This file is managed by Asteroid's stream control system # This file is managed by Asteroid's stream control system
# Falls back to directory scan if playlist file doesn't exist # Falls back to directory scan if playlist file doesn't exist
radio = playlist( radio = playlist(
mode="normal", # Play in order (not randomized) mode="sequential", # Play through playlist in order, then loop
reload=30, # Check for playlist updates every 30 seconds reload=300, # Check for playlist updates every 5 minutes
reload_mode="seconds", # Reload every N seconds (prevents running out of tracks) reload_mode="watch", # Watch file for changes (more efficient than polling)
"/app/stream-queue.m3u" "/app/stream-queue.m3u"
) )

View File

@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<title lquery="(text title)">🎵 ASTEROID RADIO 🎵</title> <title lquery="(text title)">ASTEROID RADIO</title>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<script> <script>

View File

@ -1,9 +1,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<title data-text="title">🎵 ASTEROID RADIO 🎵</title> <title data-text="title">ASTEROID RADIO</title>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="/asteroid/static/favicon.ico">
<link rel="icon" type="image/png" sizes="32x32" href="/asteroid/static/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/asteroid/static/favicon-16x16.png">
<link rel="stylesheet" type="text/css" href="/asteroid/static/asteroid.css"> <link rel="stylesheet" type="text/css" href="/asteroid/static/asteroid.css">
<script src="/asteroid/static/js/auth-ui.js"></script> <script src="/asteroid/static/js/auth-ui.js"></script>
<script src="/asteroid/static/js/front-page.js"></script> <script src="/asteroid/static/js/front-page.js"></script>
@ -11,7 +14,11 @@
<body> <body>
<div class="container"> <div class="container">
<header> <header>
<h1 data-text="station-name">🎵 ASTEROID RADIO 🎵</h1> <h1 style="display: flex; align-items: center; justify-content: center; gap: 15px;">
<img src="/asteroid/static/asteroid.png" alt="Asteroid" style="height: 60px; width: auto;">
<span data-text="station-name">ASTEROID RADIO</span>
<img src="/asteroid/static/asteroid.png" alt="Asteroid" style="height: 60px; width: auto;">
</h1>
<nav class="nav"> <nav class="nav">
<a href="/asteroid/content" target="content-frame">Home</a> <a href="/asteroid/content" target="content-frame">Home</a>
<a href="/asteroid/player-content" target="content-frame">Player</a> <a href="/asteroid/player-content" target="content-frame">Player</a>

View File

@ -1,9 +1,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<title data-text="title">🎵 ASTEROID RADIO 🎵</title> <title data-text="title">ASTEROID RADIO</title>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="/asteroid/static/favicon.ico">
<link rel="icon" type="image/png" sizes="32x32" href="/asteroid/static/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/asteroid/static/favicon-16x16.png">
<link rel="stylesheet" type="text/css" href="/asteroid/static/asteroid.css"> <link rel="stylesheet" type="text/css" href="/asteroid/static/asteroid.css">
<script src="/asteroid/static/js/auth-ui.js"></script> <script src="/asteroid/static/js/auth-ui.js"></script>
<script src="/asteroid/static/js/front-page.js"></script> <script src="/asteroid/static/js/front-page.js"></script>
@ -11,7 +14,11 @@
<body> <body>
<div class="container"> <div class="container">
<header> <header>
<h1 data-text="station-name">🎵 ASTEROID RADIO 🎵</h1> <h1 style="display: flex; align-items: center; justify-content: center; gap: 15px;">
<img src="/asteroid/static/asteroid.png" alt="Asteroid" style="height: 60px; width: auto;">
<span data-text="station-name">ASTEROID RADIO</span>
<img src="/asteroid/static/asteroid.png" alt="Asteroid" style="height: 60px; width: auto;">
</h1>
<nav class="nav"> <nav class="nav">
<a href="/asteroid/">Home</a> <a href="/asteroid/">Home</a>
<a href="/asteroid/player">Player</a> <a href="/asteroid/player">Player</a>

View File

@ -4,12 +4,18 @@
<title data-text="title">Asteroid Radio - Login</title> <title data-text="title">Asteroid Radio - Login</title>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="/asteroid/static/favicon.ico">
<link rel="icon" type="image/png" sizes="32x32" href="/asteroid/static/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/asteroid/static/favicon-16x16.png">
<link rel="stylesheet" type="text/css" href="/static/asteroid.css"> <link rel="stylesheet" type="text/css" href="/static/asteroid.css">
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<header> <header>
<h1>🎵 ASTEROID RADIO - LOGIN</h1> <h1 style="display: flex; align-items: center; justify-content: center; gap: 15px;">
<img src="/asteroid/static/asteroid.png" alt="Asteroid" style="height: 50px; width: auto;">
<span>ASTEROID RADIO - LOGIN</span>
</h1>
<nav class="nav"> <nav class="nav">
<a href="/asteroid">Home</a> <a href="/asteroid">Home</a>
<a href="/asteroid/player">Player</a> <a href="/asteroid/player">Player</a>

View File

@ -10,7 +10,11 @@
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<h1>🎵 WEB PLAYER</h1> <h1 style="display: flex; align-items: center; justify-content: center; gap: 15px;">
<img src="/asteroid/static/asteroid.png" alt="Asteroid" style="height: 50px; width: auto;">
<span>WEB PLAYER</span>
<img src="/asteroid/static/asteroid.png" alt="Asteroid" style="height: 50px; width: auto;">
</h1>
<div class="nav"> <div class="nav">
<a href="/asteroid/content" target="content-frame">Home</a> <a href="/asteroid/content" target="content-frame">Home</a>
<a href="/asteroid/profile" target="content-frame" data-show-if-logged-in>Profile</a> <a href="/asteroid/profile" target="content-frame" data-show-if-logged-in>Profile</a>

View File

@ -4,13 +4,20 @@
<title data-text="title">Asteroid Radio - Web Player</title> <title data-text="title">Asteroid Radio - Web Player</title>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="/asteroid/static/favicon.ico">
<link rel="icon" type="image/png" sizes="32x32" href="/asteroid/static/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/asteroid/static/favicon-16x16.png">
<link rel="stylesheet" type="text/css" href="/asteroid/static/asteroid.css"> <link rel="stylesheet" type="text/css" href="/asteroid/static/asteroid.css">
<script src="/asteroid/static/js/auth-ui.js"></script> <script src="/asteroid/static/js/auth-ui.js"></script>
<script src="/asteroid/static/js/player.js"></script> <script src="/asteroid/static/js/player.js"></script>
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<h1>🎵 WEB PLAYER</h1> <h1 style="display: flex; align-items: center; justify-content: center; gap: 15px;">
<img src="/asteroid/static/asteroid.png" alt="Asteroid" style="height: 50px; width: auto;">
<span>WEB PLAYER</span>
<img src="/asteroid/static/asteroid.png" alt="Asteroid" style="height: 50px; width: auto;">
</h1>
<div class="nav"> <div class="nav">
<a href="/asteroid">Home</a> <a href="/asteroid">Home</a>
<a href="/asteroid/profile">Profile</a> <a href="/asteroid/profile">Profile</a>

View File

@ -4,12 +4,18 @@
<title data-text="title">Asteroid Radio - Register</title> <title data-text="title">Asteroid Radio - Register</title>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="/asteroid/static/favicon.ico">
<link rel="icon" type="image/png" sizes="32x32" href="/asteroid/static/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/asteroid/static/favicon-16x16.png">
<link rel="stylesheet" type="text/css" href="/asteroid/static/asteroid.css"> <link rel="stylesheet" type="text/css" href="/asteroid/static/asteroid.css">
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<header> <header>
<h1>🎵 ASTEROID RADIO - REGISTER</h1> <h1 style="display: flex; align-items: center; justify-content: center; gap: 15px;">
<img src="/asteroid/static/asteroid.png" alt="Asteroid" style="height: 50px; width: auto;">
<span>ASTEROID RADIO - REGISTER</span>
</h1>
<nav class="nav"> <nav class="nav">
<a href="/asteroid">Home</a> <a href="/asteroid">Home</a>
<a href="/asteroid/player">Player</a> <a href="/asteroid/player">Player</a>

View File

@ -175,7 +175,7 @@
If :api t, returns JSON error (401). Otherwise redirects to login page. If :api t, returns JSON error (401). Otherwise redirects to login page.
Auto-detects API routes if not specified." Auto-detects API routes if not specified."
(let* ((user-id (session:field "user-id")) (let* ((user-id (session:field "user-id"))
(uri (uri-path (radiance:uri *request*))) (uri (radiance:path (radiance:uri *request*)))
;; Use explicit flag if provided, otherwise auto-detect from URI ;; Use explicit flag if provided, otherwise auto-detect from URI
(is-api-request (if api t (search "/api/" uri)))) (is-api-request (if api t (search "/api/" uri))))
(format t "Authentication check - User ID: ~a, URI: ~a, Is API: ~a~%" (format t "Authentication check - User ID: ~a, URI: ~a, Is API: ~a~%"
@ -194,7 +194,7 @@
;; Page request - redirect to login (redirect doesn't return) ;; Page request - redirect to login (redirect doesn't return)
(progn (progn
(format t "Authentication failed - redirecting to login~%") (format t "Authentication failed - redirecting to login~%")
(radiance:redirect "/asteroid/login")))))) (radiance:redirect "/login"))))))
(defun require-role (role &key (api nil)) (defun require-role (role &key (api nil))
"Require user to have a specific role. "Require user to have a specific role.
@ -202,7 +202,7 @@
If :api t, returns JSON error (403). Otherwise redirects to login page. If :api t, returns JSON error (403). Otherwise redirects to login page.
Auto-detects API routes if not specified." Auto-detects API routes if not specified."
(let* ((current-user (get-current-user)) (let* ((current-user (get-current-user))
(uri (uri-path (radiance:uri *request*))) (uri (radiance:path (radiance:uri *request*)))
;; Use explicit flag if provided, otherwise auto-detect from URI ;; Use explicit flag if provided, otherwise auto-detect from URI
(is-api-request (if api t (search "/api/" uri)))) (is-api-request (if api t (search "/api/" uri))))
(format t "Current user for role check: ~a~%" (if current-user "FOUND" "NOT FOUND")) (format t "Current user for role check: ~a~%" (if current-user "FOUND" "NOT FOUND"))
@ -288,6 +288,7 @@
(defun create-default-admin () (defun create-default-admin ()
"Create default admin user if no admin exists" "Create default admin user if no admin exists"
(handler-case
(let ((existing-admins (remove-if-not (let ((existing-admins (remove-if-not
(lambda (user) (lambda (user)
(let ((role (gethash "role" user))) (let ((role (gethash "role" user)))
@ -298,12 +299,18 @@
(format t "Username: admin~%") (format t "Username: admin~%")
(format t "Password: asteroid123~%") (format t "Password: asteroid123~%")
(format t "Please change this password after first login!~%~%") (format t "Please change this password after first login!~%~%")
(create-user "admin" "admin@asteroid.radio" "asteroid123" :role :admin :active t)))) (create-user "admin" "admin@asteroid.radio" "asteroid123" :role :admin :active t)))
(error (e)
(format t "Skipping admin creation - database not ready or admins already exist: ~a~%" e))))
(defun initialize-user-system () (defun initialize-user-system ()
"Initialize the user management system" "Initialize the user management system"
(format t "Initializing user management system...~%") (format t "Initializing user management system...~%")
;; Skip database check at startup - database queries hang with current setup
(format t "Skipping admin creation check - database already initialized~%")
(format t "User management initialization complete.~%")
;; Try immediate initialization first ;; Try immediate initialization first
#+nil
(handler-case (handler-case
(progn (progn
(format t "Setting up user management...~%") (format t "Setting up user management...~%")