Merge lp:~elachuni/rnr-server/filter-reviews into lp:rnr-server
- filter-reviews
- Merge into trunk
Proposed by
Anthony Lenton
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Łukasz Czyżykowski | ||||
Approved revision: | 106 | ||||
Merged at revision: | 105 | ||||
Proposed branch: | lp:~elachuni/rnr-server/filter-reviews | ||||
Merge into: | lp:rnr-server | ||||
Diff against target: |
437 lines (+157/-65) 6 files modified
src/reviewsapp/api/handlers.py (+13/-5) src/reviewsapp/api/urls.py (+8/-7) src/reviewsapp/tests/test_handlers.py (+116/-45) src/reviewsapp/tests/test_rnrclient.py (+2/-0) src/reviewsapp/tests/test_utilities.py (+8/-6) src/reviewsapp/utilities.py (+10/-2) |
||||
To merge this branch: | bzr merge lp:~elachuni/rnr-server/filter-reviews | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ratings and Reviews Developers | Pending | ||
Review via email: mp+46815@code.launchpad.net |
Commit message
Description of the change
Overview
========
This branch implements the agreed solution from bug #688112 providing an optional 'version' argument when fetching reviews, and making all arguments to the reviews getter optional.
Details
=======
For fetching reviews you now have an additional 'version' component in the url that allows you to filter by version. Additionally, if the language, origin, distroseries or version are specified as "any", reviews for any value of that parameter will be retrieved.
See the comments in the bug for a full discussion.
This branch needs lp:~elachuni/rnr-server/rnrclient-filter-reviews to work correctly.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/reviewsapp/api/handlers.py' |
2 | --- src/reviewsapp/api/handlers.py 2011-01-10 19:15:32 +0000 |
3 | +++ src/reviewsapp/api/handlers.py 2011-01-19 19:59:08 +0000 |
4 | @@ -87,8 +87,8 @@ |
5 | ) |
6 | allowed_methods = ('GET',) |
7 | |
8 | - def read(self, request, language, origin, distroseries, package_name, |
9 | - page='1'): |
10 | + def read(self, request, language, origin, distroseries, version, |
11 | + package_name, page='1'): |
12 | # The %2F used for slashes is itself being quoted before reaching |
13 | # the handler. |
14 | software_item = urllib.unquote_plus(urllib.unquote_plus(package_name)) |
15 | @@ -96,10 +96,18 @@ |
16 | batch_size = settings.API_REVIEWS_PAGINATION |
17 | batch_start = batch_size * (int(page) - 1) |
18 | batch_end = batch_start + batch_size |
19 | + kwargs = { |
20 | + 'language': language, |
21 | + 'repository__distroseries': distroseries, |
22 | + 'repository__origin': origin, |
23 | + 'version': version, |
24 | + } |
25 | + kwargs = dict(item for item in kwargs.items() if item[1] != 'any') |
26 | return Review.objects.filter( |
27 | - repository__origin=origin, repository__distroseries=distroseries, |
28 | - softwareitem__package_name=package_name, softwareitem__app_name=appname, |
29 | - hide=False, language=language).order_by( |
30 | + softwareitem__package_name=package_name, |
31 | + softwareitem__app_name=appname, |
32 | + hide=False, |
33 | + **kwargs).order_by( |
34 | '-usefulness_percentage')[batch_start:batch_end] |
35 | |
36 | |
37 | |
38 | === modified file 'src/reviewsapp/api/urls.py' |
39 | --- src/reviewsapp/api/urls.py 2011-01-04 16:45:55 +0000 |
40 | +++ src/reviewsapp/api/urls.py 2011-01-19 19:59:08 +0000 |
41 | @@ -83,13 +83,14 @@ |
42 | submit_usefulness_resource, name='rnr-api-recommendations'), |
43 | |
44 | # gets the reviews (and ratings) for a given pkg/app |
45 | - # GET /1.0/en/ubuntu/+binary/lucid/gnome-games;sane/page/1/ |
46 | - # GET /1.0/en/ubuntu/+binary/lucid/2vcard/ |
47 | - url(r'^1.0/(?P<language>\w+)/(?P<origin>\w+)/(?P<distroseries>\w+)/' |
48 | - r'(?P<package_name>[\w%+.;-]+)/$', show_reviews_resource, |
49 | - name='rnr-api-reviews-for-package'), |
50 | - url(r'^1.0/(?P<language>\w+)/(?P<origin>\w+)/(?P<distroseries>\w+)/' |
51 | - r'(?P<package_name>[\w%+.;-]+)/page/(?P<page>\d+)/$', |
52 | + # GET /1.0/en/ubuntu/+binary/lucid/1:2.32.0-0ubuntu1/gnome-games;sane/page/1/ |
53 | + # GET /1.0/en/ubuntu/+binary/lucid/1:2.32.0-0ubuntu1/2vcard/ |
54 | + url(r'^1.0/(?P<language>\w+)/(?P<origin>\w+)/(?P<distroseries>\w+)/' |
55 | + r'(?P<version>[-\w+.:~]+)/(?P<package_name>[\w%+.;-]+)/$', |
56 | + show_reviews_resource, name='rnr-api-reviews-for-package'), |
57 | + url(r'^1.0/(?P<language>\w+)/(?P<origin>\w+)/(?P<distroseries>\w+)/' |
58 | + r'(?P<version>[-\w+.:~]+)/(?P<package_name>[\w%+.;-]+)/' |
59 | + r'page/(?P<page>\d+)/$', |
60 | show_reviews_resource, name='rnr-api-reviews-for-package'), |
61 | |
62 | # submits a new review for a given pkg/app |
63 | |
64 | === modified file 'src/reviewsapp/tests/test_handlers.py' |
65 | --- src/reviewsapp/tests/test_handlers.py 2011-01-04 16:42:36 +0000 |
66 | +++ src/reviewsapp/tests/test_handlers.py 2011-01-19 19:59:08 +0000 |
67 | @@ -148,12 +148,11 @@ |
68 | class ShowReviewsHandlerTestCase(TestCaseWithFactory): |
69 | def test_review_for_package(self): |
70 | review = self.factory.makeReview( |
71 | - software_item=self.factory.makeSoftwareItem('package_foo'), |
72 | - repository=self.factory.makeRepository('ubuntu', 'hardy'), |
73 | - language='de') |
74 | + software_item=self.factory.makeSoftwareItem('package_foo')) |
75 | handler = ShowReviewsHandler() |
76 | |
77 | - reviews = handler.read(None, 'de', 'ubuntu', 'hardy', 'package_foo') |
78 | + reviews = handler.read(None, 'any', 'any', 'any', 'any', |
79 | + 'package_foo') |
80 | |
81 | self.assertEqual(1, len(reviews)) |
82 | self.assertEqual(review, reviews[0]) |
83 | @@ -161,12 +160,10 @@ |
84 | def test_review_for_app(self): |
85 | review = self.factory.makeReview( |
86 | software_item=self.factory.makeSoftwareItem('package_foo', |
87 | - app_name='app_foo'), |
88 | - repository=self.factory.makeRepository('ubuntu', 'hardy'), |
89 | - language='en') |
90 | + app_name='app_foo')) |
91 | handler = ShowReviewsHandler() |
92 | |
93 | - reviews = handler.read(None, 'en', 'ubuntu', 'hardy', |
94 | + reviews = handler.read(None, 'any', 'any', 'any', 'any', |
95 | 'package_foo;app_foo') |
96 | |
97 | self.assertEqual(1, len(reviews)) |
98 | @@ -174,60 +171,134 @@ |
99 | |
100 | def test_review_for_language(self): |
101 | package = self.factory.makeSoftwareItem('package_foo') |
102 | - repo = self.factory.makeRepository('ubuntu', 'hardy') |
103 | review1 = self.factory.makeReview(software_item=package, |
104 | - repository=repo, language='en') |
105 | + language='en') |
106 | review2 = self.factory.makeReview(software_item=package, |
107 | - repository=repo, language='de') |
108 | + language='de') |
109 | handler = ShowReviewsHandler() |
110 | |
111 | - reviews = handler.read(None, 'en', 'ubuntu', 'hardy', 'package_foo') |
112 | + reviews = handler.read(None, 'en', 'any', 'any', 'any', |
113 | + 'package_foo') |
114 | |
115 | self.assertEqual(1, len(reviews)) |
116 | self.assertIn(review1, reviews) |
117 | self.assertNotIn(review2, reviews) |
118 | |
119 | + def test_review_for_any_language(self): |
120 | + package = self.factory.makeSoftwareItem('package_foo') |
121 | + repository = self.factory.makeRepository('ubuntu', 'hardy') |
122 | + review1 = self.factory.makeReview(software_item=package, |
123 | + language='en', repository=repository, version='1.0') |
124 | + review2 = self.factory.makeReview(software_item=package, |
125 | + language='de', repository=repository, version='1.0') |
126 | + handler = ShowReviewsHandler() |
127 | + |
128 | + reviews = handler.read(None, 'any', 'ubuntu', 'hardy', '1.0', |
129 | + 'package_foo') |
130 | + |
131 | + self.assertEqual(2, len(reviews)) |
132 | + self.assertIn(review1, reviews) |
133 | + self.assertIn(review2, reviews) |
134 | + |
135 | def test_review_from_distroseries(self): |
136 | package = self.factory.makeSoftwareItem('package_foo') |
137 | review1 = self.factory.makeReview(software_item=package, |
138 | + repository=self.factory.makeRepository('ubuntu', 'hardy')) |
139 | + review2 = self.factory.makeReview(software_item=package, |
140 | + repository=self.factory.makeRepository('ubuntu', 'lucid')) |
141 | + handler = ShowReviewsHandler() |
142 | + |
143 | + reviews = handler.read(None, 'any', 'any', 'hardy', 'any', |
144 | + 'package_foo') |
145 | + |
146 | + self.assertEqual(1, len(reviews)) |
147 | + self.assertIn(review1, reviews) |
148 | + self.assertNotIn(review2, reviews) |
149 | + |
150 | + def test_review_from_any_distroseries(self): |
151 | + package = self.factory.makeSoftwareItem('package_foo') |
152 | + review1 = self.factory.makeReview(software_item=package, |
153 | repository=self.factory.makeRepository('ubuntu', 'hardy'), |
154 | - language='en') |
155 | + language='en', version='+-1') |
156 | review2 = self.factory.makeReview(software_item=package, |
157 | repository=self.factory.makeRepository('ubuntu', 'lucid'), |
158 | - language='en') |
159 | + language='en', version='+-1') |
160 | handler = ShowReviewsHandler() |
161 | |
162 | - reviews = handler.read(None, 'en', 'ubuntu', 'hardy', 'package_foo') |
163 | + reviews = handler.read(None, 'en', 'ubuntu', 'any', '+-1', |
164 | + 'package_foo') |
165 | |
166 | - self.assertEqual(1, len(reviews)) |
167 | + self.assertEqual(2, len(reviews)) |
168 | self.assertIn(review1, reviews) |
169 | - self.assertNotIn(review2, reviews) |
170 | + self.assertIn(review2, reviews) |
171 | |
172 | def test_review_from_origin(self): |
173 | package = self.factory.makeSoftwareItem('package_foo') |
174 | review1 = self.factory.makeReview(software_item=package, |
175 | + repository=self.factory.makeRepository('ubuntu', 'hardy')) |
176 | + review2 = self.factory.makeReview(software_item=package, |
177 | + repository=self.factory.makeRepository('debian', 'lenny')) |
178 | + handler = ShowReviewsHandler() |
179 | + |
180 | + reviews = handler.read(None, 'any', 'ubuntu', 'any', 'any', |
181 | + 'package_foo') |
182 | + |
183 | + self.assertEqual(1, len(reviews)) |
184 | + self.assertIn(review1, reviews) |
185 | + self.assertNotIn(review2, reviews) |
186 | + |
187 | + def test_review_from_any_origin(self): |
188 | + package = self.factory.makeSoftwareItem('package_foo') |
189 | + review1 = self.factory.makeReview(software_item=package, |
190 | repository=self.factory.makeRepository('ubuntu', 'hardy'), |
191 | - language='en') |
192 | - review2 = self.factory.makeReview(software_item=package, |
193 | - repository=self.factory.makeRepository('debian', 'lenny'), |
194 | - language='en') |
195 | - handler = ShowReviewsHandler() |
196 | - |
197 | - reviews = handler.read(None, 'en', 'ubuntu', 'hardy', 'package_foo') |
198 | + language='en', version='vanilla') |
199 | + review2 = self.factory.makeReview(software_item=package, |
200 | + repository=self.factory.makeRepository('debian', 'hardy'), |
201 | + language='en', version='vanilla') |
202 | + handler = ShowReviewsHandler() |
203 | + |
204 | + reviews = handler.read(None, 'en', 'any', 'hardy', 'vanilla', |
205 | + 'package_foo') |
206 | + |
207 | + self.assertEqual(2, len(reviews)) |
208 | + self.assertIn(review1, reviews) |
209 | + self.assertIn(review2, reviews) |
210 | + |
211 | + def test_review_for_version(self): |
212 | + package = self.factory.makeSoftwareItem('package_foo') |
213 | + review1 = self.factory.makeReview(software_item=package, |
214 | + version='0.2') |
215 | + review2 = self.factory.makeReview(software_item=package, |
216 | + version='0.3') |
217 | + handler = ShowReviewsHandler() |
218 | + |
219 | + reviews = handler.read(None, 'any', 'any', 'any', '0.2', |
220 | + 'package_foo') |
221 | |
222 | self.assertEqual(1, len(reviews)) |
223 | self.assertIn(review1, reviews) |
224 | self.assertNotIn(review2, reviews) |
225 | |
226 | + def test_review_for_any_version(self): |
227 | + package = self.factory.makeSoftwareItem('package_foo') |
228 | + repository = self.factory.makeRepository('ubuntu', 'hardy') |
229 | + review1 = self.factory.makeReview(software_item=package, |
230 | + language='en', repository=repository, version='1.0') |
231 | + review2 = self.factory.makeReview(software_item=package, |
232 | + language='en', repository=repository, version='2.0') |
233 | + handler = ShowReviewsHandler() |
234 | + |
235 | + reviews = handler.read(None, 'en', 'ubuntu', 'hardy', 'any', |
236 | + 'package_foo') |
237 | + |
238 | + self.assertEqual(2, len(reviews)) |
239 | + self.assertIn(review1, reviews) |
240 | + self.assertIn(review2, reviews) |
241 | + |
242 | def test_review_sorting(self): |
243 | package = self.factory.makeSoftwareItem('pkg_foo') |
244 | - repository = self.factory.makeRepository('ubuntu', 'hardy') |
245 | - review1 = self.factory.makeReview(software_item=package, |
246 | - repository=repository, |
247 | - language='en') |
248 | - review2 = self.factory.makeReview(software_item=package, |
249 | - repository=repository, |
250 | - language='en') |
251 | + review1 = self.factory.makeReview(software_item=package) |
252 | + review2 = self.factory.makeReview(software_item=package) |
253 | showHandler = ShowReviewsHandler() |
254 | usefulnessHandler = SubmitUsefulnessHandler() |
255 | |
256 | @@ -235,7 +306,8 @@ |
257 | request = Mock() |
258 | request.user = self.factory.makeUser() |
259 | usefulnessHandler.create(request, review2.id) |
260 | - reviews = showHandler.read(None, 'en', 'ubuntu', 'hardy', 'pkg_foo') |
261 | + reviews = showHandler.read(None, 'any', 'any', 'any', 'any', |
262 | + 'pkg_foo') |
263 | |
264 | self.assertEqual(2, len(reviews)) |
265 | # review2 is sorted first |
266 | @@ -246,31 +318,28 @@ |
267 | request.user = self.factory.makeUser() |
268 | usefulnessHandler.create(request, review1.id) |
269 | |
270 | - reviews = showHandler.read(None, 'en', 'ubuntu', 'hardy', 'pkg_foo') |
271 | + reviews = showHandler.read(None, 'any', 'any', 'any', 'any', |
272 | + 'pkg_foo') |
273 | |
274 | self.assertEqual(2, len(reviews)) |
275 | # review1 is sorted first |
276 | self.assertEquals(review1, reviews[0]) |
277 | |
278 | - def _make_5_reviews_for_package(self, package_name, origin='ubuntu', |
279 | - distro_series='lucid', language='en'): |
280 | + def _make_5_reviews_for_package(self, package_name): |
281 | package = self.factory.makeSoftwareItem(package_name) |
282 | - repository = self.factory.makeRepository( |
283 | - origin=origin, distro_series=distro_series) |
284 | - foo_reviews = [] |
285 | for count in range(5): |
286 | - foo_reviews.append(self.factory.makeReview( |
287 | - software_item=package, language=language, |
288 | - repository=repository)) |
289 | + self.factory.makeReview(software_item=package) |
290 | |
291 | - def _reviews_url_for_package(self, package_name, origin='ubuntu', |
292 | - distro_series='lucid', language='en', |
293 | + def _reviews_url_for_package(self, package_name, origin='any', |
294 | + distro_series='any', language='any', |
295 | + version='any', |
296 | page=None): |
297 | kwargs = { |
298 | 'language': language, |
299 | 'origin': origin, |
300 | 'distroseries': distro_series, |
301 | 'package_name': package_name, |
302 | + 'version': version, |
303 | } |
304 | if page is not None: |
305 | kwargs['page'] = page |
306 | @@ -423,7 +492,8 @@ |
307 | software_item = self.factory.makeSoftwareItem( |
308 | package_name=self.required_data['package_name'], |
309 | ratings_total=0, ratings_average=0) |
310 | - url_keys = ('language', 'origin', 'distroseries', 'package_name') |
311 | + url_keys = ('language', 'origin', 'distroseries', 'version', |
312 | + 'package_name') |
313 | url_kwargs = dict((key, self.required_data[key]) for key in url_keys) |
314 | url = reverse('rnr-api-reviews-for-package', kwargs=url_kwargs) |
315 | self.client.get(url) |
316 | @@ -484,7 +554,8 @@ |
317 | url_kwargs = dict(language=review.language, |
318 | origin=review.repository.origin, |
319 | distroseries=review.repository.distroseries, |
320 | - package_name=review.softwareitem.package_name) |
321 | + package_name=review.softwareitem.package_name, |
322 | + version=review.version) |
323 | url = reverse('rnr-api-reviews-for-package', kwargs=url_kwargs) |
324 | self.client.get(url) |
325 | key = cache_key_for_url(url) |
326 | |
327 | === modified file 'src/reviewsapp/tests/test_rnrclient.py' |
328 | --- src/reviewsapp/tests/test_rnrclient.py 2011-01-10 19:15:32 +0000 |
329 | +++ src/reviewsapp/tests/test_rnrclient.py 2011-01-19 19:59:08 +0000 |
330 | @@ -148,12 +148,14 @@ |
331 | distroseries=review.repository.distroseries, |
332 | packagename=review.package_name(), |
333 | appname=review.app_name(), |
334 | + version = review.version |
335 | ) |
336 | |
337 | self.assertEqual(1, len(reviews)) |
338 | self.assertEqual(review.package_name(), reviews[0].package_name) |
339 | self.assertEqual(review.app_name(), reviews[0].app_name) |
340 | self.assertEqual(review.summary, reviews[0].summary) |
341 | + self.assertEqual(review.version, reviews[0].version) |
342 | |
343 | def test_get_reviews_page_2(self): |
344 | # The rnr_client can get multiple pages of results. |
345 | |
346 | === modified file 'src/reviewsapp/tests/test_utilities.py' |
347 | --- src/reviewsapp/tests/test_utilities.py 2011-01-10 20:26:56 +0000 |
348 | +++ src/reviewsapp/tests/test_utilities.py 2011-01-19 19:59:08 +0000 |
349 | @@ -167,11 +167,12 @@ |
350 | |
351 | class InvalidatePaginatedReviewsTestCase(TestCaseWithFactory): |
352 | def _url_for_package(self, package_name, origin='ubuntu', |
353 | - distro_series='lucid', language='en', page=None): |
354 | + distro_series='lucid', language='en', version='1.0', page=None): |
355 | kwargs = { |
356 | 'language': language, |
357 | 'origin': origin, |
358 | 'distroseries': distro_series, |
359 | + 'version': version, |
360 | 'package_name': urllib.quote_plus(package_name), |
361 | } |
362 | if page is not None: |
363 | @@ -180,10 +181,10 @@ |
364 | return reverse('rnr-api-reviews-for-package', kwargs=kwargs) |
365 | |
366 | def _request_reviews_for_package(self, package_name, origin='ubuntu', |
367 | - distro_series='lucid', language='en', page=None): |
368 | + distro_series='lucid', language='en', version='1.0', page=None): |
369 | |
370 | url = self._url_for_package(package_name, origin, distro_series, |
371 | - language, page) |
372 | + language, version, page) |
373 | |
374 | with patch_settings(API_REVIEWS_PAGINATION=2): |
375 | response = self.client.get(url) |
376 | @@ -191,7 +192,7 @@ |
377 | return response |
378 | |
379 | def _populate_reviews_and_cache(self, package_name, origin='ubuntu', |
380 | - distro_series='lucid', language='en', pages=1): |
381 | + distro_series='lucid', language='en', version='1.0', pages=1): |
382 | package = self.factory.makeSoftwareItem(package_name) |
383 | repository = self.factory.makeRepository( |
384 | origin=origin, distro_series=distro_series) |
385 | @@ -201,8 +202,9 @@ |
386 | reviews = [] |
387 | for review_num in range(pages * 2): |
388 | reviews.append( |
389 | - self.factory.makeReview(software_item=package, language=language, |
390 | - repository=repository)) |
391 | + self.factory.makeReview(software_item=package, |
392 | + language=language, repository=repository, |
393 | + version=version)) |
394 | |
395 | # Now ensure the cache is populated by requesting each url. |
396 | self._request_reviews_for_package(package_name) |
397 | |
398 | === modified file 'src/reviewsapp/utilities.py' |
399 | --- src/reviewsapp/utilities.py 2011-01-12 18:50:58 +0000 |
400 | +++ src/reviewsapp/utilities.py 2011-01-19 19:59:08 +0000 |
401 | @@ -166,11 +166,18 @@ |
402 | |
403 | |
404 | def invalidate_paginated_reviews_for(review): |
405 | + # XXX achuni 2011-01-19: Here we're invalidating pages only for the exact |
406 | + # version, language, distroseries and origin of the review. We'd also |
407 | + # need to invalidate partial matches, up to including all reviews |
408 | + # for the package (/reviews/any/any/any/any/packagename/). This is |
409 | + # a lot of work. Is it worth it? |
410 | language = review.language |
411 | origin = review.repository.origin |
412 | distroseries = review.repository.distroseries |
413 | package_name = review.softwareitem.package_name |
414 | app_name = review.softwareitem.app_name |
415 | + version = review.version |
416 | + |
417 | if app_name: |
418 | package_app_name = "{0};{1}".format(package_name, app_name) |
419 | else: |
420 | @@ -180,7 +187,8 @@ |
421 | repository__origin=origin, repository__distroseries=distroseries, |
422 | softwareitem__package_name=package_name, |
423 | softwareitem__app_name=app_name, hide=False, |
424 | - language=language).count() |
425 | + language=language, |
426 | + version=version).count() |
427 | |
428 | # Ensure we've got a list of all the possible page numbers, |
429 | # including None (ie. first page is displayed if there is no page |
430 | @@ -190,7 +198,7 @@ |
431 | for page in pages: |
432 | url_kwargs = dict( |
433 | language=language, origin=origin, distroseries=distroseries, |
434 | - package_name=urllib.quote_plus(package_app_name)) |
435 | + version=version, package_name=urllib.quote_plus(package_app_name)) |
436 | if page: |
437 | url_kwargs['page'] = page |
438 |