Add user movie ratings and refresh movie cards #74

Merged
quoije merged 1 commits from 2026 into prod 2026-01-25 17:14:07 -05:00
quoije commented 2026-01-25 17:12:51 -05:00 (Migrated from github.com)

Store per-user 5-star ratings with averages and surface them in the player. Refresh movie list layout to show ratings and details in a cleaner card layout.


Note

Introduces per-user ratings and surfaces them across API and UI.

  • New MovieRating model with unique (movieId,userId) and 1–5 validation
  • Backend: add GET/PUT /api/movies/:id/ratings (auth) and augment movie list/detail responses with user_rating_avg, user_rating_count, user_rating
  • Movies list (app_movies.js + CSS): refreshed card layout; show user average and own rating, improved IMDb/metadata blocks
  • Player (player.html/app_player.js): star widget to set rating, saves via PUT and reflects average/count; minor header/quality alignment tweaks
  • Caching: reuse base movie list payload, then join rating aggregates and per-user ratings

Written by Cursor Bugbot for commit fe21a12c82. This will update automatically on new commits. Configure here.

Store per-user 5-star ratings with averages and surface them in the player. Refresh movie list layout to show ratings and details in a cleaner card layout. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Introduces per-user ratings and surfaces them across API and UI. > > - New `MovieRating` model with unique `(movieId,userId)` and 1–5 validation > - Backend: add `GET/PUT /api/movies/:id/ratings` (auth) and augment movie list/detail responses with `user_rating_avg`, `user_rating_count`, `user_rating` > - Movies list (`app_movies.js` + CSS): refreshed card layout; show user average and own rating, improved IMDb/metadata blocks > - Player (`player.html`/`app_player.js`): star widget to set rating, saves via PUT and reflects average/count; minor header/quality alignment tweaks > - Caching: reuse base movie list payload, then join rating aggregates and per-user ratings > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit fe21a12c82f019c26a9d05a25b199d6b20887300. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
cursor[bot] (Migrated from github.com) reviewed 2026-01-25 17:20:36 -05:00
cursor[bot] (Migrated from github.com) left a comment

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

This is the final PR Bugbot will review for you during this billing cycle

Your free Bugbot reviews will reset on February 22

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

Cursor Bugbot has reviewed your changes and found 2 potential issues. <sup>Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the [Cursor dashboard](https://www.cursor.com/dashboard?tab=bugbot).</sup> ### This is the final PR Bugbot will review for you during this billing cycle Your free Bugbot reviews will reset on February 22 <details> <summary>Details</summary> You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle. To receive Bugbot reviews on all of your PRs, visit the [Cursor dashboard](https://www.cursor.com/dashboard?tab=bugbot) to activate Pro and start your 14-day free trial. </details>
@@ -549,0 +603,4 @@
averageRating: initial?.averageRating ?? null,
ratingsCount: initial?.ratingsCount ?? 0,
userRating: initial?.userRating ?? null,
};
cursor[bot] (Migrated from github.com) commented 2026-01-25 17:20:36 -05:00

Stale fallback state after successful rating save

Medium Severity

The starting object in initUserRating captures the initial page-load rating state but is never updated after a successful save. If a user successfully saves a rating (e.g., changes from 3 to 4 stars) and then a subsequent save fails (e.g., trying to change to 5 stars), the UI reverts to the original page-load state (3 stars) instead of the last successfully saved state (4 stars). This causes the displayed rating to be inconsistent with the actual server state.

Additional Locations (1)

Fix in Cursor Fix in Web

