diff --git a/.gitignore b/.gitignore index dc0837c..4d55b48 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,16 @@ docker/music/*.m4a docker/music/*.aac docker/music/*.wma +music/library +# music/library/*/*.mp3 +# music/library/*/*.flac +# music/library/*/*.ogg +# music/library/*/*.wav +# music/library/*/*.m4a +# music/library/*/*.aac +# music/library/*/*.wma + + # Docker build artifacts docker/.env docker/.dockerignore diff --git a/asteroid.lisp b/asteroid.lisp index 5ecf4bf..bdd673e 100644 --- a/asteroid.lisp +++ b/asteroid.lisp @@ -66,8 +66,7 @@ (require-authentication) (with-error-handling (let* ((user (get-current-user)) - (user-id-raw (gethash "_id" user)) - (user-id (if (listp user-id-raw) (first user-id-raw) user-id-raw)) + (user-id (dm:id user)) (playlists (get-user-playlists user-id))) (api-output `(("status" . "success") ("playlists" . ,(mapcar (lambda (playlist) @@ -98,8 +97,7 @@ (require-authentication) (with-error-handling (let* ((user (get-current-user)) - (user-id-raw (gethash "_id" user)) - (user-id (if (listp user-id-raw) (first user-id-raw) user-id-raw))) + (user-id (dm:id user))) (create-playlist user-id name description) (if (string= "true" (post/get "browser")) (redirect "/asteroid/") @@ -666,8 +664,7 @@ (api-output `(("loggedIn" . ,(if user t nil)) ("isAdmin" . ,(if (and user (user-has-role-p user :admin)) t nil)) ("username" . ,(if user - (let ((username (gethash "username" user))) - (if (listp username) (first username) username)) + (dm:field user "username") nil))))))) ;; User profile API endpoints @@ -679,11 +676,11 @@ (user (find-user-by-id user-id))) (if user (api-output `(("status" . "success") - ("user" . (("username" . ,(first (gethash "username" user))) - ("email" . ,(first (gethash "email" user))) - ("role" . ,(first (gethash "role" user))) - ("created_at" . ,(first (gethash "created-date" user))) - ("last_active" . ,(first (gethash "last-login" user))))))) + ("user" . (("username" . ,(dm:field user "username")) + ("email" . ,(dm:field user "email")) + ("role" . ,(dm:field user "role")) + ("created_at" . ,(dm:field user "created-at")) + ("last_active" . ,(dm:field user "last-active")))))) (signal-not-found "user" user-id))))) (define-api asteroid/user/listening-stats () () @@ -746,8 +743,8 @@ ;; Auto-login after successful registration (let ((user (find-user-by-username username))) (when user - (let ((user-id (gethash "_id" user))) - (setf (session:field "user-id") (if (listp user-id) (first user-id) user-id))))) + (let ((user-id (dm:id user))) + (setf (session:field "user-id") user-id)))) ;; Redirect new users to their profile page (radiance:redirect "/asteroid/profile")) (clip:process-to-string diff --git a/auth-routes.lisp b/auth-routes.lisp index 8810a41..3095b9a 100644 --- a/auth-routes.lisp +++ b/auth-routes.lisp @@ -14,12 +14,11 @@ (if user (progn ;; Login successful - store user ID in session - (format t "Login successful for user: ~a~%" (gethash "username" user)) + (format t "Login successful for user: ~a~%" (dm:field user "username")) (handler-case (progn - (let* ((user-id (gethash "_id" user)) - (user-role-raw (gethash "role" user)) - (user-role (if (listp user-role-raw) (first user-role-raw) user-role-raw)) + (let* ((user-id (dm:id user)) + (user-role (dm:field user "role")) (redirect-path (cond ;; Admin users go to admin dashboard ((string-equal user-role "admin") "/admin") @@ -27,7 +26,8 @@ (t "/profile")))) (format t "User ID from DB: ~a~%" user-id) (format t "User role: ~a, redirecting to: ~a~%" user-role redirect-path) - (setf (session:field "user-id") (if (listp user-id) (first user-id) user-id)) + (setf (session:field "user-id") user-id) + (format t "User ID #~a persisted in session.~%" (session:field "user-id")) (radiance:redirect redirect-path))) (error (e) (format t "Session error: ~a~%" e) @@ -61,15 +61,13 @@ (let ((users (get-all-users))) (api-output `(("status" . "success") ("users" . ,(mapcar (lambda (user) - `(("id" . ,(if (listp (gethash "_id" user)) - (first (gethash "_id" user)) - (gethash "_id" user))) - ("username" . ,(first (gethash "username" user))) - ("email" . ,(first (gethash "email" user))) - ("role" . ,(first (gethash "role" user))) - ("active" . ,(= (first (gethash "active" user)) 1)) - ("created-date" . ,(first (gethash "created-date" user))) - ("last-login" . ,(first (gethash "last-login" user))))) + `(("id" . ,(dm:id user)) + ("username" . ,(dm:field user "username")) + ("email" . ,(dm:field user "email")) + ("role" . ,(dm:field user "role")) + ("active" . ,(= (dm:field user "active") 1)) + ("created-date" . ,(dm:field user "created-date")) + ("last-login" . ,(dm:field user "last-login")))) users))))) (error (e) (api-output `(("status" . "error") @@ -120,10 +118,10 @@ (unless (>= (length new-password) 8) (error 'validation-error :message "New password must be at least 8 characters")) - (let* ((user-id (session-field 'user-id)) + (let* ((user-id (session:field "user-id")) (username (when user-id (let ((user (find-user-by-id user-id))) - (when user (gethash "username" user)))))) + (when user (dm:field user "username")))))) (unless username (error 'authentication-error :message "Not authenticated")) diff --git a/database.lisp b/database.lisp index 8c141e0..d71903a 100644 --- a/database.lisp +++ b/database.lisp @@ -47,3 +47,26 @@ (format t "~2&Database collections initialized~%")) +(defun data-model-as-alist (model) + "Converts a radiance data-model instance into a alist" + (unless (dm:hull-p model) + (loop for field in (dm:fields model) + collect (cons field (dm:field model field))))) + +(defun lambdalite-db-p () + "Checks if application is using lambdalite as database backend" + (string= (string-upcase (package-name (db:implementation))) + "I-LAMBDALITE")) + +(defun data-model-save (data-model) + "Wrapper on data-model save method to bypass error using dm:save on lambdalite. +It uses the same approach as dm:save under the hood through db:save." + (if (lambdalite-db-p) + (progn + (format t "Updating lambdalite collection '~a'~%" (dm:collection data-model)) + (db:update (dm:collection data-model) + (db:query (:= '_id (dm:id data-model))) + (dm:field-table data-model))) + (progn + (format t "Updating database table '~a'~%" (dm:collection data-model)) + (dm:save data-model)))) diff --git a/template/player.ctml b/template/player.ctml index 987033e..22c611e 100644 --- a/template/player.ctml +++ b/template/player.ctml @@ -14,7 +14,7 @@