Merge lp:~michael.nelson/rnr-server/708841-caching-issue into lp:rnr-server

Proposed by Michael Nelson
Status: Merged
Merged at revision: 118
Proposed branch: lp:~michael.nelson/rnr-server/708841-caching-issue
Merge into: lp:rnr-server
Diff against target: 155 lines (+58/-3)
2 files modified
src/reviewsapp/models/reviews.py (+11/-3)
src/reviewsapp/tests/test_models.py (+47/-0)
To merge this branch: bzr merge lp:~michael.nelson/rnr-server/708841-caching-issue
Reviewer Review Type Date Requested Status
Danny Tamez (community) Approve
Review via email: mp+47816@code.launchpad.net

Description of the change

Overview
========

Fixes bug 708841 by ensuring that whenever the hide property of a review is changed, we update the stats on the corresponding softwareitem.

To post a comment you must log in.
Revision history for this message
Danny Tamez (zematynnad) wrote :

everything looks good

review: Approve
118. By Michael Nelson

Ensure hidden reviews are not included in stats.

119. By Michael Nelson

Fixed issue where Django returns None for average of zero items.

120. By Michael Nelson

Merged trunk.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/reviewsapp/models/reviews.py'
--- src/reviewsapp/models/reviews.py 2011-01-28 15:39:42 +0000
+++ src/reviewsapp/models/reviews.py 2011-01-28 16:27:06 +0000
@@ -77,10 +77,16 @@
77 app_label = 'reviewsapp'77 app_label = 'reviewsapp'
7878
79 def update_stats(self):79 def update_stats(self):
80 stats = Review.objects.filter(softwareitem=self).aggregate(80 stats = Review.objects.filter(
81 average=Avg('rating'),81 softwareitem=self, hide=False).aggregate(
82 total=Count('rating'))82 average=Avg('rating'), total=Count('rating'))
83 self.ratings_total = stats['total']83 self.ratings_total = stats['total']
84
85 # If there are no visible reviews, the average will be returned
86 # as None.
87 if stats['average'] is None:
88 stats['average'] = 0
89
84 self.ratings_average = str(stats['average'])90 self.ratings_average = str(stats['average'])
85 self.date_ratings_updated = datetime.utcnow()91 self.date_ratings_updated = datetime.utcnow()
86 self.save()92 self.save()
@@ -181,6 +187,7 @@
181 if self.review.hide != should_hide:187 if self.review.hide != should_hide:
182 self.review.hide = should_hide188 self.review.hide = should_hide
183 self.review.save()189 self.review.save()
190 self.review.softwareitem.update_stats()
184191
185 def can_be_moderated_by(self, user):192 def can_be_moderated_by(self, user):
186 """Return whether the user is allowed to moderate this object."""193 """Return whether the user is allowed to moderate this object."""
@@ -303,6 +310,7 @@
303 if self.reviewmoderation_set.approved().count() == 0:310 if self.reviewmoderation_set.approved().count() == 0:
304 self.hide = True311 self.hide = True
305 self.save()312 self.save()
313 self.softwareitem.update_stats()
306314
307 return flagged_object315 return flagged_object
308316
309317
=== modified file 'src/reviewsapp/tests/test_models.py'
--- src/reviewsapp/tests/test_models.py 2011-01-24 09:53:02 +0000
+++ src/reviewsapp/tests/test_models.py 2011-01-28 16:27:06 +0000
@@ -24,6 +24,7 @@
24 'ReviewModelTestCase',24 'ReviewModelTestCase',
25 'ReviewModerationTestCase',25 'ReviewModerationTestCase',
26 'ReviewFlagTestCase',26 'ReviewFlagTestCase',
27 'SoftwareItemTestCase',
27 ]28 ]
2829
29from django.db import IntegrityError30from django.db import IntegrityError
@@ -147,6 +148,8 @@
147 # Flagging an item which has not previously been approved148 # Flagging an item which has not previously been approved
148 # will hide that item.149 # will hide that item.
149 review = self.factory.makeReview()150 review = self.factory.makeReview()
151 stats_updated_orig = review.softwareitem.date_ratings_updated
152
150 self.assertFalse(review.hide)153 self.assertFalse(review.hide)
151 flagger = self.factory.makeUser()154 flagger = self.factory.makeUser()
152155
@@ -154,6 +157,9 @@
154 flagger, 'Offensive language', "The word 'blue' is offensive.")157 flagger, 'Offensive language', "The word 'blue' is offensive.")
155158
156 self.assertTrue(review.hide)159 self.assertTrue(review.hide)
160 # The stats were updated for the software item.
161 self.assertNotEquals(
162 stats_updated_orig, review.softwareitem.date_ratings_updated)
157163
158 def test_flag_does_not_hide_approved_items(self):164 def test_flag_does_not_hide_approved_items(self):
159 # Flagging an item which has been previously approved does not165 # Flagging an item which has been previously approved does not
@@ -161,6 +167,7 @@
161 review_moderation = self.factory.makeReviewModeration(167 review_moderation = self.factory.makeReviewModeration(
162 status=ReviewModeration.APPROVED_STATUS, num_flags=0)168 status=ReviewModeration.APPROVED_STATUS, num_flags=0)
163 review = review_moderation.review169 review = review_moderation.review
170 stats_updated_orig = review.softwareitem.date_ratings_updated
164 flagger = self.factory.makeUser()171 flagger = self.factory.makeUser()
165 self.assertFalse(review.hide)172 self.assertFalse(review.hide)
166173
@@ -168,6 +175,9 @@
168 flagger, 'Offensive language', "The word 'blue' is offensive.")175 flagger, 'Offensive language', "The word 'blue' is offensive.")
169176
170 self.assertFalse(review.hide)177 self.assertFalse(review.hide)
178 # The stats were not updated for the software item.
179 self.assertEquals(
180 stats_updated_orig, review.softwareitem.date_ratings_updated)
171181
172 def test_multiple_flag_ordering(self):182 def test_multiple_flag_ordering(self):
173 # When an object is flagged multiple times default ordering is183 # When an object is flagged multiple times default ordering is
@@ -233,6 +243,7 @@
233 # Moderating with approval unhides a review.243 # Moderating with approval unhides a review.
234 review_moderation = self.factory.makeReviewModeration(num_flags=1)244 review_moderation = self.factory.makeReviewModeration(num_flags=1)
235 review = review_moderation.review245 review = review_moderation.review
246 stats_updated_orig = review.softwareitem.date_ratings_updated
236 self.assertTrue(review.hide)247 self.assertTrue(review.hide)
237248
238 review_moderation.moderate(249 review_moderation.moderate(
@@ -241,11 +252,15 @@
241252
242 review = Review.objects.get(id=review.id)253 review = Review.objects.get(id=review.id)
243 self.assertFalse(review.hide)254 self.assertFalse(review.hide)
255 # The stats were updated for the software item.
256 self.assertNotEquals(
257 stats_updated_orig, review.softwareitem.date_ratings_updated)
244258
245 def test_moderate_rejection_hides_review(self):259 def test_moderate_rejection_hides_review(self):
246 # Moderating with rejection unhides a review.260 # Moderating with rejection unhides a review.
247 review_moderation = self.factory.makeReviewModeration(num_flags=0)261 review_moderation = self.factory.makeReviewModeration(num_flags=0)
248 review = review_moderation.review262 review = review_moderation.review
263 stats_updated_orig = review.softwareitem.date_ratings_updated
249 self.assertFalse(review.hide)264 self.assertFalse(review.hide)
250265
251 review_moderation.moderate(266 review_moderation.moderate(
@@ -253,6 +268,9 @@
253 "whatever")268 "whatever")
254269
255 review = Review.objects.get(id=review.id)270 review = Review.objects.get(id=review.id)
271 # The stats were updated for the software item.
272 self.assertNotEquals(
273 stats_updated_orig, review.softwareitem.date_ratings_updated)
256 self.assertTrue(review.hide)274 self.assertTrue(review.hide)
257275
258 def test_moderate_non_pending_moderation_errors(self):276 def test_moderate_non_pending_moderation_errors(self):
@@ -302,3 +320,32 @@
302 review_moderation.moderate, reviewer,320 review_moderation.moderate, reviewer,
303 ReviewModeration.APPROVED_STATUS, "Great.")321 ReviewModeration.APPROVED_STATUS, "Great.")
304322
323
324class SoftwareItemTestCase(TestCaseWithFactory):
325
326 def test_update_stats(self):
327 # Updating the stats calculates the average and total.
328 software_item = self.factory.makeSoftwareItem()
329 self.factory.makeReview(
330 software_item=software_item, rating="5")
331 self.factory.makeReview(
332 software_item=software_item, rating="3")
333
334 software_item.update_stats()
335
336 self.assertEqual('4.0', software_item.ratings_average)
337 self.assertEqual(2, software_item.ratings_total)
338
339 def test_update_stats_ignores_hidden(self):
340 # Updating the stats ignores hidden reviews.
341 software_item = self.factory.makeSoftwareItem()
342 self.factory.makeReview(
343 software_item=software_item, rating="5")
344 self.factory.makeReview(
345 software_item=software_item, rating="3", hide=True)
346
347 software_item.update_stats()
348
349 self.assertEqual('5.0', software_item.ratings_average)
350 self.assertEqual(1, software_item.ratings_total)
351

Subscribers

People subscribed via source and target branches