Skip to content

Commit

Permalink
Merge pull request #441 from anshg1214/add_info_in_api
Browse files Browse the repository at this point in the history
CB-437: Add entity metadata to review get endpoints
  • Loading branch information
alastair authored Jul 29, 2022
2 parents 9a414d3 + 11fe182 commit cecbfbc
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 5 deletions.
31 changes: 29 additions & 2 deletions critiquebrainz/ws/review/test/views_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,8 +295,8 @@ def test_cache_tracking(self):
cache_keys = cache.smembers(track_key, namespace="Review")
self.assertEqual(set(), cache_keys)

expected_cache_keys = {'list_entity_id=90878b63-f639-3c8b-aefb-190bdf3d1790_user_id=None_sort=popularity_sort_order=desc_entity_type=None_limit=50_offset=0_language=None_review_type=None',
'list_entity_id=90878b63-f639-3c8b-aefb-190bdf3d1790_user_id=None_sort=published_on_sort_order=desc_entity_type=None_limit=5_offset=0_language=None_review_type=None'}
expected_cache_keys = {'list_entity_id=90878b63-f639-3c8b-aefb-190bdf3d1790_user_id=None_sort=popularity_sort_order=desc_entity_type=None_limit=50_offset=0_language=None_review_type=None_include_metadata=None',
'list_entity_id=90878b63-f639-3c8b-aefb-190bdf3d1790_user_id=None_sort=published_on_sort_order=desc_entity_type=None_limit=5_offset=0_language=None_review_type=None_include_metadata=None'}

# Test cache keys are recorded
self.client.get('/review/', query_string={'sort': 'rating', 'entity_id': entity_id})
Expand All @@ -315,3 +315,30 @@ def test_cache_tracking(self):
db_review.create(**self.review)
cache_keys = cache.smembers(track_key, namespace="Review")
self.assertEqual(set(), cache_keys)

def test_entity_metadata(self):
entity_id = "f59c5520-5f46-4d2c-b2c4-822eabf53419"
db_review.create(
entity_id="f59c5520-5f46-4d2c-b2c4-822eabf53419",
entity_type='artist',
user_id=self.user.id,
text="Testing! This text should be on the page.",
rating=5,
is_draft=False,
license_id=self.license["id"],
)
db_review.create(
entity_id="f59c5520-5f46-4d2c-b2c4-822eabf53419",
entity_type='artist',
user_id=self.another_user.id,
text="Testing again! This text should be on the page.",
rating=4,
is_draft=False,
license_id=self.license["id"],
)
resp = self.client.get('/review/', query_string={'include_metadata': 'true', 'entity_id': entity_id})
self.assert200(resp)

self.assertEqual(resp.json["reviews"][0]["artist"]["name"], 'Linkin Park')
self.assertEqual(resp.json["reviews"][0]["artist"]["type"], 'Group')
self.assertEqual(resp.json["average_rating"], 4.5)
50 changes: 47 additions & 3 deletions critiquebrainz/ws/review/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

from brainzutils import cache
from flask import Blueprint, jsonify

from critiquebrainz.frontend.external import mbstore
from critiquebrainz.frontend.views import get_avg_rating
import critiquebrainz.db.review as db_review
from critiquebrainz.db import (
vote as db_vote,
Expand Down Expand Up @@ -347,6 +348,9 @@ def review_list_handler():
:query offset: result offset, default is 0 **(optional)**
:query language: language code (ISO 639-1) **(optional)**
:query review_type: ``review`` or ``rating``. If set, only return reviews which have a text review, or a rating **(optional)**
:query include_metadata: ``true`` or ``false``. Include metadata of the entity **(optional)**
**NOTE:** If entity_id is provided, then additional top-level item "average_rating" which is the average of all ratings for this entity is also included.
:resheader Content-Type: *application/json*
"""
Expand All @@ -363,6 +367,7 @@ def review_list_handler():
sort = Parser.string('uri', 'sort', valid_values=['popularity', 'published_on', 'rating', 'created'], optional=True)
sort_order = Parser.string('uri', 'sort_order', valid_values=['asc', 'desc'], optional=True)
review_type = Parser.string('uri', 'review_type', valid_values=['rating', 'review'], optional=True)
include_metadata = Parser.string('uri', 'include_metadata', optional=True)

# "rating" and "created" sort values are deprecated and but allowed here for backward compatibility
if sort == 'created':
Expand All @@ -375,6 +380,12 @@ def review_list_handler():
if not sort_order:
sort_order = 'desc'

# If an entity_id is given, then also include the average rating for the entity.
if entity_id:
include_avg_rating = True
else:
include_avg_rating = False

limit = Parser.int('uri', 'limit', min=1, max=50, optional=True) or 50
offset = Parser.int('uri', 'offset', optional=True) or 0
language = Parser.string('uri', 'language', min=2, max=3, optional=True)
Expand All @@ -386,12 +397,13 @@ def review_list_handler():

cache_key = cache.gen_key('list', f'entity_id={entity_id}', f'user_id={user_id}', f'sort={sort}',
f'sort_order={sort_order}', f'entity_type={entity_type}', f'limit={limit}',
f'offset={offset}', f'language={language}', f'review_type={review_type}')
f'offset={offset}', f'language={language}', f'review_type={review_type}', f'include_metadata={include_metadata}')
cached_result = cache.get(cache_key, REVIEW_CACHE_NAMESPACE)

if cached_result:
reviews = cached_result['reviews']
count = cached_result['count']
avg_rating = cached_result['avg_rating']
else:
reviews, count = db_review.list_reviews(
entity_id=entity_id,
Expand All @@ -404,11 +416,39 @@ def review_list_handler():
language=language,
review_type=review_type
)

reviews = [db_review.to_dict(p) for p in reviews]


if include_metadata == 'true':
entities = [(str(review["entity_id"]), review["entity_type"]) for review in reviews]
entities_info = mbstore.get_multiple_entities(entities)

retrieved_entity_mbids = entities_info.keys()
reviews = [review for review in reviews if str(review["entity_id"]) in retrieved_entity_mbids]
for review in reviews:
review[review['entity_type']] = entities_info[str(review["entity_id"])]


if include_avg_rating:
if reviews and not entity_type:
entity_type = reviews[0]["entity_type"] if reviews else None

if entity_type:
avg_rating = get_avg_rating(entity_id, entity_type)
if avg_rating:
avg_rating = avg_rating['rating']
else:
avg_rating = None
include_avg_rating = False

else:
avg_rating = None

cache.set(cache_key, {
'reviews': reviews,
'count': count,
'avg_rating': avg_rating
}, expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE)

# When we cache the results of a request, we include (entity_id, user_id, sort, limit, offset, language, review_type)
Expand All @@ -422,7 +462,11 @@ def review_list_handler():
expirein=REVIEW_CACHE_TIMEOUT,
namespace=REVIEW_CACHE_NAMESPACE)

return jsonify(limit=limit, offset=offset, count=count, reviews=reviews)

result = {"limit": limit, "offset": offset, "count": count, "reviews": reviews}
if include_avg_rating:
result["average_rating"] = avg_rating
return jsonify(**result)


# don't need to add OPTIONS here because its already added
Expand Down

0 comments on commit cecbfbc

Please sign in to comment.