;;;; users.lisp - ParenScript version of users.js
;;;; User management page for admins
(in-package #:asteroid)
(defparameter *users-js*
(ps:ps*
'(progn
;; Load user stats
(defun load-user-stats ()
(ps:chain
(fetch "/api/asteroid/user-stats")
(then (lambda (response) (ps:chain response (json))))
(then (lambda (result)
(let ((data (or (ps:@ result data) result)))
(when (and (= (ps:@ data status) "success") (ps:@ data stats))
(let ((stats (ps:@ data stats)))
(setf (ps:@ (ps:chain document (get-element-by-id "total-users")) text-content)
(or (ps:getprop stats "total-users") 0))
(setf (ps:@ (ps:chain document (get-element-by-id "active-users")) text-content)
(or (ps:getprop stats "active-users") 0))
(setf (ps:@ (ps:chain document (get-element-by-id "admin-users")) text-content)
(or (ps:getprop stats "admins") 0))
(setf (ps:@ (ps:chain document (get-element-by-id "dj-users")) text-content)
(or (ps:getprop stats "djs") 0)))))))
(catch (lambda (error)
(ps:chain console (error "Error loading user stats:" error))))))
;; Load users list
(defun load-users ()
(ps:chain
(fetch "/api/asteroid/users")
(then (lambda (response) (ps:chain response (json))))
(then (lambda (result)
(let ((data (or (ps:@ result data) result)))
(when (= (ps:@ data status) "success")
(show-users-table (ps:@ data users))
(setf (ps:@ (ps:chain document (get-element-by-id "users-list-section")) style display) "block")))))
(catch (lambda (error)
(ps:chain console (error "Error loading users:" error))
(alert "Error loading users. Please try again.")))))
;; Show users table
(defun show-users-table (users)
(let ((container (ps:chain document (get-element-by-id "users-container")))
(users-html (ps:chain users
(map (lambda (user)
(+ "
"
"| " (ps:@ user username) " | "
"" (ps:@ user email) " | "
""
""
" | "
"" (if (ps:@ user active) "✅ Active" "❌ Inactive") " | "
"" (if (ps:getprop user "last-login")
(ps:chain (ps:new (-date (* (ps:getprop user "last-login") 1000))) (to-locale-string))
"Never") " | "
""
(if (ps:@ user active)
(+ "")
(+ ""))
" | "
"
")))
(join ""))))
(setf (ps:@ container inner-h-t-m-l)
(+ ""
""
""
"| Username | "
"Email | "
"Role | "
"Status | "
"Last Login | "
"Actions | "
"
"
""
""
users-html
""
"
"
""))))
(defun hide-users-table ()
(setf (ps:@ (ps:chain document (get-element-by-id "users-list-section")) style display) "none"))
;; Update user role
(defun update-user-role (user-id new-role)
(let ((form-data (ps:new (-form-data))))
(ps:chain form-data (append "user-id" user-id))
(ps:chain form-data (append "role" new-role))
(ps:chain
(fetch "/api/asteroid/user/role"
(ps:create :method "POST" :body form-data))
(then (lambda (response) (ps:chain response (json))))
(then (lambda (result)
;; Handle Radiance API data wrapping
(let ((data (or (ps:@ result data) result)))
(if (= (ps:@ data status) "success")
(progn
(load-user-stats)
(alert (ps:@ data message)))
(alert (+ "Error updating user role: " (ps:@ data message)))))))
(catch (lambda (error)
(ps:chain console (error "Error updating user role:" error))
(alert "Error updating user role. Please try again."))))))
;; Deactivate user
(defun deactivate-user (user-id)
(when (not (confirm "Are you sure you want to deactivate this user?"))
(return))
(let ((form-data (ps:new (-form-data))))
(ps:chain form-data (append "user-id" user-id))
(ps:chain form-data (append "active" 0))
(ps:chain
(fetch "/api/asteroid/user/activate"
(ps:create :method "POST" :body form-data))
(then (lambda (response) (ps:chain response (json))))
(then (lambda (result)
;; Handle Radiance API data wrapping
(let ((data (or (ps:@ result data) result)))
(if (= (ps:@ data status) "success")
(progn
(load-users)
(load-user-stats)
(alert (ps:@ data message)))
(alert (+ "Error deactivating user: " (ps:@ data message)))))))
(catch (lambda (error)
(ps:chain console (error "Error deactivating user:" error))
(alert "Error deactivating user. Please try again."))))))
;; Activate user
(defun activate-user (user-id)
(when (not (confirm "Are you sure you want to activate this user?"))
(return))
(let ((form-data (ps:new (-form-data))))
(ps:chain form-data (append "user-id" user-id))
(ps:chain form-data (append "active" 1))
(ps:chain
(fetch "/api/asteroid/user/activate"
(ps:create :method "POST" :body form-data))
(then (lambda (response) (ps:chain response (json))))
(then (lambda (result)
;; Handle Radiance API data wrapping
(let ((data (or (ps:@ result data) result)))
(if (= (ps:@ data status) "success")
(progn
(load-users)
(load-user-stats)
(alert (ps:@ data message)))
(alert (+ "Error activating user: " (ps:@ data message)))))))
(catch (lambda (error)
(ps:chain console (error "Error activating user:" error))
(alert "Error activating user. Please try again."))))))
;; Toggle create user form
(defun toggle-create-user-form ()
(let ((form (ps:chain document (get-element-by-id "create-user-form"))))
(if (= (ps:@ form style display) "none")
(progn
(setf (ps:@ form style display) "block")
(setf (ps:@ (ps:chain document (get-element-by-id "new-username")) value) "")
(setf (ps:@ (ps:chain document (get-element-by-id "new-email")) value) "")
(setf (ps:@ (ps:chain document (get-element-by-id "new-password")) value) "")
(setf (ps:@ (ps:chain document (get-element-by-id "new-role")) value) "listener"))
(setf (ps:@ form style display) "none"))))
;; Create new user
(defun create-new-user (event)
(ps:chain event (prevent-default))
(let ((username (ps:@ (ps:chain document (get-element-by-id "new-username")) value))
(email (ps:@ (ps:chain document (get-element-by-id "new-email")) value))
(password (ps:@ (ps:chain document (get-element-by-id "new-password")) value))
(role (ps:@ (ps:chain document (get-element-by-id "new-role")) value))
(form-data (ps:new (-form-data))))
(ps:chain form-data (append "username" username))
(ps:chain form-data (append "email" email))
(ps:chain form-data (append "password" password))
(ps:chain form-data (append "role" role))
(ps:chain
(fetch "/api/asteroid/users/create"
(ps:create :method "POST" :body form-data))
(then (lambda (response) (ps:chain response (json))))
(then (lambda (result)
(let ((data (or (ps:@ result data) result)))
(if (= (ps:@ data status) "success")
(progn
(alert (+ "User \"" username "\" created successfully!"))
(toggle-create-user-form)
(load-user-stats)
(load-users))
(alert (+ "Error creating user: " (or (ps:@ data message) (ps:@ result message))))))))
(catch (lambda (error)
(ps:chain console (error "Error creating user:" error))
(alert "Error creating user. Please try again."))))))
;; Initialize on page load
(ps:chain document
(add-event-listener
"DOMContentLoaded"
load-user-stats))
;; Update user stats every 30 seconds
(set-interval load-user-stats 30000)))
"Compiled JavaScript for users management - generated at load time")
(defun generate-users-js ()
"Return the pre-compiled JavaScript for users page"
*users-js*)