### Stale fallback state after successful rating save **Medium Severity** <!-- DESCRIPTION START --> The `starting` object in `initUserRating` captures the initial page-load rating state but is never updated after a successful save. If a user successfully saves a rating (e.g., changes from 3 to 4 stars) and then a subsequent save fails (e.g., trying to change to 5 stars), the UI reverts to the original page-load state (3 stars) instead of the last successfully saved state (4 stars). This causes the displayed rating to be inconsistent with the actual server state. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: ref1_2599e9bb-7d25-4f43-a0f6-0f5dfc6622f0 --> <!-- LOCATIONS START public/js/app_player.js#L601-L606 public/js/app_player.js#L636-L639 LOCATIONS END --> <details> <summary>Additional Locations (1)</summary> - [`public/js/app_player.js#L636-L639`](https://github.com/quoije/oscars-pool/blob/fe21a12c82f019c26a9d05a25b199d6b20887300/public/js/app_player.js#L636-L639) </details> <a href="https://cursor.com/open?data=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJ1Z2JvdC12MiJ9.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjMyMGYxZjc5LWIwMmYtNGYyNy04ZGNmLTZlOGFlY2NhNTJkYiIsImVuY3J5cHRpb25LZXkiOiJDWGpxMXp6Z3dpUllTQjlsZ1lhaFU5UmtlWmFtaVdVY2JrN09rQ2Q4d1NRIiwiYnJhbmNoIjoiMjAyNiJ9LCJpYXQiOjE3NjkzNzk2MzYsImV4cCI6MTc3MTk3MTYzNn0.pCsGqL8yGkNCfJzG4c5wX9WrJ1dRzUi49CRBk1IYaxXauBwlCR13tuHHmI65YGwh8KkfrmRX1x2CzHvC1_P7cowcwDkSZpZ8Pufn1BrabWAnVHxkGWQ6BWjtuS34OVwNyQcyYKaGcW9YGW85_VcMidnXyJa8dH7QOp5_9Vi6Hi5RHpmTA6TvD0K6ByikriVxOHFuH0bhY2ynAUwPFx1OGj6RTbCjFJ-oqEiwErGJ-Nj41FeCIKf-xhP4r9WVfso2WkI44KN1eNz82eCJqMmzWPsLR0i4aN1iMQx8aHIVefuAB1Ab78QBkrcYabUWoXAjmd8sLcmGAiAIWQuXq0TW3g" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/fix-in-cursor-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/fix-in-cursor-light.svg"><img alt="Fix in Cursor" src="https://cursor.com/fix-in-cursor.svg"></picture></a>&nbsp;<a href="https://cursor.com/agents?data=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJ1Z2JvdC12MiJ9.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjMyMGYxZjc5LWIwMmYtNGYyNy04ZGNmLTZlOGFlY2NhNTJkYiIsImVuY3J5cHRpb25LZXkiOiJDWGpxMXp6Z3dpUllTQjlsZ1lhaFU5UmtlWmFtaVdVY2JrN09rQ2Q4d1NRIiwiYnJhbmNoIjoiMjAyNiIsInJlcG9Pd25lciI6InF1b2lqZSIsInJlcG9OYW1lIjoib3NjYXJzLXBvb2wiLCJwck51bWJlciI6NzQsImNvbW1pdFNoYSI6ImZlMjFhMTJjODJmMDE5YzI2YTlkMDVhMjViMTk5ZDZiMjA4ODczMDAiLCJwcm92aWRlciI6ImdpdGh1YiJ9LCJpYXQiOjE3NjkzNzk2MzYsImV4cCI6MTc3MTk3MTYzNn0.TgHApQFuDMLY0HjPgfm4VaeOz3bZ2zm9DsWMnhBaJvocdu0Ig2FA7RCstx9651iTTifhgsxR29U_j8zYuSzIylzP6c-x1y3P3zflfv4zY8vrT8VH0Kn8WODGGjFmpfyk_oPa_R8Cm5toHZfN_GaOe3zcWtW76os9NFjRUuKcl8xxK6jF1gaULBwnd2WgT4vtZZgdwWXLW-pWl2DnbIOSQdW7FiLzlnGuiBI26F4cuzElawb9_tcsrmn_ym1sWZLgvoh3UlbgQVwcUVrEKQsDioYLRVb_HMNRSGRchyV7--mq1fPCuKkbvaq_4ePfDZ4s_HJexqF5XlXKZnnXt9wqsg" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/fix-in-web-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/fix-in-web-light.svg"><img alt="Fix in Web" src="https://cursor.com/fix-in-web.svg"></picture></a>
cursor[bot] (Migrated from github.com) commented 2026-01-25 17:20:36 -05:00

Public caching enabled for user-specific rating data

High Severity

