Repository navigation
feat(reviews): verified-purchase reviews, eligibility endpoint and own-review delete - #115
Merged
Merged
Conversation
…n-review delete
- Customers can review a store or product only for a completed order placed with
that store or containing that product, once per order per subject. Reviews
record the order (new reviews.order_uuid).
- GET reviews/eligibility tells the app whether the signed-in customer can review
a subject, and why not.
- DELETE reviews/{id} now routes to delete() instead of find(), so customers can
remove their own reviews.
- Ratings must be whole stars from 1 to 5; content is limited to 2000 characters
and uploads to four image or video files.
- The review resource names the subject by public id instead of the internal row
id, and adds subject_type, verified and is_mine.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #115 +/- ##
===========================================
Coverage 100.00% 100.00%
- Complexity 2282 2307 +25
===========================================
Files 182 183 +1
Lines 9082 9154 +72
===========================================
+ Hits 9082 9154 +72
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Reviews in the customer app have to come from a real purchase. Until now, any signed-in customer could review any store or product, there was no way for the app to know whether to offer "Write a review", and customers could not delete their own reviews because
DELETE reviews/{id}was routed tofind().This PR does four things:
reviews.order_uuidcolumn.GET storefront/v1/reviews/eligibility?subject={store_or_product_id}[&order={order_id}]tells the app whether the signed-in customer can review a subject. When they can't, it says why.DELETE reviews/{id}now routes to the existingdelete()action. That action already only lets customers delete their own reviews.ratingmust be an integer from 1 to 5,contentis limited to 2000 characters, and a review carries at most 4 image or video files.subject_type,verifiedandis_mine.Related Issue
Part of the storefront-app redesign: the new review screens need verified purchases, an eligibility check and own-review delete.
Type of Change
Implementation Notes
Support/ReviewEligibilityholds the whole decision.status = completedandmeta.storefront_idequal to the store's public id.internal_idequal to the product's public id.Entity::fromStorefrontProductsets that id at checkout.order, it picks the newest completed order not yet reviewed for that subject, looking back over the last 50.order(public id or uuid), it only considers that order.sign_in_required,unsupported_subject,no_completed_order,already_reviewed. Foralready_reviewed, the latest order and its review are returned so the app can link to it.ReviewController::createruns the check after the existing subject and context guards. A refusal returns 403{error, reason}, and an accepted review storesorder_uuid.ReviewController::eligibilityreturns{can_review, reason, message, order, review}. A missing or out-of-context subject returns the controller's usual 400 errors.subject_idis the public id on public routes and stays the internal id on internal routes.is_minecompares against the customer fromCustomer-Token. That customer is looked up once per request and cached on the request attributes, so a page of reviews doesn't repeat the token lookup for every review.order_uuidis only exposed on internal routes.2026_10_07_000000_add_order_uuid_to_reviews_tableadds a nullableorder_uuidand an index on(customer_uuid, subject_uuid, order_uuid). It is guarded withhasColumn.Validation
Command output / summary:
New tests in
server/tests/Unit/Support/ReviewEligibilityTest.php:createrefusing a customer without a completed order (403 with reason, nothing stored)subject_id,subject_type,verifiedandis_mine, including the once-per-request viewer lookuporder()relationUpdated tests:
already_reviewed.phpstan (
composer test:types) isn't run in CI and reports Eloquent magic-property errors across these files onmaintoo. The new class adds the same kind of errors and no others.Documentation Impact
fleetbase/fleetbase.ioAPI Reference Impact
fleetbase/postmanAPI reference notes:
GET storefront/v1/reviews/eligibility.POST storefront/v1/reviews: optionalorder, stricter validation, and a new 403{error, reason}response.DELETE storefront/v1/reviews/{id}now deletes the review.subject_idis now a public id.subject_type,verifiedandis_mine.Documentation Notes
The storefront API docs on fleetbase.io and the Postman collection need the endpoint and fields above (follow-up).
Risk
error.order_uuid = null. They show asverified: false, and they don't block the customer from reviewing a completed order.subject_idon public responses changes from an integer to a public id string. Current storefront-app code does not read it.ReviewController::create, in the photo upload part. Expect a small rebase conflict for whichever merges second.Reviewer privacy
Public review payloads named the reviewer in full and included their email and phone number. Public responses now show the reviewer as first name and last initial ("Ada B."), with no email or phone. Internal (Console) responses are unchanged.