Skip to content

Commit

Permalink
Merge branch 'popularity' into browsing
Browse files Browse the repository at this point in the history
  • Loading branch information
gentlecat committed Jan 6, 2015
2 parents cd078ea + c2347d7 commit d9ab87c
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 13 deletions.
72 changes: 65 additions & 7 deletions critiquebrainz/data/model/review.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@
from critiquebrainz.data.model.revision import Revision
from critiquebrainz.data.model.mixins import DeleteMixin
from critiquebrainz.data.constants import review_classes
from critiquebrainz import cache
from werkzeug.exceptions import BadRequest
from flask_babel import gettext
from datetime import datetime, timedelta
from random import shuffle
import pycountry

DEFAULT_LICENSE_ID = u"CC BY-SA 3.0"
Expand Down Expand Up @@ -59,11 +62,6 @@ def to_dict(self):
review_class=self.review_class.label)
return response

@property
def first_revision(self):
"""Returns first revision of this review."""
return self.revisions[0]

@property
def last_revision(self):
"""Returns latest revision of this review."""
Expand Down Expand Up @@ -126,7 +124,7 @@ def list(cls, release_group=None, user_id=None, sort=None, limit=None,
review.
user_id: UUID of the author.
sort: Order of returned reviews. Can be either "rating" (order by
rating) or "created" (order by creation time).
rating), or "created" (order by creation time).
limit: Maximum number of reviews returned by this method.
offset: Offset that can be used in conjunction with the limit.
language: Language (code) of returned reviews.
Expand All @@ -144,7 +142,12 @@ def list(cls, release_group=None, user_id=None, sort=None, limit=None,
# SORTING:

if sort == 'rating': # order by rating (positive votes - negative votes)
# TODO: Simplify this:

# TODO: Simplify this part. It can probably be rewritten using
# hybrid attributes (by making rating property a hybrid_property),
# but I'm not sure how to do that.

# Preparing base query for getting votes
vote_query_base = db.session.query(
Vote.revision_id, # revision associated with a vote
Vote.vote, # vote itself (True if positive, False if negative)
Expand Down Expand Up @@ -222,3 +225,58 @@ def update(self, text, is_draft=None, license_id=None, language=None):
db.session.add(new_revision)
db.session.commit()
return new_revision

@classmethod
def get_popular(cls, limit=None):
"""Get list of popular reviews.
Popularity is determined by rating of a particular review. Rating is a
difference between positive votes and negative. In this case only votes
from the last month are used to calculate rating.
Results are cached for 12 hours.
Args:
limit: Maximum number of reviews to return.
Returns:
Randomized list of popular reviews.
"""
cache_key = cache.prep_cache_key('popular_reviews', [limit])
reviews = cache.get(cache_key)

if not reviews:
query = Review.query.filter(and_(Review.is_archived == False,
Review.is_draft == False)) \
.distinct(Review.release_group) # different release groups

# Preparing base query for getting votes
vote_query_base = db.session.query(
Vote.revision_id, Vote.vote, func.count().label('c')) \
.group_by(Vote.revision_id, Vote.vote) \
.filter(Vote.rated_at > datetime.now() - timedelta(weeks=4))

# Getting positive votes
votes_pos = vote_query_base.subquery('votes_pos')
query = query.outerjoin(Revision).outerjoin(
votes_pos, and_(votes_pos.c.revision_id == Revision.id,
votes_pos.c.vote == True))

# Getting negative votes
votes_neg = vote_query_base.subquery('votes_neg')
query = query.outerjoin(Revision).outerjoin(
votes_neg, and_(votes_neg.c.revision_id == Revision.id,
votes_neg.c.vote == False))

query = query.order_by(Review.release_group,
desc(func.coalesce(votes_pos.c.c, 0)
- func.coalesce(votes_neg.c.c, 0)))

if limit is not None:
query = query.limit(limit * 4)

reviews = query.all()
cache.set(cache_key, reviews, 12 * 60 * 60) # 12 hours

shuffle(reviews) # a bit more variety
return reviews[:limit]
8 changes: 4 additions & 4 deletions critiquebrainz/data/model/review_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def test_created_property(self):
text=u"Testing!",
is_draft=False,
license_id=self.license.id)
self.assertEqual(review.created, review.first_revision.timestamp)
self.assertEqual(review.created, review.revisions[0].timestamp)

def test_review_deletion(self):
review = Review.create(user=self.user,
Expand Down Expand Up @@ -97,7 +97,7 @@ def test_update(self):

# Updating should create a new revision.
self.assertEqual(len(retrieved_review.revisions), 2)
self.assertNotEqual(retrieved_review.first_revision, retrieved_review.last_revision)
self.assertNotEqual(retrieved_review.revisions[0], retrieved_review.last_revision)

# Let's try doing some things that shouldn't be allowed!

Expand All @@ -114,9 +114,9 @@ def test_revisions(self):
is_draft=False,
license_id=self.license.id)
self.assertEqual(len(review.revisions), 1)
self.assertEqual(review.first_revision, review.last_revision)
self.assertEqual(review.revisions[0], review.last_revision)

# Updating should create a new revision.
review.update(u"The worst!")
self.assertEqual(len(review.revisions), 2)
self.assertNotEqual(review.first_revision, review.last_revision)
self.assertNotEqual(review.revisions[0], review.last_revision)
4 changes: 2 additions & 2 deletions critiquebrainz/frontend/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
@frontend_bp.route('/')
def index():
# Popular reviews
popular_reviews, _ = Review.list(sort='rating', limit=6)
popular_reviews = Review.get_popular(6)
for review in popular_reviews:
# Preparing text for preview
preview = markdown(review.text, safe_mode="escape")
Expand All @@ -22,7 +22,7 @@ def index():
# Recent reviews
recent_reviews, _ = Review.list(sort='created', limit=9)

# Getting counts and formatting them
# Statistics
review_count = format_number(Review.query.filter(Review.is_archived == False).filter(Review.is_draft == False).count())
user_count = format_number(User.query.count())

Expand Down

0 comments on commit d9ab87c

Please sign in to comment.