Compare commits
No commits in common. "2effe3bdefdc9fb170d4ff4f96eda765b863e157" and "4a79558c75c861fc2e4170d058e737eef6de7075" have entirely different histories.
2effe3bdef
...
4a79558c75
|
|
@ -7,79 +7,90 @@
|
||||||
;;; User Favorites - Track likes/ratings
|
;;; User Favorites - Track likes/ratings
|
||||||
;;; ==========================================================================
|
;;; ==========================================================================
|
||||||
|
|
||||||
(defun get-favorite (user-id track-id &optional track-title)
|
|
||||||
"Gets a user's favorite track by id or name"
|
|
||||||
(when (and user-id (or track-id track-title))
|
|
||||||
(let ((query (if track-id
|
|
||||||
(db:query (:and (:= 'user-id user-id) (:= 'track-id track-id)))
|
|
||||||
(when track-title
|
|
||||||
(db:query (:and (:= 'user-id user-id) (:= 'track_title track-title)))))))
|
|
||||||
(when query
|
|
||||||
(dm:get-one "user_favorites" query)))))
|
|
||||||
|
|
||||||
(defun add-favorite (user-id track-id &optional (rating 1) track-title)
|
(defun add-favorite (user-id track-id &optional (rating 1) track-title)
|
||||||
"Add a track to user's favorites with optional rating (1-5).
|
"Add a track to user's favorites with optional rating (1-5).
|
||||||
If track-id is nil but track-title is provided, stores by title.
|
If track-id is nil but track-title is provided, stores by title."
|
||||||
When favorite already exists for user, returns it instead to avoid duplicates."
|
(when (null user-id)
|
||||||
(when (and user-id (or track-id track-title))
|
(return-from add-favorite nil))
|
||||||
(let ((favorite (get-favorite user-id track-id track-title)))
|
(let ((rating-val (max 1 (min 5 (or rating 1)))))
|
||||||
(if favorite
|
(with-db
|
||||||
favorite
|
(if track-id
|
||||||
(let ((rating-val (max 1 (min 5 (or rating 1))))
|
(postmodern:query
|
||||||
(favorite (dm:hull "user_favorites")))
|
(:raw (format nil "INSERT INTO user_favorites (\"user-id\", \"track-id\", track_title, rating) VALUES (~a, ~a, ~a, ~a)"
|
||||||
(setf (dm:field favorite "user-id") user-id)
|
user-id track-id
|
||||||
(setf (dm:field favorite "rating") rating-val)
|
(if track-title (format nil "$$~a$$" track-title) "NULL")
|
||||||
(when track-id
|
rating-val)))
|
||||||
(setf (dm:field favorite "track-id") track-id))
|
;; No track-id, store by title only
|
||||||
(when track-title
|
(when track-title
|
||||||
(setf (dm:field favorite "track_title") track-title))
|
(postmodern:query
|
||||||
(dm:insert favorite))))))
|
(:raw (format nil "INSERT INTO user_favorites (\"user-id\", track_title, rating) VALUES (~a, $$~a$$, ~a)"
|
||||||
|
user-id track-title rating-val))))))))
|
||||||
|
|
||||||
(defun remove-favorite (user-id track-id &optional track-title)
|
(defun remove-favorite (user-id track-id &optional track-title)
|
||||||
"Remove a track from user's favorites by track-id or title"
|
"Remove a track from user's favorites by track-id or title"
|
||||||
(let ((favorite (get-favorite user-id track-id track-title)))
|
(when (null user-id)
|
||||||
(when favorite
|
(return-from remove-favorite nil))
|
||||||
(dm:delete favorite))))
|
(with-db
|
||||||
|
(if track-id
|
||||||
|
(postmodern:query
|
||||||
|
(:raw (format nil "DELETE FROM user_favorites WHERE \"user-id\" = ~a AND \"track-id\" = ~a"
|
||||||
|
user-id track-id)))
|
||||||
|
(when track-title
|
||||||
|
(postmodern:query
|
||||||
|
(:raw (format nil "DELETE FROM user_favorites WHERE \"user-id\" = ~a AND track_title = $$~a$$"
|
||||||
|
user-id track-title)))))))
|
||||||
|
|
||||||
(defun update-favorite-rating (user-id track-id rating)
|
(defun update-favorite-rating (user-id track-id rating)
|
||||||
"Update the rating for a favorited track"
|
"Update the rating for a favorited track"
|
||||||
(when (null user-id)
|
(when (null user-id)
|
||||||
(return-from update-favorite-rating nil))
|
(return-from update-favorite-rating nil))
|
||||||
(let ((rating-val (max 1 (min 5 rating)))
|
(let ((rating-val (max 1 (min 5 rating))))
|
||||||
(favorite (get-favorite user-id track-id)))
|
(with-db
|
||||||
(unless favorite
|
(postmodern:query
|
||||||
(error 'not-found-error
|
(:update 'user_favorites
|
||||||
:message (format nil "Favorite #~a not found for user #~a"
|
:set 'rating rating-val
|
||||||
track-id
|
:where (:and (:= '"user-id" user-id)
|
||||||
user-id)))
|
(:= '"track-id" track-id)))))))
|
||||||
(setf (dm:field favorite "rating-val") rating-val)
|
|
||||||
(data-model-save favorite)))
|
|
||||||
|
|
||||||
(defun get-user-favorites (user-id &key (limit 50) (offset 0))
|
(defun get-user-favorites (user-id &key (limit 50) (offset 0))
|
||||||
"Get user's favorite tracks - works with both track-id and title-based favorites"
|
"Get user's favorite tracks - works with both track-id and title-based favorites"
|
||||||
(when user-id
|
(when (null user-id)
|
||||||
(dm:get "user_favorites" (db:query (:= 'user-id user-id))
|
(return-from get-user-favorites nil))
|
||||||
:amount limit
|
(with-db
|
||||||
:skip offset
|
(postmodern:query
|
||||||
:sort '(("created-date" :DESC)))))
|
(:raw (format nil "SELECT _id, rating, \"created-date\", track_title, \"track-id\" FROM user_favorites WHERE \"user-id\" = ~a ORDER BY \"created-date\" DESC LIMIT ~a OFFSET ~a"
|
||||||
|
user-id limit offset))
|
||||||
|
:alists)))
|
||||||
|
|
||||||
(defun is-track-favorited (user-id track-id)
|
(defun is-track-favorited (user-id track-id)
|
||||||
"Check if a track is in user's favorites, returns rating or nil"
|
"Check if a track is in user's favorites, returns rating or nil"
|
||||||
(when (and user-id track-id)
|
(when (null user-id)
|
||||||
(dm:get-one "user_favorites" (db:query (:and (:= 'user-id user-id)
|
(return-from is-track-favorited nil))
|
||||||
(:= 'track-id track-id))))))
|
(with-db
|
||||||
|
(postmodern:query
|
||||||
|
(:raw (format nil "SELECT rating FROM user_favorites WHERE \"user-id\" = ~a AND \"track-id\" = ~a"
|
||||||
|
user-id track-id))
|
||||||
|
:single)))
|
||||||
|
|
||||||
(defun get-favorites-count (user-id)
|
(defun get-favorites-count (user-id)
|
||||||
"Get total count of user's favorites"
|
"Get total count of user's favorites"
|
||||||
(when user-id
|
(when (null user-id)
|
||||||
(db:count "user_favorites" (db:query (:= 'user-id user-id)))))
|
(return-from get-favorites-count 0))
|
||||||
|
(with-db
|
||||||
|
(postmodern:query
|
||||||
|
(:raw (format nil "SELECT COUNT(*) FROM user_favorites WHERE \"user-id\" = ~a" user-id))
|
||||||
|
:single)))
|
||||||
|
|
||||||
(defun get-track-favorite-count (track-title)
|
(defun get-track-favorite-count (track-title)
|
||||||
"Get count of how many users have favorited a track by title"
|
"Get count of how many users have favorited a track by title"
|
||||||
(if (and track-title (not (string= track-title "")))
|
(if (and track-title (not (string= track-title "")))
|
||||||
(handler-case
|
(handler-case
|
||||||
(let ((result (db:count "user_favorites" (db:query (:= 'track_title track-title)))))
|
(with-db
|
||||||
(or result 0))
|
(let* ((escaped-title (sql-escape-string track-title))
|
||||||
|
(result (postmodern:query
|
||||||
|
(:raw (format nil "SELECT COUNT(*) FROM user_favorites WHERE track_title = '~a'" escaped-title))
|
||||||
|
:single)))
|
||||||
|
(or result 0)))
|
||||||
(error (e)
|
(error (e)
|
||||||
(declare (ignore e))
|
(declare (ignore e))
|
||||||
0))
|
0))
|
||||||
|
|
@ -112,11 +123,11 @@
|
||||||
(:raw (format nil "INSERT INTO listening_history (\"user-id\", \"track-id\", track_title, \"listen-duration\", completed) VALUES (~a, ~a, ~a, ~a, ~a)"
|
(:raw (format nil "INSERT INTO listening_history (\"user-id\", \"track-id\", track_title, \"listen-duration\", completed) VALUES (~a, ~a, ~a, ~a, ~a)"
|
||||||
user-id track-id
|
user-id track-id
|
||||||
(if track-title (format nil "'~a'" (sql-escape-string track-title)) "NULL")
|
(if track-title (format nil "'~a'" (sql-escape-string track-title)) "NULL")
|
||||||
duration (if completed 1 0))))
|
duration (if completed "TRUE" "FALSE"))))
|
||||||
(when track-title
|
(when track-title
|
||||||
(postmodern:query
|
(postmodern:query
|
||||||
(:raw (format nil "INSERT INTO listening_history (\"user-id\", track_title, \"listen-duration\", completed) VALUES (~a, '~a', ~a, ~a)"
|
(:raw (format nil "INSERT INTO listening_history (\"user-id\", track_title, \"listen-duration\", completed) VALUES (~a, '~a', ~a, ~a)"
|
||||||
user-id (sql-escape-string track-title) duration (if completed 1 0))))))))))
|
user-id (sql-escape-string track-title) duration (if completed "TRUE" "FALSE"))))))))))
|
||||||
|
|
||||||
(defun get-listening-history (user-id &key (limit 20) (offset 0))
|
(defun get-listening-history (user-id &key (limit 20) (offset 0))
|
||||||
"Get user's listening history - works with title-based history"
|
"Get user's listening history - works with title-based history"
|
||||||
|
|
@ -174,12 +185,12 @@
|
||||||
(favorites (get-user-favorites user-id)))
|
(favorites (get-user-favorites user-id)))
|
||||||
(api-output `(("status" . "success")
|
(api-output `(("status" . "success")
|
||||||
("favorites" . ,(or (mapcar (lambda (fav)
|
("favorites" . ,(or (mapcar (lambda (fav)
|
||||||
`(("id" . ,(dm:id fav))
|
`(("id" . ,(aget-profile "-ID" fav))
|
||||||
("track_id" . ,(dm:field fav "track-id"))
|
("track_id" . ,(aget-profile "TRACK-ID" fav))
|
||||||
("title" . ,(dm:field fav "track_title"))
|
("title" . ,(aget-profile "TRACK-TITLE" fav))
|
||||||
("rating" . ,(dm:field fav "rating"))))
|
("rating" . ,(aget-profile "RATING" fav))))
|
||||||
favorites)
|
favorites)
|
||||||
(list)))
|
(list))) ; Return empty list instead of null
|
||||||
("count" . ,(get-favorites-count user-id)))))))
|
("count" . ,(get-favorites-count user-id)))))))
|
||||||
|
|
||||||
(define-api asteroid/user/favorites/add (&optional track-id rating title) ()
|
(define-api asteroid/user/favorites/add (&optional track-id rating title) ()
|
||||||
|
|
@ -193,9 +204,6 @@
|
||||||
(track-id-int (when (and track-id (not (string= track-id "")))
|
(track-id-int (when (and track-id (not (string= track-id "")))
|
||||||
(parse-integer track-id :junk-allowed t)))
|
(parse-integer track-id :junk-allowed t)))
|
||||||
(rating-int (if rating (parse-integer rating :junk-allowed t) 1)))
|
(rating-int (if rating (parse-integer rating :junk-allowed t) 1)))
|
||||||
(unless user-id
|
|
||||||
(error 'authentication-error
|
|
||||||
:message "User not authenticated"))
|
|
||||||
(format t "Adding favorite: user-id=~a track-id=~a title=~a~%" user-id track-id-int title)
|
(format t "Adding favorite: user-id=~a track-id=~a title=~a~%" user-id track-id-int title)
|
||||||
(add-favorite user-id track-id-int (or rating-int 1) title)
|
(add-favorite user-id track-id-int (or rating-int 1) title)
|
||||||
(api-output `(("status" . "success")
|
(api-output `(("status" . "success")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue