Merge lp:~michael.nelson/ubuntu-webcatalog/788207-paginator into lp:ubuntu-webcatalog

Proposed by Michael Nelson
Status: Merged
Approved by: Łukasz Czyżykowski
Approved revision: 70
Merged at revision: 53
Proposed branch: lp:~michael.nelson/ubuntu-webcatalog/788207-paginator
Merge into: lp:ubuntu-webcatalog
Diff against target: 232 lines (+101/-26)
7 files modified
src/webcatalog/static/css/webcatalog.css (+3/-0)
src/webcatalog/templates/webcatalog/application_detail.html (+25/-0)
src/webcatalog/templates/webcatalog/application_review_list.html (+1/-16)
src/webcatalog/templates/webcatalog/application_review_list_snippet.html (+18/-0)
src/webcatalog/tests/test_views.py (+33/-1)
src/webcatalog/utilities.py (+10/-1)
src/webcatalog/views.py (+11/-8)
To merge this branch: bzr merge lp:~michael.nelson/ubuntu-webcatalog/788207-paginator
Reviewer Review Type Date Requested Status
Canonical ISD hackers Pending
Review via email: mp+75556@code.launchpad.net

Commit message

Load reviews snippet via ajax and add to details page.

Description of the change

Overview
========
Contrary to the name, this doesn't add pagination for the reviews - that can wait :), instead it adds the ajax reviews to the app details page.

Some points:
 * I removed the caching on the reviews view and added it to the rnr api call - so that we can provide different responses with the one view for normal and json requests.
 * I'm pulling in the YUI components from the local server (STATIC_URL) rather than from yui (I'll land the YUI code in the following branch)[1]
 * Using just io-base and node-base seems to result in 14 requests - I'm assuming we should update to use a combo loader (actually, I'll check to see if there's standard combos already provided)

Test: `fab bootstrap && fab test`

[1] https://code.launchpad.net/~michael.nelson/ubuntu-webcatalog/788207-add-YUI-resources/+merge/75695

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/webcatalog/static/css/webcatalog.css'
2--- src/webcatalog/static/css/webcatalog.css 2011-09-15 10:53:40 +0000
3+++ src/webcatalog/static/css/webcatalog.css 2011-09-16 09:53:23 +0000
4@@ -220,6 +220,9 @@
5 margin: 0;
6 float: none;
7 }
8+.reviews {
9+ padding: 16px;
10+}
11 .review {
12 margin: 8px 8px 16px 8px;
13 }
14
15=== modified file 'src/webcatalog/templates/webcatalog/application_detail.html'
16--- src/webcatalog/templates/webcatalog/application_detail.html 2011-09-15 10:53:40 +0000
17+++ src/webcatalog/templates/webcatalog/application_detail.html 2011-09-16 09:53:23 +0000
18@@ -4,6 +4,24 @@
19
20 {% block title %}Application {{ application.name }}{% endblock %}
21 {% block header %}Details for {{ application.name }}{% endblock %}
22+{% block head_extra %}
23+{{ block.super }}
24+<script src="{{ STATIC_URL }}yui/3.4.0/build/yui/yui-min.js"></script>
25+<script>
26+YUI().use('io-base', 'node-base', function (Y) {
27+ function complete(id, obj){
28+ var reviews_html = obj.responseText;
29+ var reviews_div = Y.one('#reviews_placeholder');
30+ reviews_div.set("innerHTML", reviews_html);
31+ };
32+ Y.on('io:complete', complete, Y);
33+
34+ // XXX michaeln 2011-09-16 bug=851660 Autoload further batches of results.
35+ var uri = "{% url wc-package-reviews application.distroseries.code_name application.package_name %}";
36+ Y.io(uri);
37+});
38+</script>
39+{% endblock %}
40
41 {% block content %}
42 {% include "webcatalog/breadcrumbs_snippet.html" %}
43@@ -56,5 +74,12 @@
44 </tr>
45 </table>
46 </div>
47+ <div class="reviews">
48+ <h2>{% trans "Reviews" %}</h2>
49+ <div id="reviews_placeholder">
50+ <a href="{% url wc-package-reviews application.distroseries.code_name application.package_name %}">
51+ {% blocktrans %}View the reviews for this app{% endblocktrans %}</a>
52+ </div>
53+ </div>
54 </div>
55 {% endblock %}
56
57=== modified file 'src/webcatalog/templates/webcatalog/application_review_list.html'
58--- src/webcatalog/templates/webcatalog/application_review_list.html 2011-09-15 10:53:40 +0000
59+++ src/webcatalog/templates/webcatalog/application_review_list.html 2011-09-16 09:53:23 +0000
60@@ -19,21 +19,6 @@
61 <h2>{{ application.name }}</h2>
62 <p>{{ application.comment }}</p>
63 </div>
64- {% for review in reviews %}
65- <div class="review">
66- <div class="meta">
67- <strong>{{ review.reviewer_displayname }}</strong>,
68- {{ review.date_created|slice:":10" }}
69- </div>
70- {% rating_summary review.rating %}
71- <strong>{{ review.summary }}</strong>
72- <p>{{ review.review_text }}</p>
73- <p class="usefulness">
74- {% blocktrans with favorable=review.usefulness_favorable total=review.usefulness_total %}
75- {{ favorable }} out of {{ total }} found this review helpful.
76- {% endblocktrans %}
77- </p>
78- </div>
79- {% endfor %}
80+ {% include "webcatalog/application_review_list_snippet.html" %}
81 </div>
82 {% endblock %}
83
84=== added file 'src/webcatalog/templates/webcatalog/application_review_list_snippet.html'
85--- src/webcatalog/templates/webcatalog/application_review_list_snippet.html 1970-01-01 00:00:00 +0000
86+++ src/webcatalog/templates/webcatalog/application_review_list_snippet.html 2011-09-16 09:53:23 +0000
87@@ -0,0 +1,18 @@
88+{% load i18n %}
89+{% load webcatalog %}
90+{% for review in reviews %}
91+ <div class="review">
92+ <div class="meta">
93+ <strong>{{ review.reviewer_displayname }}</strong>,
94+ {{ review.date_created|slice:":10" }}
95+ </div>
96+ {% rating_summary review.rating %}
97+ <strong>{{ review.summary }}</strong>
98+ <p>{{ review.review_text }}</p>
99+ <p class="usefulness">
100+ {% blocktrans with favorable=review.usefulness_favorable total=review.usefulness_total %}
101+ {{ favorable }} out of {{ total }} found this review helpful.
102+ {% endblocktrans %}
103+ </p>
104+ </div>
105+{% endfor %}
106
107=== modified file 'src/webcatalog/tests/test_views.py'
108--- src/webcatalog/tests/test_views.py 2011-09-15 10:53:40 +0000
109+++ src/webcatalog/tests/test_views.py 2011-09-16 09:53:23 +0000
110@@ -116,6 +116,15 @@
111
112 self.assertContains(response, 'action="apt://pkgfoo"')
113
114+ def test_link_to_package_reviews(self):
115+ response, app = self.get_app_and_response()
116+
117+ self.assertContains(response, '<a href="{0}"'.format(
118+ reverse('wc-package-reviews', args=[
119+ app.distroseries.code_name,
120+ app.package_name,
121+ ])))
122+
123 def test_button_for_non_puchase_app(self):
124 response, app = self.get_app_and_response()
125
126@@ -515,7 +524,10 @@
127 get_reviews_fn = 'rnrclient.RatingsAndReviewsAPI.get_reviews'
128 self.get_reviews_patcher = patch(get_reviews_fn)
129 self.mock_get_reviews = self.get_reviews_patcher.start()
130- self.mock_get_reviews.return_value = []
131+ eg_review = ReviewDetails.from_dict(
132+ dict(package_name='foo', summary='foo summary',
133+ rating='3.5'))
134+ self.mock_get_reviews.return_value = [eg_review]
135
136 def tearDown(self):
137 self.get_reviews_patcher.stop()
138@@ -566,5 +578,25 @@
139
140 self.assertTemplateUsed(
141 response, 'webcatalog/application_review_list.html')
142+ self.assertTemplateUsed(
143+ response, 'webcatalog/application_review_list_snippet.html')
144+ self.assertContains(response, 'review_summary1')
145+ self.assertContains(response, 'review_summary2')
146+
147+ def test_renders_reviews_only_for_json_request(self):
148+ app = self.factory.make_application()
149+ self.mock_get_reviews.return_value = [
150+ self.make_review_details(summary='review_summary1'),
151+ self.make_review_details(summary='review_summary2'),
152+ ]
153+
154+ response = self.client.get(reverse('wc-package-reviews',
155+ args=[app.distroseries.code_name, app.package_name]),
156+ HTTP_X_REQUESTED_WITH='XMLHttpRequest')
157+
158+ self.assertTemplateNotUsed(
159+ response, 'webcatalog/application_review_list.html')
160+ self.assertTemplateUsed(
161+ response, 'webcatalog/application_review_list_snippet.html')
162 self.assertContains(response, 'review_summary1')
163 self.assertContains(response, 'review_summary2')
164
165=== modified file 'src/webcatalog/utilities.py'
166--- src/webcatalog/utilities.py 2011-09-15 08:58:19 +0000
167+++ src/webcatalog/utilities.py 2011-09-16 09:53:23 +0000
168@@ -34,6 +34,7 @@
169 from httplib2 import ServerNotFoundError
170
171 from django.conf import settings
172+from django.core.cache import cache
173
174 from lazr.restfulclient.authorize import BasicHttpAuthorizer
175 from lazr.restfulclient.authorize.oauth import OAuthAuthorizer
176@@ -95,8 +96,16 @@
177 return RatingsAndReviewsAPI(service_root=settings.RNR_SERVICE_ROOT)
178
179 def get_reviews_for_package(self, package_name, distroseries, page=1):
180- return self.rnr_api.get_reviews(packagename=package_name,
181+ key = 'get_reviews_for_package-{0}-{1}-{2}'.format(
182+ package_name, distroseries, page)
183+ cached_reviews = cache.get(key)
184+ if cached_reviews is not None:
185+ return cached_reviews
186+
187+ fresh_reviews = self.rnr_api.get_reviews(packagename=package_name,
188 distroseries=distroseries, page=page)
189+ cache.set(key, fresh_reviews, settings.REVIEWS_CACHE_TIMEOUT)
190+ return fresh_reviews
191
192 def _fake_validate_token(self, token, openid_identifier, signature):
193 """ This is a version of validate_token that gets the
194
195=== modified file 'src/webcatalog/views.py'
196--- src/webcatalog/views.py 2011-09-15 11:25:35 +0000
197+++ src/webcatalog/views.py 2011-09-16 09:53:23 +0000
198@@ -35,7 +35,6 @@
199 render_to_response,
200 )
201 from django.template import RequestContext
202-from django.views.decorators.cache import cache_page
203
204 from webcatalog.models import (
205 Application,
206@@ -179,15 +178,19 @@
207 request, atts))
208
209
210-@cache_page(settings.REVIEWS_CACHE_TIMEOUT)
211 def application_reviews(request, package_name, distro, page=1):
212 app = get_object_or_404(Application, package_name=package_name,
213 distroseries__code_name=distro)
214- # XXX michaeln 2011-09-15 Don't request reviews for all languages.
215+ # XXX michaeln 2011-09-15 bug=851662 Better review language options.
216 reviews = WebServices().get_reviews_for_package(package_name,
217 distroseries=distro, page=page)
218- return render_to_response(
219- 'webcatalog/application_review_list.html', RequestContext(
220- request, dict(
221- application=app, distroseries=distro, reviews=reviews,
222- breadcrumbs=app.crumbs())))
223+
224+ context = dict(application=app, reviews=reviews)
225+ if request.is_ajax():
226+ template = 'webcatalog/application_review_list_snippet.html'
227+ else:
228+ context['distroseries'] = distro
229+ context['breadcrumbs'] = app.crumbs()
230+ template = 'webcatalog/application_review_list.html'
231+
232+ return render_to_response(template, RequestContext(request, context))

Subscribers

People subscribed via source and target branches