The GET /api/movies endpoint now includes user-specific user_rating data (each user's personal movie rating) in the response payload, but still sets Cache-Control: public, max-age=30. This allows shared caches (CDNs, proxies) to cache one user's personal ratings and serve them to other users, leaking private data. The caching should be changed to private and include Vary: Authorization to match other user-specific endpoints in this file.

Additional Locations (1)

Fix in Cursor Fix in Web

### Public caching enabled for user-specific rating data **High Severity** <!-- DESCRIPTION START --> The GET `/api/movies` endpoint now includes user-specific `user_rating` data (each user's personal movie rating) in the response payload, but still sets `Cache-Control: public, max-age=30`. This allows shared caches (CDNs, proxies) to cache one user's personal ratings and serve them to other users, leaking private data. The caching should be changed to `private` and include `Vary: Authorization` to match other user-specific endpoints in this file. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: 775354fd-1d01-41c7-922f-e040ab80d00b --> <!-- LOCATIONS START routes/movies.js#L354-L356 routes/movies.js#L342-L353 LOCATIONS END --> <details> <summary>Additional Locations (1)</summary> - [`routes/movies.js#L342-L353`](https://github.com/quoije/oscars-pool/blob/fe21a12c82f019c26a9d05a25b199d6b20887300/routes/movies.js#L342-L353) </details> <a href="https://cursor.com/open?data=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJ1Z2JvdC12MiJ9.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjVlMDM2MDBkLWE0ZjUtNGM1MC04YWQ4LWIwYmMzMTQzYTQ0NyIsImVuY3J5cHRpb25LZXkiOiJ3akVCRFZlSW9QOGxVS0NWSDRoZE1FWlJaUjMxZ3pZclVhMHFtaXFBRUdrIiwiYnJhbmNoIjoiMjAyNiJ9LCJpYXQiOjE3NjkzNzk2MzYsImV4cCI6MTc3MTk3MTYzNn0.WoAMwVsUi2asoGLeahM4cRutBECyNTGNc72-QRb47z9Tlg6iF1krz8Dxvg1_uaeMqnCoQpdN7Fw7juczy-IIchiqZzUUpHxCGZp3BuGm3IObFYfGEZKyPNuHbhAsHI24TjNjquasOLKtmMODXxf1d6LjY2DkMc0X9JEZfVF-_cox8-ekg3w0Ydk0DtV5-2kMSa606ZtI7J1pmc-MMfbdEPZfPlNfTo7YrUWCdMt0e60u7R4MIwvfQ-BKFlo9CzwNVnKJB4E_ytx6SMOxaS6fnF8bAvS_1YaKbnuayA3usNqk5WZu-F6G0jWXLdVztr9GYbM9rZmSzZRTifFIQyCKhA" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/fix-in-cursor-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/fix-in-cursor-light.svg"><img alt="Fix in Cursor" src="https://cursor.com/fix-in-cursor.svg"></picture></a>&nbsp;<a href="https://cursor.com/agents?data=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJ1Z2JvdC12MiJ9.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90OjVlMDM2MDBkLWE0ZjUtNGM1MC04YWQ4LWIwYmMzMTQzYTQ0NyIsImVuY3J5cHRpb25LZXkiOiJ3akVCRFZlSW9QOGxVS0NWSDRoZE1FWlJaUjMxZ3pZclVhMHFtaXFBRUdrIiwiYnJhbmNoIjoiMjAyNiIsInJlcG9Pd25lciI6InF1b2lqZSIsInJlcG9OYW1lIjoib3NjYXJzLXBvb2wiLCJwck51bWJlciI6NzQsImNvbW1pdFNoYSI6ImZlMjFhMTJjODJmMDE5YzI2YTlkMDVhMjViMTk5ZDZiMjA4ODczMDAiLCJwcm92aWRlciI6ImdpdGh1YiJ9LCJpYXQiOjE3NjkzNzk2MzYsImV4cCI6MTc3MTk3MTYzNn0.eXp2e2_c34OIKw8r77eTdgXBB5PYi10YAPHSuzLYYhv20IINwGj8roZqR29jwxCpE69bFdPxSqZQmLbUhoScxqbiQDFcPGO19zjEtabQ8ROnfBbyvSRcLn9v9lKQD5DTPr1gMF2DwirFNhc0CtMxlN_IiI6Bfm1ZZBKAFJJtcEl1PMDTdnfCInkI7c0MFA4yRV9izcJFOIRs0rf-NVpkGFKriqQBTraGHBgN2VkXCsI7MIlHd9b37Wmx_SEdRNUMAVTx91nvMe-yuEX0z1Y-XQUlptUi1mRHyiCj06cpNq8K_RfZn63sWL1WGFsxB-dAKs-mAJyR_QaX8UdqOmbSzw" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/fix-in-web-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/fix-in-web-light.svg"><img alt="Fix in Web" src="https://cursor.com/fix-in-web.svg"></picture></a>
Sign in to join this conversation.